天天看點

SpringMVC的異常處理和攔截器

SpringMVC的異常處理

異常處理的思路

系統中異常包括兩類:預期異常和運作時異常 RuntimeException,前者通過捕獲異常進而擷取異常資訊,後者主要通過規範代碼開發、測試通過手段減少運作時異常的發生。

系統的 dao、service、controller 出現都通過 throws Exception 向上抛出,最後由 springmvc 前端控制器交由異常處理器進行異常處理,如下圖:

SpringMVC的異常處理和攔截器

解決:

SpringMVC的異常處理和攔截器

實作步驟

1、自定義異常類

package cn.itcast.exception;

/*自定義異常類
* 1、要繼承異常*/
public class SysException extends Exception{
    private String message;

    //有參構造方法
    public SysException(String message) {
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

           

2、異常處理器

要實作HandlerExceptionResolver 接口

package cn.itcast.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/*異常處理器
* */
public class SysExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        //擷取異常對象
        SysException sys=null;
        if(sys instanceof SysException){
            //如果抛出的是系統自定義異常則直接轉換
            sys=(SysException)e;
        }else {
            //如果抛出的不是系統自定義異常則重新構造一個系統錯誤異常。
            sys=new SysException("系統正在維護。。");
        }
        //建立ModelAndView對象
        ModelAndView mv=new ModelAndView();
        mv.addObject("errorMsg",sys.getMessage());
        mv.setViewName("error");
        return mv;
    }
}

           

3、在springmvc.xml配置異常處理器

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

index.jsp

<a href="user/testException" target="_blank" rel="external nofollow" >testException</a>
           

控制器

package cn.itcast.controller;

import cn.itcast.exception.SysException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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

    @RequestMapping("/testException")
    public String testException() throws SysException {
        System.out.println("testException執行了");

        try {
            //模拟異常
            int i=1/0;
        } catch (Exception e) {
            //列印異常資訊
            e.printStackTrace();
            throw new SysException("鴨!出錯了!!");
        }

        return "success";
    }

}

           

error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--因為他存到了MOdelAndView裡面,和存到request裡面沒有差別,可以用el表達式擷取--%>
    ${errorMsg}
</body>
</html>

           

頁面顯示:

SpringMVC的異常處理和攔截器

控制台輸出:

SpringMVC的異常處理和攔截器

完整的springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">



    <!--告訴spring要掃描的包-->
    <context:component-scan base-package="cn.itcast"></context:component-scan>

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

    <!--前端控制器,那些資源不攔截-->
    <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>

    <!--配置異常處理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"></bean>
    
    <!--開啟springmvc架構注解的支援-->
    <mvc:annotation-driven/>


</beans>


           

SpringMVC中的攔截器

類似于servlet裡面的過濾器

SpringMVC的異常處理和攔截器
SpringMVC的異常處理和攔截器
SpringMVC的異常處理和攔截器

攔截器的作用

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

使用者可以自己定義一些攔截器來實作特定的功能。

談到攔截器,還要向大家提一個詞——攔截器鍊(Interceptor Chain)。攔截器鍊就是将攔截器按一定的順

序聯結成一條鍊。在通路被攔截的方法或字段時,攔截器鍊中的攔截器就會按其之前定義的順序被調用。

說到這裡,可能大家腦海中有了一個疑問,這不是我們之前學的過濾器嗎?是的它和過濾器是有幾分相似,但是也有差別,接下來我們就來說說他們的差別:

過濾器是 servlet 規範中的一部分,任何 java web 工程都可以使用。

攔截器是 SpringMVC 架構自己的,隻有使用了 SpringMVC 架構的工程才能用。

過濾器在 url-pattern 中配置了**/***之後,可以對所有要通路的資源攔截。

攔截器它是隻會攔截通路的控制器方法,如果通路的是 jsp,html,css,image 或者 js 是不會進行攔截的。

它也是 AOP 思想的具體應用

攔截器和過濾器的差別:

1、項目工程的差別:攔截器是spring架構裡面的,要在spring的環境下才能使用,而過濾器在任何Java web 項目都可使用

2、攔截内容的差別:過濾器什麼都會攔截(css,js,圖檔…),而攔截器隻會攔截控制器裡面的方法

SpringMVC的異常處理和攔截器

和處理異常一樣的思想,都是先編寫類(同時還要繼承xxx),再配置

1、編寫攔截類,實作HandlerInterceptor 接口

package cn.itcast.interception;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/*自定義攔截器
* */
public class MyInterceptor implements HandlerInterceptor {
    /*
    * controller方法執行前進行攔截的方法
    * return true --放行   如果沒有,執行controller中的方法
    * return false-- 攔截  可以使用轉發或者重定向直接跳轉到指定的頁面
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("攔截器執行了。。。前1111");
       // request.getRequestDispatcher("/test.jsp").forward(request,response);
        return true;
    }

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

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

           

2、配置攔截器

<!--配置攔截器-->
    <mvc:interceptors>
       <!--配置攔截器-->
        <mvc:interceptor>
            <!--要攔截的方法-->
            <!--<mvc:mapping path="/**"/>--><!--代表全攔截-->
            <mvc:mapping path="/user/*"/>
            <!--不要攔截的方法-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器的對象-->
            <bean class="cn.itcast.interception.MyInterceptor"></bean>
        </mvc:interceptor>
           

完整的springmvc.xml代碼

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="cn.itcast"></context:component-scan>

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

    <!--不攔截的資源-->
    <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>

    <!--配置攔截器-->
    <mvc:interceptors>
       <!--配置攔截器-->
        <mvc:interceptor>
            <!--要攔截的方法-->
            <!--<mvc:mapping path="/**"/>--><!--代表全攔截-->
            <mvc:mapping path="/user/*"/>
            <!--不要攔截的方法-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器的對象-->
            <bean class="cn.itcast.interception.MyInterceptor"></bean>
        </mvc:interceptor>

        <!--配置第二個攔截器-->
        <mvc:interceptor>
            <!--要攔截的方法-->
            <mvc:mapping path="/**"/>

            <!--配置攔截器對象-->
            <bean class="cn.itcast.interception.MyInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    <!--開啟springmvc注解的支援-->
    <mvc:annotation-driven/>

</beans>
           

控制器代碼

package cn.itcast.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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

    @RequestMapping("/testInterceptor")
    public String testException()  {
        System.out.println("testInterceptor執行了");

        return "success";
    }

}

           

index.jsp

<a href="user/testInterceptor" target="_blank" rel="external nofollow" >攔截器index</a>
           

攔截器的細節

攔截器的放行

放行的含義是指,如果有下一個攔截器就執行下一個,如果該攔截器處于攔截器鍊的最後一個,則執行控制器中的方法。

攔截器中方法的說明

* 如何調用:

按攔截器定義順序調用

* 何時調用:

隻要配置了都會調用

* 有什麼用:

如果程式員決定該攔截器對請求進行攔截處理後還要調用其他的攔截器,或者是業務處理器去進行處理,則傳回 true。

* 如果程式員決定不需要再調用其他的元件去處理請求,則傳回 false。

攔截器中的方法

預處理

/*
 	*
    * controller方法執行前進行攔截的方法
    * return true --放行   如果沒有,執行controller中的方法
    * return false-- 攔截  可以使用轉發或者重定向直接跳轉到指定的頁面
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("攔截器執行了。。。前1111");
       // request.getRequestDispatcher("/test.jsp").forward(request,response);
        return true;
    }

   
           

後處理

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

   
           

最後處理

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

預處理可以用來進行邏輯的判斷。例如判斷使用者是否登入(登陸了放行,沒登陸跳到登陸界面)

最後可以用來釋放資源

當配置兩個攔截器時:執行流程

SpringMVC的異常處理和攔截器

運作結果:

SpringMVC的異常處理和攔截器

攔截器的作用路徑

作用路徑可以通過在配置檔案中配置。

<!--配置攔截器-->
    <mvc:interceptors>
       <!--配置攔截器-->
        <mvc:interceptor>
            <!--要攔截的方法-->
            <!--<mvc:mapping path="/**"/>--><!--代表全攔截-->
            <mvc:mapping path="/user/*"/>
            <!--不要攔截的方法-->
            <!--<mvc:exclude-mapping path=""/>-->
            <!--配置攔截器的對象-->
            <bean class="cn.itcast.interception.MyInterceptor"></bean>
        </mvc:interceptor>

           

注意

<mvc:mapping path="/**" /> 用于指定對攔截的 url

<mvc:exclude-mapping path=""/> 用于指定排除的 url