本人轉(zhuǎn)自:http://www.cnblogs.com/xrq730/p/5343160.html
Model
上一篇文章SPRing MVC:基于注解的MVC(上),講了Spring MVC環(huán)境搭建、@RequestMapping以及參數(shù)綁定,這是Spring MVC中最基礎(chǔ)也是最重要的內(nèi)容,本篇文章繼續(xù)講講Spring MVC中其余的知識(shí)點(diǎn),先從Model開始。
前一篇文章比較詳細(xì)地解讀了數(shù)據(jù)從頁面請(qǐng)求到服務(wù)器后臺(tái)的一些細(xì)節(jié),那么下一個(gè)要解決的問題就是數(shù)據(jù)如何從后臺(tái)再次傳回前臺(tái),答案就是這里要說的Model,關(guān)于Model在寫例子之前我特別先說明三點(diǎn):
1、Model本身是一個(gè)接口,其實(shí)現(xiàn)類為ExtendedModelMap,除了使用Model之外還可以使用ModelAndView、ModelMap這些,不過要是沒有特殊需求,使用Model比較簡單,我個(gè)人也比較喜歡使用Model
2、Model的生命周期是Request,也就是說要通過Model傳值只能使用轉(zhuǎn)發(fā)而不能使用重定向
3、為什么要使用Model而不是用Request,最主要的原因就是減少代碼的侵入性或者說代碼的耦合度也行。因?yàn)镸odel是Spring的組件,Request是J2EE的組件,使用Model而不去使用Request可以減少對(duì)J2EE的依賴,也便于調(diào)試
OK,接下來看例子,總體的代碼還是按照上一篇文章的來,先看后臺(tái)的代碼:
@Controller@RequestMapping(value = "/test")public class TestController{ @RequestMapping public String dispatchTest(Test test, Model model) { model.addAttribute("modelKey", "modelValue"); return "test"; }}就往Model里面塞一個(gè)Key-Value,然后轉(zhuǎn)發(fā)到test.jsp下,test.jsp頁面要取Model的值,可以通過JSTL(EL表達(dá)式也可以)獲取,反正直接在jsp頁面上通過"<% ... %>"寫java腳本是行不通的。test.jsp頁面這么寫:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>test頁面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keyWords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/CSS" href="styles.css"> --> </head> <body> <c:out value="${modelKey}" /> </body></html>OK,然后訪問一下"http://localhost:8080/SpringMVC/test"這個(gè)地址,頁面上"modelValue"這幾個(gè)字符就出來了。
之前說過了,Model的生命周期是Request,那么如果頁面是重定向到test.jsp上面去,肯定是取不到"modelValue"的,可以自己試一下,因此重定向過去的話,要在后臺(tái)把數(shù)據(jù)設(shè)置到session中。
test.jsp頁面不變,Controller可以這么改:
@Controller@RequestMapping(value = "/test")public class TestController{ @RequestMapping public String dispatchTest(Test test, HttpSession session) { session.setAttribute("modelKey", "modelValue"); return "redirect:/test.jsp"; //return "test"; }}可以試一下,再訪問一下"http://localhost:8080/SpringMVC/test"這個(gè)地址,"modelValue"這幾個(gè)字符在頁面上就出來了。
在Spring MVC中,Request、Response、Session、InputStream、OutputStream這些對(duì)象是自動(dòng)注入的,但是就像之前說的,為了減少代碼的侵入性與耦合度,能不使用盡量還是不使用這些J2EE的對(duì)象的好。
攔截器(Interceptor)
SpringMVC中的攔截器相當(dāng)于J2EE中的過濾器,是非常重要和相當(dāng)有用的,它的主要作用就是攔截用戶的請(qǐng)求并進(jìn)行相應(yīng)的處理的,比如通過它來進(jìn)行權(quán)限驗(yàn)證,或者是來判斷用戶是否登陸。
在SpringMVC中使用攔截器的方法比較簡單,首先實(shí)現(xiàn)HandlerInterceptor接口,實(shí)現(xiàn)afterCompletion、postHandle、preHandle三個(gè)抽象方法,這里定義兩個(gè)Interceptor:
public class TestInterceptor1 implements HandlerInterceptor{ public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("TestInterceptor1.afterCompletion()"); } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("TestInterceptor1.postHandle()"); } public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("TestInterceptor1.preHandle()"); return true; }}public class TestInterceptor2 implements HandlerInterceptor{ public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("TestInterceptor2.afterCompletion()"); } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("TestInterceptor2.postHandle()"); } public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("TestInterceptor2.preHandle()"); return true; }}說明一下三個(gè)方法的作用:
1、afterCompletion:在整個(gè)視圖渲染完畢之后執(zhí)行方法里面的內(nèi)容,主要用于釋放一些資源
2、postHandle:在Controller執(zhí)行之后,視圖渲染之前執(zhí)行方法里面的內(nèi)容,也就是說postHandle方法可以對(duì)Model進(jìn)行操作
3、preHandle:在Controller執(zhí)行之前,執(zhí)行方法里面的內(nèi)容,注意該方法是有返回值的,當(dāng)方法返回false時(shí)整個(gè)請(qǐng)求就結(jié)束了
然后在springmvc-servlet.xml里面增加攔截器的配置:
<!-- 配置攔截器 --><mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/test" /> <bean class="com.xrq.interceptor.TestInterceptor2" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/test" /> <bean class="com.xrq.interceptor.TestInterceptor1" /> </mvc:interceptor></mvc:interceptors>假如有多個(gè)攔截器的話,"<mvc:interceptor>...</mvc:interceptor>"定義的順序就是攔截器執(zhí)行的順序。
下面繼續(xù)訪問"http://localhost:8080/SpringMVC/test",代碼執(zhí)行的結(jié)果是:
TestInterceptor2.preHandle()TestInterceptor1.preHandle()TestInterceptor1.postHandle()TestInterceptor2.postHandle()TestInterceptor1.afterCompletion()TestInterceptor2.afterCompletion()也許有些朋友對(duì)這個(gè)執(zhí)行結(jié)果不是很理解,我其實(shí)是懂的,但確實(shí)一下子也說不清楚。
如果不是很理解的朋友,可以去看一下Java設(shè)計(jì)模式里面的責(zé)任鏈模式,攔截器的這種調(diào)用方法實(shí)際上是一種鏈?zhǔn)降恼{(diào)用法,TestInterceptor2調(diào)用TestInterceptor1,TestInterceptor1方法走了才會(huì)回到TestInterceptor2的方法里面。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注