- 浏览: 292900 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
colin_i:
总结的很好,谢谢
Spring事务传播机制和数据库隔离级别 -
xiaoxi0324:
我想问,是否支持获取method内的逻辑分支,比如if分支,普 ...
javassist 学习笔记 -
z390174504:
不错,不错哦
web.xml 中的listener、 filter、servlet 加载顺序及其详解 -
chokee:
...
web.xml 中的listener、 filter、servlet 加载顺序及其详解 -
chenchangqun:
细致啊,楼主辛苦。
web.xml 中的listener、 filter、servlet 加载顺序及其详解
2、过滤器中的doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 方法
2.1、request = prepareDispatcherAndWrapRequest(request, response);分析
我们知道JSTL默认是从page,request,session,application这四个Scope逐次查找相应的EL表达式所对应的对象的值。那么如果要使用JSTL来读取Action中的变量,就需要把Action中的变量,放到request域中才行Struts2,都使用另外一种整合方式:对HttpServletRequest进行装饰(StrutsRequestWrapper )这个类会在Struts2初始化的时候,替换HttpServletRequest,运行于整个Struts2的运行过程中,当我们试图调用request.getAttribute()的时候,就会执行上面的这个方法。(这是一个典型的装饰器模式)在执行上面的方法时,会首先调用HttpServletRequest中原本的request.getAttribute(),如果没有找到,它会继续到ValueStack中去查找,而action在ValueStack中,所以action中的变量通过OGNL表达式,就能找到对应的值了。
protected HttpServletRequest prepareDispatcherAndWrapRequest( HttpServletRequest request, HttpServletResponse response) throws ServletException { //获取dispatch 的单例类,是由LocalThread 保存的,保证线程的安全 Dispatcher du = Dispatcher.getInstance(); // Prepare and wrap the request if the cleanup filter hasn't already, // cleanup filter should be // configured first before struts2 dispatcher filter, hence when its // cleanup filter's turn, // static instance of Dispatcher should be null. if (du == null) { //如果为空的话,值保存进LocalThread 中 Dispatcher.setInstance(dispatcher); // prepare the request no matter what - this ensures that the proper // character encoding // is used before invoking the mapper (see WW-9127) // request 编码设置和response 本地化设置 dispatcher.prepare(request, response); } else { dispatcher = du; } try { // Wrap request first, just in case it is multipart/form-data // parameters might not be accessible through before encoding // (ww-1278) //在这里就开始包装 request = dispatcher.wrapRequest(request, getServletContext()); } catch (IOException e) { String message = "Could not wrap servlet request with MultipartRequestWrapper!"; LOG.error(message, e); throw new ServletException(message, e); } return request; }
简单看下这个方法Dispatcher.getInstance();
private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>(); //other code public static Dispatcher getInstance() { return instance.get(); }
主要的包装在此方法进行request = dispatcher.wrapRequest(request, getServletContext());
public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException { // don't wrap more than once 如果已经包装了,就不用再包装了 if (request instanceof StrutsRequestWrapper) { return request; } String content_type = request.getContentType(); //非表单提交的request 封装,主要是图片上传等 if (content_type != null && content_type.indexOf("multipart/form-data") != -1) { MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class); //如果是非表单提交则包装成MultiPartRequestWrapper request = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext)); } else { //如果是普通表单提交,在此包装 request = new StrutsRequestWrapper(request); } return request; }
2.2、mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());方法的分析
这里的分析参照了:http://zddava.iteye.com/blog/215504
下面来看一下默认使用的ActionMapper实现DefaultActionMapper的#getMapping():
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { ActionMapping mapping = new ActionMapping();// (1) String uri = getUri(request);// (2) uri = dropExtension(uri);// (3) if (uri == null) { return null; } parseNameAndNamespace(uri, mapping, configManager);// (4) handleSpecialParameters(request, mapping);// (5) if (mapping.getName() == null) { return null; } if (allowDynamicMethodCalls) {// (6) String name = mapping.getName(); int exclamation = name.lastIndexOf("!"); if (exclamation != -1) { mapping.setName(name.substring(0, exclamation)); mapping.setMethod(name.substring(exclamation + 1)); } } return mapping; }
主要有6处需要重点说明:
(1) 关于ActionMapping类,它内部封装了如下5个字段:
private String name;// Action名 private String namespace;// Action名称空间 private String method;// 执行方法 private Map params;// 可以通过set方法设置的参数 private Result result;// 返回的结果
这些在配置文件中都是可设置的,确定了ActionMapping类的各个字段的值,就可以对请求的Action进行调用了。
(2) String uri = getUri(request);
这个步骤用于获取客户端发送的请求的URI,源代码如下:
String getUri(HttpServletRequest request) { // handle http dispatcher includes. String uri = (String) request.getAttribute("javax.servlet.include.servlet_path"); if (uri != null) { return uri; } uri = RequestUtils.getServletPath(request); if (uri != null && !"".equals(uri)) { return uri; } uri = request.getRequestURI(); return uri.substring(request.getContextPath().length()); }
这个方法首先判断请求是否来自于一个jsp的include,如果是,那么请求的"javax.servlet.include.servlet_path"属性可以获得include的页面uri,否则通过一般的方法获得请求的uri,最后返回去掉ContextPath的请求路径,比如http://127.0.0.1:8087/test/jsp/index.jsp?param=1,返回的为/jsp/index.jsp。去掉了ContextPath和查询字符串等。
(3) uri = dropExtension(uri); 负责去掉Action的"扩展名"(默认为"action"),源代码如下:
String dropExtension(String name) { //extensions 为struts2 的后缀名,可有多个,默认为action // List extensions = new ArrayList() {{ add("action");}}; if (extensions == null) { return name; } Iterator it = extensions.iterator(); //分别遍历后去掉后缀名 while (it.hasNext()) { String extension = "." + (String) it.next(); if (name.endsWith(extension)) { name = name.substring(0, name.length() - extension.length()); return name; } } return null; }
注意,这个步骤对于不是以特地扩展名结尾的请求会返回一个null的uri,进而#getMapping()也会返回null,FilterDispatcher的#doFilter()就会把这次请求当作一个普通请求对待了。
(4) parseNameAndNamespace(uri, mapping, configManager);
此方法用于解析Action的名称和命名空间,并赋给ActionMapping对象。源代码如下:
void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) { String namespace, name; // 例如 http://127.0.0.1:8087/teststruts/namespace/name.action?param=1 // dropExtension()后,获得uri为/namespace/name int lastSlash = uri.lastIndexOf("/"); if (lastSlash == -1) { namespace = ""; name = uri; } else if (lastSlash == 0) { namespace = "/"; name = uri.substring(lastSlash + 1); } else if (alwaysSelectFullNamespace) {// alwaysSelectFullNamespace默认为false,代表是否将最后一个"/"前的字符全作为名称空间。 namespace = uri.substring(0, lastSlash);// 获得字符串 namespace name = uri.substring(lastSlash + 1);// 获得字符串 name } else { // 例如 http://127.0.0.1:8087/teststruts/namespace1/namespace2/actionname.action?param=1 // dropExtension()后,获得uri为/namespace1/namespace2/actionname Configuration config = configManager.getConfiguration(); String prefix = uri.substring(0, lastSlash);// 获得 /namespace1/namespace2 namespace = ""; // 如果配置文件中有一个包的namespace是 /namespace1/namespace2,那么namespace为/namespace1/namespace2,name为actionname // 如果配置文件中有一个包的namespace是 /namespace1,那么namespace为/namespace1,name为/namespace2/actionname for (Iterator i = config.getPackageConfigs().values().iterator(); i .hasNext();) { String ns = ((PackageConfig) i.next()).getNamespace(); if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) { if (ns.length() > namespace.length()) { namespace = ns; } } } name = uri.substring(namespace.length() + 1); } if (!allowSlashesInActionNames && name != null) {// allowSlashesInActionNames代表是否允许"/"出现在Action的名称中,默认为false int pos = name.lastIndexOf('/'); if (pos > -1 && pos < name.length() - 1) { name = name.substring(pos + 1); } }// 以 name = /namespace2/actionname 为例,经过这个if块后,name = actionname mapping.setNamespace(namespace); mapping.setName(name); }
(5) handleSpecialParameters(request, mapping); 此方法用于处理Struts框架定义的四种特殊的prefix:
下边是struts2的javadoc里提供的例子:
Method prefix:调用baz的另外一个方法"anotherMethod"而不是"execute"
<a:form action="baz"> <a:textfield label="Enter your name" name="person.name"/> <a:submit value="Create person"/> <a:submit name="method:anotherMethod" value="Cancel"/> </a:form>
Action prefix:调用anotherAction的"execute"
<a:form action="baz"> <a:textfield label="Enter your name" name="person.name"/> <a:submit value="Create person"/> <a:submit name="action:anotherAction" value="Cancel"/> </a:form>
Redirect prefix:将请求重定向,下例中为定向到google
<a:form action="baz"> <a:textfield label="Enter your name" name="person.name"/> <a:submit value="Create person"/> <a:submit name="redirect:www.google.com" value="Cancel"/> </a:form>
Redirect-action prefix:重定向action,下例中为定向到dashboard.action
<a:form action="baz"> <a:textfield label="Enter your name" name="person.name"/> <a:submit value="Create person"/> <a:submit name="redirect-action:dashboard" value="Cancel"/> </a:form>
handleSpecialParameters的源代码如下:
public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) { Set<String> uniqueParameters = new HashSet<String>(); Map parameterMap = request.getParameterMap(); for (Iterator iterator = parameterMap.keySet().iterator(); iterator.hasNext();) { String key = (String) iterator.next(); if (key.endsWith(".x") || key.endsWith(".y")) {// 去掉图片按钮的位置信息,具体情况我也不是很了解 key = key.substring(0, key.length() - 2); } // 处理四种特殊的prefix:Method prefix,Action prefix,Redirect prefix,Redirect-action prefix if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key); if (parameterAction != null) {// 当发现某种特殊的predix时 parameterAction.execute(key, mapping);// 调用它的execute方法,在DefaultActionMapper的构造函数中定义 uniqueParameters.add(key);// 下边已经break了为什么还要把key加入到排重的Set里呢?? break; } } } }
(6) 处理调用的不是execute方法的情况:
Struts框架也可以处理"name!method"形式的action调用,碰到这种情况,在此处将name和method分别解析出来然后赋给ActionMapping对象。
发表评论
-
Struts2.1XX 后台不打印异常问题
2010-07-15 12:00 3019在开发的时候发现Struts2.16 在action内抛 ... -
Struts2 主要类的源码分析
2010-03-25 14:39 0下面以Struts2 请求流程(FilterDispater ... -
struts2 主要类分析
2009-12-13 17:53 0下面以Struts2 请求流程(FilterDispater ... -
struts2 处理请求流程分析(结合源码)3
2009-12-04 17:35 27882.3、dispatcher.serviceActio ... -
struts2 处理请求流程分析(结合源码)1
2009-12-04 17:33 2556struts2 源码版本2.0.11.1 本文是综合网上部分 ... -
struts2 中struts.properties 配置详解
2009-11-23 10:53 989struts.configuration #该属性指定加载S ... -
webwork拦截器interceptor 之 ActionInvocation 意义
2009-09-11 10:22 2109“将Web页面中的输入元素封装为一个(请求)数据对象”,这个对 ... -
struts2 流程源码分析及标签查询
2009-06-07 09:19 1550源码分析:http://zddava.iteye.com/ca ... -
struts2学习总结
2009-04-28 11:54 2612该文章会随着strust2 学习的深入,不断添加和更新,说 ... -
struts2中OGNL和 ValueStack(二)
2009-04-27 23:10 2393表达式语言主要有以下几大好处: 避免(MyType) re ... -
struts2中OGNL和 ValueStack(一)
2009-04-27 23:08 10489学习的时候,总分不清楚在struts2中页面的传值和取值是怎么 ... -
Struts2 拦截器总结(内置和新建)
2009-04-21 23:07 2524拦截器的类已经定义在特殊的配置文件中,这个配置文件的名 ...
相关推荐
Struts作为模型-视图-控制器(MVC)架构的一部分,负责处理Web层的请求和响应流程,简化了用户界面与后端逻辑之间的交互。Hibernate则提供了对象关系映射(ORM),将复杂的数据库操作封装成简单的Java对象处理,极大...
流程:在Struts中,用户的请求一般以*.do作为请求服务名,所有的*.do请求均被指向ActionSevlet,ActionSevlet根据Struts-config.xml中的配置信息,将用户请求封装成一个指定名称的FormBean,并将此FormBean传...
Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...
内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行...
程序采用MVC模式: JSP + Struts2 + Spring + Hibernate 3 + MySQL 数据库:MySQL 前台游客浏览、普通用户操作和后台管理3部分。结合目前网上购物平台系统的设计方案,本项目具有 以下特点:界面设计美观大方、...
8.7.1 Struts2处理表单数据 8.7.2 使用M印类型的request、session、application 8.8 疑难解惑 8.8.1 Struts Prepare And Execute Filter过滤器 8.8.2 struts.xml文件配置出错 8.9 精彩回顾 第9章 庖丁解牛 ——揭密...
关键词:SSH集成框架 Web 1主流Web开发框架分析 1.1 MVC结构模式和WebWork框架 2012年王欢认为MVC的工作原理是,使用MVC时,当用户向Web容器发送一个请求后, Web容器会根据请求和地址去调用一个Servlet进行处理,...
系统后台选用了SSH框架来实现主要的业务逻辑,其中Struts2负责Web层的请求响应分发,Spring框架处理业务对象的生命周期及依赖关系,Hibernate用于对象关系映射和数据的持久化操作。前端采用了JSP技术结合JavaScript...
四:系统自行修改了action请求为html 所以大家不要感到诧异 详细见struts.properties文件 struts.action.extension=html 操作流程 通过系统首页,可实现浏览系统推荐商品、热销商品、以及各种分类商品等内容,也...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...