Struts2中URL处理
2017-01-13 17:03
357 查看
在Struts中,碰到一个奇怪的现象对于一下两个URL可以访问到同一个Action,
链接:
http://localhost:8081/operation/operator/quotetask/operator/quotetask/queryByTaskId.do?quoteTaskId=
http://localhost:8081/operation/operator/quotetask/queryByTaskId.do?quoteTaskId=
在好奇心的驱使下,查看了Struts对于URL的处理源码,在Struts中,主要是需要通过URL找到对应的ActionMapping设置,也就是在Struts.xml中配置的action,其寻找过程如下:
1. 在web.xml中,配置了.do结尾的请求,都会被struts的
2. 在StrutsPrepareAndExecuteFilter中的doFilter中,执行寻找ActionMapping,并执行对应的action方法逻辑
在PrepareOperations.findActionMapping中的逻辑
最后处理URL的地方在DefaultActionMapper.parseNameAndNamespace中
链接:
http://localhost:8081/operation/operator/quotetask/operator/quotetask/queryByTaskId.do?quoteTaskId=
http://localhost:8081/operation/operator/quotetask/queryByTaskId.do?quoteTaskId=
在好奇心的驱使下,查看了Struts对于URL的处理源码,在Struts中,主要是需要通过URL找到对应的ActionMapping设置,也就是在Struts.xml中配置的action,其寻找过程如下:
1. 在web.xml中,配置了.do结尾的请求,都会被struts的
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter过滤器过滤。
2. 在StrutsPrepareAndExecuteFilter中的doFilter中,执行寻找ActionMapping,并执行对应的action方法逻辑
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { prepare.setEncodingAndLocale(request, response); // 创建Struts值栈ValueStack prepare.createActionContext(request, response); // 设置当前分发工具类Dispatcher到当前线程中 prepare.assignDispatcherToThread(); request = prepare.wrapRequest(request); // 寻找相应的ActionMapping ActionMapping mapping = prepare.findActionMapping(request, response, true); if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { execute.executeAction(request, response, mapping); } } } finally { prepare.cleanupRequest(request); } }
在PrepareOperations.findActionMapping中的逻辑
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) { ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY); if (mapping == null || forceLookup) { try { mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager()); if (mapping != null) { request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping); } } catch (Exception ex) { dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); } } return mapping; }
最后处理URL的地方在DefaultActionMapper.parseNameAndNamespace中
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) { String namespace, name; int lastSlash = uri.lastIndexOf("/"); if (lastSlash == -1) { namespace = ""; name = uri; } else if (lastSlash == 0) { // ww-1046, assume it is the root namespace, it will fallback to // default // namespace anyway if not found in root namespace. namespace = "/"; name = uri.substring(lastSlash + 1); } else if (alwaysSelectFullNamespace) { // Simply select the namespace as everything before the last slash namespace = uri.substring(0, lastSlash); name = uri.substring(lastSlash + 1); } else { // Try to find the namespace in those defined, defaulting to "" Configuration config = configManager.getConfiguration(); String prefix = uri.substring(0, lastSlash); namespace = ""; boolean rootAvailable = false; // Find the longest matching namespace, defaulting to the default //找到对应的namespace(operator/quotetask) for (PackageConfig cfg : config.getPackageConfigs().values()) { String ns = cfg.getNamespace(); if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) { if (ns.length() > namespace.length()) { namespace = ns; } } if ("/".equals(ns)) { rootAvailable = true; } } // 找到对应的namspace,并用uri中,去除namespace,用于获取对应的action名字 name = uri.substring(namespace.length() + 1); // Still none found, use root namespace if found if (rootAvailable && "".equals(namespace)) { namespace = "/"; } } // 以上两个URL之所以能访问到同一个action, 关键在此处, 通过前面去掉namespace后,最后获得两个actionName为: operator/quotetask/queryByTaskId 与 /queryByTaskId .在以下代码中,直接获取最后一个"/"后的串,则都获得queryByTaskId.并找到对应的ActionMapping if (!allowSlashesInActionNames) { int pos = name.lastIndexOf('/'); if (pos > -1 && pos < name.length() - 1) { name = name.substring(pos + 1); } } mapping.setNamespace(namespace); mapping.setName(cleanupActionName(name)); }
总结: 在struts中,对与URL的处理,是直接忽略了namespace 与 actionName之间的字符串的。无论是 operator/quotetask/queryByTaskId, operator/quotetask/operator/quotetask/queryByTaskId, 还是operator/quotetask/operator/quotetask/operator/quotetask/queryByTaskId最后获取到的actionMapping都是 namespace: operator/quotetask, actionName: queryByTaskId
相关文章推荐
- (转)java 中的try catch finally 语句中含有return语句的执行情况(总结版)
- java hashCode() equals()
- java 的hashCode值计算
- Java多线程--初识线程与基本使用
- Spring Boot . 3 -- Spring Boot Auto_configuration 是如何实现的?
- Eclipse创建J2EE WEB项目出现project facet问题
- java的锁,synchronize和lock
- javap的基本用法
- java中枚举类的用法
- Eclipse搭建SpringMVC
- CI持续集成系统中的Java环境安装
- java 反射 模拟spring自动注入
- 使用Struts2的标签库(一)
- 深入理解JVM—JVM内存模型
- Java考试题之四
- Java考试题之四
- Java考试题之四
- JVM虚拟机类加载机制-过程
- Spring 读取配置文件的俩种方式
- java实现pdf转图片pdf