Struts2里的Action

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

Action

一、Action基础

Action是什么
  1. 在Struts2中一个Action类就代表一次请求或者调用,每个请求的动作都对应于一个相应的Action,一个Action类是一个独立的工作单元。
  2. Action就是用来处理请求对象的,相当于Servlet中的Servlet类。
  3. 在MVC模式中充当着模型的角色。
Action的基本配置
  1. 不管Action采用何种实现方式,要正确运行,都需要在Struts.xml中进行配置,这是使用Action的基础。
    package struts2.com.test;
    
    import com.opensymphony.xwork2.Action;
    
    public class HellowordAction implements {
    		public String execute() {
    				return "success";
    		}
     }
    
    

    struts.xml的配置
    <struts>
     <package name="verify" extends="struts-default">
         <action name="registerAction" class="struts2.com.test.HellowordAction">
            ....
         </action>
     </package>
    </struts>
    

    class的值为Action类的全路径名:一个类的全路径名=这个类的包名+“.”+类名。

二、Action的实现

POJO的实现
  1. 在Struts2中,Action可以不实现任何特殊的接口或者继承特殊的类,仅仅是一个POJO就可以,但是要有一个公共的为空的构造方法,其实缺省的构造方法就可以了,还要有一个execute方法,格式如下:
    public String execute() throws Exception{
        ....
    }
    

    • 可见的修饰符public
    • 不需要传入参数
    • 返回一个字符串
    • 可以抛出异常,也可以不抛出。
  2. 实际上我们在书写Action类的时候一般会继承ActionSupport类或者实现Action接口,因为他们为我们封装了一些方法和常量,可以让我们更简单更好的开发功能。具体的方法和字段可以查看struts2的官方帮助文档。
  3. POJO实质上可以理解为简单的实体类,顾名思义POJO类的作用是方便程序员使用数据库中的数据表,对于广大的程序员,可以很方便的将POJO类当做对象来进行使用,当然也是可以方便的调用其get,set方法。POJO类也给我们在struts框架中的配置带来了很大的方便。
继承ActionSupport类
  1. 由于Xwork的Action接口非常简单,为程序员提供的帮助有限,因此,在实际开发中我们都会使用继承ActionSupport类来实现Action的方式。
    import com.opensymphony.xwork2.ActionSupport;
    public class ActionSupport_1 extends ActionSupport {
    .....
    }
    

    • 本身实现了Action接口,所以继承ActionSupport相当于实现Action接口
    • ActionSupport也提供了很多新的方法。
  2. 示例基本的数据验证
    • 要实现数据验证的功能,只需要在Action类中重写vaildate方法即可:在该方法内部进行校验,如果不满足要求,则提示。我这里只用到校验密码,所以只写了密码
      • 提交页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登陆验证</title>
    </head>
    <body>
    <form action="action_1" >
        <input type="password" name="password" placeholder="请输入密码">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    

    • Action类
     package struts2.com.test;
    
     import com.opensymphony.xwork2.ActionSupport;
    
     public class ActionSupport_1 extends ActionSupport {
    
    		private String password;
    
    		public String getPassword() {
    				return password;
    		}
    
    		public void setPassword(String password) {
    				this.password = password;
    		}
    
    		@Override
    		public String execute() throws Exception {
    				System.out.println("登陆成功");
    				return SUCCESS;
    		}
    
    		@Override
    		public void validate() {
    				if (password == null || password.trim().length() == 0)
    						this.addFieldError("passwordmsg", "密码为空");
    				if (password.trim().length() < 6)
    						this.addFieldError("passwordmsg", "密码长度必须大于6位");
    		}
    
    }
    
    

    
    

    如果验证结果不符合要求,那么使用父类提供的addFieldError方法来添加验证的错误信息。addFieldError方法有两个参数,前面是key,后边是具体消息。
    • validate方法没有返回值,那么当验证后,如果有数据没有通过验证,该返回到什么页面呢?
      • 这就需要在struts.xml中的Action配置中,添加一个input的result配置,也就是说当有数据没有通过验证即调用了addFieldError方法,这时就会自动陶砖回到该action标签中名称为input的result所配置的页面。
       <action name="action_1" class="struts2.com.test.ActionSupport_1">
            <!--suppress Struts2ModelInspection -->
            <result name="success">hellowordactionsuccess.jsp</result>
            <!--suppress Struts2ModelInspection -->
            <result name="input">hellowordactionerror_1.jsp</result>
        </action>
      

      • 从以上程序的运行后发现,当我们的请求调用该Action时会先调用validate方法,当该方法运行结束后,调用Action的运行环境就会去判断存放消息验证的集合,如果其中有值,那么就会直接跳转到名称为input所配置的页面上。所以我们在验证不通过的时候,execute方法中的语句时没有在控制台中输出的。
execute方法内部实现方式
  1. 书写一个Action类,我们可以使用书写一个简单的POJO,也可以是实现接口Action或者继承ActionSupport类,
  2. 这三种方式都会默认调用Action类里的execute方法(如果action标签中没有指定method属性),所以我们看看完整的Action是怎样工作的
    • 收集用户传递过来的数据,在执行execute方法之前,页面提交的值就会自动的对应到这些属性上,这个功能是拦截器做的,后面会讲到拦截器。
    • 把收集到的数据组织成为逻辑层需要的类型和格式。
    • 调用逻辑层接口,来执行业务逻辑处理。
    • 准备下一个页面所需要展示的数据,存放在相应的地方。
    • 转向下一个页面。

三、Action的数据

基本的数据对应方式
  1. 在struts2中,页面数据和Action有两种基本对应方式,分别是:属性驱动和模型驱动。
  2. 属性驱动又有两种情况:一种基本数据类型的属性对应;另一种是JavaBean风格的属性对应。为了区分它们,我们称其为:"基本数据类型的属性对应",为属性驱动,而"JavaBean风格的属性对应"为直接使用域对象。
    1. 属性驱动FieldDriven(基本数据类型的数据对应)


      • 基本数据类型的属性对应,就是web页面上提交的属性name的值和Action的属性或者与属性相应的getter、setter相对应,这种做法就是基本数据类型的属性对应的属性驱动。比如:
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>登陆验证</title>
      </head>
      <body>
      <form action="action_1" >
          <input type="password" name="password" placeholder="请输入密码">
          <input type="submit" value="提交">
      </form>
      </body>
      </html>
      

       package struts2.com.test;
      
       import com.opensymphony.xwork2.ActionSupport;
      
       public class ActionSupport_1 extends ActionSupport {
      
      	private String password;
      
      	public String getPassword() {
      			return password;
      	}
      
      	public void setPassword(String password) {
      			this.password = password;
      	}
      
      	@Override
      	public String execute() throws Exception {
      			System.out.println("登陆成功");
      			return SUCCESS;
      	}
      }
      

      如果用户不想为每个属性都提供setter/getter方法,那么可以将字段设置为public修饰的,这样我们就能不使用set/get方法赖访问这些数据了,但是在实际的开发中我们要更好的实现封装,隐藏类的实现细节,我们最好使用private来修饰自己的属性。(我在后面的开发时发现idea中如果类的属性设置为public修饰,在jsp页面中的name属性会显示为红色,但是测试是可以使用的,没有错误)

    2. 属性驱动(域对象属性的对应)


      • 当我们要传入多个数据的话,那么Action里面的属性也就要变多,而且每次处理一次不同的请求即不同的Action都要创建这些属性字段,所以我们可以将这些属性字段封装在一个用户类中,这个类就是用来封装这些数据的,然后再Action类中使用这个对象就好,比如:
        • 用户对象
          package struts2.com.verify;
          
          /**
           * 用户注册
           */
          public class UserMode {
          	private String name;//姓名
          	private int age;//年龄
          	private String account;//账号
          
          	public String getName() {
          			return name;
          	}
          
          	public void setName(String name) {
          			this.name = name;
          	}
          
          	public int getAge() {
          			return age;
          	}
          
          	public void setAge(int age) {
          			this.age = age;
          	}
          
          	public String getAccount() {
          			return account;
          	}
          
          	public void setAccount(String account) {
          			this.account = account;
          	}
          
          	@Override
          	public String toString() {
          			return "name=" + name + ",age=" + age + ",account=" + account;
          	}
          }
          
          
        • Action对象
          package struts2.com.verify;
          
            import com.opensymphony.xwork2.ActionSupport;
          
            public class RegisterAction extends ActionSupport {
          
          	private UserMode userMode = new UserMode();
          
          	@Override
          	public String execute() throws Exception {
          			System.out.println("传入的数据为=" + userMode);
          			return SUCCESS;
          	}
          
          	public UserMode getUserMode() {
          			return userMode;
          	}
            }      
          

          • 登陆界面
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <%@ taglib prefix="s" uri="/struts-tags" %>
          <html>
          <head>
              <title>注册</title>
          </head>
          <body>
          用户注册
          <hr>
          <s:form  action="registerAction" method="POST">
          
              <s:textfield name="userMode.account" label="账号"/>
              <s:textfield name="userMode.name" label="姓名"/>
              <s:textfield name="userMode.age" label="年龄"/>
              <s:submit value="提交"/>
              <s:reset value="重置"/>
          </s:form>
          </body>
          </html>
          

          • struts.xml
          <action name="registerAction" class="struts2.com.verify.RegisterAction">
          <result name="success">registerSuccess.jsp</result>
          </action>
          

          • 成功页面,获取信息
          <s:property value="userMode.name" />
          

          • 控制台输出
          传入的数据为=name=李宁,age=18,account=123456
          
    3. 模型驱动


      • 这种数据对应的方式是让Action实现一个ModelDriven的接口,这个接口需要我们实现一个geyModel的方法,这个方法的返回就是Action所使用的数据模型对象。
        • Action类:
        package struts2.com.test;
        
        import com.opensymphony.xwork2.ActionSupport;
        import com.opensymphony.xwork2.ModelDriven;
        import struts2.com.verify.UserMode;
        
        public class ModelDriven_1 extends ActionSupport implements ModelDriven {
        		private UserMode userMode = new UserMode();
        
        		@Override
        		public String execute() throws Exception {
        				System.out.println("传入的数据为=" + userMode);
        				return SUCCESS;
        		}
        
        		@Override
        		public Object getModel() {
        				return userMode;
        		}
        }
        

        • 注册页面
        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
         <%@ taglib prefix="s" uri="/struts-tags" %>
         <html>
         <head>
             <title>注册</title>
         </head>
         <body>
         用户注册
         <hr>
         <s:form  action="modeldriven" method="POST">
             <s:textfield name="account" label="账号"/>
             <s:textfield name="name" label="姓名"/>
             <s:textfield name="age" label="年龄"/>
             <s:submit value="提交"/>
             <s:reset value="重置"/>
         </s:form>
         </body>
         </html>
        

        • struts.xml
         <action name="modeldriven" class="struts2.com.test.ModelDriven_1">
         <result name="success">../verify/registerSuccess.jsp</result>
         </action>
        

        • 注册成功页面,获取属性信息
        <s:property value="name" />
        

        • 控制台输出
        传入的数据为=name=李宁,age=14,account=123
        

      这里获取属性值和注册页面都不需要使用对象.属性名来获取值和传值,前面的两种方式都需要这样,因为使用ModelDriven的方式,一个Action只能对应一个Model,因此不需要添加前缀。


      • 两种驱动方式的优点和缺点:
        • 优点:基本数据类型的属性对应:简单,页面name和属性直接对应。缺点:导致Action零乱,功能不单一。
      • 直接使用域对象:
        • 优点:把模型数据从Action中分离出来,让Action专注于处理请求,使结构更加清晰;缺点:页面对应时必须要加Action中类对象这样的前缀,优点麻烦。
      • 模型驱动
        • 优点:把模型数据从Action中分离出来了,使程序结构清晰。而且页面不需要书写前缀;缺点:需要实现接口,而且把模型数据和Action做了绑定,这极大的限制了一个Action对应多数据模型的能力,当然也可以做到,就是在这个模型里面包含其他的数据模型。
处理多个传入值
传入一组数目不确定的字符串

我们将一组数据传入到同一个属性里去即用相同的name,然后再Action类里就会存在相同name值的字段名里存着这些提交的一组数据,那么我们获取的时候,只需要写上该字段的名称和遍历的下标就可以了。

  1. 比如我们使用checkbox类型的输入框
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>传入多个值</title>
</head>
<body>
<form action="collection.action">
    <input type="checkbox" name="habits" value="运动" >运动
    <input type="checkbox" name="habits" value="唱歌">唱歌
    <input type="checkbox" name="habits" value="跳舞">跳舞
    <input type="submit" value="提交">
</form>
<form action="collection.action">
    <input type="checkbox" name="list" value="唱" >唱
    <input type="checkbox" name="list" value="跳">跳
    <input type="checkbox" name="list" value="rap">rap
    <input type="submit" value="提交">
</form>
</body>
</html>
  1. Action类定义一个私有的数组或者集合。
package struts2.com.test;

import com.opensymphony.xwork2.ActionSupport;
import struts2.com.verify.UserMode;

import java.util.List;

public class CollectionAction extends ActionSupport {
		private String[] habits;
		private List<String> list;
		private List<UserMode> users;

		public List<UserMode> getUsers() {
				return users;
		}

		public void setUsers(List<UserMode> users) {
				this.users = users;
		}

		public List<String> getList() {
				return list;
		}

		public void setList(List<String> list) {
				this.list = list;
		}

		public String[] getHabits() {
				return habits;
		}

		public void setHabits(String[] habits) {
				this.habits = habits;
		}

		@Override
		public String execute() throws Exception {
				System.out.println(users);
				return SUCCESS;
		}
}
  1. 页面获取这些集合或者数组里的值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>获取集合的值</title>
</head>
<body>
1:<s:property value="habits[0]" /><br>
2:<s:property value="habits[1]" /><br>
3:<s:property value="habits[2]" /><br>
4:<s:property value="list[0]" /><br>
5:<s:property value="list[1]" /><br>
6:<s:property value="list[2]" /><br>
</body>
</html>

传入一组数目不确定的域对象

域对象也就是说这些数据对应的是一个类里面的字段,当我们传入的值是对应的一个类里面的字段时我们可以这样

  1. 页面数据提交
<form action="collection.action">
    <input type="checkbox" name="users.name" value="唱1" >唱1
    <input type="checkbox" name="users.age" value="11">11
    <input type="checkbox" name="users.account" value="rap1">rap1
    <input type="submit" value="提交">
</form>
  1. Action类就和上面的类一样。
  2. 获取数据
7:<s:property value="users" /><br>
8:<s:property value="users" /><br>
9:<s:property value="users" /><br>
10:<s:property value="users.account" /><br>
11:<s:property value="users.name" /><br>
12:<s:property value="users[0].age" />

这里的三个users是三个同一类的对象,这三个对象是不同的,我们要获取同一对象的值就要带上对象的下标,比如:users[0].age。这样我们才能取到同一对象里的数据。


Struts拥有自动类型转换的功能,比如前端页面请求的数据为String类型,但是Action类中对应的属性字段为int类型,那么struts的拦截器会自动转换成int类型的,保存在字段里。


三、Action的配置

<package>的配置
  1. <package>元素可以把逻辑上相关的一组Action、Result、Intercepter等元素封装起来,形成一个独立的模块,package可以继承其他的package,也可以作为父包被引用,<package name="verify" extends="struts-default">verify这个包就继承了struts-default这个包。
  2. package元素有如下属性:
    • name:包的名称。必须配置
    • extends:要继承的包,后面配置的是被继承的包的名称。可选,默认继承struts-default包
    • namespace:包的命名空间。可选
    • abstract:定义包为抽象的,也就是不能包含Action的定义。可选
    1. namespace
      • namespace配置的是包的命名空间,同一个命名空间里面不能有同名的Action。可以有效的防止action重名的冲突,因为配置了namespace后,在访问action的时候就需要添加namespace来作为action的前缀。
      • 如果不配置namespace,表示是默认的namespace,那么访问的时候就不需要添加了。
    2. abstract
      • abstract用来定义包为抽象的,也就是不能包含Action的定义,但是抽象包可以被其他包继承,因此这里面可以定义其他包需要的元素,比如:ResultType、Interceptor等。
<action>的配置
分模块配置
  1. 一个<struts>元素可以有多个<package>子元素
  2. 一个<package>元素可以有多个<action>子元素
  3. 我们常常会使用在struts.xml中引用其他的struts配置文件,这样的单独模块可以让文件更好维护比如:
    <include file="verify/sturts_verify.xml"/>
默认类配置方式
  1. 在配置struts.xml的时候,对于<action>元素来说,name是必须的,class属性可以省略,class属性的默认值是: com.opensymphony.xwork2.ActionSupport

四、Action的其他重要知识

Action的生命周期

Action不是在启动服务器的时候就初始化了,而是在当用户访问请求该Action的时候,才会被初始化,当请求结束后就会消失。而且每次请求都会创建一个对象,前面说过每个请求都会对应一个实例。

调用非execute方法
  1. 在前面说过当我们不想使用execute方法作为业务处理模型时,我们可以在action标签中配置method属性,来告诉struts找谁来处理业务。
  2. 在请求的url中直接指定的方式,也可以让我们不用配置method就能不使用execute方法赖处理业务。
<form action="helloword!create.action">

这里的.action可以不写,struts会自动添加的。

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看