Struts 详细配置
<package name="default" extends="struts-default" namespace="/sys">
<action name="hello" class="com.idev.action.HelloAction" method="hello">
<result name="success" type="dispatcher">/index.jsp</result>
</action>
</package>
package: 表示包
name: 是自定义的,一般和模块名称相关,在整个项目中唯一。
extends: 表示继承 必须直接或者间接继承 struts-default,因为在 struts-default 中定义了 Struts2 的相关功能。
namespace: 表示命名空间,和分模块开发相关,分工协作时使用,直接决定请求的 URL 的匹配,一个请求的 URL 想要被 URL 匹配需要加上对应的namespace。
如: namespace="/user",该 namespace 下有一个 add 的 Action,那么要请求该 Action 的 URL 为 /user/add.action
action: 一个 action 对应一个请求,name 表示请求的 url 名称去掉后缀,在同一个包下唯一。
class: 表示处理请求的类的全名(包名+类名),如果不写默认为com.opensymphony.xwork2.ActionSupport。
method: 指明处理请求的方法名称,默认执行的是 execute 方法,处理方法 必须是 public String xxx(){}; 的无参方法。
result: 表示对结果的处理,其中 name 属性 必须和 action 中处理方法的返回值匹配,默认为 success。
Struts2 的 Action 接口提供了 5 个返回值类型。
Action.SUCCESS 表示处理方法执行成功
Action.NONE 表示处理方法执行成功 但是不需要视图显示。
Action.ERROR 表示处理方法执行失败
Action.INPUT 表示处理方法需要更多的输入信息才能执行成功。
Action.LOGIN 表示处理方法不能执行,需要用户登录
type: 表示结果集的跳转类型,默认是转发。
dispatcher 转发
redirect 重定向
redirectAction 跳转到另一个 Action
stream 流
/ 表示根路径
处理请求数据
在 Struts2 中可以有 3 种方式来接收请求提交的数据。属性驱动方式,对象驱动方式 ,模型驱动方式。
当不需要在处理类中获取对象时应该采用属性驱动。
当属性较少并且需要在处理类中获取对象时应该采用对象驱动方式。
当属性比较多,并且需要在处理类中获取对象应该采用模型驱动。
实际开发过程中还要根据团队的方式采用大家都使用的方式,保持团队一致。一般在对象驱动和模型驱动中选择。
属性驱动方式
要求页面表单项的名称和 Action 处理类的属性名一致。并且在 Action 处理类中提供与属性相对应的 get 和 set 方法。
这样在Action 处理方法中即可获取到表单中数据值了。如果是转发,也可以在页面中通过 EL 表达式把 Action 处理类的属性值获取到。
<input type="text" name="name"/>
public class UserAction {
private String name;
public String add(){
System.out.println(name);
msg="数据获取成功";‘
return Action.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
对象驱动方式
在 Action 处理类中获取对象,不需要程序员手动创建对象。这种方式需要在处理类中声明对象属性,在表单项的名称由 对象.对象属性 组成。
<input type="text" name="user.name"/>
public class UserAction {
private User user = new User();
public String add(){
System.out.println(user);
return Action.SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
模型驱动方式
在对象驱动方式上,可以实现在处理类中直接获取对象,但是对象驱动方式相比于属性驱动方式来说,页面的编写更为复杂,当属性非常多时,编写效率降低。
所以 Struts2 提供了模型驱动,模型驱动综合了属性驱动和对象驱动的优点,但是模型驱动具有侵入性。使用模型驱动处理类需要实现 ModelDriven 接口,重写 getModel() 方法。
<input type="text" name="name"/>
public class UserModelAction implements ModelDriven<User> {
private User user= new User();
public String add(){
System.out.println(user);
return Action.SUCCESS;
}
@Override
public User getModel() {
return user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Action 的配置优化
当一个 Action 处理类中处理多个业务时,Action 的配置文件将会急剧增加,导致配置文件比较臃肿的问题。Struts2 提供了 2 种方案来解决这个问题。
一种是 动态方法调用 ,另一种是使用 通配符 来配置 Action。
动态方法调用
1.开启动态方法调用
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
2. 请求时采用动态方法调用
请求方式: actionName!methodName[.action]
<action name="userAction" class="com.idev.action.UserAction">
<!-- 重定向 -->
<result type="redirect">userAction!list.action</result>
<result name="list">/list.jsp</result>
<result name="update">/update.jsp</result>
<result name="error">/error.jsp</result>
</action>
通配符配置
通过 * 通配符来简化 action 的配置。
* 表示匹配所有请求的 action 名。
{1} 表示匹配第一个 * 所代表的内容。
<action name="*" class="com.idev.action.UserAction" method="{1}">
<result type="redirectAction">list</result>
<result name="list">/list.jsp</result>
<result name="update">/update.jsp</result>
<result name="error">/error.jsp</result>
</action>
例如:
通过 http://localhost:8080/project/add.action?name=xxx 访问,此时 action 的 name="add",method="add";
ThreadLocal 和 ActionContext
Struts2 可以将表单中的数据自动设置到处理类的属性上,还有类型转换等其他功能。那么 Struts2 是如何去做到这件事情的呢?
Strtus2完成这些功能是由拦截器来完成,并且在这个过程中数据进行迁移的动作,数据从request对象中迁移到了处理类上。数据迁移是由 ActionContext 来完成的。
ThreadLocal
ThreadLocal 是一个容器,其中存放的数据是线程安全的。ThreadLocal 是一种典型以空间换时间的办法来做到线程安全。
public class ThreadLocalTest {
public static void main(String[] args) throws InterruptedException {
final ThreadLocal<Integer> t = new ThreadLocal<>();
//设置值
t.set(20);
new Thread(new Runnable() {
@Override
public void run() {
t.set(50);
System.out.println(Thread.currentThread().getName()+"===="+tl.get());
}
}).start();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"======"+tl.get());
}
}
ValueStack
它是一个接口 com.opensymphony.xwork2.util.ValueStack,同时是一个容器,主要用于携带 Action 数据到页面。在页面上通过 OGNL 表达式获取数据。
1. ValueStack 有一个实现类叫 OgnlValueStack。
2. 每一个 Action 都有一个 ValueStack.(一个 Request, 一个 Action, 一个 ValueStack)ValueStack 生命周期就是 Request 的生命周期。
3. ValueStack 中存储了当前 Action 对象以及其它常用 Web 对象(request, session, application, parameters)。
4. struts2 框架将 ValueStack 以 "struts.valueStack" 为名存储到 request 域中。
5. ValueStack 由两部分构成,root 属性(CompoundRoot) 和 context 属性(OgnlContext),并且context 中含有 root。
* CompoundRoot 是一个 ArrayList
* OgnlContext 是一个 Map
6. List 集合中存储的是 Action 相关信息,Map 集合中存储的是相关映射信息,包含 paramters, request, session, application, attr 等。
ActionContext
ActionContext 是 Action 处理类执行的上下文对象。ActionContext 是一个 Map 结构的对象,一个容器。ActionContext 是线程安全的。并且ActionContext 在 Struts2 执行过程中负责数据的存储。
ActionContext 是将 ServletAPI 中的数据进行了解耦,在 Action 执行过程中,Struts2 都是从 ActionContext 中获取数据。实现了线程安全,但降低了执行效率。
获取 Servlet API
在 Struts2 如果想要将用户登录数据存入四大作用域中。可以有两种方式来存。
一种解耦合方式,一种 耦合方式。
解耦合方式
通过 ActionContext 获取, 解耦合方式获取的都是 Map 对象。
好处在于方便测试,没有侵入性,ActionContext 可以不在 Servlet 容器环境中使用。
获取 Session,并设置属性。
Map<String,Object> session = ActionContext.getContext().getSession();
session.put("user", user);
获取 Request 和 Application
Map<String,Object> request = (Map<String, Object>) ActionContext.getContext().get("request");
Map<String,Object> application = ActionContext.getContext().getApplication();
耦合方式
耦合方式获取的都是 Servlet 对象
通过 ActionContext 获取
获取 HttpServletRequest 对象:
HttpServletRequest req = (HttpServletRequest)ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
HttpSession session = req.getSession();
session.setAttribute("user", user);
获取 HttpServletResponse 对象:
HttpServletResponse resp = (HttpServletResponse)ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE);
获取 ServletContext 对象:
ServletContext sc =(ServletContext)ActionContext.getContext().get(StrutsStatics.SERVLET_CONTEXT);
通过 ServletActionContext 获取
通过 ServletActionContext 获取相关对象
HttpServletRequest req = ServletActionContext.getRequest();
HttpServletResponse resp = ServletActionContext.getResponse();
HttpSession session = req.getSession();
ServletContext sc = ServletActionContext.getServletContext();
通过实现接口的方式来获取
public class UserAction4 implements ServletRequestAware{
private User user;
private HttpServletRequest req;
@Override
public void setServletRequest(HttpServletRequest request) {
this.req = request;
}
public String login(){
if("idev".equals(user.getName())) {
//通过 ServletActionContext 以耦合方式获取 ServletAPI 对象
HttpSession session = this.req.getSession();
session.setAttribute("currentUser", user);
return Action.SUCCESS;
}
return Action.LOGIN;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
OGNL 表达式
OGNL: (Object-Graph Navigation Language) 对象图导航语言
OGNL 将数据分为两类;常用的和不常用,大的和小的。
在 OGNL 中,把常用的数据放在根对象(root),不常用的数据放在 Context (上下文),是一个 Map;
public class OgnlTest {
public static void main(String[] args) throws OgnlException {
Map<String,Object> map = new HashMap<String,Object>();
map.put("address", "北京");
map.put("user", new User("张三","1111"));
User user = new User("idev","2222");
//OGNL 表达式获取根对象的数据 直接获取即可
System.out.println(Ognl.getValue("name", map, user));
//OGNL 表达式获取上下文对象 需要加 # 获取
System.out.println(Ognl.getValue("#address", map, user));
System.out.println(Ognl.getValue("#user.name", map, user));
}
}
//输出结果为: idev
北京
张三
通过 OGNL 表达式获取数据
Struts2 将 ActionContext 对象作为 OGNL 的上下文对象,ValueStack 作为 OGNL 的根对象。
ValueStack 是一个栈接口。称为值栈。在一个请求来时会创建一个 ValueStack,将 Action 的属性值放入值栈中。创建 Action 处理类后将值栈中的属性值设置到处理类上。Action 中的属性值会放入 ValueStack。在请求结束时ValueStack消亡。
在 Struts2 中使用 OGNL 表达式获取值,需要添加Struts2 的标签库,并且需要使用特定的标签来获取值。
1. 导入标签库
<%@taglib prefix="s" uri="/struts-tags" %>
2. 使用标签获取
从值栈中获取:
<s:property value="user.name"/>
从 ActionContext--session 中获取:
<s:property value="#session.user.name"/>
从 ActionContext--attr 中获取:
<s:property value="#attr.user.name"/>
从 ActionContext--parameters 中获取:
<s:property value="#parameters['user.name']"/>
自动类型转换
表单中提交的数据到 Servlet 后都是字符串类型,有时需要手动进行类型转换。但是到 Struts2 后,基本数据类型 Struts2 都可以自动转换。但是如果是自定义类型,Struts2 不能自动转换。
这个时候需要程序员进行手动转换或者使用 Struts2 提供的类型转换机制来实现。
使用 Struts2 的类型转换机制步骤:
1. 编写类型转换器,继承 StrutsTypeConverter,该类由 OGNL 调用
public class PointConverter extends StrutsTypeConverter{
/**
* 从 字符串 转换为 指定类型
* context 是 ActionContext
* values 是表单提交数据
* toClass 是要转换的类型
*/
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
String value = values[0]; //value="2,3"
Point point = new Point();
point.setX(Integer.parseInt(value.split(",")[0]));
point.setY(Integer.parseInt(value.split(",")[0]));
return point;
}
/**
* 从 指定类型 转换为 字符串
*/
@Override
public String convertToString(Map context, Object obj) {
Point point = (Point)obj;
return "("+point.getX()+","+point.getY()+")";
}
}
2. 编写类型转换器的配置文件
在 src 目录下创建全局的配置文件,名称为:
xwork-conversion.properties
为相关的类配置转换器:
com.idev.beans.Point=com.idev.converter.PointConverter
数据校验
编程方式
Struts2 提供了 2 种机制来进行后端数据的验证。一种是 编程方式,一种 验证框架。
通过编程方式来进行数据校验需要继承 ActionSupport 类。在 ActionSupport 类中有一个 validate 方法,该方法中用来实现数据校验。
在处理类的中重写 validate 方法。在 Action 的执行过程中,先执行validate 方法,再执行处理业务方法。
1. 在处理类中重写 validate 方法,并将验证的逻辑写在这个方法中。
public class UserAction extends ActionSupport{
private String name;
private String pwd;
/**
* 在validate方法中 进行数据校验
* 在validate方法中 如果没有添加错误信息,那么验证通过
*/
public void validate() {
if(name==null||name.length()<4){
//验证不通过
this.addFieldError("name", "输入的用户名不合法");
}
if(pwd==null||pwd.length()<6){
this.addFieldError("pwd", "输入的密码长度不合法");
}
}
@Override
public String execute() throws Exception {
System.out.println("执行execute");
System.out.println("name="+name);
System.out.println("pwd="+pwd);
return Action.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}, 土包子
}
2. 在action的配置中 加上结果为 input 的配置
<action name="add" class="com.idev.action.UserAction">
<result name="input">/add.jsp</result>
<result>/success.jsp</result>
</action>
3. 在jsp页面中需要使用struts2的<s:fieldError>标签显示错误信息。
<form action="add.action" method="post">
用户名:<input type="text" name="name"/>
<s:fielderror fieldName="name"></s:fielderror><br>
密码:<input type="password" name="pwd"/>
<s:fielderror fieldName="pwd"></s:fielderror><br>
年龄:<input type="text" name="age"/>
<s:fielderror fieldName="age"></s:fielderror><br>
<input type="submit" value="提交"/>
</form>
对编程方式的优化
当一个Action中处理方法比较多时,所有方法的验证都放入 validate 中将会不太合适。
如果有多个处理方法需要验证,那么需要为每个方法都添加其相对应的验证方法。规则为处理方法前加 validate 并且将处理方法的首字母大写。如:处理方法为 add,那么其验证方法 validateAdd( )。
这样在执行 add.action 时,会先执行 validateAdd( ),再执行 validate( ), 再执行 add( ),也就是说当一个 Action 处理类中有多个处理方法时,需要分别为每个方法添加对应的验证方法。
public class UserAction extends ActionSupport{
private String name;
private String pwd;
public void validateAdd(){
//校验逻辑代码
}
/**
* 在validate方法中 进行数据校验
* 在validate方法中 如果没有添加错误信息,那么验证通过
*/
public void validate() {
System.out.println("执行 validate 方法");
}
public String add() throws Exception {
System.out.println("执行 add ");
System.out.println("name="+name);
System.out.println("pwd="+pwd);
return Action.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
验证框架
由于验证数据的规则随着系统需求可能会发生变更。如果采用硬编码的方式来验证数据,那么规则发生改变时,需要从新编写代码。有可能会引入新的 Bug 进入系统。这种方式不是很好,所以 Struts2 除了编程验证外还提供了一种验证框架来进行数据校验。
Struts2 校验框架的使用:
1. 处理类继承 ActionSupport
2. 在 Action 所在包下提供一个验证配置文件,名称为:
actionName--validation.xml
3. 在配置文件中需要为每个表单域提供验证规则
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<!-- 一个field表示验证一个表单域 -->
<field name="name">
<!-- field-validator 表示验证器,Struts2提供了很多默认的验证器 -->
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>请输入用户名</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">4</param>
<param name="maxLength">10</param>
<message>用户名在${minLength}到${maxLength}之间</message>
</field-validator>
</field>
<field name="pwd">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>请输入密码</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<message>密码最少是6</message>
</field-validator>
</field>
<field name="age">
<field-validator type="required">
<message>必须输入年龄</message>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">256</param>
<message>年龄必须在1到256之间</message>
</field-validator>
</field>
</validators>
拦截器
Struts2 能完成数据的设置,数据封装,数据的类型转换,数据的校验等等。Struts2 是如何来完成这些功能的?Struts2 的所有功能都是由 拦截器 来完成的。
拦截器是 Struts2 的核心。拦截器是一个类似于过滤器的类。在执行 action 的处理方法前会先执行拦截器然后再执行 action 的处理方法,然后再执行拦截器。再响应。
拦截器是 单例 的,所有 action 执行的都是同一个拦截器。所以在自定义拦截器时要注意线程安全的问题,拦截器只拦截 action。
拦截器在 Struts2 中是可以自由配置和自由装配的。并且 Struts2 中拦截器是可以自定义的,所以如果 Struts2 没有提供项目所需功能时,可以通过自定义拦截器来实现,拦截器定义的位置在 struts-default.xml 中。
自定义拦截器
自定义拦截器有两种方式实现,一种实现Interceptor 接口,一种是继承 AbstractInterceptor 类来实现,两者类似,重写 intercept 方法即可。
1. 编写类,实现 Interceptor 接口
package com.idev.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class ActionExecuteTimeInterceptor implements Interceptor{
@Override
public void destroy() {}
@Override
public void init() {}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
long start = System.currentTimeMillis();
//执行下一个拦截器,如果下面没有拦截器则执行 action 的处理方法,并将结果返回。
String result = invocation.invoke();
System.out.println("执行时间为:"+(System.currentTimeMillis() - start));
return result;
}
}
2. 在 struts.xml 中配置拦截器
<interceptors>
<!-- 配置自定义拦截器 name 是唯一的, class 是自定义拦截器的完整类名-->
<interceptor name="executeTime" class="com.idev.interceptor.ActionExecuteTimeInterceptor"></interceptor>
</interceptors>
3. 在对应 action 中引用自定义拦截器
<package name="default" extends="struts-default" namespace="/">
<!-- 拦截器配置 -->
<interceptors>
<interceptor name="executeTime" class="com.idev.interceptor.ActionExecuteTimeInterceptor"></interceptor>
</interceptors>
<action name="add" class="com.idev.action.UserAction" method="add">
<result>/success.jsp</result>
<!-- 在action中引用自定义的拦截器 -->
<interceptor-ref name="executeTime"></interceptor-ref>
</action>
</package>
方法拦截器
方法拦截器是比拦截器粒度更细的拦截器,只拦截方法。通过配置方法拦截器可以有效提高系统性能。
1. 继承 MethodFilterInterceptor,重写 doIntercept 方法
//自定义方法拦截器
public class AddMethodInterceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("进入方法拦截器");
return invocation.invoke();
}
}
2. 配置方法拦截器
<interceptor name="addInterceptor" class="cn.sxt.interceptor.AddMethodInterceptor">
<!-- 配置哪些方法 需要被拦截 -->
<param name="includeMethods">add</param>
<!-- 排除哪些方法不被拦截
<param name="excludeMethods"></param> -->
</interceptor>
拦截器优化配置
手动引入 Struts2 的拦截器
如果引用了自定义拦截器,那么 Struts2 的拦截器将不再起作用。如果需要使用 Struts2 的拦截器需要手动引入。
<action name="add" class="com.idev.action.UserAction" method="add">
<result>/success.jsp</result>
<!-- 在action中引用自定义的拦截器 -->
<interceptor-ref name="executeTime"></interceptor-ref>
<interceptor-ref name="helloInterceptor"></interceptor-ref>
<!-- 手动引入 Struts2 的拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
使用拦截器栈
当自定义拦截器比较多时,在 action 中引用拦截器将会变得比较麻烦,所以呢,Struts2 提供了 拦截器栈 。拦截器栈是用来引用已经定义好的拦截器的。一个拦截器栈可以包括多个拦截器,引用拦截器栈的方式和引用拦截器的方式一样。
<interceptors>
<!-- 定义拦截器 -->
<interceptor name="helloInterceptor" class="com.idev.interceptor.HelloInterceptor"></interceptor>
<interceptor name="executeTime" class="com.idev.interceptor.ActionExecuteTimeInterceptor"></interceptor>
<!-- 定义拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="executeTime"></interceptor-ref>
<interceptor-ref name="helloInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="add" class="com.idev.action.UserAction" method="add">
<result>/success.jsp</result>
<!-- 在 action 中引用自定义的拦截器 -->
<interceptor-ref name="myStack"></interceptor-ref>
</action>
设置默认拦截器栈
在 Struts2 如果没有自定义拦截器时,action 类会引用默认的拦截器栈。想将自定义拦截器设置为默认拦截器应该如何操作?
在 package 节点中定义一个 default-interceptor-ref 即可
<!-- 设置默认拦截器 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<action name="add" class="cn.sxt.action.UserAction" method="add">
<result>/success.jsp</result>
</action>
拦截器案例
登录拦截器,实现用户登录检查。
1. 自定义拦截器
public class LoginInterceptor extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//判断执行的 Action 是否为 login.action
//如果不是判断用户是否登录
//如果登录了,执行下一个拦截器,如果没有登录则去登录
//获取执行 action 的名称
String actionName=invocation.getProxy().getActionName();
//如果是来 login 的则跳过
if("login".equals(actionName)){
return invocation.invoke();
}
Object obj = ServletActionContext.getRequest().getSession().getAttribute("currentUser");
if(obj != null){
return invocation.invoke();
}
return Action.LOGIN;
}
}
2. 对应的 action 处理类
package com.idev.action;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
import com.idev.vo.User;
public class UserAction {
private User user;
public String login(){
if("idev".equals(user.getName()) && "1111".equals(user.getPwd())){
ServletActionContext.getRequest().getSession().setAttribute("currentUser", user);
return Action.SUCCESS;
}
return Action.LOGIN;
}
public String show(){
return Action.SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3. 对应的 struts.xml 配置
<struts>
<package name="default" extends="struts-default" namespace="/">
<!-- 配置拦截器 -->
<interceptors>
<!-- 配置自定义拦截器 -->
<interceptor name="loginInterceptor" class="cn.sxt.interceptor.LoginInterceptor"></interceptor>
<!-- 配置拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="loginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 配置默认拦截器 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<!-- 定义全局结果集,所有 action 处理方法的返回结果只要是 login,都跳转到 login.jsp -->
<global-results>
<result name="login">/login.jsp</result>
</global-results>
<action name="login" class="com.idev.action.UserAction" method="login">
<result>/success.jsp</result>
</action>
<action name="show" class="com.idev.action.UserAction" method="show">
<result>/show.jsp</result>
</action>
</package>
</struts>
Struts2 的文件上传
单文件上传
Struts2 默认的上传文件最大为 2 MB ;
1. form 表单写法,method 必须是 post, 加属性 enctype="multipart/form-data"
<form action="upload.action" method="post" enctype="multipart/form-data">
文件:<input type="file" name="file"/><input type="submit" value="上传"/>
</form>
2. 对应 Action 处理类写法
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
public class UploadAction {
//File 的名称和表单域中的名称相同
private File file;
//获取文件名,该属性名必须是: 表单域名+FileName
private String fileFileName;
//获取文件的类型,该属性名必须是: 表单域名+ContentType
private String fileContentType;
//上传的处理方法
public String upload(){
String path=ServletActionContext.getServletContext().getRealPath("/upload");
try {
FileUtils.copyFile(file, new File(path,fileFileName));
} catch (IOException e) {
e.printStackTrace();
}
return Action.SUCCESS;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getFileFileName() {
return fileFileName;
}
public void setFileFileName(String fileFileName) {
this.fileFileName = fileFileName;
}
public String getFileContentType() {
return fileContentType;
}
public void setFileContentType(String fileContentType) {
this.fileContentType = fileContentType;
}
}
批量文件上传
1. struts.xml 文件配置
<struts>
<!--
设置上传文件大小的常量
maxSize 上传总文件大小
maximumSize是单个文件大小
maximumSize=20M maxSize=200M,说明一次最大可以上传 10 个 20M 大小的文件
-->
<constant name="struts.multipart.maxSize" value="209715200"></constant>
<package name="default" extends="struts-default" namespace="/">
<action name="batch" class="cn.sxt.action.BatchUploadAction" method="upload">
<result>/success.jsp</result>
<interceptor-ref name="fileUpload">
<!-- 设置上传的单个文件大小 -->
<param name="maximumSize">20971520</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
</struts>
2. 对应的 Action 处理类
import java.io.File;
import java.io.IOException;
import com.opensymphony.xwork2.Action;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
public class BatchUploadAction {
//File 的名称和表单域中的名称相同
private File[] file;
//获取文件名,该属性名必须是: 表单域名+FileName
private String[] fileFileName;
//获取文件的类型,该属性名必须是: 表单域名+ContentType
private String[] fileContentType;
//上传的处理方法
public String upload(){
String path=ServletActionContext.getServletContext().getRealPath("/upload");
try {
for(int i=0;i<file.length;i++)
FileUtils.copyFile(file[i], new File(path, fileFileName[i]));
} catch (IOException e) {
e.printStackTrace();
}
return Action.SUCCESS;
}
public File[] getFile() {
return file;
}
public void setFile(File[] file) {
this.file = file;
}
public String[] getFileFileName() {
return fileFileName;
}
public void setFileFileName(String[] fileFileName) {
this.fileFileName = fileFileName;
}
public String[] getFileContentType() {
return fileContentType;
}
public void setFileContentType(String[] fileContentType) {
this.fileContentType = fileContentType;
}
}
Struts2 的文件下载
1. 页面写法
<a href="download.action?fileName=jstl-1.2.jar">jstl</a><br/>
2. Action 处理类
public class DownloadAction {
private String fileName;
public String execute(){
return Action.SUCCESS;
}
//获取文件流
public InputStream getInputStream() throws FileNotFoundException{
String path=ServletActionContext.getServletContext().getRealPath("/download");
return new FileInputStream(new File(path, fileName));
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
3. 对应的 struts.xml
<package name="default" extends="struts-default" namespace="/">
<action name="download" class="com.idev.action.DownloadAction">
<result type="stream">
<!-- 根据 inputName 生产的 get 方法 到 Action 中去取的该方法的返回值 -->
<param name="inputName">inputStream</param>
<!-- 设置下载的文件 直接保存 -->
<param name="contentDisposition">attachment;filename=${fileName}</param>
</result>
</action>
</package>
Struts2 中的 AJAX
案例: 异步获取用户列表
导入相关 jar 包
asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-beanutils-1.8.0.jar
commons-collections-3.1.jar
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
commons-lang-2.4.jar
commons-lang3-3.1.jar
commons-logging-1.1.1.jar
ezmorph-1.0.6.jar
freemarker-2.3.19.jar
jackson-core-asl-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
javassist-3.11.0.GA.jar
json-lib-2.3-jdk15.jar
jstl-1.2.jar
log4j-1.2.17.jar
ognl-3.0.5.jar
struts2-core-2.3.4.jar
struts2-json-plugin-2.3.4.jar
xwork-core-2.3.4.jar
-----------------------------------------
1. Action 处理类
public class UserAction {
private String result;
public String list(){
List<User> list = new ArrayList<User>();
list.add(new User("张三","男",33));
list.add(new User("李四","男",23));
list.add(new User("王五","男",23));
//将 list 转为 json 字符串
result = JSONArray.fromObject(list).toString();
return Action.SUCCESS;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
2. 对应 struts.xml 文件
<package name="default" extends="json-default" namespace="/">
<action name="list" class="com.idev.action.UserAction" method="list">
<!-- result 的类型为 "json",param 的 name 为 "root" -->
<result type="json">
<param name="root">result</param>
</result>
</action>
</package>
3. jsp 页面 (用到了 jquery,需引入)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ajax</title>
<script type="text/javascript" src="jquery-1.11.3.min.js"></script>
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
$.post("list.action",function(data){
eval("var result=" + data);
var html = "";
for(var i=0;i<result.length;i++){
html += "<tr><td>"+result[i].name+
"</td><td>"+result[i].sex+
"</td><td>"+result[i].age+"</td></tr>";
}
$("#content").html(html);
});
});
});
</script>
</head>
<body>
<button id="btn">获取数据</button>
<table width="80%" align="center">
<tr>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
</tr>
<tbody id="content"></tbody>
</table>
</body>
</html>
Struts2 的异常处理
1. 异常测试处理类
public class UserAction {
public String add()throws NullPointerException{
throw new NullPointerException("数据为null");
}
}
2. struts.xml 配置
<package name="default" extends="struts-default" namespace="/">
<action name="add" class="com.idev.action.UserAction" method="add">
<result>/success.jsp</result>
<!-- 配置异常处理,result 指向结果集的名称,exception 属性写发生的异常的全名,可以是其父类 -->
<exception-mapping result="nullException" exception="java.lang.NullPointerException"></exception-mapping>
<!-- 发生异常后 到达的页面 -->
<result name="nullException">/error.jsp</result>
</action>
</package>
通常会配置全局的异常处理
<package name="default" extends="struts-default" namespace="/">
<!-- 配置全局的异常处理 -->
<global-results>
<result name="nullException">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="nullException" exception="java.lang.NullPointerException"></exception-mapping>
</global-exception-mappings>
<action name="add" class="cn.sxt.action.UserAction" method="add">
<result>/success.jsp</result>
</action>
</package>