SpringMVC = SpringMVC響應,異常處理以及攔截器

springmvc 響應,同步-頁面跳轉,異步-網絡請求返回數據 ; ajax異步交互; restful前後端分離開發風格;

異常統一處理;攔截器

一.SpringMVC的響應:

(1)頁面跳轉=====轉發

方式一:簡單方式

方式 二: forward關鍵字:

此關鍵字的底層就是:request.getRequestDispatcher("跳轉路徑").forward(req,resp);

此關鍵字在使用後,不在經過視圖解析器進行字符串的拼接...

    @RequestMapping("/quick")
    public String quick(){
//        return "success";  //方式一
//        int i=1/0;
        return "forward:/WEB-INF/pages/success.jsp"; //方式二
    }

方式三:servlet原生API

 

轉發攜帶數據:(request域)

方式一:ServletAPI

    @RequestMapping("/requestApiData") //
    public void requestApiData(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException, IOException{
       request.setAttribute("message","requestApiData==方式四轉發攜帶數據:");
        request.getRequestDispatcher("/WEB-INF/pages/successData.jsp").forward(request,response);
    }

方式二:ModelAndView對象

 @RequestMapping("/modelAndView")
    public ModelAndView modelAndView(ModelAndView  modelAndView){
        modelAndView.addObject("message","modelAndView==方式四轉發攜帶數據:");
        modelAndView.setViewName("successData");
        return modelAndView;
    }

方式三:Model對象:

    @RequestMapping("/quickModel")
    public String quickModel(Model model){
        model.addAttribute("message","quickModel==b不會收到的");
        return "successData";
    }

 

(2)頁面跳轉---重定向

方式一:redirect 關鍵字

此關鍵字的底層:response.sendRedirect("web項目地址+重定向地址");

而且還在此技術上進行了優化,我們不需要再去編寫web項目地址,直接編寫重定向地址.

 //方式一
    @RequestMapping("/redirect")
    public String redirect(){
        return "redirect:/index.jsp";
    }

方式二:servlet原生API

    @RequestMapping("/responseRedirect")
    public void responseRedirect(HttpServletRequest request,HttpServletResponse response,HttpSession session) throws ServletException ,IOException{
        response.sendRedirect(request.getContextPath()+"/index.jsp");
    }

 

二、ajax異步交互

需求:

發送$.ajax()

響應new ObjectMapper().writeValueAsString()

關於SpringMVC框架,ajax異步請求,後端響應json

在SpringMVC中,這個功能主要是通過兩個註解@RequestBody 和 @ResponseBody實現的

注意:

SpringMVC默認用MappingJackson2HttpMessageConverter對json數據進行轉換,需要加入jackson的包

<!--jsckson -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>

(1)RequestBody

用於接收前端傳遞的請求體中的json數據, 並可以自動轉換封裝進指定的對象中。

 

開啓靜態資源放行:

頁面引入jquery文件

編寫ajax代碼:

<button id="ajaxBtn">發送ajax請求</button>
<script>
    $('#ajaxBtn').click(function () {
        // alert(1)

        /*
            使用: $.ajax() 函數
            規則:
                1.ajax提交的數據必須是一個標準的json字符串
                2.ajax提交的方式必須爲post,數據必須在請求體中
                3.ajax提交的MIME類型必須爲:application/json;charset=utf-8
         */
        $.ajax({
            url: '${pageContext.request.contextPath}/ajaxRequest',
            type: 'POST',
            data: '{"username":"lucy","age":18}',
            contentType:'application/json;charset=utf-8',
            success: function (resp) {

            }
        });
    })
</script>

編寫User實體類:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private String username;

    private Integer age;
}

獲取請求體的json數據

 

(2)@ResponseBody

用於將controller方法返回的對象通過轉換器轉換爲指定的格式(通常爲json)之後,寫入到response對象的響應體中。

 

總結:

@RequestBody:將請求體中的json字符串,轉爲指定類型的java對象

@ResponseBody:將java對象轉爲json字符串,再設置到響應體中,返回到瀏覽器(客戶端)

 

三.Restful設計風格

Restful是一種軟件架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。主要用於客戶端和服務器交互類的軟件,基於這個風格設計的軟件可以更簡潔,更有層次,更易於實現緩存機制等。

應用場景:前(html)後端(servlet)分離開發的架構中(ajax交互)

Restful規範了HTTP請求動作,使用四個詞語分別表示對資源的CRUD操作:

  • GET(獲取)、POST(新建)、PUT(更新)、DELETE(刪除)

 

模擬Restful風格代碼:ajax交互

/*@Controller
@ResponseBody*/
@RestController
public class RestFulController {

    // 查詢所有
    // @RequestMapping(value = "/user", method = RequestMethod.GET)
    @GetMapping("/user")
   // @ResponseBody // 就相當於 response.getWriter().write()
    public String findAll() {
        System.out.println("查詢所有");
        return "findAll";
    }

    // 查詢一個
    // @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    @GetMapping("/user/{id}")
   // @ResponseBody
    public String findById(@PathVariable Integer id) {
        System.out.println("查詢一個");
        return "findById:" + id;
    }

    // 新增
   //  @RequestMapping(value = "/user", method = RequestMethod.POST)
    @PostMapping("/user")
    // @ResponseBody
    public String save(User user) {
        System.out.println("新增");
        return "save";
    }

    // 修改
    // @RequestMapping(value = "/user", method = RequestMethod.PUT)
    @PutMapping("/user")
   // @ResponseBody
    public String update(User user) {
        System.out.println("新增");
        return "update";
    }

    // 刪除
    // @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
    @DeleteMapping("/user/{id}")
   // @ResponseBody
    public String delete(@PathVariable Integer id) {
        System.out.println("刪除");
        return "delete:" + id;
    }

}

測試:瀏覽器默認只能發送:get、post請求

進入公司,如何測試自己後端代碼?藉助於postman工具,它可以模擬瀏覽器發送請求(get、post、put、delete)等請求方式...

 

 

四.異常處理

java對於異常的處理一般有兩種方式:

  • 一種是當前方法處理(try-catch),這種處理方式會造成業務代碼和異常處理代碼的耦合。

  • 一種是當前方法不處理, 出現異常後直接拋給調用者處理。

使用Spring框架後,我們的代碼最終是由框架來調用的。也就是說,異常最終會拋到框架中, 然後由框架指定異常處理器來統一處理異常。

(1)自定義異常處理器:

編寫異常處理器類:

// 全局異常處理器
public class GlobalExceptionResolver implements HandlerExceptionResolver {

    /**
     *
     * @param request  請求對象
     * @param response 響應對象
     * @param handler  處理器對象(某一個方法method對象)
     * @param ex       異常對象
     * @return ModelAndView
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 獲得異常信息
        String message = ex.getMessage();
        // 創建 ModelAndView
        ModelAndView modelAndView = new ModelAndView();

        // 將異常信息存儲到model中
        modelAndView.addObject("message", message);

        // 指定異常友情提示頁面
        modelAndView.setViewName("forward:/error.jsp");
        return modelAndView;
    }
}

將對對象交給ioc容器:

  <!--配置全局異常處理器-->
    <bean id="globalExceptionResolver"  class="com.wsl.web.exception.GlobalExceptionResolver"></bean>

注意:

全局異常處理器:

錯誤頁面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>error</title>
</head>
<body>
<h4>錯誤頁面...</h4>
<span>${message}</span>
</body>
</html>

 

(2)@ControllerAdvice

對所有的controller(控制器)進行異常捕獲的增強,捕獲什麼異常自己來定,方法自己寫...

/*
    對所有controller進行異常增強,底層就是AOP
 */
@ControllerAdvice
public class GlobalControllerAdvie {

    // 捕獲所有異常(如果沒有子異常捕獲,老大哥來兜底....)
    @ExceptionHandler(Exception.class)
    public String resolverHandler(Exception ex, Model model) {
        model.addAttribute("message", "捕獲所有異常..");
        return "forward:/error.jsp";
    }

    // 捕獲空指針異常
    @ExceptionHandler(NullPointerException.class)
    public String resolverNullPointHandler(NullPointerException npe, Model model) {
        model.addAttribute("message", "捕獲空指針異常..");
        return "forward:/error.jsp";
    }

    // 捕獲數學異常

    // 捕獲數組越界異常

    // 捕獲內存溢出異常
}
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


@ControllerAdvice
public class MyGlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public String resolverHandler(Exception ex, Model model){
        model.addAttribute("message","捕獲異常");
        return "forward:/error.jsp";
    }

    @ExceptionHandler(NullPointerException.class)
    public String resolverNullPointHandler(NullPointerException point,Model model){
        model.addAttribute("message","空指針異常");
        return "forward:/error.jsp";
    }

    @ExceptionHandler(ArithmeticException .class)
    public String resolverNAttHandler(NullPointerException point,Model model){
        model.addAttribute("message","算術異常");
        return "forward:/error.jsp";
    }
}

注意:這個只能捕獲SpringMVC的異常問題、

 

(3)Web.xml (tomcat提供異常處理) 使用web提供的異常機制:

   <!--捕獲異常
        error-code 錯誤狀態碼
        location  出現錯誤後,跳轉的提示頁面
    -->
    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext.xml</param-value>
		</init-param>
		<load-on-startup>4</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<error-page>
		<error-code>404</error-code>
		<location>/404.jsp</location>
	</error-page>
</web-app>

 

五.攔截器

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

SpringMVC的攔截器(Interceptor)類似於Servlet中的過濾器(Filter),用於對處理器進行預處理
後處理
 
攔截器對比過濾器:
二者規範不同:Filter是在servlet規範中定義,用於servlet容器中,而攔截器是spring框架提供的,用
spring容器內。
使用範圍不同:Filterservlet規定的,只能用於web工程中,而攔截器沒有此限制。
 
=============================
 
1. 自定義一個類實現HandleInterceptor接口,或者繼承HandlerInterceptorAdaptor抽象類。
2. 實現HandlerInterceptor接口的三個方法:
preHandle() : 在目標方法之前執行,一般用於預處理
postHandle():在目標方法執行之後執行,一般用於後處理
afterCompletion():整個請求處理完畢,在視圖渲染完畢時回調,一般用於資源的清理或性能的統計
 
 
 
 

(1)入門:

編寫目標資源(TargetController)

@Controller
public class TargetController {

    @RequestMapping("/target")
    public String target() {
        System.out.println("目標方法執行了...");
        return "success";
    }
}

自定義攔截器:

// 自定義攔截器
public class MyIntercepter1 implements HandlerInterceptor {

    /*
        在controller目標方法執行之前,攔截
            返回值:
                true 放行
                false 攔截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("preHandle1...");
        // request 轉發
        // response 重定向
        // handler 獲取目標方法的一切信息,進行增強...
        return true;
    }
}

定義攔截器攔截規則(spring-mvc.xml)

    <!--配置攔截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- @RequestMapping("/target") -->
            <mvc:mapping path="/target"/>
            <bean class="com.wsl.web.intercept.MyIntercepter1"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

測試:

(2)攔截器API介紹

 

// 自定義攔截器
public class MyIntercepter1 implements HandlerInterceptor {

    /*
        在controller目標方法執行之前,攔截
            返回值:
                true 放行
                false 攔截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("preHandle1...");
        // request 轉發
        // response 重定向
        // handler 獲取目標方法的一切信息,進行增強...
        return true;
    }

    /*
        在controller目標方法執行之後,進行增強
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("postHandle1...");
    }

    /*
        在視圖渲染完畢後,進行資源釋放
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("afterCompletion1....");
    }
}

(3)攔截器鏈

開發中攔截器可以單獨使用,也可以同時使用多個攔截器形成一條攔截器鏈。

開發步驟和單個攔截器是一樣的,只不過註冊的時候註冊多個,注意這裏註冊的順序就代表攔截器執行的順序。

 

例子和入門案例一致,創建另外一個MyIntercepter2,對象

1.攔截器執行先後問題:mvc:interceptor 誰先聲明,誰先攔截

攔截器方法的執行順序:先進後出

六:配置文件:

Spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		 http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd
		 http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">

    <!--開啓註解組件掃描-->
    <context:component-scan base-package="com.wsl.web"/>



    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>


    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5024000"></property>
    </bean>

    <!--配置攔截器-->
    <!--攔截器的配置順序決定了攔截器的執行順序-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/target"/>
            <bean class="com.wsl.web.interceptor.MyIntercepter01"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/target"/>
            <bean class="com.wsl.web.interceptor.MyIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

    <!--配置錯誤頁面-->
    <!--<bean id="globalExceptionResolver" class="com.wsl.web.execption.GobalExpectionResolver"></bean>-->

    <!--開啓mvc註解支持-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <mvc:default-servlet-handler></mvc:default-servlet-handler>

</beans>

pom.xml

 <dependencies> 
    <!--mysql驅動-->  
    <dependency> 
      <groupId>mysql</groupId>  
      <artifactId>mysql-connector-java</artifactId>  
      <version>5.1.47</version> 
    </dependency>  
    <!--druid連接池-->  
    <dependency> 
      <groupId>com.alibaba</groupId>  
      <artifactId>druid</artifactId>  
      <version>1.1.15</version> 
    </dependency>  
    <!--spring-jdbc-->  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-jdbc</artifactId>  
      <version>5.1.5.RELEASE</version> 
    </dependency>  
    <!--spring核心-->  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-context</artifactId>  
      <version>5.1.5.RELEASE</version> 
    </dependency>  
    <!--junit-->  
    <dependency> 
      <groupId>junit</groupId>  
      <artifactId>junit</artifactId>  
      <version>4.12</version> 
    </dependency>  
    <!--spring整合junit-->  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-test</artifactId>  
      <version>5.1.5.RELEASE</version> 
    </dependency>  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-orm</artifactId>  
      <version>5.1.5.RELEASE</version> 
    </dependency>  
    <dependency> 
      <groupId>org.aspectj</groupId>  
      <artifactId>aspectjweaver</artifactId>  
      <version>1.9.5</version> 
    </dependency>  
    <!--springMVC-->  
    <dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-webmvc</artifactId>  
      <version>5.1.5.RELEASE</version> 
    </dependency>  
    <!--servlet-->  
    <dependency> 
      <groupId>javax.servlet</groupId>  
      <artifactId>servlet-api</artifactId>  
      <version>2.5</version>  
      <scope>provided</scope> 
    </dependency>  
    <!--jsp-->  
    <dependency> 
      <groupId>javax.servlet</groupId>  
      <artifactId>jsp-api</artifactId>  
      <version>2.0</version>  
      <scope>provided</scope> 
    </dependency>  
    <dependency> 
      <groupId>org.projectlombok</groupId>  
      <artifactId>lombok</artifactId>  
      <version>1.18.10</version> 
    </dependency>  
    <dependency> 
      <groupId>commons-fileupload</groupId>  
      <artifactId>commons-fileupload</artifactId>  
      <version>1.4</version> 
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.9</version>
    </dependency>

  </dependencies>
  
  <build> 
    <plugins> 
      <plugin> 
        <groupId>org.apache.maven.plugins</groupId>  
        <artifactId>maven-compiler-plugin</artifactId>  
        <version>3.1</version>  
        <configuration> 
          <source>1.8</source>  
          <target>1.8</target>  
          <encoding>UTF-8</encoding> 
        </configuration> 
      </plugin> 
    </plugins> 
  </build> 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext.xml</param-value>
		</init-param>
		<load-on-startup>4</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>


	<error-page>
		<error-code>404</error-code>
		<location>/404.jsp</location>
	</error-page>
</web-app>

 

 

 

 

 

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