struts2 之执行原理|源码解析|拦截器|权限案例(04)
2017-07-27 22:47
656 查看
拦截器:struts的核心
拦截器和过滤器区别
只对action起作用.Filter:可以对所有的请求进行过滤.
FilterChain:过滤器链 访问一个资源的时候有可能匹配到多个过滤器
在拦截器中有一个拦截器栈(访问一个action的时候匹配到的多个拦截器)
拦截器的方法
Interceptor:生命周期方法(接口)init()
destroy()
intercept(ActionInvocation invocation):拦截
struts的执行流程
这个土黄的色部分就是过滤器,现在就只有一个过滤器—StrutsPrepareAndExecuteFilter
详细的执行流程,我用markdown画了个简单的流程图
Created with Raphaël 2.1.01.请求2.核心过滤器3.是否是action4.是action继续往核心走5.创建action的代理对象(ActionProxy)6.action执行处理类(ActionInvocation对象:真正干活的对象)7.把所有的拦截器放到一个容器中8.顺序递归执行这一组拦截器9.执行action原来的逻辑10.方法的返回值封装Result对象11.到达跳转的资源(例如jsp)12.把执行权又交给ActionInvocation对象13.倒序的执行这一组拦截器14.核心过滤器放行后的代码15.服务器16.将response对象拆分成响应信息(响应行 响应头 响应体)返回值浏览器17.浏览器解析执行直接放行yesno
执行流程源码解析
核心过滤过滤器//StrutsPrepareAndExecuteFilter类的doFilter方法核心部分 request = prepare.wrapRequest(request);//对request进行加强 ActionMapping mapping = prepare.findActionMapping(request, response, true);//查找Aciton的映射把request放进去, //得到请求路径,去struts.xml得到一个Aciton的映射 if (mapping == null) {//如果为空,放行 boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else {//如果不为空执行拦截器 execute.executeAction(request, response, mapping);//这个就是进入核心的方法, }
我们下面可以继续看下execute.executeAction方法
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { //继续往下层探究 dispatcher.serviceAction(request, response, servletContext, mapping); }
继续往下层探究dispatcher.serviceAction方法
//直接看最重要的东西 try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace();// String name = mapping.getName();//拿到要执行的名字 String method = mapping.getMethod();//拿到要执行的方法 Configuration config = configurationManager.getConfiguration(); //创建ActionPorxy代理对象 ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! //判断有没有结果,如果没执行,肯定没有结果 if (mapping.getResult() != null) { Result result = mapping.getResult(); result.execute(proxy.getInvocation()); } else { //执行execute方法,我们继续探究这个方法 proxy.execute(); }
StrutsActionProxy的execute方法,我们继续探究这个方法
public String execute() throws Exception { ActionContext previous = ActionContext.getContext(); ActionContext.setContext(invocation.getInvocationContext()); try { // This is for the new API: // return RequestContextImpl.callInContext(invocation, new Callable<String>() { // public String call() throws Exception { // return invocation.invoke(); // } // }); //执行invocation的invoke方法,这里就是真正干活的方法(拦截器),我们继续深入这个方法,看看他是怎么工作的 return invocation.invoke(); } finally { if (cleanupContext) ActionContext.setContext(previous); } }
继续看DefaultActionInvocation的invoke方法
//迭代执行拦截方法 if (interceptors.hasNext()) { final InterceptorMapping interceptor = interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); UtilTimerStack.push(interceptorMsg); try { //执行拦截方法,每个拦截方法最后都return回来,继续迭代执行,到这一步就不继续深入吧,有兴趣的可以自己去看看 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally { UtilTimerStack.pop(interceptorMsg); } } else { //所有的拦截器都执行完了,最后就把执行权给Action,action执行完了就有一个result对象,然后就根据result进行转发或者重定向 resultCode = invokeActionOnly(); }
为了深入理解拦截器我们就自己定义一个拦截器
自定义拦截器
1.编写一个类
a.实现Interceptor接口或继承AbstractInterceptor类或继承MethodFilterInterceptor(配置不拦截那些方法)b.重写拦截的方法
2.编写配置文件
方式1:a.注册拦截器
b.在action中配置拦截器
方式2:
a.注册拦截器栈
b.在action中配置拦截器栈
//拦截action执行前的操作
protected String doIntercept(ActionInvocation invocation) throws Exception { //拦截action执行前的操作 System.out.println("MyInterceptor1拦截到了请求"); //放行 String res = invocation.invoke(); //拦截action执行后的操作 System.out.println("MyInterceptor--1--拦截到了响应"); return res; }
同样的 我做了3个这样简单的拦截器
然后继续注册配置拦截器
<!-- 方式1:注册拦截器,在action中使用拦截器 --> <interceptors> <!-- 注册拦截器 --> <interceptor name="MyInterceptor1" class="com.itheima.a_hello.MyInterceptor1"></interceptor> <interceptor name="MyInterceptor2" class="com.itheima.a_hello.MyInterceptor2"></interceptor> <interceptor name="MyInterceptor3" class="com.itheima.a_hello.MyInterceptor3"></interceptor> </interceptors> <action name="demo" class="com.itheima.a_hello.DemoAction"> <!-- 在action中使用拦截器 --> <interceptor-ref name="MyInterceptor1"></interceptor-ref> <interceptor-ref name="MyInterceptor2"></interceptor-ref> <interceptor-ref name="MyInterceptor3"></interceptor-ref> <!-- 若在action显式的使用了某个拦截器,默认的拦截器就失效了 --> <interceptor-ref name="defaultStack"/> </action>
最后运行结果如下:
MyInterceptor1拦截到了请求
MyInterceptor2拦截到了请求
MyInterceptor3拦截到了请求
Action执行了~~~
MyInterceptor–3–拦截到了响应
MyInterceptor–2–拦截到了响应
MyInterceptor–1–拦截到了响应
先顺序再倒叙
然后我们可以继续做一个案例,很常用的案例
案例-权限拦截
步骤分析:
先做登录案例
1.创建用户表2.创建用户的持久化类和映射文件
3.创建user的action service dao
1.将login.htm修改为login.jsp
修改表单提交路径:/crm_/user_login.action
给子标签添加name属性
2.在action中编写login方法
调用service 查询用户 参数:user 返回值:existUser
判断existUser是否为空,
若为空,添加提示信息,转发到login.jsp
若不为空,将用户存入session中,重定向到首页
3.在login.jsp上获取错误信息
在top.jsp上展示用户信息
再做拦截案例
1.编写一个拦截器(继承MethodFilterInterceptor 放行login方法)逻辑:
判断session中有无用户
若有:放行
若无:添加提示信息 转发到login
代码:
public class PrivilegeInterceptor extends MethodFilterInterceptor { @Override protected String doIntercept(ActionInvocation invocation) throws Exception { //判断session有无用户 Object obj = ActionContext.getContext().getSession().get("existUser"); if(obj == null){ //没有登录 生成提示信息 转发到login.jsp ActionSupport action = (ActionSupport) invocation.getAction(); action.addActionMessage("权限不足,请先登录"); return "login"; } //放行 return invocation.invoke(); } }
2.编写一个父包 注册拦截器栈
3.让我们所有的package继承父包 就可以在自己的action中使用拦截器
配置如下:
<package name="mypackage" extends="struts-default"> <!-- 注册拦截器栈 --> <interceptors> <interceptor name="PrivilegeInterceptor" class="com.itheima.web.interceptor.PrivilegeInterceptor"/> <!-- 定义拦截器栈 --> <interceptor-stack name="myStack"> <interceptor-ref name="PrivilegeInterceptor"> <!-- 拦截器放行login方法 --> <param name="excludeMethods">login</param> </interceptor-ref> <!-- struts 默认的拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 默认拦截器 --> <default-interceptor-ref name="myStack"/> <!-- 全局的结果视图 --> <global-results> <result name="login">/login.jsp</result> </global-results> </package>
注意:
1.登录页面打开的时候应该在最大的窗口打开在login.jsp上添加以下js代码
if(top.location != self.location){ top.location = self.location; }
2.放行login方法
3.在action中添加错误信息
addActionMessage(String msg)
在jsp上展示错误信息
<s:actionMessage/>
4.在拦截器中获取action
invocation.getAction();
5.设置默认的拦截器
<!-- 默认拦截器 --> <default-interceptor-ref name="myStack"/>
相关文章推荐
- Rhyme/Struts2源码解析以及拦截器原理模拟
- struts2拦截器的实现原理及源码解析
- struts2源码分析及拦截器实现原理
- struts2拦截器的实现原理及源码剖析
- struts2源码解析一 Struts2 日记原理及配置方法
- struts2拦截器的实现原理及源码剖析
- Shiro整合SSH开发2:结合Struts2实现登陆和退出以及Shiro执行流程和原理解析
- Struts2执行流程源码解析
- struts2核心与拦截器的原理解析
- Struts2原理解析(结合源码)
- Struts2拦截器权限验证(源码)!
- struts2拦截器的实现原理及源码剖析
- struts2拦截器的实现原理及源码剖析
- struts2拦截器的实现原理及源码剖析
- struts2拦截器的实现原理及源码剖析
- struts2 文件上传 和部分源码解析,以及一般上传原理
- Java程序员从笨鸟到菜鸟之(四十六)细谈struts2(八)拦截器的实现原理及源码剖析
- struts2拦截器的实现原理及源码剖析
- struts2拦截器的实现原理及源码剖析
- struts2拦截器实现原理案例分析