今天做畢業設計,前臺往后臺賦值,習慣性的用了modelDriven。但是剛寫完就奇怪它的機理是怎樣的,它怎么知道我前臺傳的參是哪個Model的屬性(之前用servlet都是手動),于是手賤的ctrl點進去,簡單了解了一下
之前記得要使用modelDriven必須使用modelDriven的攔截器,但是我沒加這個攔截器也實現了功能,看默認攔截器defaultStack原來所謂的默認攔截器就是一系列攔截器的集合
看modelDriven的源碼可以看到
1 @Override 2 3 public String intercept(ActionInvocation invocation) throws Exception { 4 5 //獲取 Action 對象: EmployeeAction 對象, 此時該 Action 已經實現了 ModelDriven 接口 6 7 //public class EmployeeAction implements RequestAware, ModelDriven<Employee> 8 9 Object action = invocation.getAction();10 11 //判斷 action 是否是 ModelDriven 的實例12 13 if (action instanceof ModelDriven) {14 15 //強制轉換為 ModelDriven 類型16 17 ModelDriven modelDriven = (ModelDriven) action;18 19 //獲取值棧20 21 ValueStack stack = invocation.getStack();22 23 //調用 ModelDriven 接口的 getModel() 方法24 25 //即調用 EmployeeAction 的 getModel() 方法26 27 /*28 29 public Employee getModel() {30 31 employee = new Employee();32 33 return employee;34 35 }36 37 */38 39 Object model = modelDriven.getModel();40 41 if (model != null) {42 43 //把 getModel() 方法的返回值壓入到值棧的棧頂. 實際壓入的是 EmployeeAction 的 employee 成員變量44 45 stack.push(model);46 47 }48 49 if (refreshModelBeforeResult) {50 51 invocation.addPReResultListener(new RefreshModelBeforeResult(modelDriven, model));52 53 }54 55 }56 57 return invocation.invoke();
發現它什么也沒實現,就是modelDriven接口,如果實現了就調用了它的getModel方法,然后把得到的壓入棧頂。沒有賦值操作
那么流程圖應該是這樣:
那么setName()賦值操作是誰做的?ParametersInterceptor
那么結論是:
1)ModelDrivenInterceptor只是將實現了ModelDriven的action的model放入值棧而已,所以你才可以直接使用<input type="text" name="type" />傳值。2)如果action沒有實現此接口,那么配置ModelDrivenInterceptor沒有任何意義3)ModelDrivenInterceptor并不負責注入值,賦值的是ParametersInterceptor
如果還要深究的話
ParametersInterceptor攔截器繼承自MethodFilterInterceptor,其主要功能是把ActionContext中的請求參數設置到ValueStack中,如果棧頂是當前Action則把請求參數設置到了Action中,如果棧頂是一個model(Action實現了ModelDriven接口)則把參數設置到了model中。
ParametersInterceptor攔截器主要源碼:
1 @Override 2 public String doIntercept(ActionInvocation invocation) throws Exception { 3 Object action = invocation.getAction();//獲取當前執行的Action對象 4 if (!(action instanceof NoParameters)) {//判斷Action是否實現了NoParameters接口,實現該接口表示該Action沒有任何請求參數 5 ActionContext ac = invocation.getInvocationContext();//獲取ActionContext對象 6 final Map<String, Object> parameters = retrieveParameters(ac);//獲取請求參數Map 7 //省略... 8 if (parameters != null) {//如果請求參數不為null 9 Map<String, Object> contextMap = ac.getContextMap();//獲取ActionContext內部的context Map,即OgnlContext對象 10 try { 11 //省略... 12 ValueStack stack = ac.getValueStack();//獲取值棧 13 setParameters(action, stack, parameters);//為值棧設置參數 14 } finally { 15 //省略... 16 } 17 } 18 } 19 return invocation.invoke();//調用下一個攔截器 20 }
可以知道為什么要實現自動賦值,只需要實現modelDriven接口就行了
其中最重要邏輯代碼是setParometers()方法
1 protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) { 2 ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware) 3 ? (ParameterNameAware) action : null;//判斷Action有無實現ParameterNameAware接口 4 5 Map<String, Object> params; 6 Map<String, Object> acceptableParameters;//合法參數集合 7 //判斷參數設置是否有序,ordered默認為false,即無序 8 if (ordered) { 9 params = new TreeMap<String, Object>(getOrderedComparator());//如果有序則要獲取比較器 10 acceptableParameters = new TreeMap<String, Object>(getOrderedComparator()); 11 params.putAll(parameters); 12 } else { 13 params = new TreeMap<String, Object>(parameters); 14 acceptableParameters = new TreeMap<String, Object>(); 15 } 16 //迭代請求參數 17 for (Map.Entry<String, Object> entry : params.entrySet()) { 18 String name = entry.getKey(); 19 //判斷參數是否合法,如果Action實現了ParameterNameAware則acceptableName(name)返回true且parameterNameAware.acceptableParameterName(name) 20 //也返回true該參數才是合法的;如果Action沒有實現ParameterNameAware則參數是否合法由acceptableName(name)方法決定 21 boolean acceptableName = acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name)); 22 //如果參數合法 23 if (acceptableName) { 24 acceptableParameters.put(name, entry.getValue());//把合法參數添加到合法參數集合中 25 } 26 } 27 28 ValueStack newStack = valueStackFactory.createValueStack(stack); 29 //省略... 30 for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {//迭代合法參數 31 String name = entry.getKey();//參數名 32 Object value = entry.getValue();//參數值 33 try { 34 newStack.setValue(name, value);//將該參數設置到ValueStack中 35 } catch (RuntimeException e) { 36 //省略... 37 } 38 } 39 //省略... 40 //看該方法的名稱是將合法參數添加到ActionContext中,但在該攔截器中,該方法為空實現,無任何代碼 41 //該方法被聲明為protected,即子類可以覆蓋該方法以改變行為 42 addParametersToContext(ActionContext.getContext(), acceptableParameters); 43 }
先判斷提交過來的參數是否合法,因為提交過來的參數會影響到值棧所以struts2要對提交過來的參數進行合法性檢查,以防止惡意用戶的攻擊,凡是請求參數中表達式中含有等號(=),逗號(,),#號(#)的都是非法表達式
至于怎么判斷是否合法,我已經沒興趣了,知道是acceptableName(name)方法決定的。
了解了這么多感覺用的更隨心所欲了。急需做無聊的畢業設計
新聞熱點
疑難解答