struts2最近又看了一边,每看一次都有一次的收获,这里总结struts2中的一些重要的知识点:
action介绍:
1:action类代表着一次请求或者调用,每个请求的动作都对应一个相应的action类,action是一个独立的工作单元
2:struts2中action充当着MVC中模型的角色,但是实际中其实action处理的是逻辑部分,和dispatcher共同担任了MVC中controler的角色,不同的是dispatcher担任的是业务部分
3:在struts2中,action可以不实现任何特殊的接口或者继承特殊的类,仅仅看成是一个pojo类,但是还有一个空参的execute方法
4:实现Action类,这个类中主要定义了一些常量
public abstract interface com.opensymphony.xwork2.Action {
// Field descriptor #4 Ljava/lang/String;
public static final java.lang.String SUCCESS = "success";
// Field descriptor #4 Ljava/lang/String;
public static final java.lang.String NONE = "none";
// Field descriptor #4 Ljava/lang/String;
public static final java.lang.String ERROR = "error";
// Field descriptor #4 Ljava/lang/String;
public static final java.lang.String INPUT = "input";
// Field descriptor #4 Ljava/lang/String;
public static final java.lang.String LOGIN = "login";
// Method descriptor #16 ()Ljava/lang/String;
public abstract java.lang.String execute() throws java.lang.Exception;
}
5:继承ActionSupport类,由于ActionSupport本身实现了Action接口,所以继承ActionSupport实际上就是相当于实现了Action接口,自定义的Action类继承了ActionSupport类的时候,通常需要重写execute()方法
6:ActionSupport类还实现了几个其他的接口,提供了更多的功能
#: com.opensymphony.xwork2.Validateable:提供validate()方法来为Action增加验证的功能
#: com.opensymphony.xwork2.Validateaware:提供方法来保存和恢复action或field级的错误信息
#: com.opensymphony.xwork2.TextProvider:提供获取本地信息文本的功能
#: com.opensymphony.xwork2.LocaleProvider:提供getLocale()方法来获取本地消息
7:execute方法的内部实现方式
execute方法在实际的开发中通常需要做下面的事情
7.1:收集用户传递过来的数据
7.2:把用户收集的数据组织成逻辑层需要的类型和格式
7.3:调用逻辑层接口,来执行业务逻辑处理
7.4:准备下一个页面中所需要展示的数据,存放在相应的地方
7.5:转向下一个页面
1. public class HelloWorldAction extends ActionSupport {
2. private String account;
3. private String password;
4. private String submitFlag;
5.
6. public String execute() throws Exception {
7. //收集参数 ,一般使用的是HttpServletRequest,一般只要页面中元素的名称和action中的属性相对应,会通过param拦截器自动的注入的
8. //组织参数 一般是数据组织成逻辑层的类型或格式就可以了
9. //调用逻辑层来进行逻辑处理,businessExecute方法中一般执行的是与数据库操作相关的
10. this.businessExecute();
11. //准备下一个页面所需要的数据 ,例如向跳转的中,显示XXX,你已登陆成功
12. //转向下一个页面,通过返回的result来告知跳到那个jsp页面或者action中的某个方法
13. return "toWelcome";
14. }
8:action中的数据来源
在struts2中,页面中的数据和action中的属性,有两种基本的对应方式,分别是,属性驱动(filedDriven)和模型驱动(ModelDriven)
属性驱动的两种情况:
1:基本类型的属性对应
2:javaBean风格的属性对应**
基本类型的属性驱动:
就是web页面中要提交的html控件的name属性,和action属性或者属性对应的getter/setter相对应,这种做法就是基本类型的属性对应的属性驱动(有点绕口,哈哈)
比如在登陆界面中这样写:
<form action="XXX" method="post">
<input type="text" name="userName"/><br/>
<input type="text" name="gender"/><br/>
<input type="submit" value="提交"/>
</form>
在action中是这样写的:
public class Demo extends ActionSupport{
//和页面上的input控件中的userName,以及gender相对应,并生成setter和gerter方法
//Ctrl + Alt +s 快速的找到生成个getter 和 setter方法
private String userName;
private String gender;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
这里的action中的userName 和 gender都是private 外界是不能访问的,所以生成setter/getter方法来设置值,当然你如果觉得为每个属性提供getter/setter方法比较累赘,那么你只需把userName和gender方法设置成public就可以了,但是一般不建议属性直接对外部开放
属性驱动(filedDriven):
如果action中的属性比较多,那么setter/getter方法将会特别多,造成代码特别的凌乱,我们可以把有相关联系的单独的提取出来做成一个javaBean类,例如刚才的userName和gender可以提成一个user对象中的属性
User.java
package javaBean;
public class User {
private String userName;
private String gender;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
新的action中Demo.action
public class Demo extends ActionSupport{
private User user= new User();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
当然了jsp也没中也要有相应的改动:
<form action="XXX" method="post">
<input type="text" name="User.userName"/><br/>
<input type="text" name="User.gender"/><br/>
<input type="submit" value="提交"/>
</form>
模型驱动ModelDriven:
struts2中海油另外的一种数据对应的方式叫做模型驱动,基本实现是让action实现一个ModelDriver的接口,这个接口需要我们实现一个genModel的方法,这个方法的返回值就是action所使用的数据模型对象
把刚才action中的代码修改成ModelDriven的实现方式,只是添加了ModelDriven的实现,另外去掉了Userde 的setter/getter方法,其他的基本不变
public class Demo extends ActionSupport implements ModelDriven{
private User user= new User();
public Object getModel(){
return user;
}
}
当然jsp页面中也许做一点改动的:
<form action="XXX" method="post">
<input type="text" name="userName"/><br/>
<input type="text" name="gender"/><br/>
<input type="submit" value="提交"/>
</form>
<!-- 去掉user这个前缀 ,因为一个action对应一个model,如果加上前缀,反而找不到属性了-->
到底该用哪个对应方式呢:
属性驱动(基本数据类型的属性对应),比较凌乱,对于属性比较少的只有一两个可以使用
javaBean属性对应,优先推荐这个
模型驱动:
这三种方式是可以混合使用的,甚至是三种方式可以一起使用,但是属性驱动(基本数据类型的属性)和模型驱动有可能发生冲突,因为都不带前缀,如果出现这种冲突的情况,那么优先模型驱动的对应方式。
Action的生命周期
Struts2的Action的生命周期是:Struts2为每个请求都重新初始化一个Action的实例。可以稍微改造一下代码来验证一下。
1:给HelloWorldAction加上一个public无参的构造方法,在里面输出一句话。
大家都知道,一个Java类如果没有写构造方法,那么会有一个默认的public无参的构造方法,这里只是把它明确的写出来了,因此这么做,并没有改变Action的任何功能,只是想看一下到底什么时候,Action会被初始化。示例代码如下:
1. public LoginAction (){
2. System.out.println("LoginAction被初始化");
3. }
2:然后在execute方法上也加入一个打印Action自己这个对象实例的语句,示例代码如下:
1. public String execute() throws Exception {
2. System.out.println(this);
3. this.businessExecute();
4. return "toWelcome";
5. }
在打印一个对象实例的时候,实际上是调用的这个类的toString方法,但是LoginAction类没有实现toString方法,所以,会调用到Object的toString方法。Object的toString方法会打印出自己的全类名和Object的hashcode方法的返回值,这个hashcode方法返回一个数字,只要这个数字不同,则被打印的对象就绝不是同一个对象。
修改做完之后,重新启动Tomcat,仔细察看后台的输出信息,你会发现启动的时候,并没有打印出来那句“LoginAction被初始化”,这说明了Action的初始化并不是在Tomcat启动的时候进行的。
我们提交表单并刷新再次提交,大家观察console上的输出。
“LoginAction被初始化”这句话被打印了两次,说明LoginAction对象的构造方法被调用了两次。
而且两次打印的toString分别是“login.LoginAction@922804”和“login.Login@18e8541”,这说明了为两次web请求服务的LoginAction对象不是同一个。
因此请记住,Struts2中的Action在每一次web请求的时候都要新建一个实例。