文章目錄
(一)異常處理:基本介紹和搭建環境
(二)異常處理:演示程序異常
(三)異常處理:異常處理代碼編寫
(四)攔截器:基本介紹和搭建環境
(五)攔截器:編寫controller
(六)攔截器:入門代碼編寫
(七)攔截器:接口剩餘的方法演示
(一)異常處理:基本介紹和搭建環境
我們先看看我們傳統的異常,如下:
(dao把異常扔給service,service把異常扔給web,最後異常會呈現在客戶端,這種方式不友好)
我們希望服務器真的出現了異常的時候,網頁用戶點擊某個按鍵或者觸發某個事件需要請求服務器時會跳轉到一個非常友好的頁面(服務器出現故障,請聯繫管理員…)
- 思路:
異常都是向上拋出的,最終讓DispatcherServlet(前端控制器)找異常處理器進行異常的處理 - 分析:
下面開始搭建環境
首先創建一個JavaWeb的maven工程,如下:
配置pom.xml,如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
配置web.xml,如下:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置前端控制器-->
<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:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置解決中文亂碼的過濾器-->
<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>
</web-app>
補全目錄,如下:
配置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="com.zzq"></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 location="/css/" mapping="/css/**"/> <!-- 樣式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 圖片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
<!-- 開啓SpringMVC框架註解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
最後刪除現有的index.jsp,創建新的index.jsp,如下:
至此,環境搭建完成,下面開始編寫代碼
(二)異常處理:演示程序異常
前端方法如下:
<a href="user/testException">異常處理</a>
寫一個success.jsp,如下:
後端方法如下:
@RequestMapping("/testException")
public String testException() throws Exception {
System.out.println("testException方法執行了...");
//模擬異常
int a = 10 / 0;
return "success";
}
運行效果如下:
可以看到異常直接被拋到客戶端了
(三)異常處理:異常處理代碼編寫
首先寫一個自定義異常類繼承自Exception,如下:
接下來改造剛纔的拋出異常的方法,如下:
然後寫一個異常處理器,如下:
/**
* 異常處理器
*/
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 處理異常業務邏輯
*
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param ex
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
//獲取異常對象
SysException e = null;
if (ex instanceof SysException) {
e = (SysException) ex;
} else {
e = new SysException("系統正在維護...");
}
//創建ModelAndView對象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg", e.getMessage());
mv.setViewName("error");
return mv;
}
}
還需要在springmvc.xml配置異常處理器,如下:
<!-- 配置異常處理器-->
<bean id="sysExceptionResolver" class="com.zzq.exception.SysExceptionResolver"></bean>
最後寫一個error.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${errorMsg}
</body>
</html>
運行效果如下:
(四)攔截器的介紹和搭建環境
SpringMVC的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理
下面對比Servlet的過濾器和SpringMVC的攔截器,如下:
之前介紹Filter的時候介紹過過濾器鏈,其實攔截器也有攔截器鏈(Interceptor Chain)
攔截器鏈就是將攔截器按一定的順序聯結成一條鏈
在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用,如下:
那麼過濾器跟攔截器有什麼區別呢?
- 過濾器是Servlet規範中的一部分, 任何JavaWeb工程都可以使用。
- 攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
- 過濾器在url-pattern中配置了
/*
之後,可以對所有要訪問的資源攔截。 - 攔截器它是隻會攔截訪問的控制器方法,如果訪問的是
jsp,html,css,image,js
是不會攔截的
攔截器也是AOP思想的具體應用
我們要想自定義攔截器,要求必須實現:HandlerInterceptor接口
下面開始搭建環境
創建一個JavaWeb的maven工程,如下:
配置pom.xml,如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
配置web.xml,如下:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置前端控制器-->
<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:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置解決中文亂碼的過濾器-->
<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>
</web-app>
補全目錄,如下:
配置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="com.zzq"></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 location="/css/" mapping="/css/**"/> <!-- 樣式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 圖片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
<!-- 開啓SpringMVC框架註解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
配置success.jsp,如下:
最後依然刪除現有的index.jsp,創建一個新的index.jsp,如下:
至此,攔截器的環境搭建完畢,下面開始編寫代碼
(五)攔截器:編寫controller
前端代碼如下:
<a href="user/testInterceptor">攔截器</a>
後端代碼如下:
(六)攔截器:入門代碼編寫
步驟:
- 編寫攔截器類,實現HandlerInterceptor接口
- 配置攔截器
首先編寫一個攔截器類,如下:
我們發現implements了接口,但是卻沒有報錯,不需要實現方法,我們看看接口的源碼,如下:
這是JDK1.8的新特性,接口允許有默認方法,可以有具體的方法體
如果我們還是想重寫接口的方法也可以,操作步驟如下:
我們先寫一個預處理方法,如下:
/**
* 預處理: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;
}
然後在springmvc.xml中配置攔截器,如下:
<!-- 配置攔截器-->
<mvc:interceptors>
<!-- 配置攔截器-->
<mvc:interceptor>
<!-- 要攔截的具體的方法-->
<mvc:mapping path="/user/*"/>
<!-- 不要攔截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置攔截器對象-->
<bean class="com.zzq.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
注意:mapping path
和exclude-mapping path
只需要二選一即可
爲了方便展示,我們修改success.jsp,如下:
運行效果如下:
(七)攔截器:接口剩餘的方法演示
我們再演示一下不放行的情況,如下:
運行結果如下:
我們希望預處理不放行的話,可以跳轉到一個比較友好的異常處理頁面,如下:
運行結果如下:
接着演示後處理方法,如下:
運行效果如下:
其實後處理也可以做頁面跳轉,如下:
此時會跳轉到error.jsp頁面的(可以理解爲先跳轉到success.jsp,然後再跳轉到error.jsp),如下:
我們演示最後一個方法,如下:
/**
* success.jsp頁面執行後,改方法會執行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1執行了...最後");
}
運行效果如下:
其實afterCompletion方法通常是用來釋放資源的,後續結合案例再做具體演示
下面演示一下攔截器鏈,我們再創建一個攔截器,如下:
最後配置springmvc.xml,如下:
<!-- 配置攔截器-->
<mvc:interceptors>
<!-- 配置第一個攔截器-->
<mvc:interceptor>
<!-- 要攔截的具體的方法-->
<mvc:mapping path="/user/*"/>
<!-- 不要攔截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置攔截器對象-->
<bean class="com.zzq.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
<!-- 配置第二個攔截器-->
<mvc:interceptor>
<!-- 要攔截的具體的方法-->
<mvc:mapping path="/user/*"/>
<!-- 不要攔截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<!-- 配置攔截器對象-->
<bean class="com.zzq.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
運行效果如下:
注意:我們的執行順序是類似出棧入棧的,具體看下圖
(在返回的時候,要先執行攔截器2,後執行攔截器1)