目錄
- 一、請求轉發和重定向
- 1. 請求轉發
- 2. 請求重定向
- 二、例外處理
- 1. 例外處理步驟:
- 1. 自定義例外類
- 2. 修改 Controller 拋出例外
- 3. 定義全域例外處理類
- 4. 定義例外回應頁面
- 5. springmvc的組態檔
- 三、攔截器
- 1. 攔截器使用步驟
- 2. 一個攔截器的執行
- 3. 多個攔截器的執行
- 4. 攔截器和過濾器的區別
一、請求轉發和重定向
當處理器對請求處理完畢后,向其它資源進行跳轉時,有兩種跳轉方式:請求轉發與重定向,而根據所要跳轉的資源型別,又可分為兩類:跳轉到頁面與跳轉到其它處理器
注意,對于請求轉發的頁面,可以是WEB-INF中頁面;而重定向的頁面,是不能為WEB-INF中頁的,因為重定向相當于用戶再次發出一次請求,而用戶是不能直接訪問 WEB-INF 中資源的

SpringMVC 框架把原來 Servlet 中的請求轉發和重定向操作進行了封裝,現在可以使用簡單的方式實作轉發和重定向,
forward:表示轉發,實作 request.getRequestDispatcher("xx.jsp").forward()
redirect:表示重定向,實作 response.sendRedirect("xxx.jsp")
1. 請求轉發
處理器方法回傳 ModelAndView 時,需在 setViewName()指定的視圖前添加 forward:,且此時的視圖不再與視圖決議器一同作業,這樣可以在配置了決議器時指定不同位置的視圖,視圖頁面必須寫出相對于專案根的路徑,forward 操作不需要視圖決議器,
處理器方法回傳 String,在視圖路徑前面加入 forward: 視圖完整路徑
還是第一個案例中
/**
* 處理器方法回傳ModelAndView,實作轉發forward
* 語法: setViewName("forward:視圖檔案完整路徑")
* forward特點: 不和視圖決議器一同使用,就當專案中沒有視圖決議器,不受視圖決議器的限制了
*/
@RequestMapping(value = https://www.cnblogs.com/mengd/p/"/doForward.do")
public ModelAndView doForward(String name , Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
// mv.setViewName("show");
//顯式轉發
// mv.setViewName("forward:/WEB-INF/view/show.jsp");
// 配置了視圖決議器,但是這個檔案不在view目錄之下就可以使用這樣的方法,因為forward不受視圖決議器的限制
mv.setViewName("forward:/hello.jsp");
return mv;
}
2. 請求重定向
在處理器方法回傳的視圖字串的前面添加 redirect:,則可實作重定向跳轉
/**
* 處理器方法回傳ModelAndView,實作重定向redirect
* 語法:setViewName("redirect:視圖完整路徑")
* redirect特點: 不和視圖決議器一同使用,就當專案中沒有視圖決議器
*
* 框架對重定向的操作:
* 1.框架會把Model中的簡單型別的資料,轉為string使用,作為hello.jsp的get請求引數使用,
* 目的是在 doRedirect.do 和 hello.jsp 兩次請求之間傳遞資料
*
* 2.在目標hello.jsp頁面可以使用引數集合物件 ${param}獲取請求引數值
* ${param.myname}
*
* 3.重定向不能訪問/WEB-INF資源
*/
@RequestMapping(value = https://www.cnblogs.com/mengd/p/"/doRedirect.do")
public ModelAndView doRedirect(String name , Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
//重定向
mv.setViewName("redirect:/hello.jsp");
// 相當于這樣,內部作為get請求,通過param可以獲取的到
//http://localhost:8080/08_forword/hello.jsp?myname=lisi&myage=22
//重定向不能訪問/WEB-INF資源
// mv.setViewName("redirect:/WEB-INF/view/show.jsp");
return mv;
}
二、例外處理
SpringMVC 框架處理例外的常用方式:使用@ExceptionHandler 注解處理例外
使用注解@ExceptionHandler 可以將一個方法指定為例外處理方法,該注解只有一個可選屬性 value,為一個 Class<?>陣列,用于指定該注解的方法所要處理的例外類,即所要匹配的例外
而被注解的方法,其回傳值可以是 ModelAndView、String,或 void,方法名隨意,方法引數可以是 Exception 及其子類物件、HttpServletRequest、HttpServletResponse 等,系統會自動為這些方法引數賦值
1. 例外處理步驟:
- 新建maven web專案
- 加入依賴
- 新建一個自定義例外類 MyUserException , 再定義它的子類NameException ,AgeException
- 在controller拋出NameException , AgeException
- 創建一個普通類,作用全域例外處理類
- 在類的上面加入@ControllerAdvice
- 在類中定義方法,方法的上面加入@ExceptionHandler
- 創建處理例外的視圖頁面
- 創建springmvc的組態檔
- 組件掃描器 ,掃描@Controller注解
- 組件掃描器,掃描@ControllerAdvice所在的包名
- 宣告注解驅動
1. 自定義例外類
MyUserException是父類
package com.md.exception;
/**
* @author MD
* @create 2020-08-14 20:31
*/
public class MyUserException extends Exception {
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
//-------------------------------
package com.md.exception;
/**
* 當用戶的年齡有例外拋出AgeException
* @author MD
* @create 2020-08-14 20:33
*/
public class AgeException extends MyUserException {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
//----------------------------
package com.md.exception;
/**
* 當用戶的姓名有例外拋出NameException
* @author MD
* @create 2020-08-14 20:32
*/
public class NameException extends MyUserException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
2. 修改 Controller 拋出例外
/**
*此時拋出的例外是下面兩個例外的父類
*/
@RequestMapping(value = https://www.cnblogs.com/mengd/p/"/some.do")
public ModelAndView doSome(String name , Integer age) throws MyUserException {
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
// 根據請求引數拋出例外
if (!"md".equals(name)){
throw new NameException("姓名不正確");
}
if (age == null || age > 100){
throw new AgeException("年齡有誤");
}
mv.setViewName("show");
return mv;
}
3. 定義全域例外處理類
package com.md.handler;
import com.md.exception.AgeException;
import com.md.exception.NameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/**
* @author MD
* @create 2020-08-14 20:38
*/
/**
* @ControllerAdvice : 控制器增強(也就是說給控制器類增加功能--例外處理功能)
* 位置:在類的上面,
* 特點:必須讓框架知道這個注解所在的包名,需要在springmvc組態檔宣告組件掃描器,
* 指定@ControllerAdvice所在的包名
*/
@ControllerAdvice
public class GlobalException {
//定義方法,處理發生的例外
/*
處理例外的方法和控制器方法的定義一樣, 可以有多個引數,可以有ModelAndView,
String, void,物件型別的回傳值
形參:Exception,表示Controller中拋出的例外物件,
通過形參可以獲取發生的例外資訊,
@ExceptionHandler(例外的class):表示例外的型別,當發生此型別例外時,
由當前方法處理
*/
@ExceptionHandler(value = https://www.cnblogs.com/mengd/p/NameException.class)
public ModelAndView doNameException(Exception ex) {
// 處理NameException例外
/*
例外發生處理邏輯:
1.需要把例外記錄下來, 記錄到資料庫,日志檔案,
記錄日志發生的時間,哪個方法發生的,例外錯誤內容,
2.發送通知,把例外的資訊通過郵件,短信,微信發送給相關人員,
3.給用戶友好的提示,
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "姓名是md,其他用戶不能訪問");
mv.addObject("ex", ex);
mv.setViewName("nameError");
return mv;
}
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception ex) {
// 處理AgeException例外
/*
例外發生處理邏輯:
1.需要把例外記錄下來, 記錄到資料庫,日志檔案,
記錄日志發生的時間,哪個方法發生的,例外錯誤內容,
2.發送通知,把例外的資訊通過郵件,短信,微信發送給相關人員,
3.給用戶友好的提示,
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "年齡過大");
mv.addObject("ex", ex);
mv.setViewName("AgeError");
return mv;
}
// 這個只能有一個,也就是萬能的例外處理方法
// 處理其他例外,NameException、AgeException之外的例外,也就是除了自定義之外的例外都能處理
@ExceptionHandler
public ModelAndView doOtherException(Exception ex) {
// 處理OtherException例外
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "404");
mv.addObject("ex", ex);
mv.setViewName("defaultError");
return mv;
}
}
4. 定義例外回應頁面
nameError.jsp
<%--
Created by IntelliJ IDEA.
User: MD
Date: 2020/8/14
Time: 20:54
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>nameError.jsp</h1>
<h2>提示:${msg}</h2>
<h2>系統例外資訊:${ex.message}</h2>
</body>
</html>
<h1>ageError.jsp</h1>
<h2>提示:${msg}</h2>
<h2>系統例外資訊:${ex.message}</h2>
<%--和上面都一樣,這里就省略了--%>
<h1>defaultError.jsp</h1>
<h2>提示:${msg}</h2>
<h2>系統例外資訊:${ex.message}</h2>
5. springmvc的組態檔
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--宣告組件掃描器-->
<context:component-scan base-package="com.md.controller"/>
<!--宣告springmvc框架中的視圖決議器,幫助開發人員設定視圖檔案路徑-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前綴:視圖檔案的路徑-->
<property name="prefix" value=https://www.cnblogs.com/mengd/p/"/WEB-INF/view/" />
這樣就可以了
三、攔截器
SpringMVC 中的 Interceptor 攔截器是非常重要和相當有用的,它的主要作用是攔截指定的用戶請求,并進行相應的預處理與后處理,
- 攔截器是springmvc中的一種,需要實作HandlerInterceptor介面,
- 攔截器和過濾器類似,功能方向側重點不同, 過濾器是用來過濾器請求引數,設定編碼字符集等作業,
- 攔截器是攔截用戶的請求,做請求做判斷處理的,
- 攔截器是全域的,可以對多個Controller做攔截, 一個專案中可以有0個或多個攔截器, 他們在一起攔截用戶的請求,
- 攔截器常用在:用戶登錄處理,權限檢查, 記錄日志,
1. 攔截器使用步驟
- 新建maven web專案
- 加入依賴
- 創建Controller類
- 創建一個普通類,作為攔截器使用
- 實作HandlerInterceptor介面
- 實作介面中的三個方法
- 創建show.jsp
- 創建springmvc的組態檔
- 組件掃描器 ,掃描@Controller注解
- 宣告攔截器,并指定攔截的請求uri地址
2. 一個攔截器的執行
Controller類
@RequestMapping(value = https://www.cnblogs.com/mengd/p/"/some.do")
public ModelAndView doSome(String name , Integer age) {
System.out.println("-------MyController的doSome()");
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
還是在之前的專案中,定義個普通類,作為攔截器
package com.md.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
/**
* 攔截器類,攔截用戶的請求
* @author MD
* @create 2020-08-14 21:18
*/
public class MyInterceptor implements HandlerInterceptor {
// 快捷鍵:ctrl + O
private long btime = 0;
/*
* preHandle叫做預處理方法,
* 重要:是整個專案的入口,門戶, 當preHandle回傳true 請求可以被處理,
* preHandle回傳false,請求到此方法就截止,
*
* 引數:
* Object handler : 被攔截的控制器物件
* 回傳值boolean
* true:請求是通過了攔截器的驗證,可以執行處理器方法
* 執行順序
攔截器: preHandle()
-------MyController的doSome()
攔截器: postHandle()
攔截器: afterCompletion()
*
* false:請求沒有通過攔截器的驗證,請求到達攔截器就截止了, 請求沒有被處理
* 僅僅輸出這一句話,
* 攔截器: preHandle()
*
*
* 特點:
* 1.方法在控制器方法(MyController的doSome)之前先執行的,
* 用戶的請求首先到達此方法
*
* 2.在這個 方法中可以獲取請求的資訊, 驗證請求是否符合要求,
* 可以驗證用戶是否登錄, 驗證用戶是否有權限訪問某個連接地址(url),
* 如果驗證失敗,可以截斷請求,請求不能被處理,
* 如果驗證成功,可以放行請求,此時控制器方法才能執行,
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
btime = System.currentTimeMillis();
System.out.println("攔截器: preHandle()");
// 計算的業務邏輯,根據計算的結果,回傳true或者false
// 給瀏覽器一個反饋
// request.getRequestDispatcher("/tips.jsp").forward(request,response);
//
// return false;
return true;
}
/*
postHandle:后處理方法,
引數:
Object handler:被攔截的處理器物件MyController
ModelAndView modelAndView:處理器方法的回傳值
特點:
1.在處理器方法之后執行的(MyController.doSome())
2.能夠獲取到處理器方法的回傳值ModelAndView,可以修改ModelAndView中的
資料和視圖,可以影響到最后的執行結果,
3.主要是對原來的執行結果做二次修正,
ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("攔截器: postHandle()");
// 對原來的doSome執行的結果進行調整
if (modelAndView != null){
modelAndView.addObject("mydate" , new Date());
modelAndView.setViewName("other");
}
}
/*
afterCompletion:最后執行的方法
引數
Object handler:被攔截器的處理器物件
Exception ex:程式中發生的例外
特點:
1.在請求處理完成后執行的,框架中規定是當你的視圖處理完成后,對視圖執行了forward,就認為請求處理完成,
2.一般做資源回收作業的, 程式請求程序中創建了一些物件,在這里可以洗掉,把占用的記憶體回收,
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("攔截器: afterCompletion()");
long etime = System.currentTimeMillis();
System.out.println("計算從preHandle到請求處理完成的時間:"+(etime - btime ));
}
}
創建springmvc的組態檔
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--宣告組件掃描器-->
<context:component-scan base-package="com.md.controller"/>
<!--宣告springmvc框架中的視圖決議器,幫助開發人員設定視圖檔案路徑-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前綴:視圖檔案的路徑-->
<property name="prefix" value=https://www.cnblogs.com/mengd/p/"/WEB-INF/view/" />
攔截器中方法與處理器方法的執行順序

3. 多個攔截器的執行
再定義一個攔截器
package com.md.handler;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("111111111111攔截器: preHandle()");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("11111111111111111攔截器: postHandle()");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("111111111111111攔截器: afterCompletion()");
}
}
//---------------------------------------
package com.md.handler;
public class MyInterceptor2 implements HandlerInterceptor {
// 快捷鍵:ctrl + O
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("2222222222222222攔截器: preHandle()");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("2222222222222222攔截器: postHandle()");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("122222222222222222攔截器: afterCompletion()");
}
}
//---------------------------------------
多個攔截器的注冊,在springmvc的組態檔
<!-- 宣告攔截器: 攔截器可以一個或者多個
在框架中保存是在一個ArrayList , 先宣告的在前面,
-->
<mvc:interceptors>
<!--宣告第一個攔截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--宣告攔截器物件-->
<bean class="com.md.handler.MyInterceptor"/>
</mvc:interceptor>
<!--宣告第二個攔截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--宣告攔截器物件-->
<bean class="com.md.handler.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 回傳的都是true,執行的順序-->
<!--111111111111攔截器: preHandle()-->
<!--2222222222222222攔截器: preHandle()-->
<!-- -------MyController的doSome()-->
<!--2222222222222222攔截器: postHandle()-->
<!--11111111111111111攔截器: postHandle()-->
<!--122222222222222222攔截器: afterCompletion()-->
<!--111111111111111攔截器: afterCompletion()-->
<!-- 第一個true,第一個false,執行順序-->
<!--111111111111攔截器: preHandle()-->
<!--2222222222222222攔截器: preHandle()-->
<!--111111111111111攔截器: afterCompletion()-->
<!-- 回傳的都是false,執行的順序-->
<!--111111111111攔截器: preHandle()-->
</beans>
當有多個攔截器時,形成攔截器鏈,攔截器鏈的執行順序,與其注冊順序一致,需要再次強調一點的是,當某一個攔截器的 preHandle()方法回傳 true 并被執行到時,會向一個專門的方法堆疊中放入該攔截器的 afterCompletion()方法

4. 攔截器和過濾器的區別
- 過濾器是servlet中的物件, 攔截器是框架中的物件
- 過濾器實作Filter介面的物件, 攔截器是實作HandlerInterceptor
- 過濾器是用來設定request,response的引數,屬性的,側重對資料過濾的,
- 攔截器是用來驗證請求的,能截斷請求,
- 過濾器是在攔截器之前先執行的,
- 過濾器是tomcat服務器創建的物件、攔截器是springmvc容器中創建的物件
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/61806.html
標籤:Java
上一篇:求此代碼
