一、拦截器,拦截器栈
1、拦截器的作用
拦截器本质上和servlet的过滤器是一样的。在struts2中,拦截器能够对Action前后进行拦截,拦截器是一个可插拨的,你可以选择使用拦截器,也可以卸载拦截器。
2、拦截器执行顺序
在struts.xml文件中,<intercepto-ref/>中先引用的先执行,后引用的后执行。如果某个拦截器出错或不允许通过,那么下一个拦截器是不允许执行的。
需要拦截哪个Action,就在哪个Action对应的<action>标签中配置即可。
在部署web应用时,拦截器的空参构造方法和init()方法各执行一次,每次请求时intercept()方法都会执行一次。
3、自定义拦截器
1) 声明一个拦截器
<pacakge > <interceptors> <interceptor name="LoginInterceptor" class="interceptor.LoginInterceptor"> </interceptor> </interceptors> <action ></action> </package>
注意:这里interceptors与action标签同级。其中class对应拦截器的全路径。name对应拦截器的名称,这个可以自己随便定义,建议与类名相同,此名称要唯一。
2)引用一个拦截器:
<action> <!-- 引用自定义的拦截器 --> <interceptor-ref name="LoginInterceptor"></interceptor-ref> <action>
注意:如何引用一个拦截器?即在Action中<action>标签下配置即可。这里name名称与自定义的名称要一致。
4、自定义拦截器栈
1)声明一个拦截器栈
interceptor-stack标签中进行配置需要引用的拦截器,如下:
<interceptors> <interceptor name="LoginInterceptor" class="interceptor.LoginInterceptor"></interceptor> <interceptor-stack name="amosStack"> <interceptor-ref name="LoginInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors>
2)引用一个拦截器栈:
<!-- 引用自定义的拦截器栈 --> <interceptor-ref name="amosStack"></interceptor-ref>
二、需求分析
如图所示,访问upload.jsp进行上传文件--》LoginInterceptor拦截器进行拦截---》
1、未登录,那么跳转页面到登录页面---》进行登录页面--》登录成功---》可以点击返回到上传文件页面;
2、已登录,登录直接开始上传文件。
三、代码分析:
upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ 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> <body> <s:form action="UploadAction" enctype="multipart/form-data" method="POST"> <s:textfield label="上传用户" name="username"/> <s:file label="上传文件" name="upload" /> <s:file label="上传文件" name="upload" /> <%-- <s:file label="上传文件" name="upload" /> --%> <s:submit value="提交"/> </s:form> </body> </html>
upload_success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ 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> <body> <s:form action="UploadAction" enctype="multipart/form-data" method="POST"> <s:textfield label="上传用户" name="username"/> <s:file label="上传文件" name="upload" /> <s:file label="上传文件" name="upload" /> <%-- <s:file label="上传文件" name="upload" /> --%> <s:submit value="提交"/> </s:form> </body> </html>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ 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>login</title> </head> <body> <s:form action="LoginAction" method="POST"> <s:textfield label="上传用户" name="username"/> <s:submit value="登录"/> </s:form> </body> </html>
login_success.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>login success</title> </head> <body> 登录成功<br> <%-- ${pageContext.request.contextPath } --%> <a href="upload.jsp" >返回上传页面</a> </body> </html>
sturts.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> <!-- <include file="config/upload.xml"></include> --> <!-- 加载其他配置文件 --> <include file="config/upload-interceptor.xml"></include> </struts>
upload-sturts.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="login" extends="struts-default"> <action name="LoginAction" class="interceptor.LoginAction" method="loginMethod"> <result> /login_success.jsp </result> </action> </package> <package name="upload" extends="struts-default"> <interceptors> <interceptor name="LoginInterceptor" class="interceptor.LoginInterceptor"></interceptor> <interceptor-stack name="amosStack"> <interceptor-ref name="LoginInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <action name="UploadAction" class="action.UploadAction" method="uploadMethod"> <param name="uploadPath">/home/amosli/develop/struts2_learn/</param> <result name="success" type="dispatcher"> /WEB-INF/upload_success.jsp </result> <result name="input" type="dispatcher"> upload.jsp </result> <result name="toLoginJsp" type="dispatcher"> login.jsp </result> <!-- 对系统的拦截器进行设置 --> <interceptor-ref name="fileUpload"> <!-- 对单个上传文件的大小进行设置,5M --> <param name="maximumSize">5242880</param> <!-- 对允许的文件扩展名进行设置,这里以英文逗号隔开 --> <param name="allowedExtensions">.txt,.xml</param> <!-- 对允许的文件类型进行设置,这里以英文逗号进行隔开 --> <param name="allowedTypes">text/plain,text/xml</param> </interceptor-ref> <!-- 引用自定义的拦截器 --> <!-- <interceptor-ref name="LoginInterceptor"></interceptor-ref> --> <!-- 显示引用默认的拦截器 --> <!-- <interceptor-ref name="defaultStack"></interceptor-ref> --> <!-- 引用自定义的拦截器栈 --> <interceptor-ref name="amosStack"></interceptor-ref> </action> </package> </struts>
LoginAction.java
package interceptor; import java.util.Map; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; /** * @ClassName: LoginAction * @Description: 用户登录 * @author: amosli * @email:amosli@infomorrow.com * @date Jan 17, 2014 12:11:35 AM */ public class LoginAction extends ActionSupport { private static final long serialVersionUID = 3514444221760688282L; private String username; public void setUsername(String username) { this.username = username; } public String loginMethod() { // 取得HTPPSession Map<String, Object> session = ActionContext.getContext().getSession(); session.put("username", username); return SUCCESS; } }
LoginInterceptor.java
package interceptor; import java.util.Map; import action.UploadAction; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; /** * @ClassName: LoginInterceptor * @Description: 登录拦截器 * @author: amosli * @email:amosli@infomorrow.com * @date Jan 17, 2014 11:42:54 PM */ public class LoginInterceptor implements Interceptor { private static final long serialVersionUID = 8314579656513662711L; public LoginInterceptor() { System.out.println("LoginInterceptor():" + this.hashCode()); } public void destroy() { System.out.println("destroy()"); } public void init() { System.out.println("init()"); } public String intercept(ActionInvocation invocation) throws Exception { System.out.println("LoginInterceptor"); // //获取此拦截器将要拦截的action // Object action = invocation.getAction(); // System.out.println("action:"+action);//action:action.UploadAction@6522cf92 // //获取action的返回值 // String resultValue = invocation.invoke(); // System.out.println("resultValue:"+resultValue);// resultValue:success // 如果拦截器将要拦截的action为UploadAction,那么判断用户是否已经登录 if (invocation.getAction() instanceof UploadAction) { Map<String, Object> session = ActionContext.getContext().getSession(); if (session.get("username") != null) {// 判断用户是否已经登录 // 如果返回值为"success"那么将会匹配到配置文件中为result属性为"success"的内容。 // 如果返回值为invocation.invoke(),那么将会执行uploadaction方法 return invocation.invoke(); } else { return "toLoginJsp"; } } return null; } }
UploadAction.java
package action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import com.opensymphony.xwork2.ActionSupport; /** * @ClassName: UploadAction * @Description: 文件上传 * @author: amosli * @email:amosli@infomorrow.com * @date Jan 14, 2014 1:50:28 AM */ public class UploadAction extends ActionSupport { private static final long serialVersionUID = -8920466592471253212L; private String username;// 用户名 private String[] uploadContentType;// 上传文件的类型,(Fileupload拦截器传入的参数) private File[] upload;// 上传的文件,(Fileupload拦截器传入的参数) private String[] uploadFileName;// 上传文件的真实文件名,(Fileupload拦截器传入的参数) private String uploadPath; public void setUploadPath(String uploadPath) { this.uploadPath = uploadPath; } public void setUsername(String username) { this.username = username; } public String[] getUploadContentType() { return uploadContentType; } public void setUploadContentType(String[] uploadContentType) { this.uploadContentType = uploadContentType; } public File[] getUpload() { return upload; } public void setUpload(File[] upload) { this.upload = upload; } public String[] getUploadFileName() { return uploadFileName; } public void setUploadFileName(String[] uploadFileName) { this.uploadFileName = uploadFileName; } public String getUsername() { return username; } public String uploadMethod() throws Exception { // ServletContext context = ServletActionContext.getServletContext(); // String real_path = context.getRealPath("/WEB-INF/upload/"); for (int i = 0; i < upload.length; i++) { InputStream inputStream = new FileInputStream(upload[i]); OutputStream outputStream = new FileOutputStream(uploadPath + "/" + uploadFileName[i]); byte[] b = new byte[1024]; int len = 0; while ((len = inputStream.read(b)) > 0) { outputStream.write(b, 0, len); } // 关闭流 inputStream.close(); outputStream.close(); // 删除tmp文件,最好是用tyrcatch finally进行删除 // upload[i].delete(); } return SUCCESS; } }
其中文件上传的代码主要引用上一篇文章中的,所以这里主要讲LoginInterceptor.java拦截器的代码分析:
实现Interceptor接口,重写其方法,这里主要注意intercept()方法。这里通过ActionInvocation类型的参数获取session值判断用户是否已经登录。
1)如果没有登录返回值为"toLoginJsp",这里对应upload-interceptor.xml中的result name,将其转发到login.jsp页面;
2)如果已经登录,那么执行上传,但这里需要注意的是, 如果返回值为"success"那么将会匹配到配置文件中为result属性为"success"的内容,如果返回值为invocation.invoke(),那么将会执行UploadAction方法,所以这里切记要return invocation.invoke();否则文件上传失败。
其中upload-sturts.xml的配置也是细节问题,主要可以参考文章开头的内容。
四、执行效果: