大部分 Action共享常见的关注点. 一些Action需要输入验证. 另外一些Action可能需要预处理文件上传. 还有一些 Action可能需要防止重复提交 . 许多Action需要在页面显示前生成下拉列表和其他控件.
框架使用 “拦截器” 策略使得解决共享这些关注点变得十分容易. 当你请求与某个 “action”匹配资源, 框架将调用 Action对象. 但是, 在Action执行前, 调用可以被另外的对象拦截. 在Action 执行完后, 调用可以再次被拦截. 毫无疑问, 我们称呼这些对象为 “拦截器.”
默认拦截器栈定义是为了满足大部分应用. 大部分应用不需要添加拦截器或修改拦截器栈 .
拦截器可以在Action调用前或后 执行代码. 框架的核心功能以拦截器方式实现. 特性如防重复提交,类型转换, 对象创建, 验证, 文件上传, 页面预处理等等,都是在拦截器中实现. 每个拦截器都是可插拔的, 因而你可以精确地决定哪些特性该Action需要支持.
每个Action可以配置不同的拦截集合. 你自定义的拦截器可以和框架内置的拦截器混合在一起使用. 拦截为 Action类 “设置状态” , 完成大部分 “heavy lifting” 在 Action执行前.
Interceptor接口
拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor 接口.
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
init 方法在拦截器实例化后且在调用intercept方法前调用.这里是放置资源分配代码的位置 .
intercept 方法是拦截器代码书写的地方. 正如 action方法, intercept 返回一个结果,让 Struts 使用该结果把请求转发到另外一个web资源 .调用ActionInvocation类型的参数的 invoke 方法将执行该action (如果是栈中最后一个拦截器) 或其它拦截器.
记住invoke将返回在result被执行后 (例如. 在JSP已经渲染后), 适合应用在 open-session-in-view 模式. 如果你想要在结果执行前做某些事情, 你需要实现一个PreResultListener.
重写 destroy 方法来释放资源当应用关闭时 .
AbstractInterceptor
AbstractInterceptor类提供了 init 和 destroy空实现, 它可以使用在不打算实现这些方法的地方.
映射
拦截器使用 interceptor 元素来声明, 嵌套在 interceptors 元素中. 摘自struts-default.xml:
<struts>
...
<package name="struts-default">
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
...
</interceptors>
</package>
...
</struts>
我们做一个用于登录权限验证的拦截器,实现当你没登录时访问action会给你转发到登录界面,做不了其他操作
代码如下:
登录界面:
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<s:head />
<body>
${message}
<s:property value="#tip"/>
<s:property value="errors.message01[0]"/>
<s:form action="login">
<!--key作用 1、生成input的name 2、要查找属性文件的key 3、当找不到时,就显示key -->
<s:textfield name="user.name" label="姓名"></s:textfield>
<s:textfield name="user.password" label="密码"></s:textfield>
<s:submit />
</s:form>
<s:debug></s:debug>
</body>
</html>
LoginAction
package com.lgh.bookstruts.action;
import org.apache.struts2.ServletActionContext;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.lgh.bookstruts.model.User;
import com.lgh.bookstruts.util.HibernateUtil;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private User user;
public LoginAction() {
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtil.getSession();
ts = session.beginTransaction();
// 这里使用了hibernate对数据库进行操作
String hql = "select count(*) from User u where u.name = :name and u.password = :password";
Query query = session.createQuery(hql);
query.setParameter("name", user.getName());
query.setParameter("password", user.getPassword());
Long longNum = (Long) query.uniqueResult();
System.out.println(longNum);
if(longNum >0){
ActionContext.getContext().getSession().put("loginId", "hadLogin");
return SUCCESS;
}else{
// ServletActionContext.getRequest().setAttribute("message", "用户名密码错误");
addFieldError("message01", "用户名密码错误!!");
}
ts.commit();
} catch (Exception e) {
if(ts != null){
ts.rollback();
}
e.printStackTrace();
}finally{
if(session != null){
session.close();
}
}
return INPUT;
}
}
如果用户名和密码正确,就在session中放一个数据用于标记已登录
ActionContext.getContext().getSession().put("loginId", "hadLogin");
LoginAction-validation.xml
用于验证
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<!-- 以上内容,根据使用版本的不同,有可能会引发错误 -->
<validators>
<validator type="requiredstring">
<param name="fieldname">user.name</param>
<message>用户名不能为空</message>
</validator>
<!-- 字段验证器 -->
<field name="user.password">
<field-validator type="requiredstring" short-circuit="true">
<message>密码不能为空</message>
</field-validator>
</field>
</validators>
配置:
<action name="login" class="com.lgh.bookstruts.action.LoginAction"
method="execute">
<result name="success" type="redirect">/fileupload.jsp</result>
<result name="input">/login.jsp</result>
</action>
成功后的页面:
fileupload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="upload" method="post" enctype="multipart/form-data">
上传文件:<input name="book" type="file"><br>
文件类型:<input name="books.desc" type="text">
<input type="submit">
</form>
</body>
</html>
这也是另一个action的页面
拦截器
LoginInterceptor.java
package com.lgh.bookstruts.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class LoginInterceptor extends AbstractInterceptor {
public LoginInterceptor() {
// TODO Auto-generated constructor stub
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// 取得请求相关的ActionContext实例
ActionContext ctx = invocation.getInvocationContext();
Map session = ctx.getSession();
String res = (String) session.get("loginId");
if("hadLogin".equals(res)){
return invocation.invoke();
}
System.out.println("你还没有登录");
ctx.put("tip", "你还没有登录");
return Action.LOGIN;
}
}
配置拦截器
<interceptors>
<interceptor name="needlogin" class="com.lgh.bookstruts.interceptor.LoginInterceptor"></interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="needlogin"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
在fileupload中使用新建的拦截器栈myStack
<!-- 定义全局Result -->
<global-results>
<!-- 当返回login视图名时,转入/login.jsp页面 -->
<result name="login">/login.jsp</result>
</global-results>
<action name="upload" class="com.lgh.bookstruts.action.FileUploadAction" method="execute">
<interceptor-ref name="myStack" />
<result name="success" type="redirect">filelist</result>
<result name="input">/fileupload.jsp</result>
</action>
这里时我在这个项目中所使用的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>
<constant name="struts.devMode" value="true"></constant>
<!-- 设置上传文件的大小 -->
<constant name="struts.multipart.maxSize" value="3024000"></constant>
<package name="basicstruts2" extends="struts-default,json-default">
<interceptors>
<interceptor name="needlogin" class="com.lgh.bookstruts.interceptor.LoginInterceptor"></interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="needlogin"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义全局Result -->
<global-results>
<!-- 当返回login视图名时,转入/login.jsp页面 -->
<result name="login">/login.jsp</result>
</global-results>
<action name="upload" class="com.lgh.bookstruts.action.FileUploadAction" method="execute">
<interceptor-ref name="myStack" />
<result name="success" type="redirect">filelist</result>
<result name="input">/fileupload.jsp</result>
</action>
<action name="login" class="com.lgh.bookstruts.action.LoginAction" method="execute">
<result name="success" type="redirect">/fileupload.jsp</result>
<result name="input">/login.jsp</result>
</action>
<action name="loginX">
<result name="success">/login.jsp</result>
</action>
<action name="filelist" class="com.lgh.bookstruts.action.FileListAction" method="execute">
<interceptor-ref name="myStack" />
<result name="success">/booklist.jsp</result>
</action>
<action name="downloadX" class="com.lgh.bookstruts.action.FileDownloadXAction" method="execute">
<result name="success" type="stream">
<param name="contentType">${contentType}</param>
<param name="inputName">is</param>
<param name="contentDisposition">attachment;filename="${f}";filename*=utf-8''${f}</param>
<param name="bufferSize">1024</param>
</result>
</action>
</package>
<include file="example.xml" />
<!-- Add packages here -->
</struts>
好了,写到这基本上登录权限拦截器基本上就可以使用了,我们进行一下测试
直接请求fileupload
这时候进行上传文件就会上传成功,进入下载列表界面