把 Struts2 用熟练,日常围着两份文件转:struts.properties 管常量,struts.xml 管 package / action / result。这两份读明白,动态方法调用和参数绑定才不会晕。
下面按原笔记往下走:核心文件 → Action 按命名空间往上搜的顺序 → 三种动态方法调用 → 三种收参数方式。
一、struts 核心文件
1. struts.properties 常量
开发期常用的常量可以写在 struts.properties,也可以用 <constant> 写进 struts.xml,效果一样。
#是否开启开发模式
struts.devMode=true
#所有匹配 *.action 的请求都由 struts2 处理
struts.action.extension=do
#struts 配置文件改动后,是否重新加载
struts.configuration.xml.reload=true
#请求参数的编码方式
struts.i18n.encoding=UTF-8
#每次 HTTP 请求系统都重新加载资源文件,有助于开发
struts.i18n.reload=true
#文件上传最大值
struts.multipart.maxSize=102400
#设置上传文件临时目录
struts.multipart.saveDir=d:/temp
#让 struts2 支持动态方法调用
struts.enable.DynamicMethodInvocation=true
#允许标签中使用表达式语法
struts.tag.altSyntax=true
2. struts.xml 核心结构
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="packageName" namespace="/test" extends="struts-default">
<action name="actionName" class="com.ittx.struts.action.UserAction" method="methodName">
<result>/sucess.jsp</result>
<result name="ADD">/result.jsp</result>
</action>
</package>
</struts>
| 标签 |
作用 |
关键属性 |
| package |
把多个 Action 组织成一个模块 |
name、extends、namespace。namespace=/test 时访问地址是 http://localhost:8080/struts2/test/actionName.action |
| action |
定义访问名、类、方法及返回页 |
name、class、method |
| result |
指定响应类型和响应页面 |
name 对应 Action 返回值;type 不写则用父 package 默认 dispatcher |
更完整的 struts.xml 示例(include、拦截器栈、全局 result、param):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- include 是组件化方式:每个功能模块独立 xml,再用 include 引用 -->
<include file="struts-default.xml"></include>
<!--
package 的名字必须唯一;可以 extends 父 package,父 package 必须写在子 package 前面
abstract=true 时不能定义 action
namespace 影响 URL,例如 /test 对应 http://localhost:8080/struts2/test/XX.action
-->
<package name="com.kay.struts2" extends="struts-default" namespace="/test">
<interceptors>
<interceptor name="timer" class="com.kay.timer"></interceptor>
<interceptor name="logger" class="com.kay.logger"></interceptor>
<interceptor-stack name="mystack">
<interceptor-ref name="timer"></interceptor-ref>
<interceptor-ref name="logger"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 默认拦截器:每个 Action 自动引用;Action 里若另引拦截器,默认拦截器失效 -->
<default-interceptor-ref name="mystack"></default-interceptor-ref>
<global-results>
<result name="input">/error.jsp</result>
</global-results>
<!-- 一个 Action 可多次映射,只要 name 不同 -->
<action name="hello" class="com.kay.struts2.Action.LoginAction">
<interceptor-ref name="timer"></interceptor-ref>
<result name="success" type="dispatcher">/talk.jsp</result>
<!-- name 对应 Action 中的 get/set -->
<param name="url">http://www.sina.com</param>
</action>
</package>
</struts>
二、Action 搜索顺序
新建项目命名为 struts2,按下面配置一个 Action:
<package name="hello" namespace="/test" extends="struts-default">
<action name="helloworld" class="com.ittx.struts.action.HelloWorldAction" method="execute">
<result name="success">/hello.jsp</result>
</action>
</package>
部署后访问 http://localhost:8080/struts2/test/sdf/dsf/32/d/helloworld.action 依然能打到这个 Action。Struts2 会按命名空间逐级往上截来搜:
-
先找 namespace 为 /test/sdf/dsf/32/d 的包里有没有 helloworld
-
-
-
-
如果一路截完都不存在,就会到 namespace 为 ""(默认命名空间)的包里继续找 helloworld。
三、动态方法调用
一个 Action 要对应多个请求时,不必拆成一堆 Action 类。动态方法调用常见三种:method 属性、感叹号 !、通配符。
第一种:Action 的 method 属性
在 Action 里加 add()、update(),再在 xml 里用 method 指过去:
public class UserAction extends ActionSupport {
public String add() {
log.debug("执行add添加用户操作 >>>>>>");
return "ADD";
}
public String update() {
log.debug("执行update用户操作 >>>>>>");
return "UPDATE";
}
}
<action name="userAdd" class="com.ittx.strutsproject.action.UserAction" method="add">
<result name="ADD">/add_student.jsp</result>
</action>
<action name="userUpdate" class="com.ittx.strutsproject.action.UserAction" method="update">
<result name="UPDATE">/update_student.jsp</result>
</action>
-
添加:http://localhost:8080/struts2/userAdd.action
-
修改:http://localhost:8080/struts2/userUpdate.action
第二种:感叹号方式 !
方法不多时,method 属性还好写。若有上百个方法,xml 会膨胀。这时可以用 actionName!methodName:
<action name="user" class="com.ittx.strutsproject.action.UserAction">
<result>/sucess.jsp</result>
<result name="ADD">/add_student.jsp</result>
<result name="UPDATE">/update_student.jsp</result>
</action>
-
添加:http://localhost:8080/struts2/user!add.action
-
修改:http://localhost:8080/struts2/user!update.action
必须开启动态方法调用。Struts 2.5 还要在 package 下放开方法:
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- Struts 2.5 感叹号 / 通配符无效时,在 package 下加: -->
<global-allowed-methods>regex:.*</global-allowed-methods>
第三种:通配符方式
<package name="student" namespace="/student" extends="struts-default">
<!-- 解决 struts2.5 通配符调用无效 -->
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="user_*" class="com.ittx.strutsproject.action.UserAction" method="{1}">
<result>/sucess.jsp</result>
<result name="ADD">/add_student.jsp</result>
<result name="UPDATE">/update_student.jsp</result>
</action>
</package>
-
添加:http://localhost:8080/struts2/user_add.action
-
修改:http://localhost:8080/struts2/user_update.action
user_* 里的 {1} 会替换成第一段通配内容,于是 user_add 调 add()。
四、struts2 接收参数的几种形式
1. 用 Action 的属性
在 Action 里定义要接收的字段,提供 setter / getter,名称和提交参数一致,不用自己做类型转换。GET、POST 都可以,例如 testAction?name=admin。
<form action="./user_add.do" method="post">
姓名:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
<input type="submit" value="提交"/><br>
</form>
public class TestAction extends ActionSupport {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
2. 使用 DomainModel
Action 里不必堆很多属性,改为持有一个 Model 对象。表单字段写成 对象名.属性名。注意:不要自己 new,Struts 会自动实例化。
<form action="./user_add.do" method="post">
姓名:<input type="text" name="user.username"/><br>
密码:<input type="text" name="user.password"/><br>
<input type="submit" value="提交"/><br>
</form>
public class TestAction extends ActionSupport {
// 错误写法:不能自己实例化,struts 会自动实例化
// private Users users = new Users();
private Users users;
public Users getUsers() { return users; }
public void setUsers(Users users) { this.users = users; }
}
public class User {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
3. 使用 ModelDriven
Action 实现 ModelDriven,框架调用 getModel() 拿到对象。表单字段名直接写属性名,不必加对象前缀。这里要手动 new 模型。
<form action="./user_add.do" method="post">
姓名:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
<input type="submit" value="提交"/><br>
</form>
public class sysAction extends ActionSupport implements ModelDriven<User> {
private User user = new User(); // 手动实例化
public User getModel() {
return user; // 返回实例
}
}
一句话总结:struts.xml 把 URL 指到 Action;动态方法优先用通配符 user_* + method=”{1}”;收参数三种:Action 属性、DomainModel(别自己 new)、ModelDriven(要自己 new)。