上一章自己实现Struts2(四)实现ActionInvocation我已经实现好了action和拦截器的调用者ActionInvocation
类,现在就来实现一下Struts2的入口——StrutsPrepareAndExecuteFilter
类。
分析StrutsPrepareAndExecuteFilter
再把Struts2框架流程图贴上来
![](https://i-blog.csdnimg.cn/blog_migrate/97236970869268c3cd4ac9897773af1b.png)
大家将FilterDispatcher看成StrutsPrepareAndExecuteFilter好了,它已经被替代的了,我实在是找不到有StrutsPrepareAndExecuteFilter的图呀~.~。在第一章自己实现Struts2(一)Struts流程介绍和环境搭建我把Struts2框架执行流程简单地介绍了一下,现在我再介绍一下(当然是复制粘贴过来的了)
-
客户端提交一个请求,被StrutsPrepareAndExecuteFilter拦截到了(StrutsPrepareAndExecuteFilter配置的拦截路径一般都是/*)。
-
在StrutsPrepareAndExecuteFilter拦截到请求后会访问ActionMapper来分析请求信息以决定是否调用某个action(因为有可能请求的是其它的静态资源或者不符合规定后缀的)。
-
如果要访问action,那么StrutsPrepareAndExecuteFilter会把请求的处理交给ActionProxy对象。
-
ActionProxy对象会通过ConfigurationManager加载核心配置文件struts.xml(Struts的action的配置信息文件)。
-
ActionProxy读取到要访问的action的配置信息后创建一个ActionInvocation对象,ActionInvocation实现了命令模式,在action调用的前后递归地调用涉及到的拦截器(Interceptor)。
-
一旦action执行完毕,会返回一个result,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。
可以看到跟StrutsPrepareAndExecuteFilter有关的步骤是1、2、3,那我要做的StrutsPrepareAndExecuteFilter不仅要实现步骤1的功能,还把步骤2中ActionMapper要做的事情实现(当然了ActionMapper在Struts2中只是个接口),还有实现步骤4和5中ActionProxy要做的事情,所以我的Struts2是没有ActionMapper和ActionProxy的了,糅合在StrutsPrepareAndExecuteFilter中了。当然这是为了简单,我实现的功能并不多,将来也不会去扩展。
StrutsPrepareAndExecuteFilter还要实现一步就是根据6中ActionInvocation中返回的结果串如SUCCESS
去配置信息查找得到要请求转发的路径。
自定义的StrutsPrepareAndExecuteFilter功能就这么多,下面就来实现一下。
实现StrutsPrepareAndExecuteFilter
来新建一个StrutsPrepareAndExecuteFilter,让它实现javax.servlet.Filter
接口。
一、准备好所有的配置信息,我定义了以下几个成员变量,这些对象就存放struts.xml
中的全部配置信息。
private List<String> interceptors;
private String extension;
private Map<String, ActionConfig> actionConfigs;
准备这些配置信息很简单,就是直接调用ConfigurationManager来获取配置信息,在初始化方法中准备。
public void init(FilterConfig filterConfig) throws ServletException {
interceptors = ConfigurationManager.getInterceptors();
extension = ConfigurationManager.getConstant("struts.action.extension");
actionConfigs = ConfigurationManager.getActions();
}
二、分析请求要访问的action(可能不用访问action,只是访问其他资源),加载该action的配置信息,这一步放在doFilter方法中
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String reqPath = req.getServletPath();
if (!reqPath.endsWith(extension)) {
chain.doFilter(request, response);
return;
} else {
reqPath = reqPath.substring(1);
reqPath = reqPath.replaceAll("." + extension, "");
ActionConfig config = actionConfigs.get(reqPath);
if (config == null) {
throw new RuntimeException("未找到" + reqPath + "的配置信息");
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
三、根据上面的分析结果去调用ActionInvocation类,会返回一个结果串
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String reqPath = req.getServletPath();
if (!reqPath.endsWith(extension)) {
chain.doFilter(request, response);
return;
} else {
reqPath = reqPath.substring(1);
reqPath = reqPath.replaceAll("." + extension, "");
ActionConfig config = actionConfigs.get(reqPath);
if (config == null) {
throw new RuntimeException("未找到" + reqPath + "的配置信息");
}
ActionInvocation invocation = new ActionInvocation(interceptors, config, req, resp);
String result = invocation.invoke(invocation);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
四、根据上面的结果串去配置信息查找要请求转发的路径,并执行请求转发
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String reqPath = req.getServletPath();
if (!reqPath.endsWith(extension)) {
chain.doFilter(request, response);
return;
} else {
reqPath = reqPath.substring(1);
reqPath = reqPath.replaceAll("." + extension, "");
ActionConfig config = actionConfigs.get(reqPath);
if (config == null) {
throw new RuntimeException("未找到" + reqPath + "的配置信息");
}
ActionInvocation invocation = new ActionInvocation(interceptors, config, req, resp);
String result = invocation.invoke(invocation);
String dispatcherPath = config.getResults().get(result);
if (dispatcherPath == null || "".equals(dispatcherPath.trim())) {
throw new RuntimeException("未找到" + result + "对应的路径");
}
req.getRequestDispatcher(dispatcherPath).forward(request, response);
ActionContext.actionContext.remove();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
需要注意的是最后一句ActionContext.actionContext.remove();
在一个请求结束后要把它对应的ActionContext对象从ThreadLocal中移除,释放资源。
到了这里,整个StrutsPrepareAndExecuteFilter就完成了
StrutsPrepareAndExecuteFilter类完整代码:
package edu.jyu.filter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.jyu.config.ActionConfig;
import edu.jyu.config.ConfigurationManager;
import edu.jyu.context.ActionContext;
import edu.jyu.invocation.ActionInvocation;
/**
* 核心拦截器
*
* @author Jason
*/
public class StrutsPrepareAndExecuteFilter implements Filter {
private List<String> interceptors;
private String extension;
private Map<String, ActionConfig> actionConfigs;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
interceptors = ConfigurationManager.getInterceptors();
extension = ConfigurationManager.getConstant("struts.action.extension");
actionConfigs = ConfigurationManager.getActions();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String reqPath = req.getServletPath();
if (!reqPath.endsWith(extension)) {
chain.doFilter(request, response);
return;
} else {
reqPath = reqPath.substring(1);
reqPath = reqPath.replaceAll("." + extension, "");
ActionConfig config = actionConfigs.get(reqPath);
if (config == null) {
throw new RuntimeException("未找到" + reqPath + "的配置信息");
}
ActionInvocation invocation = new ActionInvocation(interceptors, config, req, resp);
String result = invocation.invoke(invocation);
String dispatcherPath = config.getResults().get(result);
if (dispatcherPath == null || "".equals(dispatcherPath.trim())) {
throw new RuntimeException("未找到" + result + "对应的路径");
}
req.getRequestDispatcher(dispatcherPath).forward(request, response);
ActionContext.actionContext.remove();
}
}
@Override
public void destroy() {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
好了,StrutsPrepareAndExecuteFilter大功告成,项目已经上传到Github上
https://github.com/HuangFromJYU/JStruts2
如果大家有什么问题或者发现什么错误可以发邮件到jasonwong_hjj@qq.com,共同学习共同进步