SpringMVC框架攔截器,異常處理與響應,並且實現文件上傳與下載。

在這裏插入圖片描述


寫在前面:本文簡單講解SpringMVC的響應數據處理,以及文件上傳與下載,響應JSON格式,異常處理,攔截器的介紹等。。
作者還在學習階段,如果寫得不好請見諒。
公衆號:小白編碼



第一章:響應數據和結果視圖

1. 返回字符串

  1. Controller方法返回字符串可以指定邏輯視圖的名稱,根據視圖解析器爲物理視圖的地址。
@RequestMapping(value="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
// 跳轉到XX頁面
return "success";
}

UserController:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("testString")
    public String testString(Model model){
        System.out.println("testString執行了!!");
        // 模擬從數據庫中查詢的數據
        User user = new User();
        user.setUsername("小白");
        user.setPassword("123");
        model.addAttribute("user",user);
        return "success";
    }
}

jsp:請求地址

<a href="user/testString">testString</a>

success.jsp:EL表達式取值

<h3>測試成功!</h3>
${requestScope.user.username} 
${requestScope.user.password}

2. 無返回值情況

  1. 如果控制器的方法返回值編寫成void,執行程序報404的異常, 默認查找JSP頁面沒有找到。
  2. 默認會跳轉到 @RequestMapping(value="/initUpdate") initUpdate.jsp的頁面。
  3. 可以使用請求轉發或者重定向跳轉到指定的頁面

jsp:

<a href="user/testVoid">testVoid</a>

控制器:

    /**
     * 無返回值情況
     * 請求轉發一次請求,不用編寫項目的名稱
     * 請求重定向二次請求,需要獲取項目名稱
     */
    @RequestMapping("testVoid")
    public void testVoid(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        System.out.println("testVoid執行了!!");

        // 編寫請求轉發的程序,
//         req.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(req,resp);

        // 重定向,不能直接進WEB-INF的文件夾
         resp.sendRedirect(req.getContextPath()+"/index.jsp");

        // 設置中文亂碼
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        // 直接會進行響應輸出流到頁面!
        resp.getWriter().print("你好");

    }

請求轉發成功:

在這裏插入圖片描述

重定向:

在這裏插入圖片描述
打開響應流頁面:
在這裏插入圖片描述
運行方式:
在這裏插入圖片描述

3 .返回ModelAndView對象

ModelAndView 對象是 Spring 提供的一個對象,可以用來調整具體的 JSP 視圖

jsp:

<a href="user/testModelAndView">testModelAndView</a>

控制器:

    /**
     * 返回ModelAndView
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        // 創建ModelAndView對象
        ModelAndView mv = new ModelAndView();
        System.out.println("testModelAndView方法執行了...");
        // 模擬從數據庫中查詢出User對象
        User user = new User();
        user.setUsername("小鳳");
        user.setPassword("456");
        user.setAge(30);

        // 把user對象存儲到mv對象中,也會把user對象存入到request對象
        mv.addObject("user",user);

        // 跳轉到success的.jsp頁面
        mv.setViewName("success");

        return mv;
    }

測試結果:

在這裏插入圖片描述

第二章:SpringMVC框架提供的轉發和重定向

1. forward請求轉發

jsp:

<a href="user/testForward">testForward</a>

controller方法返回String類型,想進行請求轉發可以編寫成:

控制器:

   /**
     * 使用forward關鍵字進行請求轉發
     * "forward:轉發的JSP路徑",不走視圖解析器了,所以需要編寫完整的路徑
     * @return
     * @throws Exception
     */
    @RequestMapping("/testForward")
    public String testForward() throws Exception {
        System.out.println("testForward...");
// return "forward:/WEB-INF/pages/success.jsp";
        return "forward:/WEB-INF/pages/success.jsp";
    }

結果:
在這裏插入圖片描述

2. redirect重定向

jsp:

<a href="user/testRedirect">testRedirect</a>

控制器:

    /**
     * 重定向
     * @return
     * @throws Exception
     */
    @RequestMapping("/testRedirect")
    public String testRedirect() throws Exception {
        System.out.println("testRedirect...");
        return "redirect:/index.jsp";
// return "redirect:/user/findAll";
    }

在這裏插入圖片描述

第三章:SpringMVC響應JSON數據

在這裏插入圖片描述

@ResponseBody 註解

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

  1. mvc:resources標籤配置不過濾
  2. location元素表示webapp目錄下的包下的所有文件
  3. mapping元素表示以/static開頭的所有請求路徑,如/static/a 或者/static/a/b
<!-- 設置靜態資源不過濾 -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 樣式 -->
    <mvc:resources location="/img/" mapping="/img/**"/> <!-- 圖片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-1.7.2.js"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn").click(function () {
                // alert("hello");
                $.ajax({
                    //請求地址
                    url:"user/testAjax",
                    //表示發給服務器的數據
                    data:{"name":"小白","age":18},
                    //響應的數據類型
                    dataType: "json",
                    //設置字符集
                    contentType:"application/json;charset=UTF-8",
                    //表示請求類型
                    type: "post",
                    success:function (data) {
                        alert(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
<button id="btn">發送ajax請求</button>
</body>
</html>

控制器:獲取請求體數據

	/**
	*  獲取請求體數據
 	*  @return
 	*  @throws Exception
    */
    @RequestMapping("/testAjax")
    public void testAjax(@RequestBody String body) throws Exception {
   		 System.out.println(body);
    }

導入依賴: 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>

控制器:將請求過來的字符串轉換成JavaBean:

@Controller
public class HelloController {
    @RequestMapping("/testResponseJson")
    public void testResponseJson(@RequestBody User user){
        System.out.println("Json字符封裝成javaBean:"+ user);
    }
}

控制器:將JavaBean對象轉換成Json響應到客戶端:

    /**
     * 異步請求
     *
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/testAjax",method = RequestMethod.POST)
    public @ResponseBody
    User testAjax(@RequestBody User user){
        // 客戶端發送ajax的請求,傳的是json字符串,後端把json字符串封裝到user對象中
        System.out.println(user);
        // 做響應,模擬查詢數據庫
        user.setUsername("小黑");
        user.setPassword("123");
        //做響應
        return user;
    }

jsp:

   <script type="text/javascript">
        $(function () {
            $("#btn").click(function () {
                // alert("hello");
                $.ajax({
                    //請求地址
                    url:"user/testAjax",
                    //表示發給服務器的數據
                    data:'{"username":"小白","password":"123","age":18}',
                    //響應的數據類型
                    dataType: "json",
                    //設置字符集
                    contentType:"application/json;charset=UTF-8",
                    //表示請求類型
                    type: "post",
                    success:function (data) {
                        alert(data);
                        alert(data.username);
                        alert(data.password);
                        alert(data.age)
                    }
                });
            });
        });
    </script>

第四章:文件上傳與下載

文件上傳前提:

  • form表單enctype取值必須是:multipart/form-data
  • 默認值是:application/x-www-form-urlencoded)
  • enctype:是表單請求正文的類型
  • method屬性取值必須是Post C 提供一個文件選擇域<input type="file" />

當form表單的enctype取值不是默認值後,request.getParameter()將失效。

依賴導入:

        <!--      文件上傳-->
      <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>

jsp:表單:

<%--enctype="multipart/form-data"
當form表單的enctype取值爲Mutilpart/form-data時,
請求正文內容就變成: 每一部分都是MIME類型描述的正文--%>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="上傳文件"/>

1.傳統方式文件傳輸:

控制器:

    @RequestMapping("/fileupload")
    public String fileupload(HttpServletRequest req) throws Exception {
        System.out.println("測試成功!");
        // 使用fileupload組件完成文件上傳
        // 上傳的位置
        String path = req.getSession().getServletContext().getRealPath("/uploads/");
        //創建File對象,一會向該路徑下上傳文件
        File file = new File(path);
        // 判斷路徑是否存在,如果不存在,創建該路徑
        if (!file.exists()) {
            file.mkdir();
        }
        // 解析request對象,獲取上傳文件項
        DiskFileItemFactory factory = new DiskFileItemFactory();//磁盤文件項工廠
        ServletFileUpload upload = new ServletFileUpload(factory);
        //解析request(裝的都是文件項)
        List<FileItem> items = upload.parseRequest(req);
        //遍歷
        for (FileItem item: items){
            // 進行判斷,當前item對象是否是上傳文件項
            if(item.isFormField()){
                // 說明普通表單向
            }else {
                // 說明上傳文件項
                // 獲取上傳文件的名稱
                String filename = item.getName();
                // 把文件的名稱設置唯一值,uuid
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid+"_"+filename;
                item.write(new File(path,filename));
                //刪除臨時文件
                item.delete();
            }
        }

        return "success";
    }

2.SpringMVC文件傳輸

在這裏插入圖片描述
jsp表單<input type="file" name="upload" />name必須和MultipartFile的名稱一樣

<h3>SpringMVC方式文件上傳</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload" /><br/>
    <input type="submit" value="上傳" />
</form>

文件解析器配置:

    <!--    配置文件解析器對象,要求id名稱密續是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--        設置最大上傳文件內存  10485760=10M -->
        <property name="maxInMemorySize" value="10485760"></property>
    </bean>

控制器:

    @RequestMapping("/fileupload2")
    public String fileupload2(HttpServletRequest req, MultipartFile upload) throws Exception {
        System.out.println("測試成功!");
        // 使用fileupload組件完成文件上傳
        // 上傳的位置
        String path = req.getSession().getServletContext().getRealPath("/uploads/");
        //創建File對象,一會向該路徑下上傳文件
        File file = new File(path);
        // 判斷路徑是否存在,如果不存在,創建該路徑
        if (!file.exists()) {
            file.mkdir();
        }

        // 說明上傳文件項
        // 獲取上傳文件的名稱
        String filename = upload.getName();
        // 把文件的名稱設置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "_" + filename;
        // 完成文件上傳
        upload.transferTo(new File(file,filename));

        return "success";
    }

3.跨服務器文件上傳:

在這裏插入圖片描述

在實際開發中,我們會有很多處理不同功能的服務器。(注意:此處說的不是服務器集羣)

  • 應用服務器: 負責部署我們的應用

  • 數據庫服務器: 運行我們的數據庫

  • 緩存和消息服務器: 負責處理大併發訪問的緩存和消息

  • 文件服務器: 負責存儲用戶上傳文件的服務器。

流程:

1.配置一個新的工程,創建uploads文件夾
在這裏插入圖片描述

2.配置服務器:
在這裏插入圖片描述
在這裏插入圖片描述

3.導入開發需要的jar包

<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>

4.編寫文件上傳的JSP頁面:

<h3>跨服務器方式文件上傳</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="上傳"/>
</form>

5.編寫控制器:

/**
 * 跨服務器文件上傳
 *
 * @param upload
 * @return
 * @throws Exception
 */
@RequestMapping("/fileupload3")
public String fileupload3( MultipartFile upload) throws Exception {
    System.out.println("跨服務器上傳成功!");
    // 使用fileupload組件完成文件上傳
    // 定義圖片服務器的請求路徑
    String path = "http://localhost:9090/uploads/";


    // 說明上傳文件項
    // 獲取上傳文件的名稱
    String filename = upload.getName();
    // 把文件的名稱設置唯一值,uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid + "_" + filename;
    // 創建客戶端對象
    Client client = Client.create();
    //連接圖片服務器
    WebResource webResource = client.resource(path + filename);
    // 上傳文件
    webResource.put(upload.getBytes());
    return "success";
}

如果報405:在tomcat配置文件中加入這個參數
在這裏插入圖片描述

測試上傳成功:

在這裏插入圖片描述

第五章: SpringMVC異常處理

在這裏插入圖片描述

異常處理思路

  • Controller調用serviceservice調用dao,異常都是向上拋出的,最終由DispatcherServlet異常處理器進行異常的處理

SpringMVC的異常處理:

jsp:

<h3>異常處理</h3>
<a href="user/testException">testException</a>

自定義異常類:

@Data
public class SysException extends Exception{

    //存儲 提示信息
    private String message;

    public SysException(String message) {
        this.message = message;
    }
}

自定義異常處理器:實現HandlerExceptionResolver接口

public class SysExceptionResolver implements HandlerExceptionResolver {

    /**
     * 跳轉到具體頁面
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

        SysException e = null;
        //① a instanceof A:判斷對象a是否是類A的實例。如果是,返回true;如果不是,返回false。
        //② 如果 a instanceof A返回true,則 a instanceof B也返回true.其中,類B是類A的父類。
        if (ex instanceof SysException){
            //強轉(如果ex是SysException的實例)
            e = (SysException) ex;
        }else {
            e = new SysException("系統維護中...");
        }

        // 創建ModelAndView對象
        ModelAndView mv = new ModelAndView();

        // 把message信息存儲到mv對象中,也會把message對象存入到request域對象
        mv.addObject("message",e.getMessage());

        // 跳轉到異常頁面.jsp
        mv.setViewName("error");

        return mv;
    }
}

配置異常處理器:

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

控制器:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testException")
    public String testException() throws SysException{//往瀏覽器拋異常Exception
        System.out.println("testException執行了!");
        //模擬異常

        try {
            int i = 1 / 0;
        } catch (Exception e) {
            // 打印異常信息
            e.printStackTrace();
            // 拋出自定義異常信息
            throw new SysException("查詢所有用戶出現了錯誤...");
        }

        return "success";
    }

}

error.jsp:

<h1>${requestScope.message}</h1>

測試:

在這裏插入圖片描述
結果:跳轉到了異常頁面。

在這裏插入圖片描述

第六章:SpringMVC框架中的攔截器

​ Spring MVC 的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。

  1. 可以定義攔截器鏈,連接器鏈就是將攔截器按着一定的順序結成一條鏈,在訪問被攔截的方法時,攔截器鏈
    中的攔截器會按着定義的順序執行。
  2. 過濾器是Servlet規範的一部分,任何框架都可以使用過濾器技術。
  3. 攔截器是SpringMVC框架獨有的。
  4. 過濾器配置了/*,可以攔截任何資源。
  5. 攔截器只會對控制器中的方法進行攔截。
  6. 它也是AOP思想的具體應用。
  7. 我們要想自定義攔截器, 要求必須實現:HandlerInterceptor接口。

過濾器與攔截器區別:

  • 過濾器是servlet規範中的一部分,任何java web工程都可以使用
  • 攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
  • 過濾器在url-pattern中配置了**/***之後,可以對所有要訪問的資源攔截。
  • 攔截器它是隻會攔截訪問的控制器方法,如果訪問的是jsp,html,css,image或者js是不會進行攔截的。

1.單個攔截器:

控制器:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        System.out.println("testInterceptor!");

        return "success";
    }
}

1.創建類,實現HandlerInterceptor接口,重寫需要的方法

/**
 * @author JUNSHI [email protected]
 * @create 2020-05-30 14:35
 */
public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * 預處理 controller方法執行前
     * return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1執行了...");
        return true;
    }
}

2.在springmvc.xml中配置攔截器類

 <!--    配置攔截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 哪些方法進行攔截 默認請求鏈接的/user/下所有都攔截 -->
            <mvc:mapping path="/user/*"/>
            <!-- 哪些方法不進行攔截
            <mvc:exclude-mapping path=""/>
            -->
            <!-- 註冊攔截器對象 -->
            <bean class="cn.codewhite.interceptor.MyInterceptor1"/>
        </mvc:interceptor>
    </mvc:interceptors>

運行結果:

在這裏插入圖片描述

HandlerInterceptor接口中的方法

  1. preHandle方法是controller方法執行前攔截的方法

    • 可以使用request或者response跳轉到指定的頁面

    • return true放行,執行下一個攔截器,如果沒有攔截器,執行controller中的方法。

    • return false **不放行,**不會執行controller中的方法。

  2. postHandle是controller方法執行後執行的方法,在JSP視圖執行前。

    • 可以使用request或者response跳轉到指定的頁面

    • 如果指定了跳轉的頁面,那麼controller方法跳轉的頁面將不會顯示。

  3. postHandle方法是在JSP執行後執行

    • request或者response不能再跳轉頁面了

2.多個攔截器:

多個攔截器執行順序:

在這裏插入圖片描述
在這裏插入圖片描述
index.jsp:

<h3>攔截器</h3>
<a href="user/testInterceptor">testInterceptor</a>

success.jsp:

<h3>執行成功!</h3>
<% System.out.println("success.jsp執行了"); %>

控制器:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        System.out.println("testInterceptor!");

        return "success";
    }
}

攔截器1:

public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * 預處理 controller方法執行前
     * return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
     * return false不放行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("攔截器1:preHandle攔截器攔截了  前111");
        return true;
    }

    /**
     *  後處理方法,controller方法執行後,success.jsp執行之前
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("攔截器1:postHandle方法執行了 後111");
    }

    /**
     * success.jsp頁面執行後,該方法會執行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("攔截器1:afterCompletion方法執行了 最後111");
    }

}

攔截器2:

/**
 * 自定義攔截器2
 */
public class MyInterceptor2 implements HandlerInterceptor {

    /**
     * 預處理 controller方法執行前
     * return true放行,執行下一個攔截器,如果沒有,執行controller中的方法
     * return false不放行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("攔截器2:preHandle攔截器攔截了  前222");
        return true;
    }

    /**
     *  後處理方法,controller方法執行後,success.jsp執行之前
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("攔截器2:postHandle方法執行了 後222");
    }

    /**
     * success.jsp頁面執行後,該方法會執行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("攔截器2:afterCompletion方法執行了 最後222");
    }


}

springmvc.xml:

   <!--    配置攔截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--        配置第一個攔截器-->
            <!-- 哪些方法進行攔截 默認請求鏈接的/user/下所有都攔截 -->
            <mvc:mapping path="/user/*"/>
            <!-- 哪些方法不進行攔截
            <mvc:exclude-mapping path=""/>
            -->
            <!-- 註冊攔截器對象 -->
            <bean class="cn.codewhite.interceptor.MyInterceptor1"/>
        </mvc:interceptor>
        <!--        配置第二個攔截器-->
        <mvc:interceptor>
            <!-- 哪些方法進行攔截,url-->
            <mvc:mapping path="/**"/>
            <!-- 哪些方法不進行攔截
            <mvc:exclude-mapping path=""/>
            -->
            <!-- 註冊攔截器對象 -->
            <bean class="cn.codewhite.interceptor.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

運行結果:
在這裏插入圖片描述

寫在後邊

以上都是SpringMVC的一些重要內容,如果需要SSM框架的PDF版筆記可以找我。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章