<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="java">
学习了Struts2 中的Action,把常用到的地方记录下来。Struts2的Action在MVC的设计模式中充当了controller的角色,用于接受参数,处理部分逻辑等,相当于Servlet。其部分使用讲解如下:
一、Action的配置在struts.xml中进行Action的配置,具体可参看here。
二、Action的三种写法(Action都要在struts中配置映射)
1、自己编写普通的Java类来作为Action。
这里在类中只需要声明一个返回类型为String的public方法。
public void actionMethod(){
System.out.println("Action ActionMethod called!");
return success;
}
要注意的是,如果方法的名字不为execute,那么要在struts.xml中的action节点配置method属性(Action默认调用的方法)才可以调用到本方法,否则struts报找不到execute错误。
<action name="first" class="com.tas.strutslearn.Action1" method="<span style="font-family: Arial, Helvetica, sans-serif;">actionMethod</span>">
<result>/index.jsp</result>
</action>
2、编写Java类并实现com.opensymphony.xwork2.Action接口,然后重写execute方法。
package com.tas.strutslearn;
import com.opensymphony.xwork2.Action;
public class Action2 implements Action{
@Override
public String execute() throws Exception {
System.out.println("Action2 execute called!");
return SUCCESS;
}
}
3、编写Java类并继承com.opensymphony.xwork2.ActionSupport类,查看ActionSupport源码可知,本类实现了Action接口,并实现了一些其他的方法,所以在通常的使用中,会采取这种方法来编写Action。
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
public class Action3 extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.print("Action3 execute called!!");
return SUCCESS;
}
}
三、 Action的动态方法调用
如果一个Action中有多个方法,如下:
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
public class Action3 extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.print("Action3 execute called!!");
return SUCCESS;
}
public String delete(){
System.out.print("Action3 delete called!!");
return SUCCESS;
}
public String add(){
System.out.print("Action3 add called!!");
return SUCCESS;
}
}
那么如果指定调用哪个方法呢?以前我都是采用的在struts.xml中配置多个Action,用method区分的方法来实现:
<!-- 调用Action3的delete方法 -->
<action name="thirddelete" class="com.tas.strutslearn.Action3" method="delete">
<result>/index.jsp</result>
</action>
<!-- 调用Action3的add方法 -->
<action name="thirdadd" class="com.tas.strutslearn.Action3" method="add">
<result>/index.jsp</result>
</action>
在struts2中,还有一种方法可以实现,那就是“动态方法调用”,解决了一个Action有多个请求需要配置太多的问题。使用如下:
(1)在struts中配置常量
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
这个常量在struts2-core-2.3.4.jar/org.apache.struts2/default.properties中可以找到,发现其默认为true,所以这个常量一般不用配置(为false则关闭了动态方法调用)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICO4kTOzYjMwEzMyYDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
(2)访问时只需要在访问路径后+“!方法名”即可,如下:
如我这里访问http://localhost:8080/002_struts2.3.4_ActionUse/third!add就可以看到方法add被调用。
注意:我们知道,早package节点配置namespace属性的时候,如果配置成“/”或“”,则在访问的路径中action前加上什么都可以访问到如http://localhost:8080/002_struts2.3.4_ActionUse/sdfsdf/dsdf//third。可是如果在这些东西中有!的话,那么struts2会认为这是动态方法调用,就会报错。所以官网上边还是不推荐使用动态方法调用这种办法。好在2.3.4版本及以后版本修复了本bug,所以,如果你使用的是2.3.4版本以前的版本,请尽量不要使用动态方法调用。
四、Action使用通配符的访问方式
通过第三部分我们发现,方法太多的时候,使用单个method属性配置麻烦,使用动态方法调用的方式又可能不安全,struts2提供了第三种方法--通配符匹配访问。通配方式不用多说,就是按照顺序出现的*和后面的按顺序的数字相匹配。
(1)struts.xml如下
<action name="third_*" class="com.tas.strutslearn.Action3" method="{1}">
<result>/index.jsp</result>
</action>
访问时输入http://localhost:8080/002_struts2.3.4_ActionUse/third_delete。则访问了delete方法。
(2)struts.xml如下
<action name="*_*" class="com.tas.strutslearn.{1}" method="{2}">
<result>/index.jsp</result>
</action>
访问时输入http://localhost:8080/002_struts2.3.4_ActionUse/Action3_add则访问了add方法。
其他的匹配方式自己想想就可以写出来。
五、默认的Action
如果在浏览器上乱输入地址,如http://localhost:8080/002_struts2.3.4_ActionUse/sdfsfdsd/dfsdf,struts肯定会找不到“Action dfsdf的,这时,如果配置了默认的action,则不会报出错误,页面会跳转到默认的Action上边去。默认的action节点属性为<default-action-ref>
struts.xml
<default-action-ref name="error"></default-action-ref>
<action name="error">
<result>/error.jsp</result>
</action>
这样,当找不到action的时候就会跳转到error.jsp中去。 需要注意的是<default-action-ref> 节点必须放在error的前面(直接就作为namespace下的第一个节点吧),否则会报错。
六、Action的参数传递
这部分是struts2的重点。
(1)第一种方式是通过属性的驱动。
action写法如下:
package com.tas.strutslearn;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport{
private String username;
private String password;
private int age;
private Date birthday;
public void setUsername(String username) {
System.out.println("UserAction setUsername called!!");
this.username = username;
}
public void setPassword(String password) {
System.out.println("UserAction setPassword called!!");
this.password = password;
}
public void setAge(int age) {
System.out.println("UserAction setAge called!!");
this.age = age;
}
public void setBirthday(Date birthday) {
System.out.println("UserAction setBirthday called!!");
this.birthday = birthday;
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return super.execute();
}
public String getUser(){
System.out.println("username:"+username);
System.out.println("password:"+password);
System.out.println("age:"+age);
System.out.println("birthday:"+birthday);
return SUCCESS;
}
}
表单的写法如下:
<form action="/002_struts2.3.4_ActionUse/user_getUser" method="post">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="password"><br>
年 龄:<input type="text" name="age"><br>
生 日:<input type="text" name="birthday"><br>
<input type="submit" value="提交">
</form>
表单的元素的name属性一定要和Action中的属性名称一致。运行过程如下
可以看到其中的属性都是通过属性对应的set方法设置上去的,所以在Action中必须要写上属性的set方法。
(2)模型驱动
第一种通过属性驱动的方式,我们可以看到这种方式不利于软件项目的分层,面向对象的设计应该是尽量地将属性封装起来。
这种方式需要实现接口ModelDriven<User>,UserAction1.java(User类的创建省略):
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.tas.strutslean.entity.User;
public class UserAction1 extends ActionSupport implements ModelDriven<User>{
private User user;
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return super.execute();
}
public String getUserInf(){
System.out.println("username:"+user.getUsername());
System.out.println("password:"+user.getPassword());
System.out.println("age:"+user.getAge());
System.out.println("birthday:"+user.getBirthday());
return SUCCESS;
}
@Override
public User getModel() {
if(user==null){
user = new User();
}
return user;
}
}
user.jsp:
<form action="/002_struts2.3.4_ActionUse/user_getUserInf" method="post">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="password"><br>
年 龄:<input type="text" name="age"><br>
生 日:<input type="text" name="birthday"><br>
<input type="submit" value="提交">
</form>
由此可以发现,User对象的创建已交由getModel方法执行。
(3)现在问题来了,属性驱动麻烦,这种ModelDriver由只能实现一个对象的数据传递,所有都还是有缺陷,所以需要第三种方法:
UserBookAction.java:
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
import com.tas.strutslean.entity.Book;
import com.tas.strutslean.entity.User;
public class UserBookAction extends ActionSupport{
private User user;
private Book book;
public User getUser() {
System.out.println("UserBookAction getUser called!!");
return user;
}
public void setUser(User user) {
System.out.println("UserBookAction setUser called!!");
this.user = user;
}
public Book getBook() {
System.out.println("UserBookAction getBook called!!");
return book;
}
public void setBook(Book book) {
System.out.println("UserBookAction setBook called!!");
this.book = book;
}
public String getUserBookInf(){
System.out.println("username:"+user.getUsername());
System.out.println("password:"+user.getPassword());
System.out.println("age:"+user.getAge());
System.out.println("birthday:"+user.getBirthday());
System.out.println("author:"+book.getAuthor());
System.out.println("bookname:"+book.getBookname());
return SUCCESS;
}
}
表单:
<form action="/002_struts2.3.4_ActionUse/userbook" method="post">
用户名:<input type="text" name="user.username"><br>
密 码:<input type="password" name="user.password"><br>
年 龄:<input type="text" name="user.age"><br>
生 日:<input type="text" name="user.birthday"><br>
作 者:<input type="text" name="book.author"><br>
书 名:<input type="text" name="book.bookname"><br>
<input type="submit" value="提交">
</form>
运行程序如下:
通过结果我们可以发现struts给传递对象并封装的过程:是否存在对象--》不存在new一个--》赋值一个属性--》获取对象--》赋值第二个属性--》获取对象。。。。
补充:(1)我们并没有设置程序的编码为中文,可是我们表单提交上来的数据没有乱码,这个是怎么做到的呢?这个也是struts已经设置好了的,在default.properties(目录上面有图)中可以看到有常量struts.i18n.encoding=UTF-8。
(2)我们传递过来的参数只是String,可是到了后台却变成了int,Date等,这个也是由struts处理好了的。再也不用像Servlet里的那样,要request.getParameter()获取属性,然后再转换类型。
写完了,我现在好开心。