学习java EE开发有一段时间了,但感觉看到后面,又忘了前面,真心感觉必须得写点东西来复习一下了,首先还是从最基础的部分写起吧。本文主要介绍的是struts拦截器的简单例子结构。
首先简单回顾一下struts框架的处理历程见下图。
a) 客户端初始化一个指向Servlet容器的请求;
b) 根据Web.xml配置,请求首先经过ActionContextCleanUp过滤器,其为可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助(SiteMesh Plugin),主要清理当前线程的ActionContext和Dispatcher;
c) 请求经过插件过滤器,如:SiteMesh、etc等过滤器;
d) 请求经过核心过滤器FilterDispatcher,执行doFilter方法,在该方法中,询问ActionMapper来决定这个请求是否需要调用某个Action;
e) 如果ActionMapper决定需要调用某个Action,则ActionMapper会返回一个ActionMapping实例(存储Action的配置信息),并创建ActionProxy(Action代理)对象,将请求交给代理对象继续处理;
f) ActionProxy对象根据ActionMapping和Configuration Manager询问框架的配置文件,找到需要调用的Action类;
g) ActionProxy对象创建时,会同时创建一个ActionInvocation的实例;
h) ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用;
i) 一旦Action执行完毕,ActionInvocation实例负责根据struts.xml中的配置创建并返回Result。Result通常是一个需要被表示的JSP或者FreeMarker的模版,也可能是另外的一个Action链;
j) 如果要在返回Result之前做些什么,可以实现PreResultListener接口,PreResultListener可以在Interceptor中实现,也可以在Action中实现;
拦截器一般在action里面进行配置,共同存在配置文件struts.xml里面,其作用主要是对请求进行过滤和传参。当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。Struts 2中已经定义了默认的拦截器栈,其定义在struts-default.xml中,其中默认的拦截器有18个,框架访问action的异常处理,配置信息处理,转发重定向选择,上传等。拦截器一般都要实现com.opensymphony.xwork2.interceptor.Interceptor接口或继承AbstractInterceptor,其中
void init();
void destroy();
String intercept(ActionInvocation invocation) throws Exception其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。自定义拦截器的一般写法
package interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implements Interceptor {
public void destroy() {
// TODO Auto-generated method stub
}
public void init() {
// TODO Auto-generated method stub
}
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println(“Action执行前插入 代码”);
//执行目标方法 (调用下一个拦截器, 或执行Action)
final String res = invocation.invoke();
System.out.println(“Action执行后插入 代码”);
return res;
}
}
Struts2拦截器需要在struts.xml中声明,如下struts.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="MyInterceptor" class="interceptor.MyInterceptor"></interceptor>
<interceptor-stack name="myInterceptorStack"> <!--定义自己的拦截器栈-->
<interceptor-ref name="MyInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<action name="loginAction" class="loginAction">
<result name="fail">/index.jsp </result>
<result name="success">/success.jsp</result>
<interceptor-ref name="myInterceptorStack"></interceptor-ref>
</action>
</package>
</struts>
3,action中的执行方法
Action中默认的执行方法是execute方法,这个方法执行请求,然后转向其他的页面,这是常规的做法,但有时候我们不想用这个方法名,为了代码的可读性,我们希望让他执行我们自己定义的方法,下面我们就来看一下执行其他方法的两种方法:
<action name="LoginAction" class="com.bzu.action.LoginAction" method="login">
<result name="success">success.jsp</result>
<result name="fail">fail.jsp</result>
<result name="input">login.jsp</result>
</action>
<action name="RegisteAction" class="com.bzu.action.LoginAction" method="registe">
<result name="success">success.jsp</result>
<result name="fail">fail.jsp</result>
<result name="input">login.jsp</result>
</action>
2.DMI(动态直接调用)这种方法,不需要进行struts.xml的配置。而是在html或者jsp页面中通过标示符号指定了要调用的方法。 关键的标示符号为”!”号,具体看一下下面表单:
“
">
<s:actionerror/>
username:<s:textfield name="username"></s:textfield>
password:<s:password name="password"></s:password>
<s:submit value="提交"></s:submit>
</s:form>
3.提交按钮指定提交方法,普通的提交按钮我们会这么写:
当我们想提交到我们指定的方法时我们可以在这个标签里添加一个method属性指定要提交的方法,如下:
<s:submit value="提交" method="login"></s:submit>
4.使用通配符配置Action,这种方法可以解决action配置文件混乱的问题,减少action的配置:
">
<result name="success">/WEB-INF/jsp/{1}_success.jsp</result>
</action>
<span style="font-size:18px;"><span style="color:#000000;"> </span></span>
在name属性的值后面加上*,意思是只要你请求的action名字以helloworld开头,本action就是你找的action,然后method是大括号加上1,这个1代表第一个星号的值,这样就可以动态执行请求的方法。
获取servletAPI的主要2种方法:
ActionContextcontext=ActionContext.getContext(); --得到Action执行的上下文
Maprequest=(Map)context.get("request");--得到HttpServletRequest的Map对象
Mapsession=context.getSession();--得到HttpSession的Map对象
Mapapplication=context.getApplication();--得到ServletContext的Map对象
Action类还有另一种获得ServletAPI的解耦方式,这就是我们可以让他实现某些特定的接口,让Struts2框架在运行时向Action实例注入request、session和application对象。这种方式也就是IOC(控制反转)方式,与之对应的三个接口和它们的方法如下所示:
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;}
}