<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC ## 原創內容,轉載請注明iteye?[http://jinnianshilongnian.iteye.com/](/) ## 4.15、MultiActionController 之前學過的控制器如AbstractCommandController、SimpleFormController等一般對應一個功能處理方法(如新增),如果我要實現比如最簡單的用戶增刪改查(CRUD Create-Read-Update-Delete),那該怎么辦呢? #### 4.15.1?解決方案 1、每一個功能對應一個控制器,如果是CRUD則需要四個控制器,但這樣我們的控制器會暴增,肯定不可取; 2、使用Spring Web MVC提供的MultiActionController,用于支持在一個控制器里添加多個功能處理方法,即將多個請求的處理方法放置到一個控制器里,這種方式不錯。 #### 4.15.2?問題 1、? MultiActionController如何將不同的請求映射不同的請求的功能處理方法呢? Spring Web MVC提供了MethodNameResolver(方法名解析器)用于解析當前請求到需要執行的功能處理方法的方法名。默認使用InternalPathMethodNameResolver實現類,另外還提供了ParameterMethodNameResolver和PropertiesMethodNameResolver,當然我們也可以自己來實現,稍候我們仔細研究下它們是如何工作的。 2、那我們的功能處理方法應該怎么寫呢? public (ModelAndView | Map | String | void) actionName(HttpServletRequest request, HttpServletResponse response, [,HttpSession session] [,AnyObject]); 哦,原來如此,我們只需要按照如上格式寫我們的功能處理方法即可;此處需要注意一下幾點: **1、返回值:即模型和視圖部分;** ModelAndView:模型和視圖部分,之前已經見過了; Map:只返回模型數據,邏輯視圖名會根據RequestToViewNameTranslator實現類來計算,稍候討論; String:只返回邏輯視圖名; void:表示該功能方法直接寫出response響應(如果其他返回值類型(如Map)返回null則和void進行相同的處理); **2、actionName:**功能方法名字;由methodNameResolver根據請求信息解析功能方法名,通過反射調用; **3、形參列表:**順序固定,“[]”表示可選,我們來看看幾個示例吧: **//表示到新增頁面** public ModelAndView toAdd(HttpServletRequest request, HttpServletResponse response); **//表示新增表單提交,在最后可以帶著命令對象** public ModelAndView add(HttpServletRequest request, HttpServletResponse response, UserModel user); **//列表,但只返回模型數據,視圖名會通過RequestToViewNameTranslator實現來計算** public Map list(HttpServletRequest request, HttpServletResponse response); **//文件下載,返回值類型為void,表示該功能方法直接寫響應** public void fileDownload(HttpServletRequest request, HttpServletResponse response) **//第三個參數可以是session** public ModelAndView sessionWith(HttpServletRequest request, HttpServletResponse response, HttpSession session); **//如果第三個參數是session,那么第四個可以是命令對象,順序必須是如下順序** public void sessionAndCommandWith(HttpServletRequest request, HttpServletResponse response, HttpSession session, UserModel user) **4、異常處理方法,**MultiActionController提供了簡單的異常處理,即在請求的功能處理過程中遇到異常會交給異常處理方法進行處理,式如下所示: public ModelAndView anyMeaningfulName(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception) MultiActionController會使用最接近的異常類型來匹配對應的異常處理方法,示例如下所示: **//處理PayException** public ModelAndView processPayException(HttpServletRequest request, HttpServletResponse response, PayException ex) **//處理Exception** public ModelAndView processException(HttpServletRequest request, HttpServletResponse response,? Exception ex) #### 4.15.3?MultiActionController類實現 **類定義:**public class MultiActionController extends AbstractController implements LastModified ,繼承了AbstractController,并實現了LastModified接口,默認返回-1; **核心屬性:** **delegate:**功能處理的委托對象,即我們要調用請求處理方法所在的對象,默認是this; **methodNameResolver:**功能處理方法名解析器,即根據請求信息來解析需要執行的delegate的功能處理方法的方法名。 **核心方法:** ``` //判斷方法是否是功能處理方法 private boolean isHandlerMethod(Method method) { //得到方法返回值類型 Class returnType = method.getReturnType(); //返回值類型必須是ModelAndView、Map、String、void中的一種,否則不是功能處理方法 if (ModelAndView.class.equals(returnType) || Map.class.equals(returnType) || String.class.equals(returnType) || void.class.equals(returnType)) { Class[] parameterTypes = method.getParameterTypes(); //功能處理方法參數個數必須>=2,且第一個是HttpServletRequest類型、第二個是HttpServletResponse //且不能Controller接口的handleRequest(HttpServletRequest request, HttpServletResponse response),這個方法是由系統調用 return (parameterTypes.length >= 2 && HttpServletRequest.class.equals(parameterTypes[0]) && HttpServletResponse.class.equals(parameterTypes[1]) && !("handleRequest".equals(method.getName()) && parameterTypes.length == 2)); } return false; } ``` ``` //是否是異常處理方法 private boolean isExceptionHandlerMethod(Method method) { //異常處理方法必須是功能處理方法 且 參數長度為3、第三個參數類型是Throwable子類 return (isHandlerMethod(method) && method.getParameterTypes().length == 3 && Throwable.class.isAssignableFrom(method.getParameterTypes()[2])); } ``` ``` private void registerHandlerMethods(Object delegate) { //緩存Map清空 this.handlerMethodMap.clear(); this.lastModifiedMethodMap.clear(); this.exceptionHandlerMap.clear(); //得到委托對象的所有public方法 Method[] methods = delegate.getClass().getMethods(); for (Method method : methods) { //驗證是否是異常處理方法,如果是放入exceptionHandlerMap緩存map if (isExceptionHandlerMethod(method)) { registerExceptionHandlerMethod(method); } //驗證是否是功能處理方法,如果是放入handlerMethodMap緩存map else if (isHandlerMethod(method)) { registerHandlerMethod(method); registerLastModifiedMethodIfExists(delegate, method); } } } ``` ``` protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { try { //1、使用methodNameResolver 方法名解析器根據請求解析到要執行的功能方法的方法名 String methodName = this.methodNameResolver.getHandlerMethodName(request); //2、調用功能方法(通過反射調用,此處就粘貼代碼了) return invokeNamedMethod(methodName, request, response); } catch (NoSuchRequestHandlingMethodException ex) { return handleNoSuchRequestHandlingMethod(ex, request, response); } } ``` 接下來,我們看一下MultiActionController如何使用`MethodNameResolver來解析請求到功能處理方法的方法名。` #### 4.15.4?`MethodNameResolver` `**1、InternalPathMethodNameResolver:**``MultiActionController的默認實現,提供從請求URL路徑解析功能方法的方法名,從請求的最后一個路徑(/)開始,并忽略擴展名;如請求URL是“/user/list.html”,則解析的功能處理方法名為“list”,即調用list方法。該解析器還可以指定前綴和后綴,通過prefix和suffix屬性,如指定prefix=”test_”,則功能方法名將變為test_list;` `**2、ParameterMethodNameResolver:**``提供從請求參數解析功能處理方法的方法名,并按照如下順序進行解析:` `(1、?``methodParamNames:``根據請求的參數名解析功能方法名(功能方法名和參數名同名);` ``` <property name="methodParamNames" value="list,create,update"/> ? ``` `? 如上配置時,如果請求中含有參數名list、create、update時,則功能處理方法名為list、create、update,這種方式的可以在當一個表單有多個提交按鈕時使用,不同的提交按鈕名字不一樣即可。` `? ParameterMethodNameResolver也考慮到圖片提交按鈕提交問題:` `??? &lt;input type="image" name="list"&gt; 和submit類似可以提交表單,單擊該圖片后會發送兩個參數“list.x=x軸坐標”和“list.y=y軸坐標”(如提交后會變為list.x=7&list.y=5);因此我們配置的參數名(如list)在會加上“.x” 和 “.y”進行匹配。` ``` for (String suffix : SUBMIT_IMAGE_SUFFIXES) {//SUBMIT_IMAGE_SUFFIXES {“.x”, “.y”} if (request.getParameter(name + suffix) != null) {// name是我們配置的methodParamNames return true; } } ``` `(2、paramName:``根據請求參數名的值解析功能方法名,默認的參數名是action,即請求的參數中含有“action=query”,則功能處理方法名為query;` `(3、logicalMappings:``邏輯功能方法名到真實功能方法名映射,如下所示:` ``` <property name="logicalMappings"> <props> <prop key="doList">list</prop> </props> </property> ``` `? 即如果步驟1或2解析出邏輯功能方法名為doList(邏輯的),將會被重新映射為list功能方法名(真正執行的)。` `(4、defaultMethodName:``默認的方法名,當以上策略失敗時默認調用的方法名。` `**3、PropertiesMethodNameResolver:**``提供自定義的從請求URL解析功能方法的方法名,使用一組用戶自定義的模式到功能方法名的映射,映射使用`Properties對象存放,具體配置示例如下: ``` <bean id="propertiesMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/create">create</prop> <prop key="/update">update</prop> <prop key="/delete">delete</prop> <prop key="/list">list</prop> <!-- 默認的行為 --> <prop key="/**">list</prop> </props> </property> </bean>? ``` `對于/create請求將調用create方法,Spring內部使用PathMatcher進行匹配(默認實現是AntPathMatcher)。` ### 4.15.5?RequestToViewNameTranslator 用于直接將請求轉換為邏輯視圖名。默認實現為`DefaultRequestToViewNameTranslator。` `**1、DefaultRequestToViewNameTranslator:**``將請求URL轉換為邏輯視圖名,默認規則如下:` `? http://localhost:9080/web上下文/list -------&gt; 邏輯視圖名為list` `? http://localhost:9080/web上下文/list.html -------&gt; 邏輯視圖名為list(默認刪除擴展名)` `? http://localhost:9080/web上下文/user/list.html -------&gt; 邏輯視圖名為user/list` #### 4.15.6?示例 `**(1、控制器UserController**` ``` package cn.javass.chapter4.web.controller; //省略import public class UserController extends MultiActionController { //用戶服務類 private UserService userService; //邏輯視圖名 通過依賴注入方式注入,可配置 private String createView; private String updateView; private String deleteView; private String listView; private String redirectToListView; //省略setter/getter public String create(HttpServletRequest request, HttpServletResponse response, UserModel user) { if("GET".equals(request.getMethod())) { //如果是get請求 我們轉向 新增頁面 return getCreateView(); } userService.create(user); //直接重定向到列表頁面 return getRedirectToListView(); } public ModelAndView update(HttpServletRequest request, HttpServletResponse response, UserModel user) { if("GET".equals(request.getMethod())) { //如果是get請求 我們轉向更新頁面 ModelAndView mv = new ModelAndView(); //查詢要更新的數據 mv.addObject("command", userService.get(user.getUsername())); mv.setViewName(getUpdateView()); return mv; } userService.update(user); //直接重定向到列表頁面 return new ModelAndView(getRedirectToListView()); } public ModelAndView delete(HttpServletRequest request, HttpServletResponse response, UserModel user) { if("GET".equals(request.getMethod())) { //如果是get請求 我們轉向刪除頁面 ModelAndView mv = new ModelAndView(); //查詢要刪除的數據 mv.addObject("command", userService.get(user.getUsername())); mv.setViewName(getDeleteView()); return mv; } userService.delete(user); //直接重定向到列表頁面 return new ModelAndView(getRedirectToListView()); } public ModelAndView list(HttpServletRequest request, HttpServletResponse response) { ModelAndView mv = new ModelAndView(); mv.addObject("userList", userService.list()); mv.setViewName(getListView()); return mv; } //如果使用委托方式,命令對象名稱只能是command protected String getCommandName(Object command) { //命令對象的名字 默認command return "command"; } } ``` **增刪改:**如果是GET請求方法,則表示到展示頁面,POST請求方法表示真正的功能操作; `**? getCommandName:**`表示是命令對象名字,默認command,對于委托對象實現方式無法改變,因此我們就使用默認的吧。 `**(2、spring配置文件chapter4-servlet.xml**` ``` <bean id="userService" class="cn.javass.chapter4.service.UserService"/> <bean name="/user/**" class="cn.javass.chapter4.web.controller.UserController"> <property name="userService" ref="userService"/> <property name="createView" value="user/create"/> <property name="updateView" value="user/update"/> <property name="deleteView" value="user/delete"/> <property name="listView" value="user/list"/> <property name="redirectToListView" value="redirect:/user/list"/> <!-- 使用PropertiesMethodNameResolver來解析功能處理方法名 --> <!--property name="methodNameResolver" ref="propertiesMethodNameResolver"/--> </bean> ``` `? **userService:**用戶服務類,實現業務邏輯;` `?**?依賴注入:**對于邏輯視圖頁面通過依賴注入方式注入,redirectToListView表示增刪改成功后重定向的頁面,防止重復表單提交;` `?**?默認使用InternalPathMethodNameResolver解析請求URL到功能方法名。**` `**(3、視圖頁面**` `**(3.1、list頁面(WEB-INF/jsp/user/list.jsp)**` ``` <a href="${pageContext.request.contextPath}/user/create">用戶新增</a><br/> <table border="1" width="50%"> <tr> <th>用戶名</th> <th>真實姓名</th> <th>操作</th> </tr> <c:forEach items="${userList}" var="user"> <tr> <td>${user.username }</td> <td>${user.realname }</td> <td> <a href="${pageContext.request.contextPath}/user/update?username=${user.username}">更新</a> | <a href="${pageContext.request.contextPath}/user/delete?username=${user.username}">刪除</a> </td> </tr> </c:forEach> </table> ``` `**(3.2、update頁面(WEB-INF/jsp/user/update.jsp)**` ``` <form action="${pageContext.request.contextPath}/user/update" method="post"> 用戶名: <input type="text" name="username" value="${command.username}"/><br/> 真實姓名:<input type="text" name="realname" value="${command.realname}"/><br/> <input type="submit" value="更新"/> </form> ``` `**(4、測試:**` **默認的InternalPathMethodNameResolver將進行如下解析:** http://localhost:9080/springmvc-chapter4/user/list————&gt;list方法名; http://localhost:9080/springmvc-chapter4/user/create————&gt;create方法名; http://localhost:9080/springmvc-chapter4/user/update————&gt;update功能處理方法名; http://localhost:9080/springmvc-chapter4/user/delete————&gt;delete功能處理方法名。 **我們可以將默認的InternalPathMethodNameResolver改為PropertiesMethodNameResolver:** ``` <bean id="propertiesMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/user/create">create</prop> <prop key="/user/update">update</prop> <prop key="/user/delete">delete</prop> <prop key="/user/list">list</prop> <prop key="/**">list</prop><!-- 默認的行為 --> </props> </property> <property name="alwaysUseFullPath" value="false"/><!-- 不使用全路徑 --> </bean> <bean name="/user/**" class="cn.javass.chapter4.web.controller.UserController"> <!—省略其他配置,詳見配置文件--> <!-- 使用PropertiesMethodNameResolver來解析功能處理方法名 --> <property name="methodNameResolver" ref="propertiesMethodNameResolver"/> </bean> ``` **/**表示默認解析到list功能處理方法。** 如上配置方式可以很好的工作,但必須繼承MultiActionController,Spring Web MVC提供給我們無需繼承MultiActionController實現方式,即使有委托對象方式,繼續往下看吧。 ### 4.15.7、委托方式實現 `**(1、控制器UserDelegate**` `?? 將UserController復制一份,改名為UserDelegate,并把繼承MultiActionController去掉即可,其他無需改變。` `**(2、spring配置文件chapter4-servlet.xml**` ``` <!—委托對象--> <bean id="userDelegate" class="cn.javass.chapter4.web.controller.UserDelegate"> <property name="userService" ref="userService"/> <property name="createView" value="user2/create"/> <property name="updateView" value="user2/update"/> <property name="deleteView" value="user2/delete"/> <property name="listView" value="user2/list"/> <property name="redirectToListView" value="redirect:/user2/list"/> </bean> <!—控制器對象--> <bean name="/user2/**" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController"> <property name="delegate" ref="userDelegate"/> <property name="methodNameResolver" ref="parameterMethodNameResolver"/> </bean> ``` **delegate:**`控制器對象通過`delegate屬性指定委托對象,即實際調用delegate委托對象的功能方法。 **methodNameResolver:**此處我們使用ParameterMethodNameResolver解析器; ``` <!—ParameterMethodNameResolver --> <bean id="parameterMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <!-- 1、根據請求參數名解析功能方法名 --> <property name="methodParamNames" value="create,update,delete"/> <!-- 2、根據請求參數名的值解析功能方法名 --> <property name="paramName" value="action"/> <!-- 3、邏輯方法名到真實方法名的映射 --> <property name="logicalMappings"> <props> <prop key="doList">list</prop> </props> </property> <!—4、默認執行的功能處理方法 --> <property name="defaultMethodName" value="list"/> </bean> ``` `**1、**`**methodParamNames:**create,update,delete,當請求中有參數名為這三個的將被映射為功能方法名,如“&lt;input type="submit" name="create" value="新增"/&gt;”提交后解析得到的功能方法名為create; `**2、paramName:**`當請求中有參數名為action,則將值映射為功能方法名,如“&lt;input type="hidden" name="action" value="delete"/&gt;”,提交后解析得到的功能方法名為delete; `**3、logicalMappings:**`邏輯功能方法名到真實功能方法名的映射,如: http://localhost:9080/springmvc-chapter4/user2?action=doList; `??? 首先請求參數“action=doList”,則第二步解析得到邏輯功能方法名為doList;` `??? 本步驟會把doList再轉換為真實的功能方法名list。` `**4、defaultMethodName:**`以上步驟如果沒有解析到功能處理方法名,默認執行的方法名。 `**(3、視圖頁面**` `**(3.1、list頁面(WEB-INF/jsp/user2/list.jsp)**` ``` <a href="${pageContext.request.contextPath}/user2?action=create">用戶新增</a><br/> <table border="1" width="50%"> <tr> <th>用戶名</th> <th>真實姓名</th> <th>操作</th> </tr> <c:forEach items="${userList}" var="user"> <tr> <td>${user.username }</td> <td>${user.realname }</td> <td> <a href="${pageContext.request.contextPath}/user2?action=update&username=${user.username}">更新</a> | <a href="${pageContext.request.contextPath}/user2?action=delete&username=${user.username}">刪除</a> </td> </tr> </c:forEach> </table>? ``` `**(3.2、update頁面(WEB-INF/jsp/user2/update.jsp)**` ``` <form action="${pageContext.request.contextPath}/user2" method="post"> <input type="hidden" name="action" value="update"/> 用戶名: <input type="text" name="username" value="${command.username}"/><br/> 真實姓名:<input type="text" name="realname" value="${command.realname}"/><br/> <input type="submit" value="更新"/> </form>? ``` `? 通過參數`name=_"action"_ value=_"update"_`來指定要執行的功能方法名update。` `**(3.3、create頁面(WEB-INF/jsp/user2/create.jsp)**` ``` <form action="${pageContext.request.contextPath}/user2" method="post"> 用戶名: <input type="text" name="username" value="${command.username}"/><br/> 真實姓名:<input type="text" name="realname" value="${command.realname}"/><br/> <input type="submit" name="create" value="新增"/> </form>? ``` `? 通過參數`name=_"create"_`來指定要執行的功能方法名create。` `**(4、測試:**` **使用ParameterMethodNameResolver將進行如下解析:** http://localhost:9080/springmvc-chapter4/user2?create????? ————&gt;create功能處理方法名(參數名映射); http://localhost:9080/springmvc-chapter4/user2?action=create————&gt;create功能處理方法名(參數值映射); http://localhost:9080/springmvc-chapter4/user2?update????? ————&gt;update功能處理方法名; http://localhost:9080/springmvc-chapter4/user2?action=update————&gt;update功能處理方法名; http://localhost:9080/springmvc-chapter4/user2?delete????? ————&gt;delete功能處理方法名; http://localhost:9080/springmvc-chapter4/user2?action=delete————&gt;delete功能處理方法名; http://localhost:9080/springmvc-chapter4/user2?doList????? ————&gt;通過logicalMappings解析為list功能處理方法。 http://localhost:9080/springmvc-chapter4/user2?action=doList————&gt;通過logicalMappings解析為list功能處理方法。 http://localhost:9080/springmvc-chapter4/user2————&gt;默認的功能處理方法名list(默認)。 原創內容,轉載請注明iteye?[http://jinnianshilongnian.iteye.com/](/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看