SpringMVC核心技術(shù)
請(qǐng)求重定向和轉(zhuǎn)發(fā)
當(dāng)處理器對(duì)請(qǐng)求處理完畢后,向其它資源進(jìn)行跳轉(zhuǎn)是,有兩種跳轉(zhuǎn)方式:請(qǐng)求轉(zhuǎn)發(fā)與重定向。而根據(jù)索要跳轉(zhuǎn)的資源類(lèi)型,又可分為兩類(lèi):跳轉(zhuǎn)到頁(yè)面與跳轉(zhuǎn)到其他處理器。
注意:對(duì)于請(qǐng)求轉(zhuǎn)發(fā)的頁(yè)面,可以是WEB-INF中頁(yè)面,而重定向的頁(yè)面,是不能為WEB-INF中的,因?yàn)橹囟ㄏ蛳喈?dāng)于用戶(hù)再次發(fā)出一次請(qǐng)求,而用戶(hù)不能直接訪(fǎng)問(wèn)WEB-INF中的資源。

SpringMVC框架把原來(lái)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.getRequestDispathcer("xx.jsp").forward();
redirect:表示重定向,實(shí)現(xiàn)response.sendRediect("xxx.jsp");
請(qǐng)求轉(zhuǎn)發(fā)
處理器方法返回 ModelAndView 時(shí),需在 setViewName()指定的視圖前添加 forward:,且此時(shí)的視圖不再與視圖解析器一同工作,這樣可以在配置了解析器時(shí)指定不同位置的視圖。視圖頁(yè)面必須寫(xiě)出相對(duì)于項(xiàng)目根的路徑。forward 操作不需要視圖解析器。處理器方法返回 String,在視圖路徑前面加入 forward: 視圖完整路徑。
@RequestMapping(value = "/some",produces = "text/plain;charset=utf-8")
public ModelAndView testForward(String name,Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("name",name);
mv.addObject("age",age);
mv.setViewName("forward:/WEB-INF/view/show.jsp");
return mv;
}
請(qǐng)求重定向
在處理器方法返回的視圖字符串的前面添加 redirect:,則可實(shí)現(xiàn)重定向跳轉(zhuǎn)。
@RequestMapping(value = "/other")
public ModelAndView testRedirect(String name,Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("name",name);
mv.addObject("age",age);
mv.setViewName("redirect:/other.jsp");
return mv;
}
異常處理
使用注解@ExceptionHandler 可以將一個(gè)方法指定為異常處理方法。該注解只有一個(gè)可選屬性 value,為一個(gè) Class<?>數(shù)組,用于指定該注解的方法所要處理的異常類(lèi),即所要匹配的異常。而被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名隨意,方法參數(shù)可以是 Exception 及其子類(lèi)對(duì)象、HttpServletRequest、HttpServletResponse 等。系統(tǒng)會(huì)自動(dòng)為這些方法參數(shù)賦值。對(duì)于異常處理注解的用法,也可以直接將異常處理方法注解于 Controller 之中。
代碼演示
第一步:自定義兩個(gè)異常類(lèi)
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
public class AgeException extends MyException {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
public class NameException extends MyException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
第二步:在controller方法中拋出異常
@RequestMapping(value = "exception")
public ModelAndView askForException(String name,Integer age) throws MyException {
ModelAndView mv = new ModelAndView();
if(!"zs".equals(name)){
throw new NameException("姓名不正確?。?!");
}
if (age == null || age > 80){
throw new AgeException("年齡太大了?。。?);
}
mv.addObject("name",name);
mv.addObject("age",age);
mv.setViewName("show");
return mv;
第三步:定義三個(gè)異常響應(yīng)頁(yè)面
nameError.jsp
<br/>
提示信息:${msg}
<br/>
系統(tǒng)信息:${ex.message}
ageError.jsp
<br/>
提示信息:${msg}
<br/>
系統(tǒng)信息:${ex.message}
otherError.jsp
<br/>
提示信息:${msg}
<br/>
系統(tǒng)信息:${ex.message}
第四步:定義全局異常處理類(lèi)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = NameException.class)
public ModelAndView nameException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","姓名不是zs");
mv.addObject("ex",ex);
mv.setViewName("nameError");
return mv;
}
@ExceptionHandler(value = AgeException.class)
public ModelAndView ageException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","年齡超過(guò)80歲啦");
mv.addObject("ex",ex);
mv.setViewName("ageError");
return mv;
}
@ExceptionHandler
public ModelAndView otherException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","未知異常");
mv.addObject("ex",ex);
mv.setViewName("otherError");
return mv;
}
}
第五步:在spring配置controller和handler的注解掃描
<!--開(kāi)啟Controller注解掃描-->
<context:component-scan base-package="school.xauat.controller"></context:component-scan>
<!--配置視圖解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--開(kāi)啟注解驅(qū)動(dòng)-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--開(kāi)啟ControllerAdvice注解掃描-->
<context:component-scan base-package="school.xauat.handler"></context:component-scan>
SpringMVC攔截器
SpringMVC 中的 Interceptor 攔截器是非常重要和相當(dāng)有用的,它的主要作用是攔截指定的用戶(hù)請(qǐng)求,并進(jìn)行相應(yīng)的預(yù)處理與后處理。其攔截的時(shí)間點(diǎn)在“處理器映射器根據(jù)用戶(hù)提交的請(qǐng)求映射出了所要執(zhí)行的處理器類(lèi),并且也找到了要執(zhí)行該處理器類(lèi)的處理器適配器,在處理器適配器執(zhí)行處理器之前”。當(dāng)然,在處理器映射器映射出所要執(zhí)行的處理器類(lèi)時(shí),已經(jīng)將攔截器與處理器組合為了一個(gè)處理器執(zhí)行鏈,并返回給了中央調(diào)度器。
定義攔截器類(lèi)
public class myInterceptor implements HandlerInterceptor {
private Long beginTime;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法執(zhí)行");
beginTime = System.currentTimeMillis();
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle方法執(zhí)行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion方法執(zhí)行");
Long endTime = System.currentTimeMillis();
System.out.println("程序執(zhí)行時(shí)間" + (endTime - beginTime) + "ms");
}
}
在springMVC配置文件注冊(cè)攔截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="school.xauat.handler.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
自定義攔截器,需要實(shí)現(xiàn) HandlerInterceptor 接口。而該接口中含有三個(gè)方法:
preHandle(request,response, Object handler):
該方法在處理器方法執(zhí)行之前執(zhí)行。其返回值為 boolean,若為 true,則緊接著會(huì)執(zhí)行處理器方法,且會(huì)將 afterCompletion()方法放入到一個(gè)專(zhuān)門(mén)的方法棧中等待執(zhí)行。
postHandle(request,response, Object handler,modelAndView):
該方法在處理器方法執(zhí)行之后執(zhí)行。處理器方法若最終未被執(zhí)行,則該方法不會(huì)執(zhí)行。由于該方法是在處理器方法執(zhí)行完后執(zhí)行,且該方法參數(shù)中包含 ModelAndView,所以該方法可以修改處理器方法的處理結(jié)果數(shù)據(jù),且可以修改跳轉(zhuǎn)方向。
afterCompletion(request,response, Object handler, Exception ex):
當(dāng) preHandle()方法返回 true 時(shí),會(huì)將該方法放到專(zhuān)門(mén)的方法棧中,等到對(duì)請(qǐng)求進(jìn)行響應(yīng)的所有工作完成之后才執(zhí)行該方法。即該方法是在中央調(diào)度器渲染(數(shù)據(jù)填充)了響應(yīng)頁(yè)面之后執(zhí)行的,此時(shí)對(duì) ModelAndView 再操作也對(duì)響應(yīng)無(wú)濟(jì)于事。
afterCompletion 最后執(zhí)行的方法,清除資源,例如在 Controller 方法中加入數(shù)據(jù)
攔截器中方法和處理器方法的執(zhí)行順序如下圖

當(dāng)有多個(gè)攔截器時(shí)

攔截器過(guò)濾器的區(qū)別
攔截器和過(guò)濾器的區(qū)別
1、過(guò)濾器是Servlet中的對(duì)象。攔截器是框架中的對(duì)象
2、過(guò)濾器是實(shí)現(xiàn)Filter接口的對(duì)象。攔截器是實(shí)現(xiàn)HandlerInterceptor接口
3、過(guò)濾器用來(lái)設(shè)置request和response的參數(shù)、屬性。
4、過(guò)濾器是在攔截器之前先執(zhí)行的
5、過(guò)濾器是Tomcat服務(wù)器中創(chuàng)建的對(duì)象,攔截器是springmvc容器中創(chuàng)建的對(duì)象
6、過(guò)濾器是一個(gè)執(zhí)行時(shí)間點(diǎn),攔截器有三個(gè)執(zhí)行時(shí)間點(diǎn)
7、過(guò)濾器可以處理jsp、js、html等,攔截器是側(cè)重?cái)r截對(duì)controller的對(duì)象,如果你的請(qǐng)求不能被中央調(diào)度器接受,這個(gè)請(qǐng)求就不會(huì)執(zhí)行攔截內(nèi)容
SpringMVC執(zhí)行流程理解

SpringMVC執(zhí)行流程分析
(1)瀏覽器提交請(qǐng)求到中央調(diào)度器
(2)中央調(diào)度器直接將請(qǐng)求轉(zhuǎn)給處理器映射器。
(3)處理器映射器會(huì)根據(jù)請(qǐng)求,找到處理該請(qǐng)求的處理器,并將其封裝為處理器執(zhí)行鏈后返回給中央調(diào)度器。
(4)中央調(diào)度器根據(jù)處理器執(zhí)行鏈中的處理器,找到能夠執(zhí)行該處理器的處理器適配器。
(5)處理器適配器調(diào)用執(zhí)行處理器。
(6)處理器將處理結(jié)果及要跳轉(zhuǎn)的視圖封裝到一個(gè)對(duì)象 ModelAndView 中,并將其返回給處理器適配器。
(7)處理器適配器直接將結(jié)果返回給中央調(diào)度器。
(8)中央調(diào)度器調(diào)用視圖解析器,將 ModelAndView 中的視圖名稱(chēng)封裝為視圖對(duì)象。
(9)視圖解析器將封裝了的視圖對(duì)象返回給中央調(diào)度器
(10)中央調(diào)度器調(diào)用視圖對(duì)象,讓其自己進(jìn)行渲染,即進(jìn)行數(shù)據(jù)填充,形成響應(yīng)對(duì)象。
(11)中央調(diào)度器響應(yīng)瀏覽器。
總結(jié)
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Mybatis CURD及模糊查詢(xún)功能的實(shí)現(xiàn)
這篇文章主要介紹了Mybatis CURD及模糊查詢(xún)功能的實(shí)現(xiàn),有查詢(xún)刪除,插入,更新功能,通過(guò)實(shí)例代碼講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-06-06
Spring數(shù)據(jù)庫(kù)多數(shù)據(jù)源路由配置過(guò)程圖解
這篇文章主要介紹了Spring數(shù)據(jù)庫(kù)多數(shù)據(jù)源路由配置過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
SpringBoot項(xiàng)目配置明文密碼泄露問(wèn)題的處理方式
這篇文章主要介紹了SpringBoot項(xiàng)目配置明文密碼泄露問(wèn)題的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java基礎(chǔ)詳解之集合框架工具Collections
這篇文章主要介紹了Java基礎(chǔ)詳解之集合框架工具Collections,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下2021-04-04
Java深入了解數(shù)據(jù)結(jié)構(gòu)之哈希表篇
哈希表是一種根據(jù)關(guān)鍵碼去尋找值的數(shù)據(jù)映射結(jié)構(gòu),該結(jié)構(gòu)通過(guò)把關(guān)鍵碼映射的位置去尋找存放值的地方,說(shuō)起來(lái)可能感覺(jué)有點(diǎn)復(fù)雜,我想我舉個(gè)例子你就會(huì)明白了,最典型的的例子就是字典2022-01-01
MyBatis查詢(xún)數(shù)據(jù),賦值給List集合時(shí),數(shù)據(jù)缺少的問(wèn)題及解決
這篇文章主要介紹了MyBatis查詢(xún)數(shù)據(jù),賦值給List集合時(shí),數(shù)據(jù)缺少的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
java實(shí)現(xiàn)單鏈表倒轉(zhuǎn)的方法
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)單鏈表倒轉(zhuǎn)的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

