1. 程式人生 > >SpringMVC響應檢視丶檔案上傳丶異常處理丶攔截器

SpringMVC響應檢視丶檔案上傳丶異常處理丶攔截器

SpringMVC響應資料和結果檢視

返回值分類

  1. 返回字串

    1. Controller方法返回字串可以指定邏輯檢視的名稱,根據檢視解析器為物理檢視的地址。
    2. 引數可以寫一個Model來儲存域物件中的值
    3. 應用例子:
    @Controller
    @RequestMapping("/user")
    public class UserController {
        /**
        * 請求引數的繫結
        */
        @RequestMapping(value="/update")
        public String initUpdate(Model model) {
            // 模擬從資料庫中查詢的資料
            User user = new User();
            user.setUsername("張三");
            user.setPassword("123");
            model.addAttribute("user", user);
            //此處返回一個邏輯檢視的字串
            return "list";
        }
    }
    
  2. 返回值是void

    1. 如果控制器的方法返回值編寫成void,執行程式報404的異常,預設查詢JSP頁面沒有找到。
      1. 預設會跳轉到@RequestMapping(value="/update") 即update的頁面。
    2. 可以使用請求轉發或者重定向或者直接寫回內容跳轉到指定的頁面
    3. 例子:
    @RequestMapping(value="/login")
    public void login(HttpServletRequest request,HttpServletResponse response) throws
    Exception {
        System.out.println("請求轉發或者重定向");
        // 請求轉發
        // request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request,
        response);
        // 重定向
        // response.sendRedirect(request.getContextPath()+"/login1.jsp");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        // 直接響應資料
        response.getWriter().print("你好");
        return;
    }
    
  3. 返回值是ModelAndView物件

    1. ModelAndView物件是Spring提供的一個物件,可以用來調整具體的JSP檢視
    2. 例子:
    /**
    * 返回ModelAndView物件
    * 可以傳入檢視的名稱(即跳轉的頁面),還可以傳入物件。
    * @return
    * @throws Exception
    */
    @RequestMapping(value="/findAll")
    public ModelAndView findAll() throws Exception {
        ModelAndView mv = new ModelAndView();
        // 設定跳轉到list.jsp的頁面
        mv.setViewName("list");
        // 模擬從資料庫中查詢所有的使用者資訊
        List<User> users = new ArrayList<>();
        User user1 = new User();
        user1.setUsername("張三");
        user1.setPassword("123");
        User user2 = new User();
        user2.setUsername("趙四");
        user2.setPassword("456");
        users.add(user1);
        users.add(user2);
        // 新增物件,相當與向域物件中新增鍵值對
        mv.addObject("users", users);
        return mv;
    }
    

SpringMVC中的轉發以及重定向

  1. Forward轉發

    1. controller方法返回String型別,想進行請求轉發也可以編寫成
    /**
    * 使用forward關鍵字進行請求轉發
    * "forward:轉發的JSP路徑",不走檢視解析器了,所以需要編寫完整的路徑
    * 也可以轉發到某個方法之上
    * @return
    * @throws Exception
    */
    @RequestMapping("/delete")
    public String delete() throws Exception {
        System.out.println("delete方法執行了...");
        // return "forward:/WEB-INF/pages/success.jsp";
        return "forward:/user/findAll";
    }
    
  2. Redirect重定向

    1. controller方法返回String型別,想進行重定向也可以編寫成
    /**
    * 重定向
    * @return
    * @throws Exception
    */
    @RequestMapping("/count")
    public String count() throws Exception {
        System.out.println("count方法執行了...");
        return "redirect:/add.jsp";
        // return "redirect:/user/findAll";
        // ps:不用再專案名稱(虛擬目錄)
        //    重定向(相當於瀏覽器直接訪問)不能訪問WEB-INF下的資源
     }
    

ResponseBody響應json資料

  1. DispatcherServlet會攔截到所有的資源,導致一個問題就是靜態資源(img、css、js)也會被攔截到,從而
    不能被使用。解決問題就是需要配置靜態資源不進行攔截,在springmvc.xml配置檔案新增如下配置

    • mvc:resources標籤配置不過濾
    1. location元素表示webapp目錄下的包下的所有檔案
    2. mapping元素表示以/static開頭的所有請求路徑,如/static/a 或者/static/a/b
    <!-- 設定靜態資源不過濾 -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 樣式 -->
    <mvc:resources location="/images/" mapping="/images/**"/> <!-- 圖片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
    
  2. 使用@RequestBody獲取請求體資料(ajax的非同步json資料)

    @RequestMapping("/testJson")
    public void testJson(@RequestBody String body) {
        System.out.println(body);
    }
    
  3. 使用@RequestBody註解把json的字串轉換成JavaBean的物件

    /**
    * 獲取請求體的資料
    * @param body
    */
    @RequestMapping("/testJson")
    //可以自動把json字串轉換為javabean物件(需要匯入jar包或者依賴)
    public void testJson(@RequestBody User user) {
    System.out.println(user);
    }
    
  4. 使用@ResponseBody註解把JavaBean物件轉換成json字串,直接響應

    @RequestMapping("/testJson")
    public @ResponseBody User testJson(@RequestBody User user) {
    System.out.println(user);
    user.setAddressName("上海");
    return user;
    }
    
  5. json字串和JavaBean物件互相轉換的過程中,需要使用jackson的jar包

    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>2.9.0</version>
    </dependency>
    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-core</artifactId>
       <version>2.9.0</version>
    </dependency>
    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
       <version>2.9.0</version>
    </dependency>
    

    SpringMVC實現檔案上傳

    普通檔案上傳

    1. 匯入jar包或者依賴

      <dependency>
         <groupId>commons-fileupload</groupId>
         <artifactId>commons-fileupload</artifactId>
         <version>1.3.1</version>
      </dependency>
      <dependency>
         <groupId>commons-io</groupId>
         <artifactId>commons-io</artifactId>
         <version>2.4</version>
      </dependency>
      
    2. 編寫檔案上傳的jsp檔案

      1. 三個關鍵點:
        1. 上傳方式:post
        2. form的enctype為:multipart/form-data
        3. 檔案的type是file
      檔案上傳
      <form action="user/fileupload" method="post" enctype="multipart/form-data">
         選擇檔案:<input type="file" name="upload"/><br/>
         <input type="submit" value="上傳檔案"/>
      </form>
      
    3. 編寫檔案上傳的Controller控制器

      /**
      * 檔案上傳
      * @throws Exception
      */
      @RequestMapping(value="/fileupload")
      public String fileupload(HttpServletRequest request) throws Exception {
         // 先獲取到要上傳的檔案目錄
         String path = request.getSession().getServletContext().getRealPath("/uploads");
         // 建立File物件,一會向該路徑下上傳檔案
         File file = new File(path);
         // 判斷路徑是否存在,如果不存在,建立該路徑
         if(!file.exists()) {
         file.mkdirs();
         }
         // 建立磁碟檔案項工廠
         DiskFileItemFactory factory = new DiskFileItemFactory();
         ServletFileUpload fileUpload = new ServletFileUpload(factory);
         // 解析request物件
         List<FileItem> list = fileUpload.parseRequest(request);
         // 遍歷
         for (FileItem fileItem : list) {
         // 判斷檔案項是普通欄位,還是上傳的檔案
         if(fileItem.isFormField()) {
         }else {
         // 上傳檔案項
         // 獲取到上傳檔案的名稱
         String filename = fileItem.getName();
         // 上傳檔案
         fileItem.write(new File(file, filename));
         // 刪除臨時檔案
         fileItem.delete();
         }
         }
         return "success";
      }
      

SpringMVC的檔案上傳

  1. SpringMVC框架提供了MultipartFile物件,該物件表示上傳的檔案,要求變數名稱必須和表單file標籤的name屬性名稱相同。

  2. 程式碼:

    /**
    * SpringMVC方式的檔案上傳
    *
    * @param request
    * @return
    * @throws Exception
    */
    @RequestMapping(value="/fileupload2")
    public String fileupload2(HttpServletRequest request,MultipartFile upload) throws
    Exception {
        System.out.println("SpringMVC方式的檔案上傳...");
        // 先獲取到要上傳的檔案目錄
        String path = request.getSession().getServletContext().getRealPath("/uploads");
        // 建立File物件,一會向該路徑下上傳檔案
        File file = new File(path);
        // 判斷路徑是否存在,如果不存在,建立該路徑
        if(!file.exists()) {
        file.mkdirs();
        }
        // 獲取到上傳檔案的名稱
        String filename = upload.getOriginalFilename();
        //獲取uuid
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        // 把檔案的名稱唯一化
        filename = uuid+"_"+filename;
        // 上傳檔案
        upload.transferTo(new File(file,filename));
        return "success";
    }
    
  3. 配置檔案解析器物件

    <!-- 配置檔案解析器物件,要求id名稱必須是multipartResolver -->
    <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--配置上傳檔案的最大大小-->
        <property name="maxUploadSize" value="10485760"/>
    </bean>
    

SpringMVC跨伺服器方式檔案上傳

  1. 搭建一個圖片伺服器(模擬)

    1. 複製並開啟一個tomcat,改變一下埠號如:8088
    2. 在webapp下的root檔案下新建一個uploads資料夾
  2. 實現springmvc的跨伺服器檔案上傳

    1. 匯入需要的jar(jersey)
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-core</artifactId>
        <version>1.18.1</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.18.1</version>
    </dependency>
    
    1. 編寫檔案上傳的jsp

      <h3>跨伺服器的檔案上傳</h3>
      <form action="user/fileupload3" method="post" enctype="multipart/form-data">
      選擇檔案:<input type="file" name="upload"/><br/>
        <input type="submit" value="上傳檔案"/>
      </form>
      
  3. 編寫控制器

    /**
    * SpringMVC跨伺服器方式的檔案上傳
    *
    * @param request
    * @return
    * @throws Exception
    */
    @RequestMapping(value="/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception {
        System.out.println("SpringMVC跨伺服器方式的檔案上傳...");
        // 定義圖片伺服器的請求路徑
        String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
        // 獲取到上傳檔案的名稱
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        // 把檔案的名稱唯一化
        filename = uuid+"_"+filename;
        // 向圖片伺服器上傳檔案
        // 建立客戶端物件
        Client client = Client.create();
        // 連線圖片伺服器
        WebResource webResource = client.resource(path+filename);
        // 上傳檔案
        webResource.put(upload.getBytes());
        return "success";
    }
    

SpringMVC的異常處理

  1. 異常處理的思路:

    1. Controller呼叫service,service呼叫dao,異常都是向上丟擲的,最終有DispatcherServlet找異常處理器進
      行異常的處理。
  2. SpringMVC的異常處理

    1. 自定義異常類

      public class SysException extends Exception{
      //定義一個唯一的serialVersionUID
      private static final long serialVersionUID = 4055945147128016300L;
      // 異常提示資訊
      private String message;
      public String getMessage() {
      return message;
      }
      public void setMessage(String message) {
      this.message = message;
      }
      public SysException(String message) {
      this.message = message;
      }
      }
      
    2. 自定義異常處理器

      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import org.springframework.web.servlet.HandlerExceptionResolver;
      import org.springframework.web.servlet.ModelAndView;
      /**
      * 異常處理器
      * @author rt
      */
      public class SysExceptionResolver implements HandlerExceptionResolver{
      /**
      * 跳轉到具體的錯誤頁面的方法
      */
      public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse
      response, Object handler,
      Exception ex) {
      ex.printStackTrace();
      SysException e = null;
      // 獲取到異常物件
      if(ex instanceof SysException) {
      e = (SysException) ex;
      }else {
      e = new SysException("請聯絡管理員");
      }
      ModelAndView mv = new ModelAndView();
      // 存入錯誤的提示資訊
      mv.addObject("message", e.getMessage());
      // 跳轉的Jsp頁面
      mv.setViewName("error");
      return mv;
      }
      }
      
    3. 配置異常處理器

      <!-- 配置異常處理器 -->
      <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
      

SpringMVC框架中的攔截器

攔截器的概述

  1. SpringMVC框架中的攔截器用於對處理器進行預處理和後處理的技術。

  2. 可以定義攔截器鏈,聯結器鏈就是將攔截器按著一定的順序結成一條鏈,在訪問被攔截的方法時,攔截器鏈
    中的攔截器會按著定義的順序執行。

  3. 攔截器和過濾器的功能比較類似,有區別
    1. 過濾器是Servlet規範的一部分,任何框架都可以使用過濾器技術。
    2. 攔截器是SpringMVC框架獨有的。
    3. 過濾器配置了/*,可以攔截任何資源。
    4. 攔截器只會對控制器中的方法進行攔截。
  4. 攔截器也是AOP思想的一種實現方式
  5. 想要自定義攔截器,需要實現HandlerInterceptor介面。

自定義攔截器步驟

  1. 建立類,實現HandlerInterceptor介面,重寫需要的方法
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 自定義攔截器1
* @author rt
*/
public class MyInterceptor1 implements HandlerInterceptor{
/**
* controller方法執行前,進行攔截的方法
* return true放行
* return false攔截
* 可以使用轉發或者重定向直接跳轉到指定的頁面。
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler)
throws Exception {
System.out.println("攔截器執行了...");
return true;
}
}
  1. 在springmvc.xml中配置攔截器類
<!-- 配置攔截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 哪些方法進行攔截 -->
        <mvc:mapping path="/user/*"/>
        <!-- 哪些方法不進行攔截
        <mvc:exclude-mapping path=""/>
        -->
        <!-- 註冊攔截器物件 -->
        <bean class="cn.xxx.demo1.MyInterceptor1"/>
    </mvc:interceptor>
</mvc:interceptors>

HandlerInterceptor介面中的方法

  1. preHandle方法是controller方法執行前攔截的方法
    1. 可以使用request或者response跳轉到指定的頁面
    2. return true放行,執行下一個攔截器,如果沒有攔截器,執行controller中的方法。
    3. return false不放行,不會執行controller中的方法。
  2. postHandle是controller方法執行後執行的方法,在JSP檢視執行前。
    1. 可以使用request或者response跳轉到指定的頁面
    2. 如果指定了跳轉的頁面,那麼controller方法跳轉的頁面將不會顯示。
  3. postHandle方法是在JSP執行後執行
    1. request或者response不能再跳轉頁面了

配置多個攔截器

<!-- 配置攔截器 -->
<mvc:interceptors>
    <mvc:interceptor>
    <!-- 哪些方法進行攔截 -->
    <mvc:mapping path="/user/*"/>
    <!-- 哪些方法不進行攔截
    <mvc:exclude-mapping path=""/>
    <!-- 註冊攔截器物件 -->
    <bean class="cn.itcast.demo1.MyInterceptor1"/>
    </mvc:interceptor>
    <mvc:interceptor>
    <!-- 哪些方法進行攔截 -->
    <mvc:mapping path="/**"/>
    <!-- 註冊攔截器物件 -->
    <bean class="cn.itcast.demo1.MyInterceptor2"/>
    </mvc:interceptor>
</mvc:interceptors>

攔截器的指定流程

前置攔截器執行了!!
controller執行了!!!
後置方法執行了!!!
跳轉頁面執行
最終的方法執行了