SpringMVC核心技術(shù)
請求重定向和轉(zhuǎn)發(fā)
當(dāng)處理器對請求處理完畢后,向其它資源進(jìn)行跳轉(zhuǎn)是,有兩種跳轉(zhuǎn)方式:請求轉(zhuǎn)發(fā)與重定向。而根據(jù)索要跳轉(zhuǎn)的資源類型,又可分為兩類:跳轉(zhuǎn)到頁面與跳轉(zhuǎn)到其他處理器。
注意:對于請求轉(zhuǎn)發(fā)的頁面,可以是WEB-INF中頁面,而重定向的頁面,是不能為WEB-INF中的,因?yàn)橹囟ㄏ蛳喈?dāng)于用戶再次發(fā)出一次請求,而用戶不能直接訪問WEB-INF中的資源。
SpringMVC
框架把原來Servlet中的請求轉(zhuǎn)發(fā)和重定向操作進(jìn)行了封裝,現(xià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");
請求轉(zhuǎn)發(fā)
處理器方法返回 ModelAndView 時(shí),需在 setViewName()指定的視圖前添加 forward:,且此時(shí)的視圖不再與視圖解析器一同工作,這樣可以在配置了解析器時(shí)指定不同位置的視圖。視圖頁面必須寫出相對于項(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; }
請求重定向
在處理器方法返回的視圖字符串的前面添加 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ù)組,用于指定該注解的方法所要處理的異常類,即所要匹配的異常。而被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名隨意,方法參數(shù)可以是 Exception 及其子類對象、HttpServletRequest、HttpServletResponse 等。系統(tǒng)會自動為這些方法參數(shù)賦值。對于異常處理注解的用法,也可以直接將異常處理方法注解于 Controller 之中。
代碼演示
第一步:自定義兩個(gè)異常類
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)頁面
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}
第四步:定義全局異常處理類
@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","年齡超過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的注解掃描
<!--開啟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> <!--開啟注解驅(qū)動--> <mvc:annotation-driven></mvc:annotation-driven> <!--開啟ControllerAdvice注解掃描--> <context:component-scan base-package="school.xauat.handler"></context:component-scan>
SpringMVC攔截器
SpringMVC 中的 Interceptor 攔截器是非常重要和相當(dāng)有用的,它的主要作用是攔截指定的用戶請求,并進(jìn)行相應(yīng)的預(yù)處理與后處理。其攔截的時(shí)間點(diǎn)在“處理器映射器根據(jù)用戶提交的請求映射出了所要執(zhí)行的處理器類,并且也找到了要執(zhí)行該處理器類的處理器適配器,在處理器適配器執(zhí)行處理器之前”。當(dāng)然,在處理器映射器映射出所要執(zhí)行的處理器類時(shí),已經(jīng)將攔截器與處理器組合為了一個(gè)處理器執(zhí)行鏈,并返回給了中央調(diào)度器。
定義攔截器類
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配置文件注冊攔截器
<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,則緊接著會執(zhí)行處理器方法,且會將 afterCompletion()方法放入到一個(gè)專門的方法棧中等待執(zhí)行。
postHandle(request,response, Object handler,modelAndView):
該方法在處理器方法執(zhí)行之后執(zhí)行。處理器方法若最終未被執(zhí)行,則該方法不會執(zhí)行。由于該方法是在處理器方法執(zhí)行完后執(zhí)行,且該方法參數(shù)中包含 ModelAndView,所以該方法可以修改處理器方法的處理結(jié)果數(shù)據(jù),且可以修改跳轉(zhuǎn)方向。
afterCompletion(request,response, Object handler, Exception ex):
當(dāng) preHandle()方法返回 true 時(shí),會將該方法放到專門的方法棧中,等到對請求進(jìn)行響應(yīng)的所有工作完成之后才執(zhí)行該方法。即該方法是在中央調(diào)度器渲染(數(shù)據(jù)填充)了響應(yīng)頁面之后執(zhí)行的,此時(shí)對 ModelAndView 再操作也對響應(yīng)無濟(jì)于事。
afterCompletion 最后執(zhí)行的方法,清除資源,例如在 Controller 方法中加入數(shù)據(jù)
攔截器中方法和處理器方法的執(zhí)行順序如下圖
當(dāng)有多個(gè)攔截器時(shí)
攔截器過濾器的區(qū)別
攔截器和過濾器的區(qū)別
1、過濾器是Servlet中的對象。攔截器是框架中的對象
2、過濾器是實(shí)現(xiàn)Filter接口的對象。攔截器是實(shí)現(xiàn)HandlerInterceptor接口
3、過濾器用來設(shè)置request和response的參數(shù)、屬性。
4、過濾器是在攔截器之前先執(zhí)行的
5、過濾器是Tomcat服務(wù)器中創(chuàng)建的對象,攔截器是springmvc容器中創(chuàng)建的對象
6、過濾器是一個(gè)執(zhí)行時(shí)間點(diǎn),攔截器有三個(gè)執(zhí)行時(shí)間點(diǎn)
7、過濾器可以處理jsp、js、html等,攔截器是側(cè)重?cái)r截對controller的對象,如果你的請求不能被中央調(diào)度器接受,這個(gè)請求就不會執(zhí)行攔截內(nèi)容
SpringMVC執(zhí)行流程理解
SpringMVC執(zhí)行流程分析
(1)瀏覽器提交請求到中央調(diào)度器
(2)中央調(diào)度器直接將請求轉(zhuǎn)給處理器映射器。
(3)處理器映射器會根據(jù)請求,找到處理該請求的處理器,并將其封裝為處理器執(zhí)行鏈后返回給中央調(diào)度器。
(4)中央調(diào)度器根據(jù)處理器執(zhí)行鏈中的處理器,找到能夠執(zhí)行該處理器的處理器適配器。
(5)處理器適配器調(diào)用執(zhí)行處理器。
(6)處理器將處理結(jié)果及要跳轉(zhuǎn)的視圖封裝到一個(gè)對象 ModelAndView 中,并將其返回給處理器適配器。
(7)處理器適配器直接將結(jié)果返回給中央調(diào)度器。
(8)中央調(diào)度器調(diào)用視圖解析器,將 ModelAndView 中的視圖名稱封裝為視圖對象。
(9)視圖解析器將封裝了的視圖對象返回給中央調(diào)度器
(10)中央調(diào)度器調(diào)用視圖對象,讓其自己進(jìn)行渲染,即進(jìn)行數(shù)據(jù)填充,形成響應(yīng)對象。
(11)中央調(diào)度器響應(yīng)瀏覽器。
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
聊聊java 過濾器、監(jiān)聽器、攔截器的區(qū)別(終結(jié)篇)
這篇文章主要介紹了聊聊java 過濾器、監(jiān)聽器、攔截器的區(qū)別(終結(jié)篇),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作及問題小結(jié)
這篇文章主要介紹了在Springboot+Mybatis-plus不使用SQL語句進(jìn)行多表添加操作,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04Spring中使用copyProperties方法進(jìn)行對象之間的屬性賦值詳解
這篇文章主要介紹了Spring中使用copyProperties方法進(jìn)行對象之間的屬性賦值詳解,使用org.springframework.beans.BeanUtils.copyProperties方法進(jìn)行對象之間屬性的賦值,避免通過get、set方法一個(gè)一個(gè)屬性的賦值,需要的朋友可以參考下2023-12-12JAVA實(shí)現(xiàn)簡單系統(tǒng)登陸注冊模塊
這篇文章主要介紹了一個(gè)簡單完整的登陸注冊模塊的實(shí)現(xiàn)過程,文章條理清晰,在實(shí)現(xiàn)過程中加深了對相關(guān)概念的理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-07-07Java?nacos動態(tài)配置實(shí)現(xiàn)流程詳解
使用動態(tài)配置的原因是properties和yaml是寫到項(xiàng)目中的,好多時(shí)候有些配置需要修改,每次修改就要重新啟動項(xiàng)目,不僅增加了系統(tǒng)的不穩(wěn)定性,也大大提高了維護(hù)成本,非常麻煩,且耗費(fèi)時(shí)間2022-09-09