OA学习笔记-010-Struts部分源码分析、Intercepter、ModelDriver、OGNL、EL
一、分析
二、
1.OGNL
在访问action前,要经过各种intercepter,其中ParameterFilterInterceptor会把各咱参数放到ValueStack里,从而使OGNL可以访问这些参数,而ValueStack里包含对象stack和map
(1)map
赋值:ActionContext.getContext().put("roleList", roleList);
取值:在jsp中通过ognl取<s:iterator value="#roleList">或<s:iterator value="%{#roleList}">
注:因为struts标签默认使用ognl表达式,所以可以省略“%{}”,而“#”是表示从map中取值,不会去对象栈中去取
(2)对象stack
压栈:ActionContext.getContext().getValueStack().push(role);
取值:
1 <table cellpadding="0" cellspacing="0" class="mainForm"> 2 <tr> 3 <td width="100">岗位名称</td> 4 <td><s:textfield name="name" cssClass="InputStyle" /> *</td> 5 </tr> 6 <tr> 7 <td>岗位说明</td> 8 <td><s:textarea name="description" cssClass="TextareaStyle"></s:textarea></td> 9 </tr> 10 </table>
struts标签会自动去对象statck中找%{name}、%{description}
2.El表达式
若使用了struts框架,则request会被装饰类StrutsRequestWrapper代换,StrutsRequestWrapper包装了ServletRequest,也提供了访问valuestack的方法,所以使El表达式可以访问request中的值及访问valuestack,
在jsp中写${name},此时的取值顺序是(1)先以request中取,若取不到就到valuestack取,源码如下:
1 /* 2 * $Id$ 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 package org.apache.struts2.dispatcher; 23 24 import com.opensymphony.xwork2.ActionContext; 25 import com.opensymphony.xwork2.util.ValueStack; 26 27 import javax.servlet.http.HttpServletRequest; 28 import javax.servlet.http.HttpServletRequestWrapper; 29 30 import static org.apache.commons.lang3.BooleanUtils.isTrue; 31 32 /** 33 * <!-- START SNIPPET: javadoc --> 34 * 35 * All Struts requests are wrapped with this class, which provides simple JSTL accessibility. This is because JSTL 36 * works with request attributes, so this class delegates to the value stack except for a few cases where required to 37 * prevent infinite loops. Namely, we don't let any attribute name with "#" in it delegate out to the value stack, as it 38 * could potentially cause an infinite loop. For example, an infinite loop would take place if you called: 39 * request.getAttribute("#attr.foo"). 40 * 41 * <!-- END SNIPPET: javadoc --> 42 * 43 */ 44 public class StrutsRequestWrapper extends HttpServletRequestWrapper { 45 46 private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute"; 47 private final boolean disableRequestAttributeValueStackLookup; 48 49 /** 50 * The constructor 51 * @param req The request 52 */ 53 public StrutsRequestWrapper(HttpServletRequest req) { 54 this(req, false); 55 } 56 57 /** 58 * The constructor 59 * @param req The request 60 * @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility) 61 */ 62 public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) { 63 super(req); 64 this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup; 65 } 66 67 /** 68 * Gets the object, looking in the value stack if not found 69 * 70 * @param key The attribute key 71 */ 72 public Object getAttribute(String key) { 73 if (key == null) { 74 throw new NullPointerException("You must specify a key value"); 75 } 76 77 if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) { 78 // don't bother with the standard javax.servlet attributes, we can short-circuit this 79 // see WW-953 and the forums post linked in that issue for more info 80 return super.getAttribute(key); 81 } 82 83 ActionContext ctx = ActionContext.getContext(); 84 Object attribute = super.getAttribute(key); 85 86 if (ctx != null && attribute == null) { 87 boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE)); 88 89 // note: we don't let # come through or else a request for 90 // #attr.foo or #request.foo could cause an endless loop 91 if (!alreadyIn && !key.contains("#")) { 92 try { 93 // If not found, then try the ValueStack 94 ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE); 95 ValueStack stack = ctx.getValueStack(); 96 if (stack != null) { 97 attribute = stack.findValue(key); 98 } 99 } finally { 100 ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE); 101 } 102 } 103 } 104 return attribute; 105 } 106 }
例如:
1 <s:iterator value="#roleList"> 2 ${id}, 3 ${name}, 4 ${description}, 5 <s:a action="role_delete?id=%{id}" onclick="return confirm('确定要删除吗?')">删除</s:a>, 6 <s:a action="role_editUI?id=%{id}">修改</s:a> 7 <br/> 8 </s:iterator>
分析:s:iterator每次循环都会把当前对象压栈,循环结束就弹栈,${id}的访问顺序时先到对象栈里找,再到map里找,所以肯定可以找到
3.ModelDriven
ModelDriven的原理是,访问action前,ModelDrivenInterceptor会把model压到对象栈里,从而页面提交的比如id,name等字段会优先封闭到model里
源码如下:
1 @Override 2 public String intercept(ActionInvocation invocation) throws Exception { 3 Object action = invocation.getAction(); 4 5 if (action instanceof ModelDriven) { 6 ModelDriven modelDriven = (ModelDriven) action; 7 ValueStack stack = invocation.getStack(); 8 Object model = modelDriven.getModel(); 9 if (model != null) { 10 stack.push(model); 11 } 12 if (refreshModelBeforeResult) { 13 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); 14 } 15 } 16 return invocation.invoke(); 17 }
用法如:
1 <s:form action="role_add"> 2 <s:textfield name="name"></s:textfield> 3 <s:textarea name="description"></s:textarea> 4 <s:submit value="提交"></s:submit> 5 </s:form>
一提交,字段会自动封装到role里去,因为RoleAction实现了ModelDriven
1 @Override 2 public String intercept(ActionInvocation invocation) throws Exception { 3 Object action = invocation.getAction(); 4 5 if (action instanceof ModelDriven) { 6 ModelDriven modelDriven = (ModelDriven) action; 7 ValueStack stack = invocation.getStack(); 8 Object model = modelDriven.getModel(); 9 if (model != null) { 10 stack.push(model); 11 } 12 if (refreshModelBeforeResult) { 13 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); 14 } 15 } 16 return invocation.invoke(); 17 }