官网对struts2通配符使用的介绍:
<action name="*_*" class="com.netshuai.action.{1}Action" method="{2}">
<result name="success">/{2}_{1}Success.jsp</result>
</action>
如上所示,所有文件都采用统一的命名规范,第一个*为分类名称,第二个*为操作名,{1}和{2}分别代表第一个和第二个*的替换值,所有action实现类都命名为分类名称+Action。
如分类名称为User,操作名为add,则访问的action名为User_add.action,action实现类名为UserAction,返回页面的名为add_UserSuccess.jsp
另:{0}代表显示所有通配符内容,如<result name="success">/{2}_{1}Success.jsp</result>改为<resultname="success">/{0}Success.jsp</result>,则返回的名为User_addSuccess.jsp
下面我们来介绍struts2的通配符方面的实现的内部原理
AbstractMatcher类是主要的匹配和计算通配符的类,下面我们来学习他的match方法
/** * <p> Matches the path against the compiled wildcard patterns. </p> * * @param potentialMatch The portion of the request URI for selecting a config. * @return The action config if matched, else null */ public E match(String potentialMatch) { E config = null; 所有已经编译好的通配符的list,即已经将表达式的字符串转换为整形数组 if (compiledPatterns.size() > 0) { if (log.isDebugEnabled()) { log.debug("Attempting to match '" + potentialMatch + "' to a wildcard pattern, "+ compiledPatterns.size() + " available"); } 在这里,我们的match方法中传递的map(vars)终于派上了用场,它是用来存储匹配成功的字符, Map<String,String> vars = new LinkedHashMap<String,String>(); for (Mapping<E> m : compiledPatterns) { if (wildcard.match(vars, potentialMatch, m.getPattern())) { if (log.isDebugEnabled()) { log.debug("Value matches pattern '" + m.getOriginalPattern() + "'"); } config = convert(potentialMatch, m.getTarget(), vars); break; } } } return config; }
下面我们来关注下convert方法:我们关注它的子类,ActionConfigMatcher
在进行convert方法的时候,传递了一个map,下面我们通过一个模拟WildCardMatcher类的方法,给我们看下,这个map
到底是什么:
运行这段模拟的java代码:
1 public static void main(String[] args) throws URISyntaxException { 2 WildcardHelper w = new WildcardHelper(); 3 int[] a = w.compilePattern("*_*"); 4 for (int i = 0; i < a.length; i++) { 5 int j = a[i]; 6 System.out.print(j + ","); 7 } 8 Map<String,String> vars = new LinkedHashMap<String,String>(); 9 //User_add.action,页面请求的action,请求通过struts2的处理后,他会把后缀action给截取掉 10 //所以,我们模拟的时候,将action给去掉 11 w.match(vars, "User_add", a); 12 System.out.println(); 13 System.out.println(vars); 14 }
结果:
1 -4,-1,95,-1,-5, 2 {0=User_add, 1=User, 2=add}
现在终于知道了这个map的作用了,这个map存放的值是为了在取如下配置中的
<action name="*_*" class="com.netshuai.action.{1}Action" method="{2}">
<result name="success">/{2}_{1}Success.jsp</result>
</action>
{1}和{2}中的值,另外,struts2对这个{下标}的这个下标的最大值进行了限定,最大的值为9,请看下面的官网的介绍
In the action mapping and action results, the wildcard-matched values can be accessed with the token {N} where N is a number from 1 to 9 indicating which wildcard-matched value to substitute. The whole request URI can be accessed with the {0} token.{0代表struts2的请求全路径},
1 /** 2 * <p> Clones the ActionConfig and its children, replacing various 3 * properties with the values of the wildcard-matched strings. </p> 4 * 5 * @param path The requested path 6 * @param orig The original ActionConfig 7 * @param vars A Map of wildcard-matched strings 8 * @return A cloned ActionConfig with appropriate properties replaced with 9 * wildcard-matched values 10 */ 11 @Override public ActionConfig convert(String path, ActionConfig orig, 12 Map<String, String> vars) { 13 14 String className = convertParam(orig.getClassName(), vars);转换类名 15 String methodName = convertParam(orig.getMethodName(), vars);转换方法名 16 String pkgName = convertParam(orig.getPackageName(), vars);转换包名 17 替换参数 18 Map<String,String> params = replaceParameters(orig.getParams(), vars); 19 替换result配置 20 Map<String,ResultConfig> results = new LinkedHashMap<String,ResultConfig>(); 21 for (String name : orig.getResults().keySet()) { 22 ResultConfig result = orig.getResults().get(name); 23 name = convertParam(name, vars); 24 ResultConfig r = new ResultConfig.Builder(name, convertParam(result.getClassName(), vars)) 25 .addParams(replaceParameters(result.getParams(), vars)) 26 .build(); 27 results.put(name, r); 28 } 29 30 List<ExceptionMappingConfig> exs = new ArrayList<ExceptionMappingConfig>(); 31 for (ExceptionMappingConfig ex : orig.getExceptionMappings()) { 32 String name = convertParam(ex.getName(), vars); 33 String exClassName = convertParam(ex.getExceptionClassName(), vars); 34 String exResult = convertParam(ex.getResult(), vars); 35 Map<String,String> exParams = replaceParameters(ex.getParams(), vars); 36 ExceptionMappingConfig e = new ExceptionMappingConfig.Builder(name, exClassName, exResult).addParams(exParams).build(); 37 exs.add(e); 38 } 39 重新的构造针当前action的配置:config 40 return new ActionConfig.Builder(pkgName, orig.getName(), className) 41 .methodName(methodName) 42 .addParams(params) 43 .addResultConfigs(results) 44 .addInterceptors(orig.getInterceptors()) 45 .addExceptionMappings(exs) 46 .location(orig.getLocation()) 47 .build(); 48 }
下面我们学习下convertParam方法:
1 /** 2 * <p> Inserts into a value wildcard-matched strings where specified 3 * with the {x} syntax. If a wildcard-matched value isn't found, the 4 * replacement token is turned into an empty string. 5 * </p> 6 * 7 * @param val The value to convert 8 * @param vars A Map of wildcard-matched strings 9 * @return The new value 10 */ 11 protected String convertParam(String val, Map<String, String> vars) { 12 if (val == null) { 13 return null; 14 } 15 16 int len = val.length(); 17 StringBuilder ret = new StringBuilder(); 18 char c; 19 String varVal; 20 for (int x=0; x<len; x++) { 21 c = val.charAt(x); 22 if (x < len - 2 && 23 c == '{' && '}' == val.charAt(x+2)) { 24 varVal = (String)vars.get(String.valueOf(val.charAt(x + 1))); 25 if (varVal != null) { 26 ret.append(varVal); 27 } 28 x += 2;在这里,将类似于{1}的值进行了替换,替换为解析好的map中的值,替换后进行+2,向后叠加 29 } else { 30 ret.append(c); 31 } 32 } 33 34 return ret.toString(); 35 }
-end