上一章 Struts2框架的上传和下载
一、拦截器
导读
拦截器可谓struts2的核心,其最基本的bean的注入(即使用)就是通过默认的拦截器实现的,一般在struts.xml的配置中,package内直接或间接继承了struts-default.xml,这样struts2默认的拦截器就会起作用.
小结:Struts2框架的拦截器是写在了struts-default.xml文件中的
Struts2之所以强大就是因为有了拦截器
1.什么是拦截器
是在AOP(Aspect-Oriented Programming==面向切面编程)中针对某一个方法或者字段被访问之前,进行拦截然后在之前或者之后加入某些操作的,例如我们做web开发时经常用的技术。
比如:权限控制、日志等。我们也可以将多个Interceptor连在一起组成Interceptor栈
备注:1)AOP是一种面向切面的编程思想
2)拦截器是AOP的一个实现
2.拦截器实现的原理
拦截器是通过动态代理的方式来调用的,其实拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。
简而言之: 就是可以在Action执行的前或者后进行一些处理的类
代理模式是Java中常见的设计模式之一,其分为两大类:
1.静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。
在程序运行前,代理类的.class文件就已经存在了
2.动态代理:在程序运行时,运用反射机制动态创建而成,常见的有jdk
代理和cglib代理
3.拦截器的作用
拦截器可以帮助实现很多公共的内容,其中有重复提交,类型转换,对象初始化,验证,文件上传,页面初始化,传参的编码等等。由于每个拦截器都可以像热插拔的模块,所以可以在我们定义的Action中正确地去使用需要的拦截器
简而言之:就是在一个Action执行时,让我们为它再提升一些功能,给Action更好的的实现效果
4.拦截器的分类
1.struts2自带的拦截器
2.自定义拦截器:就是为了提升struts2现有的或者就是满足项目所特殊需
求的经由自己创建并实现的拦截器(就是一些java类)
5.拦截器与过滤器的区别
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖于servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象(通过ActionContext这个类),而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
ps:
过滤器和拦截器触发时机不一样:
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前
二、自定义拦截器
导读
作为框架,我们知道可扩展性是不可或缺的,因为世上没有是完全是不变的。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事
1.实现自定义拦截器的两种方法
2.简单实现自定义拦截器
1.创建UserLoginInterceptor.java这个java类并实现 Interceptor接口
1.1)重写intercept()方法:
@Override
public String intercept(ActionInvocation action) throws Exception {
System.out.println("自定义拦截器:");
action.invoke();//在StudentAction.java执行之后进行拦截
Map<String, Object> session = ActionContext.getContext().getSession();
Object value = session.get("name");
System.out.println("在自定义拦截器中获取session中name="+value);
if (value!=null) {
System.out.println("session中有值,正常放行");
}
ActionContext.getContext().put("error", "您没有登录");
return "message";
}
2.在struts.xml中配置,将刚才自定义的拦截器配置一下
2.1将自定义的拦截器和struts2的默认的拦截器栈搭配在一起构建城一个新的拦截器栈
<interceptors>
<interceptor name="userLoginInterceptor" class="com.rj.bd.intector.action.UserLoginInterceptor">
</interceptor>
<interceptor-stack name="myInterceptorNewStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="userLoginInterceptor"/>
</interceptor-stack>
</interceptors>
2.2针对自定义拦截器UserLoginInterceptor.java中
return "message"在struts.xml中配置一个全局结果节点
<global-results>
<result name="message">/jsp/error.jsp</result>
</global-results>
3.创建两个jsp分别叫做error.jsp和list.jsp都放在/jsp/目录下
error.jsp:<s:property value="error"/>
list.jsp:简单的写上:登录成功即可(只是验证自定义拦截器)
4.创建一个StudentAction.java类
package com.rj.bd.student.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
/**
* @desc 模拟用户登录
* @author HYZ
* @time 2021年3月15日
*/
public class StudentAction {
public String login(){
//1.获取一个Map结构的session对象
Map<String, Object> session = ActionContext.getContext().getSession();
//2.存入一组数据
session.put("name", "凌异州");
System.out.println("写入到session中的数据:"+session);
return "success";
}
}
5.在struts.xml中配置这个action,且配置的时候要让该action用上我们的新的默认的拦截器栈
<action name="student" class="com.rj.bd.action.student.StudentAction" >
<interceptor-ref name="myInterceptorNewStack"/>
<result name="success" type="dispatcher">/jsp/list.jsp</result>
</action>
6.在index.jsp进行一个登录访问:
<a href="<%=request.getContextPath()%>/student!login.action">
通过Action请求来测试自定义拦截器
</a>
PS:
一旦在struts.xml中自定义了拦截器,就意味着会使得struts2这个
框架的默认的拦截器栈失效,所以要配置的时候最好是配置成一个新拦截器栈
3.注解的使用
1.在web.xml中配置struts2的启动的过滤器
<!-- 启动Struts2框架 -->
<filter>
<filter-name>StrutsPrepareAndExecuteFilter</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>StrutsPrepareAndExecuteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.在StudentAction.java类中进行操作
@ParentPackage(value = "std")//父母包,对应<package extends="struts-default">
@Namespace(value = "/student")//当前模块的名字,可以省略不写
PS:这些是需要写在StudentAction.java的类名字上
/**
* @Action,这个注解对应<action>节点
* value(),表示action的请求名称,也就是<action>节点中的name属性
* results(),表示action的多个result;这个
属性是一个数组属性,因此可以定义多个Result
* interceptorRefs(),表示action的多个拦截器。
这个属性也是一个数组属性,因此可以定义多个拦截器;
* exceptionMappings(),这是异常属性,它是一
个ExceptionMapping的数组属性,表示action的异常,
在使用时必须引用相应的拦截器
*
*
*
*/
PS:这些是需要写在Action类中方法上
@Action(value="login",
results={
@Result(name="sucss",location="/inters/list.jsp",type="dispatcher"),
@Result(name="error",location="/inters/error.jsp",type="dispatcher")
},//表示结果跳转
//注解式异常处理,此时还是不需要使用struts.xml,且当前的
exceptionMappings={
@ParentPackage(value = "struts-default")必须是struts-default
@ExceptionMapping(exception="java.lang.Exception",result="error")
}
//interceptorRefs={@InterceptorRef("myInterceptorNewStack")}
//如果你要是用新的拦截器栈的话 那就要再次配上struts.xml,且当前Action
类中的@Parentpackage的value要与struts.xml中的package节点中的name属性值要保存一样
三、Struts2与Servlet的关系
Struts2中获取servlet的3种方式
PS: 是由Strust2中提供的ActionContext对象实现的
ActionContext context=ActionContext.getContext(); //得到Action执行的上下文
Map request=(Map)context.get("request"); //得到HttpServletRequest的Map对象
Map session=context.getSession();//得到HttpSession的Map对象
Map application=context.getApplication();//得到ServletContext的Map对象
PS: 通过spring将request,session,application等对象注入到XXXAction.java类中
(本质上不是由Struts2提供的)
public class SampleAction implementsAction,
RequestAware, SessionAware, ApplicationAware{
private Map request;
private Map session;
private Map application;
@Override
public void setRequest(Map request){
this.request = request;
}
@Override
public void setSession(Map session){
this.session = session;
}
@Override
public void setApplication(Map application){
this.application = application;
}
}
PS: 是通过Struts2框架中的ServletActionContext这个对象获取Servlet的API
直接访问Servlet API将使你的Action与Servlet环境耦合在一起,
我们知道对于HttpServletRequest、 HttpServletResponse和
ServletContext这些对象,它们都是由Servlet容器来构造的,与这些
对象绑定在一起,测试时就需要有Servlet容器,不便于Action的单元测
试。但有时候,我们又确实需要直接访问这些对象,那么当然是以完成任务
需求为主。要直接获取HttpServletRequest和ServletContext对象,
可以使用org.apache.struts2. ServletActionContext类,该类是
ActionContext的子类,在这个类中定义下面两个静态方法.