四乳乌、SpringMVC核心技術(shù)
4.1 請(qǐng)求重定向
SpringMVC框架把原來Servlet表中的請(qǐng)求轉(zhuǎn)發(fā)和重定向操作進(jìn)行了封裝誉简,現(xiàn)在可以可以使用簡(jiǎn)單的方式實(shí)現(xiàn)轉(zhuǎn)發(fā)和重定向
forward:表示轉(zhuǎn)發(fā),實(shí)現(xiàn)request.getRequestDispatcher("xx.jsp").forward(request,response);镣丑,轉(zhuǎn)發(fā)在服務(wù)器內(nèi)部進(jìn)行操作唧取,一次請(qǐng)求
redirect:表示重定向航夺,實(shí)現(xiàn)response.sendRedirect("xxx.jsp"),用戶地址欄變化腥光,二次請(qǐng)求关顷,由于是用戶發(fā)起,不能訪問WEB-INF下的內(nèi)容
請(qǐng)求
格式:
modelAndView.setViewName("forward:/hello.jsp");
使用封裝的請(qǐng)求轉(zhuǎn)發(fā)武福,可以不通過視圖解析器解寝,這里路徑名使用的是全路徑名
轉(zhuǎn)發(fā)的顯示頁面可以自定義
案例:
請(qǐng)求頁面:
<p>SpringMVC封裝的請(qǐng)求轉(zhuǎn)發(fā)</p>
<form action="doForward.do" method="post">
名稱:<input type="text" name="name"> <br>
年齡:<input type="text" name="age"> <br>
<input type="submit" value="提交">
</form>
后端控制器:
@Controller
public class MyController {
@RequestMapping(value = "/doForward.do")
public ModelAndView doForward(String name,String age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","姓名 - " +name);
modelAndView.addObject("age","年齡 - " + age);
modelAndView.setViewName("forward:/hello.jsp");
return modelAndView;
}
}
配置文件:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 聲明注解掃描-->
<context:component-scan base-package="com.GeekRose.controller"/>
<!-- 聲明視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
顯示效果:
重定向
重定向的語法格式:
modelAndView.setViewName("redirect:/hello.jsp");
實(shí)現(xiàn)重定向的步驟:
- 發(fā)出請(qǐng)求的前端資源
<p>SpringMVC封裝的請(qǐng)求重定向</p>
<form action="doRedirect.do" method="post">
名稱:<input type="text" name="name"> <br>
年齡:<input type="text" name="age"> <br>
<input type="submit" value="提交">
</form>
- 后端控制器接收請(qǐng)求,添加數(shù)據(jù)艘儒,請(qǐng)求重定向
@RequestMapping("/doRedirect.do")
public ModelAndView doRedirect(String name,String age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","姓名 - " +name);
modelAndView.addObject("age","年齡 - " + age);
modelAndView.setViewName("redirect:/hello.jsp");
return modelAndView;
}
- 重定向頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>顯示</title>
</head>
<body>
<p>this is webapp / hello.jsp</p>
得到的數(shù)據(jù): <br>
name: ${name} <br>
age: ${age} <br>
</body>
</html>
- 顯示效果:
-
分析:
請(qǐng)求重定向后頁面地址欄發(fā)生變化
加入的數(shù)據(jù)沒有得到
在地址欄中發(fā)現(xiàn)數(shù)據(jù)出現(xiàn)在地址欄的請(qǐng)求參數(shù)上
-
結(jié)論:
請(qǐng)求重定向是兩次請(qǐng)求聋伦,request域中無法得到上一個(gè)request的數(shù)據(jù),重定向的頁面地址欄會(huì)變化界睁,加入的數(shù)據(jù)作為請(qǐng)求參數(shù)出現(xiàn)
-
得到數(shù)據(jù)的解決方案
顯示頁面中將el表達(dá)式默認(rèn)request域改為從param參數(shù)中農(nóng)獲取
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>顯示</title>
</head>
<body>
<p>this is webapp / hello.jsp</p>
得到的數(shù)據(jù): <br>
name: ${param.name} <br>
age: ${param.age} <br>
</body>
</html>
- 顯示效果
${param.name}相當(dāng)于
數(shù)據(jù)相當(dāng)于:<%=request.getParameter("name")%>
-
當(dāng)我們要訪問WEB-INF下的數(shù)據(jù)觉增,會(huì)發(fā)生404
重定向不能訪問受保護(hù)資源
框架對(duì)重定向的操作:
-
框架會(huì)把Model中的簡(jiǎn)單類型數(shù)據(jù),轉(zhuǎn)為string使用翻斟,作為hello.jsp的get請(qǐng)求參數(shù)使用
目的:在doRedirect.do 和 hello.jsp兩次請(qǐng)求之間可以傳遞數(shù)據(jù)
在目標(biāo)hello.jsp頁面可以使用參數(shù)集合對(duì)象{param.myname}
注意:
關(guān)鍵:SpringMVC的請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向不和視圖解析器一起使用
4.2 異常處理
業(yè)務(wù)功能和異常處理進(jìn)行解耦合,使用的aop思想访惜,SpringMVC框架采用的是統(tǒng)一全局異常處理方案嘹履,把Controller中的所有異常處理都集中到一個(gè)地方。采用的是aop的思想债热,把業(yè)務(wù)邏輯和異常處理代碼分開砾嫉。
使用兩個(gè)注解:
@ExceptionHandler
@ControllerAdvice
異常處理步驟:
新建Maven web項(xiàng)目
加入依賴
新建一個(gè)自定義異常類 MyUserException 再定義它的子類NameException AgeException
MyUserException
public class MyUserException extends Exception{
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
NameException
public class NameException extends MyUserException{
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
AgeException
public class AgeException extends MyUserException{
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
- 在controller拋出NameException,AgeException
@Controller
public class MyController {
@RequestMapping(value = "/doSome.do")
public ModelAndView doSome(String name,Integer age) throws MyUserException {
ModelAndView modelAndView = new ModelAndView();
if (!"zs".equals(name)){
throw new NameException("姓名不正確窒篱!");
}
if (age == null || age > 90){
throw new AgeException("年齡不正確焕刮!");
}
modelAndView.addObject("name","姓名 - " +name);
modelAndView.addObject("age","年齡 - " + age);
modelAndView.setViewName("show");
return modelAndView;
}
}
-
創(chuàng)建一個(gè)普通類舶沿,作用全局異常處理類
在類上面加入@ControllerAdvice
在類中定義方法,方法上面加入@ExceptionHandler
//@ControllerAdvice 注解表示控制器通知 / 增強(qiáng)
@ControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler 注解映射解決具體異常的方法
// 有一個(gè)參數(shù) 就是要解決異常的class類
// 形參Exception配并,表示Controller中跑出的異常對(duì)象括荡,通過形參可以獲取發(fā)生的異常信息
// 方法返回值和對(duì)應(yīng)的切入點(diǎn)的返回值一樣
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception ex){
// 處理Name異常
/*
異常處理邏輯:
1\. 需要把異常記錄下來,記錄到數(shù)據(jù)庫(kù)溉旋,日志文件
記錄日志發(fā)生的時(shí)間畸冲,哪個(gè)方法發(fā)生的,異常錯(cuò)誤內(nèi)容
2\. 發(fā)送通知观腊,把異常信息通過郵件 / 短信 / 微信發(fā)生給相關(guān)人員
3\. 給用戶友好的提示
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg","姓名不準(zhǔn)確");
mv.addObject("ex",ex);
mv.setViewName("errorName");
return mv;
}
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","年齡不正確");
mv.addObject("ex",ex);
mv.setViewName("errorAge");
return mv;
}
@ExceptionHandler
public ModelAndView doOtherException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","這是其他類型的異常");
mv.addObject("ex",ex);
mv.setViewName("otherError");
return mv;
}
}
當(dāng)我們的異常不是name和age產(chǎn)生召夹,即其他異常就會(huì)映射到不加value的@ExceptionHandler注解下的方法來處理
- 創(chuàng)建處理異常的視圖頁面
errorName.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>errorName</title>
</head>
<body>
<h3>this is name error</h3>
友情提示:${msg} <br>
系統(tǒng)提示:${ex.message}
</body>
</html>
errorAge.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>errorAge</title>
</head>
<body>
<h3>this is age error</h3>
友情提示:${msg} <br>
用戶提示:${ex.message}
</body>
</html>
otherError.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>other error</title>
</head>
<body>
<h3>this is other error</h3>
友情提示:${msg} <br>
系統(tǒng)提示:${ex.message}
</body>
</html>
-
創(chuàng)建SpringMVC的配置文件
組件掃描器,掃描@Controller注解
組件掃描器恕沫,掃描@ControllerAdvice所在的包名
聲明注解驅(qū)動(dòng)
<?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.GeekRose.controller"/>
<!-- 聲明視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 實(shí)現(xiàn)全局異常處理還需要兩步-->
<mvc:annotation-driven />
<context:component-scan base-package="com.GeekRose.handler" />
</beans>
這里命名空間記得導(dǎo)入正確
- 效果:
當(dāng)我們輸入錯(cuò)誤數(shù)據(jù) 例如 姓名為zhangsan時(shí)
得到的處理結(jié)果為:
使用全局異常處理监憎,主要是為了實(shí)現(xiàn)解耦合,不用自己不斷寫try catch婶溯,異常處理代碼和業(yè)務(wù)邏輯代碼實(shí)現(xiàn)分離
4.3 攔截器
SpringMVC中的Interceptor攔截器是非常重要和相當(dāng)有用的鲸阔,它的主要作用是攔截指定的用戶請(qǐng)求,并進(jìn)行相應(yīng)的預(yù)處理和后處理迄委。其攔截的時(shí)間點(diǎn)在“處理器映射器根據(jù)用戶提交的請(qǐng)求映射出了所要執(zhí)行的處理器類褐筛,并且也找到了要執(zhí)行該處理器類的處理器適配器,在處理器適配器執(zhí)行處理器之前”叙身。當(dāng)然渔扎,在處理器映射器映射出所要執(zhí)行的處理器類時(shí),已經(jīng)將攔截器與處理器組合為了一個(gè)處理器執(zhí)行鏈信轿,并返回給了中央調(diào)度器晃痴。
實(shí)現(xiàn)了HandlerInterceptor接口的都是攔截器
攔截器和過濾器類似,但是側(cè)重點(diǎn)不同 功能方向不同财忽。
過濾器用來過濾請(qǐng)求參數(shù)倘核,設(shè)置編碼字符集等工作。
攔截器是攔截用戶的請(qǐng)求即彪,對(duì)請(qǐng)求做判斷處理的紧唱。
-
攔截器是全局的,可以對(duì)多個(gè)Controller做攔截隶校。
一個(gè)項(xiàng)目可以有0個(gè)或多個(gè)攔截器漏益,他們?cè)谝黄饠r截用戶的請(qǐng)求。
攔截器常用在用戶登錄處理和權(quán)限檢查記錄日志深胳。
攔截器的使用步驟:
定義類實(shí)現(xiàn)HandlerInerterceptor接口
在SpringMVC配置文件中聲明攔截器绰疤,讓框架知道攔截器的存在
攔截器的執(zhí)行時(shí)間:
在請(qǐng)求處理之前,也就是controller類中的方法執(zhí)行之前先被攔截
在控制器方法執(zhí)行之后也會(huì)執(zhí)行攔截器
在請(qǐng)求處理完成后也會(huì)執(zhí)行攔截器
預(yù)處理方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
返回值:布爾值
true
false
方法參數(shù):
HttpServletRequest 請(qǐng)求
HttpServletResponse 響應(yīng)
Object Handler 處理器對(duì)象(MyController對(duì)象)
預(yù)處理方法在執(zhí)行處理器方法前執(zhí)行(MyController.doSome)稠屠,一般用作請(qǐng)求判斷峦睡,驗(yàn)證請(qǐng)求是否符合要求∪ú海可以驗(yàn)證用戶是否登錄榨了,驗(yàn)證用戶是否有權(quán)限訪問某個(gè)連接地址(URL)
如果驗(yàn)證失敗,可以截?cái)嗾?qǐng)求攘蔽,請(qǐng)求不能被處理
如果驗(yàn)證成功龙屉,可以方形請(qǐng)求,此時(shí)控制器方法才能執(zhí)行
后處理方法
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
返回值:void
方法參數(shù):
HttpServletRequest 請(qǐng)求
HttpServletResponse 響應(yīng)
Object handler 處理器對(duì)象
ModelAndView modelAndView 數(shù)據(jù)與視圖對(duì)象
后處理方法在處理器方法(MyController.doSome)執(zhí)行后執(zhí)行满俗,一般用作數(shù)據(jù)的二次修訂
最后執(zhí)行的方法
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
返回值:void
請(qǐng)求參數(shù):
HttpServletRequest 請(qǐng)求
HttpServletResponse 響應(yīng)
Object handler 處理器對(duì)象
Exception ex 異常對(duì)象
最后執(zhí)行的方法在請(qǐng)求完成后執(zhí)行(當(dāng)請(qǐng)求進(jìn)行forward转捕,發(fā)送到視圖時(shí)被認(rèn)定為請(qǐng)求完成),一般用作資源回收處理唆垃,程序中創(chuàng)建的一些對(duì)象在這里進(jìn)行刪除五芝,釋放占用的內(nèi)存
配置文件聲明攔截器
攔截器的聲明
<!-- 聲明攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 映射地址 /** 表示工程目錄下的所有請(qǐng)求都會(huì)被攔截
/user/** 表示user下的所有請(qǐng)求都會(huì)被攔截
-->
<mvc:mapping path="/user/**"/>
<bean class="com.GeekRose.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
攔截器:看做多個(gè)Controller中公用的功能,集中到攔截器統(tǒng)一處理辕万,使用的aop思想
攔截器圖解:
多個(gè)攔截器
多個(gè)攔截器的執(zhí)行順序
攔截器的執(zhí)行順序?yàn)閿r截器的聲明順序
圖解:
當(dāng)我們定義兩個(gè)攔截器:
攔截器定義:
攔截器1:
package com.GeekRose.interceptor;
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;
public class MyInterceptor1 implements HandlerInterceptor {
private long btime;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1-preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1-postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1-afterCompletion");
}
}
攔截器2:
package com.GeekRose.interceptor;
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;
public class MyInterceptor2 implements HandlerInterceptor {
private long btime;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor2-preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor2-postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long etime = System.currentTimeMillis();
System.out.println("MyInterceptor2-afterCompletion");
}
}
攔截器聲明:
<!-- 聲明攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 映射地址 /** 表示工程目錄下的所有請(qǐng)求都會(huì)被攔截
/user/** 表示user下的所有請(qǐng)求都會(huì)被攔截
-->
<mvc:mapping path="/user/**"/>
<bean class="com.GeekRose.interceptor.MyInterceptor1" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.GeekRose.interceptor.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
兩個(gè)攔截器的預(yù)處理方法都為true
控制臺(tái)輸出:
MyInterceptor1-preHandle
MyInterceptor2-preHandle
---MyController-doSome---
MyInterceptor2-postHandle
MyInterceptor1-postHandle
MyInterceptor2-afterCompletion
MyInterceptor1-afterCompletion
多個(gè)攔截器執(zhí)行鏈:
當(dāng)攔截器1的預(yù)處理方法為true枢步,攔截器2的預(yù)處理為false
處理結(jié)果:
MyInterceptor1-preHandle
MyInterceptor2-preHandle
MyInterceptor1-afterCompletion
攔截器1預(yù)處理為true,進(jìn)入攔截器2的預(yù)處理為false渐尿,此時(shí)無法進(jìn)行執(zhí)行醉途,截?cái)嗾?qǐng)求。因?yàn)閿r截器1的預(yù)處理為true砖茸,所以攔截器1的最終執(zhí)行方法會(huì)執(zhí)行隘擎。
當(dāng)攔截器1的預(yù)處理為false,攔截器2的預(yù)處理為true
處理結(jié)果:
MyInterceptor1-preHandle
直接截?cái)嗾?qǐng)求凉夯,不會(huì)到攔截器2
只要有一個(gè)攔截器為false货葬,請(qǐng)求到此結(jié)束不會(huì)到控制器中
攔截器和過濾器的區(qū)別
過濾器是Servlet規(guī)范中的對(duì)象,攔截器是框架中的對(duì)象
過濾器實(shí)現(xiàn)Filter接口的對(duì)象劲够,攔截器是實(shí)現(xiàn)HandlerInterceptor接口
過濾器用來設(shè)置request宝惰,response的參數(shù),屬性的再沧,側(cè)重對(duì)數(shù)據(jù)過濾的尼夺,攔截器是用來驗(yàn)證請(qǐng)求的脖苏,能截?cái)嗾?qǐng)求屏箍。
過濾器是在攔截器之前先執(zhí)行的
過濾器是tomcat服務(wù)器創(chuàng)建的對(duì)象,攔截器是SpringMVC容器中創(chuàng)建的對(duì)象
-
過濾器是一個(gè)執(zhí)行時(shí)間點(diǎn)
攔截器有三個(gè)執(zhí)行時(shí)間點(diǎn)
-
過濾器可以處理jsp柬批、js顷扩、html等
攔截器是側(cè)重?cái)r截對(duì)Controller的請(qǐng)求拐邪,如果你的請(qǐng)求不能被中央調(diào)度器接收,這個(gè)請(qǐng)求不會(huì)執(zhí)行攔截器內(nèi)容
攔截器攔截普通方法執(zhí)行隘截,過濾器過濾Servlet請(qǐng)求響應(yīng)
攔截器權(quán)限登錄案例
實(shí)現(xiàn)步驟:
新建maven項(xiàng)目
修改web.xml注冊(cè)中央調(diào)度器
新進(jìn)index.jsp發(fā)起請(qǐng)求
創(chuàng)建MyController處理請(qǐng)求
創(chuàng)建結(jié)果show.jsp
創(chuàng)建一個(gè)login.jsp扎阶,模擬登錄(把用戶信息放入session中)創(chuàng)建一個(gè)logout.jsp汹胃,模擬退出系統(tǒng)(從session中刪除數(shù)據(jù))
創(chuàng)建攔截器,從session中獲取用戶的登錄數(shù)據(jù)东臀,驗(yàn)證能否訪問系統(tǒng)
創(chuàng)建一個(gè)驗(yàn)證的jsp着饥,如果驗(yàn)證失敗,給出提示
-
創(chuàng)建springmvc配置文件
聲明組件掃描器
聲明攔截器
實(shí)現(xiàn)效果:
當(dāng)我們沒有登錄權(quán)限(session沒有數(shù)據(jù)時(shí))惰赋,會(huì)被攔截器階段請(qǐng)求調(diào)到提示頁面宰掉,當(dāng)我們有登錄權(quán)限,就會(huì)訪問到數(shù)據(jù)
這里登錄登出在jsp中實(shí)現(xiàn)
代碼實(shí)現(xiàn):
發(fā)出請(qǐng)求的index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":"
+ request.getServerPort() + request.getContextPath() + "/";
%>
<head>
<title>Title</title>
<base href="<%=basePath%>>">
</head>
<body>
<h3>這是主頁</h3>
<p>登錄驗(yàn)證</p>
<form action="user/doSome.do" method="post">
名稱:<input type="text" name="name"> <br>
年齡:<input type="text" name="age"> <br>
<input type="submit" value="提交">
</form>
獲取登錄權(quán)限 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登錄</title>
</head>
<body>
<h3>log in</h3>
<%
session.setAttribute("name","zs");
%>
</body>
</html>
登出刪除權(quán)限 logout.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登出</title>
</head>
<h3>log out</h3>
<body>
<%
session.removeAttribute("name");
%>
</body>
</html>
提示頁面 tips.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
你的請(qǐng)求已經(jīng)被FBI攔截赁濒,等著open the door吧
</body>
</html>
攔截器 MyInterceptor1
public class MyInterceptor1 implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object key = request.getSession().getAttribute("name");
String keyVal = (String) key;
if (!"zs".equals(keyVal)){
request.getRequestDispatcher("/tips.jsp").forward(request,response);
return false;
}
return true;
}
}
控制器
@Controller
@RequestMapping("/user")
public class MyController {
@RequestMapping(value = "/doSome.do")
public ModelAndView doSome(String name,Integer age) {
System.out.println("---MyController-doSome---");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","姓名 - " +name);
modelAndView.addObject("age","年齡 - " + age);
modelAndView.setViewName("show");
return modelAndView;
}
}
配置文件
<?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.GeekRose.controller"/>
<!-- 聲明視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:annotation-driven />
<!-- 聲明攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 映射地址 /** 表示工程目錄下的所有請(qǐng)求都會(huì)被攔截
/user/** 表示user下的所有請(qǐng)求都會(huì)被攔截
-->
<mvc:mapping path="/user/**"/>
<bean class="com.GeekRose.interceptor.MyInterceptor1" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
效果展示:
沒有登錄權(quán)限:提交后
獲取權(quán)限:
此時(shí)我們?cè)龠M(jìn)行提交
結(jié)果:
當(dāng)我們刪除權(quán)限登出
我們?cè)偬峤粩?shù)據(jù)
結(jié)果:
4.4 SpringMVC的內(nèi)部處理流程
ApplicationContext ctx = new ClassPathXmlApplication("beans.xml");
StudentService service = (StudentService) ctx.getBean("service");
SpringMVC接收請(qǐng)求到處理完成的過程
用戶發(fā)起請(qǐng)求some.do
-
DispatcherServlet接收請(qǐng)求some.do轨奄,把請(qǐng)求轉(zhuǎn)交給處理器映射器,
處理器映射器是SpringMVC框架的一種對(duì)象拒炎,框架把實(shí)現(xiàn)了HandlerMapping接口的類都叫映射器
處理器映射器作用:根據(jù)請(qǐng)求挪拟,從SpringMVC容器對(duì)象中獲取處理器對(duì)象(MyController controller = ctx.getBean("some.do"))
框架把找到的處理器對(duì)象放到一個(gè)叫做處理器執(zhí)行鏈的類保存(HandlerExecutionChain)
HandlerExectutionChain:類中保存著
處理器對(duì)象(MyController)
項(xiàng)目中所有的攔截器(List<HandlerInterceptor> interceptorList)
-
DispatcherServlet把HandlerExecutionChain中的處理器對(duì)象交給了處理器適配器對(duì)象(多個(gè))
處理器適配器是框架中的一種對(duì)象,是SpringMVC框架中的對(duì)象击你,需要實(shí)現(xiàn)HandlerAdapter接口
處理器適配器作用:執(zhí)行處理器方法(調(diào)用MyController.doSome() 得到返回值ModelAndView)
得到的結(jié)果再通過處理器適配器返回給中央調(diào)度器
-
DispatcherServlet把3中獲取的ModelAndView交給視圖解析器對(duì)象
視圖解析器:SpringMVC中的對(duì)象舞丛,需要實(shí)現(xiàn)ViewResolver接口(可以有多個(gè))
視圖解析器作用:組成視圖完整路徑,使用前綴果漾、后綴球切,并創(chuàng)建View對(duì)象。view是一個(gè)接口绒障,表示視圖的吨凑,在框架中jsp、html不是string字符串表示户辱,而是使用view和它的實(shí)現(xiàn)類表示視圖
InternalResourceView:視圖類鸵钝,表示jsp文件,視圖解析器會(huì)創(chuàng)建InternalResourceView類對(duì)象庐镐,這個(gè)對(duì)象里面恩商,有一個(gè)屬性u(píng)rl=/WEB-INF/view/show.jsp
DispathcerServlet把4步驟中創(chuàng)建的View對(duì)象獲取到,調(diào)用View類自己的方法必逆,把Model數(shù)據(jù)放入到request作用域怠堪,執(zhí)行對(duì)象視圖的forward。請(qǐng)求結(jié)束
執(zhí)行流程圖解: