<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringMVC返回視圖常見的 5 種方式,你會幾種?| SpringMVC系列第7篇

          共 8684字,需瀏覽 18分鐘

           ·

          2021-07-06 06:16


          大家好,我是【路人甲 Java】號主路人,本文如果對你有幫助,點個在看,順便忙轉(zhuǎn)發(fā)一下,非常需要大家的支持,對 java 有興趣的朋友歡迎加我微信 itsoku 交流。

          當(dāng) http 請求被自定義的 controller 處理時,如何指定響應(yīng)的頁面呢?

          這個就是我們本文需要討論的問題。

          在 controller 中響應(yīng)頁面有很多種方式,稍后我們會一一介紹,大家需要掌握每種方式的用法以及這些方式之間的區(qū)別,以后能夠靈活使用。

          本文用到的頁面都以 jsp 為例,其他頁面模板技術(shù),比如 freemarker、velocity、thymeleaf、enjoy,這些我們后面專門再開篇講解。

          1、本文內(nèi)容

          • SpringMVC 返回頁面的3種方式及區(qū)別
          • SpringMVC 重定向的2種方式及區(qū)別

          2、軟件版本

          • idea 2020.3.3

          • jdk1.8

          • ≥maven3.6.1

          • spring5.3.6

          • apache-tomcat-9.0.46

          3、先來回顧下 servlet 中響應(yīng)頁面的 2 種方式

          SpringMVC 底層是依靠 servlet 來實現(xiàn)的,所以我們先回顧下 servlet 中響應(yīng)頁面是如何實現(xiàn)的。

          servlet 中響應(yīng)頁面有 2 種常見的方式,而 springmvc 中通常也是依靠這 2 種方式實現(xiàn)的。

          方式 1:轉(zhuǎn)向

          request.getRequestDispatcher(path).forward(request,response);

          1、path 為轉(zhuǎn)向的地址

          2、發(fā)生在服務(wù)器端,瀏覽器的地址欄不會發(fā)生變化

          3、path 指定的頁面,可以共享 request 請求中的數(shù)據(jù)

          4、path 必須是服務(wù)器端的資源

          方式 2:重定向

          response.sendRedirect(location);

          1、location 為重定向的地址

          2、重定向發(fā)生在客戶端(瀏覽器端),所以會導(dǎo)致瀏覽器地址欄發(fā)生變化,變?yōu)?location 指定的地址

          3、重定向會導(dǎo)致瀏覽器重新向服務(wù)器端發(fā)生一次請求,請求地址為 location 指定的地址

          4、location 可以為本服務(wù)器端的資源,也可以為外網(wǎng)可以訪問的任意資源,比如:http://www.baidu.com

          下面來詳解 springmvc 中響應(yīng)頁面的 5 種方式。

          4、方式 1:返回 ModelAndView

          需求

          通過 springmvc 實現(xiàn)用戶列表功能,如下圖

          如何實現(xiàn)?

          我們先來看一下如果用 servlet 是如何實現(xiàn)的,代碼如下:

          1、List<UserDto> userList = new ArrayList();
          2、request.setAttribute("userList",userList);
          3、request.getRequestDispatcher("/WEB-INF/view/user/list.jsp").forward(request,response);

          關(guān)鍵代碼就這幾行,相當(dāng)簡單。

          對應(yīng)的 jsp(/WEB-INF/view/user/list.jsp)關(guān)鍵代碼如下,一個循環(huán)遍歷用戶列表 userList

          <table border="1" cellpadding="10" cellspacing="0">
              <tr>
                  <th width="50">id</th>
                  <th width="100">name</th>
                  <th width="50">age</th>
              </tr>
              <c:forEach items="${userList}" var="user">
                  <tr align="center">
                      <td>${user.id}</td>
                      <td>${user.name}</td>
                      <td>${user.age}</td>
                  </tr>
              </c:forEach>
          </table>

          使用 springmvc 實現(xiàn)

          @Controller
          public class UserController {
              /**
               * 用戶列表(用戶id->用戶信息)
               */

              Map<Long, UserDto> userDtoMap = new ConcurrentHashMap<>();

              {
                  userDtoMap.put(1Lnew UserDto(1L"路人"30));
                  userDtoMap.put(2Lnew UserDto(2L"張三"20));
                  userDtoMap.put(3Lnew UserDto(3L"李四"18));
              }

              /**
               * 用戶列表
               *
               * @return
               */

              @RequestMapping("/user/list.do")
              public ModelAndView list() {
                  //1.創(chuàng)建ModelAndView
                  ModelAndView modelAndView = new ModelAndView();
                  //2.將所有用戶信息放到Model中
                  modelAndView.addObject("userList", userDtoMap.values());
                  //3.設(shè)置顯示的頁面
                  modelAndView.setViewName("/WEB-INF/view/user/list.jsp");
                  //4.返回ModelAndView
                  return modelAndView;
              }

          }

          這里主要看 list()這個方法,當(dāng)調(diào)用這個方法的時候,效果和上面 servlet 的效果一樣,這里用到了ModelAndView

          ModelAndView:模型&視圖

          通常我們的頁面都是動態(tài)的,客戶端看到的頁面,基本上都是模板(視圖)+數(shù)據(jù)(數(shù)據(jù)模型),經(jīng)過組裝之后輸出到客戶端的。

          所以響應(yīng)客戶端的請求,需要指定 2 個關(guān)鍵的信息:頁面、頁面中需要的數(shù)據(jù)。

          springmvc 中使用 ModelAndView 來存放這 2 個信息,通過modelAndView.addObject方法添加頁面中用到的數(shù)據(jù),通過modelAndView.setViewName("視圖名稱")來設(shè)置顯示的頁面。

          modelAndView.addObject("key","value")

          添加頁面中需要用到的數(shù)據(jù),效果同:request.setAttribute("key","value");

          modelAndView.setViewName("視圖名稱")

          指定需要顯示的視圖命名,比如 jsp 地址

          小結(jié)

          如果頁面中需要用到一些動態(tài)的數(shù)據(jù),此時可以使用 ModelAndView 作為返回值,將動態(tài)數(shù)據(jù)放到 ModelAndView 中。

          5、方式 2:直接返回視圖名稱

          當(dāng)頁面不需要用到后端的數(shù)據(jù)的時候,就只是顯示一個頁面,此時可以直接將視圖的名稱作為返回值就可以了,比如

          /**
           * 跳轉(zhuǎn)到新增頁面
           *
           * @return
           */

          @RequestMapping("/user/add.do")
          public String add() {
              //直接返回視圖的名稱(頁面的路徑)
              return "/WEB-INF/view/user/add.jsp";
          }

          6、方式 3:指定視圖解析器

          存在的問題

          大家看下上面 2 種方式,返回的視圖名稱,都以/WEB-INF/view/開頭,以.jsp結(jié)尾對不對。

          如果項目中我們規(guī)定所有的視圖都符合這種規(guī)則,即都放在/WEB-INF/view/目錄中,都是 jsp 文件,那么我們可以將視圖的名稱是不是可以簡化一下,怎么做的呢?

          具體 2 個步驟。

          step1:注冊視圖解析器

          在 springmvc 配置文件中添加下面配置,來指定視圖解析器。

          這個 bean 會對視圖的名稱進行處理,有 2 個參數(shù)需要指定

          • prefix:視圖文件前綴

          • suffix:視圖文件后綴

          最終視圖的名稱 = prefix+controller 中指定的 viewname+suffix

          <!-- 添加視圖解析器 -->
          <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="prefix" value="/WEB-INF/view/"/>
              <property name="suffix" value=".jsp"/>
          </bean>

          step2:調(diào)整 controller 中視圖的名稱

          viewName 舊值viewName 新值
          /WEB-INF/view/user/add.jspuser/add
          /WEB-INF/view/user/list.jspuser/list
          @RequestMapping("/user/add.do")
          public String add() {
              //直接返回視圖的名稱(頁面的路徑)
              return "user/add";
          }

          此時代碼是不是簡單多了。

          7、SpringMVC 實現(xiàn)重定向 2 種方式

          需求

          有時候,請求之后,需要做重定向操作,比如發(fā)送刪除用戶信息的請求/user/del/{用戶id}.do,后端處理成功之后,需重定向到用戶列表頁面/user/list.do

          這里就需要用到重定向的操作了,在 servlet 的中對應(yīng)代碼是

          response.sendRedirect(location);

          springmvc 中有好幾種實現(xiàn),這里我們主要掌握 2 種。

          方式 1:返回 String 類型

          springmvc 中實現(xiàn)重定向比較簡單,視圖的名稱必須需要以redirect:開頭,比如下面代碼,處理刪除用戶的請求,刪除成功之后,重定向到用戶列表頁面

          /**
           * 刪除用戶信息,刪除成功之后重定向到用戶列表頁
           *
           * @param userId 用戶id
           * @return
           */

          @GetMapping("/user/del/{userId}.do")
          public String del(@PathVariable("userId") Long userId, HttpServletRequest request) {
              //刪除用戶信息
              this.userDtoMap.remove(userId);
              //重定向到用戶列表頁面,此時瀏覽器地址會發(fā)生變化,變?yōu)閔ttp://localhost:8080/chat05/user/list.do
              return "redirect:/user/list.do";
          }

          方式 2:返回 ModelAndView 類型

          如果重定向的時候,我們需要向重定向的頁面攜帶參數(shù),一般我們可以這么做,代碼如下:

          return "redirect:/user/list.do?在這里拼參數(shù)";

          比如

          return "redirect:/user/list.do?p1=v1&p2=v2";

          如果遇到了這種請求,參數(shù)比較少的情況,按照上面拼接是可以的。

          springmvc 中提供了更簡單的方式,代碼如下,最終 springmv 會指定將 ModelAndView 中添加的數(shù)據(jù),拼接到重定向的 url 中

          @GetMapping("/user/del1/{userId}.do")
          public ModelAndView del1(@PathVariable("userId") Long userId) {
              //刪除用戶記錄
              this.userDtoMap.remove(userId);

              /**
               * 重定向到用戶列表頁面,此時瀏覽器地址會發(fā)生變化,
               * 變?yōu)閔ttp://localhost:8080/chat05/user/list.do?p1=v1&p2=v2
               */

              ModelAndView modelAndView = new ModelAndView();
              modelAndView.addObject("p1""v1");
              modelAndView.addObject("p2""v2");
              modelAndView.setViewName("redirect:/user/list.do");
              return modelAndView;
          }

          8、案例代碼

          git 地址

          https://gitee.com/javacode2018/springmvc-series

          案例說明

          案例中實現(xiàn)了用戶信息的增刪改查,用到了上面講到的所有技術(shù)。

          用戶列表頁

          http://localhost:8080/chat05/user/list.do

          新增用戶頁面

          http://localhost:8080/chat05/user/add.do

          修改用戶信息頁面

          刪除用戶信息

          刪除用戶信息之后,會被重定向到用戶列表頁,案例中列出了 2 種刪除,用來模擬 2 種重定向的效果。

          9、總結(jié)

          • 響應(yīng)頁面通常有 2 種方式,第 1 種返回 ModelAndView,這種方式比較適合頁面中需要后端傳遞數(shù)據(jù)的,第 2 種方式直接返回視圖的名稱,這種適合無需傳遞數(shù)據(jù)的。

          • springmvc 容器中配置 InternalResourceViewResolver 視圖解析器,用來簡化 controller 中視圖的名稱

          • 掌握重新的 2 種方式,重定向的關(guān)鍵點是視圖名稱要以redirect:開頭,這樣 springmvc 才知道你需要 springmvc 來幫你執(zhí)行重定向操作。

          10、SpringMVC 系列

          1. SpringMVC 系列第 1 篇:helloword
          2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping
          3. SpringMVC 系列第 3 篇:異常高效的一款接口測試?yán)?/a>
          4. SpringMVC 系列第 4 篇:controller 常見的接收參數(shù)的方式
          5. SpringMVC 系列第 5 篇:@RequestBody 大解密,說點你不知道的
          6. SpringMVC 系列第 6 篇:上傳文件的 4 種方式,你都會么?

          11、更多好文章

          1. Spring 高手系列(共 56 篇)
          2. Java 高并發(fā)系列(共 34 篇)
          3. MySql 高手系列(共 27 篇)
          4. Maven 高手系列(共 10 篇)
          5. Mybatis 系列(共 12 篇)
          6. 聊聊 db 和緩存一致性常見的實現(xiàn)方式
          7. 接口冪等性這么重要,它是什么?怎么實現(xiàn)?
          8. 泛型,有點難度,會讓很多人懵逼,那是因為你沒有看這篇文章!

          12、推薦一個高質(zhì)量的公眾號

          大家平時在學(xué)習(xí)技術(shù)的過程中,苦于找不到高質(zhì)量的學(xué)習(xí)資料的,可以關(guān)注一下【Java 充電社】,這個號專注于為大家提供高質(zhì)量的學(xué)習(xí)資源,已發(fā)布了大量高質(zhì)量的學(xué)習(xí)視頻、及資源,大家可以關(guān)注下。

          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  神马午夜久| 五月欧美激激激综合网色播 | 丁香五月六月婷婷 | 羞羞草视频| 97福利导航|