十二、Struts2中的拦截器
1、拦截器的重要性
Struts2中的很多功能都是由拦截器完成的。比如:servletConfig,staticParam,params,modelDriven等等。
是AOP编程思想的一种应用形式。
2、拦截器的执行时机:
\![](https://images2015.cnblogs.com/blog/479957/201606/479957-20160615220709573-165989532.png)
3、自定义拦截器
3.1、拦截器的类试图(初级版本):
3.2、编写步骤:
a、编写一个类,继承AbstractInterceptor类或者实现Interceptor接口。重写intercept方法。
1 public class MyInterceptorDemo1 extends AbstractInterceptor { 2 3 public String intercept(ActionInvocation invocation) throws Exception { 4 System.out.println("MyInterceptorDemo1拦截了:访问动作之前"); 5 //放行的含义:如果有下一个拦截器,则执行下一个拦截器。如果该拦截器是最后一个,则执行动作方法。 6 String rtValue = invocation.invoke();//此行是放行的方法 7 System.out.println("MyInterceptorDemo1拦截器"+rtValue); 8 System.out.println("MyInterceptorDemo1拦截了:访问动作之后"); 9 return rtValue; 10 } 11 12 }
b、配置拦截器:注意拦截器必须先声明再使用
1 a、声明拦截器 2 <interceptors> 3 <interceptor name="myInterceptor1" class="cn.itcast.web.interceptors.MyInterceptorDemo1"></interceptor> 4 </interceptors> 5 b、使用拦截器 6 <action name="action1" class="cn.itcast.web.action.Demo1Action" method="demo1"> 7 <!-- 使用拦截器。当我们配置了一个拦截器之后,默认的拦截器栈就失效了--> 8 <interceptor-ref name="myInterceptor1"></interceptor-ref> 9 <result name="success">/success.jsp</result> 10 </action>
3.3、执行顺序
3.4、多个拦截器的执行顺序
3.5、intercept方法的返回值
4、拦截器的应用:
4.1、检查登录的拦截器案例
配置文件:
1 <package name="myDefault" extends="struts-default" abstract="true"> 2 <interceptors> 3 <interceptor name="checkLoginInterceptorDemo2" class="cn.itcast.web.interceptors.CheckLoginInterceptorDemo2"></interceptor> 4 <interceptor-stack name="myDefaultStack"> 5 <interceptor-ref name="checkLoginInterceptorDemo2"></interceptor-ref> 6 <interceptor-ref name="defaultStack"></interceptor-ref> 7 </interceptor-stack> 8 </interceptors> 9 <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref> 10 <global-results> 11 <result name="login">/login.jsp</result> 12 </global-results> 13 </package> 14 <package name="bbs" extends="myDefault"> 15 <action name="showMain" class="cn.itcast.web.action.BBSAction" method="showMain"> 16 <result name="success">/main.jsp</result> 17 </action> 18 <action name="showOther" class="cn.itcast.web.action.BBSAction" method="showOther"> 19 <result name="success">/other.jsp</result> 20 </action> 21 <action name="login" class="cn.itcast.web.action.BBSAction" method="login"> 22 <interceptor-ref name="myDefaultStack"> 23 <!-- 为拦截器注入参数,告知拦截器要排除的方法 --> 24 <param name="checkLoginInterceptorDemo2.excludeMethods">login</param> 25 </interceptor-ref> 26 <result name="success" type="redirectAction">showMain</result> 27 </action> 28 </package>
动作类:
1 public class Demo1Action extends ActionSupport { 2 3 public String demo1(){ 4 System.out.println("Demo1Action的demo1方法执行了"); 5 return SUCCESS; 6 } 7 }
拦截器:
1 public class CheckLoginInterceptorDemo1 extends AbstractInterceptor { 2 3 public String intercept(ActionInvocation invocation) throws Exception { 4 Object obj = ServletActionContext.getRequest().getSession().getAttribute("userinfo"); 5 if(obj == null){ 6 return "login"; 7 } 8 return invocation.invoke();//放行 9 } 10 11 }
页面:
1 <html> 2 <head> 3 <title>用户登录</title> 4 </head> 5 <body> 6 <form action="${pageContext.request.contextPath}/login.action"> 7 用户名:<input type="text" name="username"/><br/> 8 <input type="submit" value="登录"/> 9 </form> 10 </body> 11 </html>
4.2、案例中的问题
问题:由于我们写了自己的拦截器,默认的拦截器不起作用了。
解决办法:
需要通过AbstractInterceptor类的子类入手,通过查看发现,该类还有一个子类是抽象的:
所以我们在自定义拦截器时,还可以继承MethodFilterInterceptor并且重写doIntercept方法。
1 public class CheckLoginInterceptorDemo2 extends MethodFilterInterceptor { 2 3 public String doIntercept(ActionInvocation invocation) throws Exception { 4 Object obj = ServletActionContext.getRequest().getSession().getAttribute("userinfo"); 5 if(obj == null){ 6 return "login"; 7 } 8 return invocation.invoke();//放行 9 } 10 11 }
并且在struts的配置文件中,配置需要拦截哪些方法,和需要放过哪些方法。
4.3、拦截器类视图(全):
十三、文件的上传(拦截器)和下载(stream结果类型)
1、文件上传
必要前提:
a.表单method必须是post;
b.enctype取值必须是multipart/form-data;
c.提供文件选择域。
动作类:
1 public class UploadAction extends ActionSupport { 2 3 private String username; 4 private File photo; 5 //struts2框架会为我们提供一个变量,用于保存文件名。 6 private String photoFileName;//该变量的命名规则有要求:必须是文件变量的名称+FileName。严格区分大小写。 7 8 9 public String upload()throws Exception{ 10 //1.获取文件要写到服务器的位置 11 String basePath = ServletActionContext.getServletContext().getRealPath("/WEB-INF/uploads"); 12 //2.判断目录是否存在 13 File file = new File(basePath); 14 if(!file.exists()){ 15 file.mkdirs(); 16 } 17 //3.写文件 18 /* 19 * 拷贝:是使用临时文件,复制一份到指定目录 20 * FileUtils 21 * 它是apache提供commons-io的jar包中一个类。 22 * copyFile方法: 23 * 把参数1复制到指定位置,指定位置是由参数2决定的 24 * 参数: 25 * 第一个:源文件 26 * 第二个:目标文件 27 * 28 * 弊端: 29 * 会保存两份文件,一份是临时文件,一份是实际写的文件 30 */ 31 //FileUtils.copyFile(photo, new File(file,photoFileName)); 32 /* 33 * 剪切:是把临时文件重命名后,存到指定目录(一般采用此种方式) 34 * 比复制的好处就是:只会保留一份文件 35 */ 36 photo.renameTo(new File(file,photoFileName)); 37 return SUCCESS; 38 }
2、文件上传的配置
2.1、文件上传大小限制(默认是2MB)
如果上传文件超过了默认大小,upload拦截器会转向一个input的逻辑视图。
改变上传文件大小限制:
1 <!-- 改变上传文件大小限制的方式:只能用修改常量的方式 --> 2 <constant name="struts.multipart.maxSize" value="10485760"></constant>
2.2、限制文件上传的类型
a、通过限制上传文件的扩展名
思路:给fileUpload拦截器注入参数
1 <action name="upload" class="cn.itcast.web.action.UploadAction" method="upload"> 2 <!-- 给上传文件的拦截器注入参数,限制上传文件的大小 3 此种方式无法限制上传文件的大小 4 <interceptor-ref name="defaultStack"> 5 <param name="fileUpload.maximumSize">10485760</param> 6 </interceptor-ref> --> 7 <interceptor-ref name="defaultStack"> 8 <!-- 限制文件的扩展名 --> 9 <param name="fileUpload.allowedExtensions">.jpg,.png,.jpeg,.bmp</param> 10 <!-- 限制文件的MIME类型 --> 11 <param name="fileUpload.allowedTypes">image/jpeg,image/png,image/pjpeg</param> 12 </interceptor-ref> 13 <result name="success">/success.jsp</result> 14 <result name="input">/index.jsp</result> 15 </action>
3、文件下载:其实就是一种结果类型(Stream)
动作类:
1 public String download() throws Exception{ 2 //3.找到要下载文件的路径 3 String basePath = ServletActionContext.getServletContext().getRealPath("/WEB-INF/uploads"); 4 //4.使用文件路径+文件名称,构建字节输入流 5 fileName = "4O5A3624.jpg";//实际开发中是从数据库中查出来的 6 inputStream = new FileInputStream(basePath+File.separator+fileName); 7 //5、返回一个成功 8 return SUCCESS; 9 /* 10 * 6.剩下的事,都交给struts2框架。是框架的stream的结果类型为我们实现的 11 * 我们需要给stream结果类型提供参数 12 * <result name="success" type="stream"> 13 <!-- 给结果类型注入参数:两个头 一个流 --> 14 <param name="contentType">application/octet-stream</param> 15 <param name="contentDisposition">attachment;filename=1.jpg</param> 16 <param name="inputStream">inputStream</param> 17 </result> 18 */ 19 }
配置文件:
1 <action name="download" class="cn.itcast.web.action.DownLoadAction" method="download"> 2 <result name="success" type="stream"> 3 <!-- 给结果类型注入参数:两个头 一个流 --> 4 <param name="contentType">application/octet-stream</param> 5 <param name="contentDisposition">attachment;filename=1.jpg</param> 6 <param name="inputStream">inputStream</param> 7 </result> 8 </action>
十四、OGNL简介
1、什么是OGNL
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个单独的开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
2、OGNL的功能
前提:OGNL是struts2整合的一个开源项目,所以在struts2中,要想使用OGNL表达式,必须使用Struts2标签库
2.1、支持普通方法的调用
1 <body> 2 <%--s:property标签 3 作用:把该标签中value属性的值所对应的内容输出到浏览器上。 4 属性: 5 value:取值不是一个普通的字符串,而是一个OGNL表达式。 6 它是去一个位置查找数据去了,把找到的结果显示出来。 7 --%> 8 <s:property value="OGNL-Expression"/><br/> 9 <%--使用引号,把value的值括起来,取值将变成一个普通的字符串 --%> 10 <s:property value="'OGNL-Expression'"/><br/> 11 <%--支持普通方法调用 --%> 12 <s:property value="'OGNL-Expression'.length()"/><br/> 13 <s:property value="'OGNL-Expression'.toUpperCase()"/><br/> 14 <s:property value="'OGNL-Expression'.split('-')[0]"/><hr/> 15 <%--OGNL还可以访问静态属性 16 @包名.包名.类名@属性名称 17 例如: 18 @java.lang.Integer@MAX_VALUE 19 --%> 20 <s:property value="@java.lang.Integer@MAX_VALUE"/> 21 <hr/> 22 <%--OGNL还可以调用静态方法 23 @包名.包名.类名@方法名称 24 例如: 25 @java.lang.Math@random() 26 --%> 27 <s:property value="@java.lang.Math@random()"/> 28 <hr/> 29 <%--OGNL操作集合对象 30 s:radio标签的list属性取值是一个OGNL表达式。 31 {'男','女'}就相当于创建了一个List集合,里面包含了两个元素 32 --%> 33 <s:radio list="{'男','女'}" name="gender" label="性别"></s:radio> 34 <hr size="50px" color="gray"/> 35 <%--OGNL操作map对象 36 #{'male':'男','female':'女'}就相当于创建了一个map。冒号左侧的作为key,冒号右侧的作为value。 37 在生成浏览器认识的html标签时: 38 会把map的key给html标签的value赋值 39 把map的value作为文本显示在页面上 40 41 例如: 42 <input type="radio" value="male">男 43 <input type="radio" value="female">女 44 --%> 45 <s:radio list="#{'male':'男','female':'女'}" name="gender" label="性别"></s:radio> 46 47 </body>
(EL表达式只能调用静态方法)