天天看點

Spring MVC 教程,快速入門,深入分析

http://elf8848.iteye.com/blog/875830

資源下載下傳:

<a href="http://dl.iteye.com/topics/download/82663b25-d84d-392c-9097-e95dcb8f7437" target="_blank">Spring_MVC_教程_快速入門_深入分析V1.1.pdf</a>

<a href="http://dl.iteye.com/topics/download/eda52cf5-07ed-3604-97ef-9bccabd2a734" target="_blank">SpringMVC核心配置檔案示例.rar</a>

作者:趙磊

部落格:http://elf8848.iteye.com

目錄 

一、前言

二、spring mvc 核心類與接口

三、spring mvc 核心流程圖

四、spring mvc DispatcherServlet說明

五、spring mvc 父子上下文的說明

六、springMVC-mvc.xml 配置檔案片段講解 

七、spring mvc 如何通路到靜态的檔案,如jpg,js,css

八、spring mvc 請求如何映射到具體的Action中的方法

九、 spring mvc 中的攔截器:

十、 spring mvc 如何使用攔截器

十一、 spring mvc 如何實作全局的異常處理

十二、 spring mvc 如何把全局異常記錄到日志中

十三、 如何給spring3 MVC中的Action做JUnit單元測試

十四、 spring mvc 轉發與重定向 (帶參數重定向)

十五、 spring mvc 處理ajax請求

十六、 spring mvc 關于寫幾個配置檔案的說明 

十七、 spring mvc 如何取得Spring管理的bean

十八、 spring mvc 多視圖控制器

十九、 &lt;mvc:annotation-driven /&gt; 到底做了什麼工作 

二十、 本文中springMVC.xml配置檔案是核心,這裡給一個下載下傳位址

一、前言:

為開發團隊選擇一款優秀的MVC架構是件難事兒,在衆多可行的方案中決擇需要很高的經驗和水準。你的一個決定會影響團隊未來的幾年。要考慮方面太多:

1、簡單易用,以提高開發效率。使小部分的精力在架構上,大部分的精力放在業務上。

2、性能優秀,這是一個最能吸引眼球的話題。

3、盡量使用大衆的架構(避免使用小衆的、私有的架構),新招聘來的開發人員有一些這方面技術積累,減低人員流動再适應的影響。

如果你還在為這件事件發愁,本文最适合你了。選擇Spring MVC吧。

Spring MVC是目前最優秀的MVC架構,自從Spring 2.5版本釋出後,由于支援注解配置,易用性有了大幅度的提高。Spring 3.0更加完善,實作了對Struts 2的超越。現在越來越多的開發團隊選擇了Spring MVC。

Spring3 MVC的優點:

1、Spring3 MVC使用簡單,學習成本低。學習難度小于Struts2,Struts2用不上的多餘功能太多。呵呵,當然這不是決定因素。

2、Spring3 MVC很容易就可以寫出性能優秀的程式,Struts2要處處小心才可以寫出性能優秀的程式(指MVC部分)

3、Spring3 MVC的靈活是你無法想像的,Spring架構的擴充性有口皆碑,Spring3 MVC當然也不會落後,不會因使用了MVC架構而感到有任何的限制。

Struts2的衆多優點:

1、老牌的知名架構,從Struts1起積累了大量使用者群體。技術文檔豐富。

2、其它方面略...   (呵呵,是不是不公平?)

二、核心類與接口:

先來了解一下,幾個重要的接口與類。現在不知道他們是幹什麼的沒關系,先混個臉熟,為以後認識他們打個基礎。

DispatcherServlet   -- 前置控制器

Spring MVC 教程,快速入門,深入分析

HandlerMapping接口 -- 處理請求的映射

HandlerMapping接口的實作類:

SimpleUrlHandlerMapping  通過配置檔案,把一個URL映射到Controller

DefaultAnnotationHandlerMapping  通過注解,把一個URL映射到Controller類上

Spring MVC 教程,快速入門,深入分析

HandlerAdapter接口 -- 處理請求的映射

AnnotationMethodHandlerAdapter類,通過注解,把一個URL映射到Controller類的方法上

Spring MVC 教程,快速入門,深入分析

Controller接口 -- 控制器

由于我們使用了@Controller注解,添加了@Controller注解注解的類就可以擔任控制器(Action)的職責,

是以我們并沒有用到這個接口。

Spring MVC 教程,快速入門,深入分析

HandlerInterceptor 接口--攔截器

無圖,我們自己實作這個接口,來完成攔截的器的工作。

ViewResolver接口的實作類

UrlBasedViewResolver類 通過配置檔案,把一個視圖名交給到一個View來處理

InternalResourceViewResolver類,比上面的類,加入了JSTL的支援

Spring MVC 教程,快速入門,深入分析

View接口

JstlView類

Spring MVC 教程,快速入門,深入分析

LocalResolver接口

Spring MVC 教程,快速入門,深入分析

HandlerExceptionResolver接口 --異常處理

SimpleMappingExceptionResolver實作類

Spring MVC 教程,快速入門,深入分析

ModelAndView類

無圖。

三、核心流程圖

本圖是我個人畫的,有不嚴謹的地方,大家對付看吧。總比沒的看強。

Spring MVC 教程,快速入門,深入分析

四、DispatcherServlet說明

使用Spring MVC,配置DispatcherServlet是第一步。

DispatcherServlet是一個Servlet,是以可以配置多個DispatcherServlet。

DispatcherServlet是前置控制器,配置在web.xml檔案中的。攔截比對的請求,Servlet攔截比對規則要自已定義,把攔截下來的請求,依據某某規則分發到目标Controller(我們寫的Action)來處理。

“某某規則”:是根據你使用了哪個HandlerMapping接口的實作類的不同而不同。

先來看第一個例子:

Spring MVC 教程,快速入門,深入分析

&lt;web-app&gt;  

    &lt;servlet&gt;  

        &lt;servlet-name&gt;example&lt;/servlet-name&gt;  

        &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;  

        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  

    &lt;/servlet&gt;  

    &lt;servlet-mapping&gt;  

        &lt;url-pattern&gt;*.form&lt;/url-pattern&gt;  

    &lt;/servlet-mapping&gt;  

&lt;/web-app&gt;  

 &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;是啟動順序,讓這個Servlet随Servletp容器一起啟動。

 &lt;url-pattern&gt;*.form&lt;/url-pattern&gt; 會攔截*.form結尾的請求。

 &lt;servlet-name&gt;example&lt;/servlet-name&gt;這個Servlet的名字是example,可以有多個DispatcherServlet,是通過名字來區分的。每一個DispatcherServlet有自己的WebApplicationContext上下文對象。同時儲存的ServletContext中和Request對象中,關于key,以後說明。

在DispatcherServlet的初始化過程中,架構會在web應用的 WEB-INF檔案夾下尋找名為[servlet-name]-servlet.xml 的配置檔案,生成檔案中定義的bean。

第二個例子:

Spring MVC 教程,快速入門,深入分析

&lt;servlet&gt;  

    &lt;servlet-name&gt;springMVC&lt;/servlet-name&gt;  

    &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;  

    &lt;init-param&gt;  

        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;  

        &lt;param-value&gt;classpath*:/springMVC.xml&lt;/param-value&gt;  

    &lt;/init-param&gt;  

    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  

&lt;/servlet&gt;  

&lt;servlet-mapping&gt;  

    &lt;url-pattern&gt;/&lt;/url-pattern&gt;  

&lt;/servlet-mapping&gt;  

指明了配置檔案的檔案名,不使用預設配置檔案名,而使用springMVC.xml配置檔案。

其中&lt;param-value&gt;**.xml&lt;/param-value&gt; 這裡可以使用多種寫法

1、不寫,使用預設值:/WEB-INF/&lt;servlet-name&gt;-servlet.xml

2、&lt;param-value&gt;/WEB-INF/classes/springMVC.xml&lt;/param-value&gt;

3、&lt;param-value&gt;classpath*:springMVC-mvc.xml&lt;/param-value&gt;

4、多個值用逗号分隔

Servlet攔截比對規則可以自已定義,攔截哪種URL合适? 

當映射為@RequestMapping("/user/add")時,為例:

1、攔截*.do、*.htm, 例如:/user/add.do

這是最傳統的方式,最簡單也最實用。不會導緻靜态檔案(jpg,js,css)被攔截。

2、攔截/,例如:/user/add

可以實作現在很流行的REST風格。很多網際網路類型的應用很喜歡這種風格的URL。

弊端:會導緻靜态檔案(jpg,js,css)被攔截後不能正常顯示。想實作REST風格,事情就是麻煩一些。後面有解決辦法還算簡單。

3、攔截/*,這是一個錯誤的方式,請求可以走到Action中,但轉到jsp時再次被攔截,不能通路到jsp。

五、父子上下文(WebApplicationContext)

如果你使用了listener監聽器來加載配置,一般在Struts+Spring+Hibernate的項目中都是使用listener監聽器的。如下

Spring MVC 教程,快速入門,深入分析

&lt;listener&gt;   

  &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;   

&lt;/listener&gt;   

Spring會建立一個WebApplicationContext上下文,稱為父上下文(父容器) ,儲存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

可以使用Spring提供的工具類取出上下文對象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

DispatcherServlet是一個Servlet,可以同時配置多個,每個 DispatcherServlet有一個自己的上下文對象(WebApplicationContext),稱為子上下文(子容器),子上下文可以通路父上下文中的内容,但父上下文不能通路子上下文中的内容。 它也儲存在 ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名稱。當一個Request對象産生時,會把這個子上下文對象(WebApplicationContext)儲存在Request對象中,key是DispatcherServlet.class.getName()

+ ".CONTEXT"。

可以使用工具類取出上下文對象:RequestContextUtils.getWebApplicationContext(request);

說明 :Spring 并沒有限制我們,必須使用父子上下文。我們可以自己決定如何使用。

方案一,傳統型:

父上下文容器中儲存資料源、服務層、DAO層、事務的Bean。

子上下文容器中儲存Mvc相關的Action的Bean.

事務控制在服務層。

由于父上下文容器不能通路子上下文容器中内容,事務的Bean在父上下文容器中,無法通路子上下文容器中内容,就無法對子上下文容器中Action進行AOP(事務)。

當然,做為“傳統型”方案,也沒有必要這要做。

方案二,激進型:

Java世界的“面向接口程式設計”的思想是正确的,但在增删改查為主業務的系統裡,Dao層接口,Dao層實作類,Service層接口,Service層實作類,Action父類,Action。再加上衆多的O(vo\po\bo)和jsp頁面。寫一個小功能 7、8個類就寫出來了。 開發者說我就是想接點私活兒,和PHP,ASP搶搶飯碗,但我又是Java程式員。最好的結果是大項目能做好,小項目能做快。是以“激進型”方案就出現了-----沒有接口、沒有Service層、還可以沒有衆多的O(vo\po\bo)。那沒有Service層事務控制在哪一層?隻好上升的Action層。

本文不想說這是不是正确的思想,我想說的是Spring不會限制你這樣做。

由于有了父子上下文,你将無法實作這一目标。解決方案是隻使用子上下文容器,不要父上下文容器 。是以資料源、服務層、DAO層、事務的Bean、Action的Bean都放在子上下文容器中。就可以實作了,事務(注解事務)就正常工作了。這樣才夠激進。

總結:不使用listener監聽器來加載spring的配置檔案,隻使用DispatcherServlet來加載spring的配置,不要父子上下文,隻使用一個DispatcherServlet,事情就簡單了,什麼麻煩事兒也沒有了。

Java--大項目能做好--按傳統方式做,規規矩矩的做,好擴充,好維護。

Java--小項目能做快--按激進方式做,一周時間就可以出一個版本,先上線接受市場(使用者)的回報,再改進,再回報,時間就是生命(成本)。

六、springMVC-mvc.xml 配置檔案片段講解 (未使用預設配置檔案名)

Spring MVC 教程,快速入門,深入分析

&lt;?xml version="1.0" encoding="UTF-8"?&gt;  

&lt;beans  

    xmlns="http://www.springframework.org/schema/beans"  

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

    xmlns:tx="http://www.springframework.org/schema/tx"  

    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-3.0.xsd   

    http://www.springframework.org/schema/tx   

    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  

    http://www.springframework.org/schema/context  

    http://www.springframework.org/schema/context/spring-context-3.0.xsd  

    http://www.springframework.org/schema/mvc  

    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"&gt;  

    &lt;!-- 自動掃描的包名 --&gt;  

    &lt;context:component-scan base-package="com.app,com.core,JUnit4" &gt;&lt;/context:component-scan&gt;  

    &lt;!-- 預設的注解映射的支援 --&gt;  

    &lt;mvc:annotation-driven /&gt;  

    &lt;!-- 視圖解釋類 --&gt;  

    &lt;bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;  

        &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;  

        &lt;property name="suffix" value=".jsp"/&gt;&lt;!--可為空,友善實作自已的依據擴充名來選擇視圖解釋類的邏輯  --&gt;  

        &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /&gt;  

    &lt;/bean&gt;  

    &lt;!-- 攔截器 --&gt;  

    &lt;mvc:interceptors&gt;  

        &lt;bean class="com.core.mvc.MyInteceptor" /&gt;  

    &lt;/mvc:interceptors&gt;       

    &lt;!-- 對靜态資源檔案的通路  方案一 (二選一) --&gt;  

    &lt;mvc:default-servlet-handler/&gt;  

    &lt;!-- 對靜态資源檔案的通路  方案二 (二選一)--&gt;  

    &lt;mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/&gt;  

    &lt;mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/&gt;  

    &lt;mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/&gt;  

&lt;/beans&gt;   

&lt;context:component-scan/&gt; 掃描指定的包中的類上的注解,常用的注解有:

@Controller 聲明Action元件

@Service    聲明Service元件    @Service("myMovieLister") 

@Repository 聲明Dao元件

@Component   泛指元件, 當不好歸類時. 

@RequestMapping("/menu")  請求映射

@Resource  用于注入,( j2ee提供的 ) 預設按名稱裝配,@Resource(name="beanName") 

@Autowired 用于注入,(srping提供的) 預設按類型裝配 

@Transactional( rollbackFor={Exception.class}) 事務管理

@ResponseBody

@Scope("prototype")   設定bean的作用域

&lt;mvc:annotation-driven /&gt; 是一種簡寫形式,完全可以手動配置替代這種簡寫形式,簡寫形式可以讓初學都快速應用預設配置方案。&lt;mvc:annotation-driven /&gt; 會自動注冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,是spring MVC為@Controllers分發請求所必須的。

并提供了:資料綁定支援,@NumberFormatannotation支援,@DateTimeFormat支援,@Valid支援,讀寫XML的支援(JAXB),讀寫JSON的支援(Jackson)。

後面,我們處理響應ajax請求時,就使用到了對json的支援。

後面,對action寫JUnit單元測試時,要從spring IOC容器中取DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,來完成測試,取的時候要知道是&lt;mvc:annotation-driven /&gt;這一句注冊的這兩個bean。

如何替換 &lt;mvc:annotation-driven /&gt;?他到底做了什麼工作,請看,最後面的 十九節 &lt;mvc:annotation-driven /&gt; 到底做了什麼工作。

&lt;mvc:interceptors/&gt; 是一種簡寫形式。通過看前面的大圖,知道,我們可以配置多個HandlerMapping。&lt;mvc:interceptors/&gt;會為每一個HandlerMapping,注入一個攔截器。其實我們也可以手動配置為每個HandlerMapping注入一個攔截器。

&lt;mvc:default-servlet-handler/&gt; 使用預設的Servlet來響應靜态檔案。

&lt;mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/&gt; 比對URL  /images/**  的URL被當做靜态資源,由Spring讀出到記憶體中再響應http。

七、如何通路到靜态的檔案,如jpg,js,css?

如何你的DispatcherServlet攔截"*.do"這樣的有字尾的URL,就不存在通路不到靜态資源的問題。

如果你的DispatcherServlet攔截"/",為了實作REST風格,攔截了所有的請求,那麼同時對*.js,*.jpg等靜态檔案的通路也就被攔截了。

我們要解決這個問題。

目的:可以正常通路靜态檔案,不可以找不到靜态檔案報404。

方案一:激活Tomcat的defaultServlet來處理靜态檔案

Spring MVC 教程,快速入門,深入分析

&lt;servlet-mapping&gt;   

    &lt;servlet-name&gt;default&lt;/servlet-name&gt;  

    &lt;url-pattern&gt;*.jpg&lt;/url-pattern&gt;     

&lt;/servlet-mapping&gt;    

&lt;servlet-mapping&gt;       

    &lt;servlet-name&gt;default&lt;/servlet-name&gt;    

    &lt;url-pattern&gt;*.js&lt;/url-pattern&gt;    

&lt;servlet-mapping&gt;        

    &lt;servlet-name&gt;default&lt;/servlet-name&gt;       

    &lt;url-pattern&gt;*.css&lt;/url-pattern&gt;      

要配置多個,每種檔案配置一個   

要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截請求,這樣請求就不會進入Spring了,我想性能是最好的吧。

Tomcat, Jetty, JBoss, and GlassFish 自帶的預設Servlet的名字 -- "default"

Google App Engine 自帶的 預設Servlet的名字 -- "_ah_default"

Resin 自帶的 預設Servlet的名字 -- "resin-file"

WebLogic 自帶的 預設Servlet的名字  -- "FileServlet"

WebSphere  自帶的 預設Servlet的名字 -- "SimpleFileServlet" 

方案二: 在spring3.0.4以後版本提供了mvc:resources ,  使用方法:

Spring MVC 教程,快速入門,深入分析

&lt;!-- 對靜态資源檔案的通路 --&gt;    

&lt;mvc:resources mapping="/images/**" location="/images/" /&gt;  

/images/**映射到ResourceHttpRequestHandler進行處理,location指定靜态資源的位置.可以是web application根目錄下、jar包裡面,這樣可以把靜态資源壓縮到jar包中。cache-period 可以使得靜态資源進行web cache 

如果出現下面的錯誤,可能是沒有配置&lt;mvc:annotation-driven /&gt;的原因。 

報錯WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name 'springMVC'

使用&lt;mvc:resources/&gt;元素,把mapping的URI注冊到SimpleUrlHandlerMapping的urlMap中,

key為mapping的URI pattern值,而value為ResourceHttpRequestHandler,

這樣就巧妙的把對靜态資源的通路由HandlerMapping轉到ResourceHttpRequestHandler處理并傳回,是以就支援classpath目錄,jar包内靜态資源的通路.

另外需要注意的一點是,不要對SimpleUrlHandlerMapping設定defaultHandler.因為對static uri的defaultHandler就是ResourceHttpRequestHandler,

否則無法處理static resources request.

方案三 ,使用&lt;mvc:default-servlet-handler/&gt;

Spring MVC 教程,快速入門,深入分析

&lt;mvc:default-servlet-handler/&gt;  

會把"/**" url,注冊到SimpleUrlHandlerMapping的urlMap中,把對靜态資源的通路由HandlerMapping轉到org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler處理并傳回.

DefaultServletHttpRequestHandler使用就是各個Servlet容器自己的預設Servlet.

補充說明:多個HandlerMapping的執行順序問題:

DefaultAnnotationHandlerMapping的order屬性值是:0

&lt;mvc:resources/ &gt;自動注冊的 SimpleUrlHandlerMapping的order屬性值是: 2147483646

&lt;mvc:default-servlet-handler/&gt;自動注冊 的SimpleUrlHandlerMapping 的order屬性值是: 2147483647

spring會先執行order值比較小的。當通路一個a.jpg圖檔檔案時,先通過 DefaultAnnotationHandlerMapping 來找處理器,一定是找不到的,因為我們沒有叫a.jpg的Action。然後再按order值升序找,由于最後一個 SimpleUrlHandlerMapping 是比對 "/**"的,是以一定會比對上,就可以響應圖檔。

通路一個圖檔,還要走層層比對。不知性能如何?

最後再說明一下,方案二、方案三 在通路靜态資源時,如果有比對的(近似)總攔截器,就會走攔截器。如果你在攔截中實作權限檢查,要注意過濾這些對靜态檔案的請求。

如何你的DispatcherServlet攔截 *.do這樣的URL字尾,就不存上述問題了。還是有字尾友善。

八、請求如何映射到具體的Action中的方法?

方案一:基于xml配置映射,可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping進行Url映射和攔截請求。

配置方法略。

方案二:基于注解映射,可以使用DefaultAnnotationHandlerMapping。

Spring MVC 教程,快速入門,深入分析

&lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt;  &lt;/bean&gt;   

但前面我們配置了&lt;mvc:annotation-driven /&gt;,他會自動注冊這個bean,就不須要我們顯示的注冊這個bean了。  

以上都可以注入interceptors,實作權限控制等前置工作。

我們使用第2種,基于注解來使用spring MVC

 并在action類上使用:

@Controller

@RequestMapping("/user")

九、Spring中的攔截器:

Spring為我們提供了:

org.springframework.web.servlet.HandlerInterceptor接口,

org.springframework.web.servlet.handler.HandlerInterceptorAdapter擴充卡,

實作這個接口或繼承此類,可以非常友善的實作自己的攔截器。

有以下三個方法:

Action之前執行:

 public boolean preHandle(HttpServletRequest request,

   HttpServletResponse response, Object handler);

生成視圖之前執行

 public void postHandle(HttpServletRequest request,

   HttpServletResponse response, Object handler,

   ModelAndView modelAndView);

最後執行,可用于釋放資源

 public void afterCompletion(HttpServletRequest request,

   HttpServletResponse response, Object handler, Exception ex)

分别實作預處理、後處理(調用了Service并傳回ModelAndView,但未進行頁面渲染)、傳回處理(已經渲染了頁面) 

在preHandle中,可以進行編碼、安全控制等處理; 

在postHandle中,有機會修改ModelAndView; 

在afterCompletion中,可以根據ex是否為null判斷是否發生了異常,進行日志記錄。 

參數中的Object handler是下一個攔截器。

十、如何使用攔截器?

自定義一個攔截器,要實作HandlerInterceptor接口:

Spring MVC 教程,快速入門,深入分析

public class MyInteceptor implements HandlerInterceptor {     

    略。。。  

}    

Spring MVC并沒有總的攔截器,不能對所有的請求進行前後攔截。

Spring MVC的攔截器,是屬于HandlerMapping級别的,可以有多個HandlerMapping ,每個HandlerMapping可以有自己的攔截器。

當一個請求按Order值從小到大,順序執行HandlerMapping接口的實作類時,哪一個先有傳回,那就可以結束了,後面的HandlerMapping就不走了,本道工序就完成了。就轉到下一道工序了。

攔截器會在什麼時候執行呢? 一個請求交給一個HandlerMapping時,這個HandlerMapping先找有沒有處理器來處理這個請求,如何找到了,就執行攔截器,執行完攔截後,交給目标處理器。

如果沒有找到處理器,那麼這個攔截器就不會被執行。

在spring MVC的配置檔案中配置有三種方法:

方案一,(近似)總攔截器,攔截所有url

Spring MVC 教程,快速入門,深入分析

   &lt;mvc:interceptors&gt;  

    &lt;bean class="com.app.mvc.MyInteceptor" /&gt;  

&lt;/mvc:interceptors&gt;  

為什麼叫“近似”,前面說了,Spring沒有總的攔截器。

&lt;mvc:interceptors/&gt;會為每一個HandlerMapping,注入一個攔截器。總有一個HandlerMapping是可以找到處理器的,最多也隻找到一個處理器,是以這個攔截器總會被執行的。起到了總攔截器的作用。

如果是REST風格的URL,靜态資源也會被攔截。

方案二, (近似) 總攔截器, 攔截比對的URL。

Spring MVC 教程,快速入門,深入分析

&lt;mvc:interceptors &gt;    

  &lt;mvc:interceptor&gt;    

        &lt;mvc:mapping path="/user/*" /&gt; &lt;!-- /user/*  --&gt;    

        &lt;bean class="com.mvc.MyInteceptor"&gt;&lt;/bean&gt;    

    &lt;/mvc:interceptor&gt;    

&lt;/mvc:interceptors&gt;    

就是比 方案一多了一個URL比對。

方案三,HandlerMappint上的攔截器。

如果是REST風格的URL,靜态資源就不會被攔截。因為我們精準的注入了攔截器。

Spring MVC 教程,快速入門,深入分析

&lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt;       

 &lt;property name="interceptors"&gt;       

     &lt;list&gt;       

         &lt;bean class="com.mvc.MyInteceptor"&gt;&lt;/bean&gt;      

     &lt;/list&gt;       

 &lt;/property&gt;       

&lt;/bean&gt;   

  如果使用了&lt;mvc:annotation-driven /&gt;, 它會自動注冊DefaultAnnotationHandlerMapping 與AnnotationMethodHandlerAdapter 這兩個bean,是以就沒有機會再給它注入interceptors屬性,就無法指定攔截器。

當然我們可以通過人工配置上面的兩個Bean,不使用 &lt;mvc:annotation-driven /&gt;,就可以 給interceptors屬性 注入攔截器了。

其實我也不建議使用 &lt;mvc:annotation-driven /&gt;,而建議手動寫詳細的配置檔案,來替代 &lt;mvc:annotation-driven /&gt;,這就控制力就強了。

十一、如何實作全局的異常處理?

在spring MVC的配置檔案中:

Spring MVC 教程,快速入門,深入分析

&lt;!-- 總錯誤處理--&gt;  

&lt;bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"&gt;  

    &lt;property name="defaultErrorView"&gt;    

        &lt;value&gt;/error/error&lt;/value&gt;  

    &lt;/property&gt;  

    &lt;property name="defaultStatusCode"&gt;    

        &lt;value&gt;500&lt;/value&gt;  

    &lt;/property&gt;     

&lt;property name="warnLogCategory"&gt;    

        &lt;value&gt;org.springframework.web.servlet.handler.SimpleMappingExceptionResolver&lt;/value&gt;  

這裡主要的類是SimpleMappingExceptionResolver類,和他的父類AbstractHandlerExceptionResolver類。

具體可以配置哪些屬性,我是通過檢視源碼知道的。

你也可以實作HandlerExceptionResolver接口,寫一個自己的異常處理程式。spring的擴充性是很好的。

通過SimpleMappingExceptionResolver我們可以将不同的異常映射到不同的jsp頁面(通過exceptionMappings屬性的配置)。

同時我們也可以為所有的異常指定一個預設的異常提示頁面(通過defaultErrorView屬性的配置),如果所抛出的異常在exceptionMappings中沒有對應的映射,則Spring将用此預設配置顯示異常資訊。

注意這裡配置的異常顯示界面均僅包括主檔案名,至于檔案路徑和字尾已經在viewResolver中指定。如/error/error表示/error/error.jsp

顯示錯誤的jsp頁面:

Spring MVC 教程,快速入門,深入分析

&lt;%@ page language="java" contentType="text/html; charset=GBK"  

    pageEncoding="GBK"%&gt;  

&lt;%@ page import="java.lang.Exception"%&gt;  

&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;  

&lt;html&gt;  

&lt;head&gt;  

&lt;meta http-equiv="Content-Type" content="text/html; charset=GBK"&gt;  

&lt;title&gt;錯誤頁面&lt;/title&gt;  

&lt;/head&gt;  

&lt;body&gt;  

&lt;h1&gt;出錯了&lt;/h1&gt;  

&lt;%  

Exception e = (Exception)request.getAttribute("exception");  

out.print(e.getMessage());  

%&gt;  

&lt;/body&gt;  

&lt;/html&gt;  

其中一句:request.getAttribute("exception"),key是exception,也是在SimpleMappingExceptionResolver類預設指定的,是可能通過配置檔案修改這個值的,大家可以去看源碼。

十二、如何把全局異常記錄到日志中?

在前的配置中,其中有一個屬性warnLogCategory,值是“SimpleMappingExceptionResolver類的全限定名”。我是在SimpleMappingExceptionResolver類父類AbstractHandlerExceptionResolver類中找到這個屬性的。檢視源碼後得知:如果warnLogCategory不為空,spring就會使用apache的org.apache.commons.logging.Log日志工具,記錄這個異常,級别是warn。

值:“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”,是“SimpleMappingExceptionResolver類的全限定名”。這個值不是随便寫的。  因為我在log4j的配置檔案中還要加入log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN,保證這個級别是warn的日志一定會被記錄,即使log4j的根日志級别是ERROR。

 十三、如何給spring3 MVC中的Action做JUnit單元測試?

 使用了spring3 MVC後,給action做單元測試變得很友善,我以前從來不給action寫單元測試的,現在可以根據情況寫一些了。

 不用給每個Action都寫單元測試吧,自己把握吧。

 JUnitActionBase類是所有JUnit的測試類的父類

Spring MVC 教程,快速入門,深入分析

package test;  

import javax.servlet.http.HttpServletRequest;  

import javax.servlet.http.HttpServletResponse;  

import org.junit.BeforeClass;  

import org.springframework.mock.web.MockServletContext;  

import org.springframework.web.context.WebApplicationContext;  

import org.springframework.web.context.support.XmlWebApplicationContext;  

import org.springframework.web.servlet.HandlerAdapter;  

import org.springframework.web.servlet.HandlerExecutionChain;  

import org.springframework.web.servlet.HandlerMapping;  

import org.springframework.web.servlet.ModelAndView;  

import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;  

import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;  

/**  

* 說明: JUnit測試action時使用的基類 

*  

* @author  趙磊 

* @version 建立時間:2011-2-2 下午10:27:03   

*/   

public class JUnitActionBase {  

    private static HandlerMapping handlerMapping;  

    private static HandlerAdapter handlerAdapter;  

    /** 

     * 讀取spring3 MVC配置檔案 

     */  

    @BeforeClass  

 public static void setUp() {  

        if (handlerMapping == null) {  

            String[] configs = { "file:src/springConfig/springMVC.xml" };  

            XmlWebApplicationContext context = new XmlWebApplicationContext();  

            context.setConfigLocations(configs);  

            MockServletContext msc = new MockServletContext();  

            context.setServletContext(msc);         context.refresh();  

            msc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);  

            handlerMapping = (HandlerMapping) context  

                    .getBean(DefaultAnnotationHandlerMapping.class);  

            handlerAdapter = (HandlerAdapter) context.getBean(context.getBeanNamesForType(AnnotationMethodHandlerAdapter.class)[0]);     

        }  

    }  

     * 執行request對象請求的action 

     *  

     * @param request 

     * @param response 

     * @return 

     * @throws Exception 

    public ModelAndView excuteAction(HttpServletRequest request, HttpServletResponse response)  

 throws Exception {  

        HandlerExecutionChain chain = handlerMapping.getHandler(request);  

        final ModelAndView model = handlerAdapter.handle(request, response,  

                chain.getHandler());  

        return model;  

}  

這是個JUnit測試類,我們可以new Request對象,來參與測試,太友善了。給request指定通路的URL,就可以請求目标Action了。

Spring MVC 教程,快速入門,深入分析

package test.com.app.user;  

import org.junit.Assert;  

import org.junit.Test;  

import org.springframework.mock.web.MockHttpServletRequest;  

import org.springframework.mock.web.MockHttpServletResponse;  

import test.JUnitActionBase;  

* 說明: 測試OrderAction的例子 

* @author  趙磊  

* @version 建立時間:2011-2-2 下午10:26:55   

public class TestOrderAction extends JUnitActionBase {  

    @Test  

    public void testAdd() throws Exception {  

    MockHttpServletRequest request = new MockHttpServletRequest();  

        MockHttpServletResponse response = new MockHttpServletResponse();  

        request.setServletPath("/order/add");  

        request.addParameter("id", "1002");  

        request.addParameter("date", "2010-12-30");  

        request.setMethod("POST");  

        // 執行URI對應的action  

        final ModelAndView mav = this.excuteAction(request, response);  

        // Assert logic  

        Assert.assertEquals("order/add", mav.getViewName());  

        String msg=(String)request.getAttribute("msg");  

        System.out.println(msg);  

 需要說明一下 :由于目前最想版本的Spring(Test) 3.0.5還不支援@ContextConfiguration的注解式context file注入,是以還需要寫個setUp處理下,否則類似于Tiles的加載過程會有錯誤,因為沒有ServletContext。3.1的版本應該有更好的解決方案,

 十四、轉發與重定向

可以通過redirect/forward:url方式轉到另一個Action進行連續的處理。

可以通過redirect:url 防止表單重複送出 。

寫法如下:

return "forward:/order/add";

return "redirect:/index.jsp";

帶參數重定向--RedirectAttributes

使用者儲存或修改後,為了防止使用者重新整理浏覽器(F5)導緻表單重複送出,一般在儲存或修改操作之後會redirect到一個結果頁面(不是forward),同時攜帶參數,如操作成功的提示資訊。因為是Redirect,Request裡的attribute不會傳遞過去。Spring在3.1才提供了這個能力--RedirectAttributes。 反複按F5,操作成功的提示資訊也不會再次出來(總共隻出現一次),效果很理想。

Spring MVC 教程,快速入門,深入分析

public String save(@ModelAttribute("group") Group group, RedirectAttributes redirectAttributes) {  

    accountManager.saveGroup(group);  

    redirectAttributes.addFlashAttribute("message", "操作成功");  

    return "redirect:/account/group/";  

 十五、處理ajax請求

jackson-core-asl-1.7.2.jar 

jackson-mapper-asl-1.7.2.jar

2、spring的配置檔案中要有這一行,才能使用到spring内置支援的json轉換。如果你手工把POJO轉成json就可以不須要使用spring内置支援的json轉換。

&lt;mvc:annotation-driven /&gt;

3、使用@ResponseBody注解

Spring MVC 教程,快速入門,深入分析

/** 

 * ajax測試 

* http://127.0.0.1/mvc/order/ajax 

 */  

@RequestMapping("/ajax")  

@ResponseBody  

public Object ajax(HttpServletRequest request){  

    List&lt;String&gt; list=new ArrayList&lt;String&gt;();  

    list.add("電視");  

nbsp;       list.add("洗衣機");  

    list.add("冰箱");  

    list.add("電腦");  

    list.add("汽車");  

    list.add("空調");  

    list.add("自行車");  

    list.add("飲水機");  

    list.add("熱水器");  

    return list;  

十六、關于寫幾個配置檔案的說明 

我看到有的人把配置檔案寫兩份:

一個是原有的applicationContext.xml,這個檔案從spring2.0-2.5時一直在使用。

别一個是新加的spring MVC的配置檔案。

其實這兩個檔案是可以寫成一個檔案的,springMVC相關的配置,資料源,事務相關配置可以都寫再一個配置檔案中。

本例子中隻使用了一個spring配置檔案叫“springMVC.xml”。

就不要再多配置一個applicationContext.xml檔案了。

web.xml檔案中也不要再配置org.springframework.web.context.ContextLoaderListener的listener了。

寫兩個配置檔案一般就會導緻掃描兩次,一定要精确控制掃描的包名,做到不重複掃描。

寫兩個配置檔案還出現事務不好使的現象,是當把@Transactional寫有Action層時出現的。

是因為父子上下文的原因,請參看前的 第五節 父子上下文,裡面有說明 。原因是父上下文不能通路子上下文。

十七、如何取得Spring管理的bean (請用第3種方法)

1、servlet方式加載時,

【web.xml】

Spring MVC 教程,快速入門,深入分析

&lt;servlet-name&gt;springMVC&lt;/servlet-name&gt;  

&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;  

&lt;init-param&gt;  

&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;  

&lt;param-value&gt;classpath*:/springMVC.xml&lt;/param-value&gt;  

&lt;/init-param&gt;  

&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  

 spring容器放在ServletContext中的key是org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC

注意後面的springMVC,是你的servlet-name配置的值,注意适時修改。

Spring MVC 教程,快速入門,深入分析

ServletContext sc=略  

WebApplicationContext attr = (WebApplicationContext)sc.getAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC");  

2、listener方式加載時:

Spring MVC 教程,快速入門,深入分析

&lt;context-param&gt;  

  &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;  

  &lt;param-value&gt;/WEB-INF/applicationContext&lt;/param-value&gt;  

&lt;/context-param&gt;  

&lt;listener&gt;  

  &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;  

&lt;/listener&gt;  

 【jsp/servlet】可以這樣取得

Spring MVC 教程,快速入門,深入分析

ServletContext context = getServletContext();  

WebApplicationContext applicationContext  = WebApplicationContextUtils .getWebApplicationContext(context);   

3、通用的方法來了,神器啊,前的  1、2兩種方法并不通用,可以抛棄了。

在配置檔案中加入:

Spring MVC 教程,快速入門,深入分析

&lt;!-- 用于持有ApplicationContext,可以使用SpringContextHolder.getBean('xxxx')的靜态方法得到spring bean對象 --&gt;  

&lt;bean class="com.xxxxx.SpringContextHolder" lazy-init="false" /&gt;  

Spring MVC 教程,快速入門,深入分析

import org.springframework.context.ApplicationContext;  

import org.springframework.context.ApplicationContextAware;  

 * 以靜态變量儲存Spring ApplicationContext, 可在任何代碼任何地方任何時候中取出ApplicaitonContext. 

 *  

public class SpringContextHolder implements ApplicationContextAware {  

private static ApplicationContext applicationContext;  

* 實作ApplicationContextAware接口的context注入函數, 将其存入靜态變量. 

*/  

public void setApplicationContext(ApplicationContext applicationContext) {  

SpringContextHolder.applicationContext = applicationContext; // NOSONAR  

* 取得存儲在靜态變量中的ApplicationContext. 

public static ApplicationContext getApplicationContext() {  

checkApplicationContext();  

return applicationContext;  

* 從靜态變量ApplicationContext中取得Bean, 自動轉型為所指派對象的類型. 

@SuppressWarnings("unchecked")  

public static &lt;T&gt; T getBean(String name) {  

return (T) applicationContext.getBean(name);  

public static &lt;T&gt; T getBean(Class&lt;T&gt; clazz) {  

return (T) applicationContext.getBeansOfType(clazz);  

* 清除applicationContext靜态變量. 

public static void cleanApplicationContext() {  

applicationContext = null;  

private static void checkApplicationContext() {  

if (applicationContext == null) {  

throw new IllegalStateException("applicaitonContext未注入,請在applicationContext.xml中定義SpringContextHolder");  

十八、多視圖控制器

當有jsp,flt (模闆)等多種頁面生成展示方式時,spring預設使用的是“視圖解析器鍊”。 真是一個鍊,是以性能不好,spring會在“視圖解析器鍊”中順序的查找,直到找到對應的 “視圖解析器” 。jsp視圖解析器一定要寫在最後面,因為一旦調用jsp,就向浏覽器發出資料了,Spring就沒有機會再嘗試下一個了。

是以自己寫一個"多視圖解析器",依靠擴充名來區分,可一次準确的選中一個 視圖解析器,提高性能(會有多少提高呢?沒測試過).

下面的例子支援jsp,flt (模闆)兩種頁面生成展示方式,你中以自己添加,支援更多。

Spring MVC 教程,快速入門,深入分析

   &lt;!-- 多視圖處理器 --&gt;  

   &lt;bean class="com.xxx.core.web.MixedViewResolver"&gt;  

    &lt;property name="resolvers"&gt;  

        &lt;map&gt;  

            &lt;entry key="jsp"&gt;  

                &lt;bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;  

                    &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;  

                    &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"&gt;&lt;/property&gt;  

                &lt;/bean&gt;  

            &lt;/entry&gt;  

            &lt;entry key="ftl"&gt;  

                &lt;bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"&gt;  

                    &lt;property name="cache" value="true"/&gt;  

                    &lt;property name="contentType" value="text/html;charset=UTF-8"&gt;&lt;/property&gt;  

                    &lt;!-- 宏指令的支援  --&gt;    

                    &lt;property name="exposeSpringMacroHelpers" value="true"/&gt;  

                    &lt;property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/&gt;  

                    &lt;property name="requestContextAttribute" value="rc"&gt;&lt;/property&gt;  

        &lt;/map&gt;  

&lt;/bean&gt;  

&lt;!-- freemarker config --&gt;  

   &lt;bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"&gt;   

       &lt;property name="templateLoaderPath" value="/WEB-INF/ftl/" /&gt;   

       &lt;property name="freemarkerSettings"&gt;   

           &lt;props&gt;   

               &lt;prop key="template_update_delay"&gt;5&lt;/prop&gt;   

               &lt;prop key="default_encoding"&gt;UTF-8&lt;/prop&gt;   

               &lt;prop key="locale"&gt;zh_CN&lt;/prop&gt;   

           &lt;/props&gt;   

       &lt;/property&gt;   

   &lt;/bean&gt;   

Spring MVC 教程,快速入門,深入分析

import java.util.Locale;  

import java.util.Map;  

import org.springframework.web.servlet.View;  

import org.springframework.web.servlet.ViewResolver;  

* 說明: 多視圖處理器 

* @version 建立時間:2011-8-19 上午09:41:09   

public class MixedViewResolver implements ViewResolver{  

    private Map&lt;String,ViewResolver&gt; resolvers;  

    public void setResolvers(Map&lt;String, ViewResolver&gt; resolvers) {  

        this.resolvers = resolvers;  

    public View resolveViewName(String viewName,Locale locale) throws Exception{  

        int n=viewName.lastIndexOf(".");  

        if(n!=-1){  

            //取出擴充名  

            String suffix=viewName.substring(n+1);  

            //取出對應的ViewResolver  

            ViewResolver resolver=resolvers.get(suffix);  

            if(resolver==null){  

                throw new RuntimeException("No ViewResolver for "+suffix);  

            }  

            return  resolver.resolveViewName(viewName, locale);  

        }else{  

            ViewResolver resolver=resolvers.get("jsp");  

十九、 &lt;mvc:annotation-driven /&gt; 到底做了什麼工作

一句 &lt;mvc:annotation-driven /&gt;實際做了以下工作:(不包括添加自己定義的攔截器)

我們了解這些之後,對Spring3 MVC的控制力就更強大了,想改哪就改哪裡。

Spring MVC 教程,快速入門,深入分析

   &lt;!-- 注解請求映射  --&gt;  

   &lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt;          

    &lt;property name="interceptors"&gt;  

        &lt;list&gt;    

            &lt;ref bean="logNDCInteceptor"/&gt;   &lt;!-- 日志攔截器,這是你自定義的攔截器 --&gt;  

            &lt;ref bean="myRequestHelperInteceptor"/&gt;   &lt;!-- RequestHelper攔截器,這是你自定義的攔截器--&gt;   

            &lt;ref bean="myPermissionsInteceptor"/&gt;  &lt;!-- 權限攔截器,這是你自定義的攔截器--&gt;   

            &lt;ref bean="myUserInfoInteceptor"/&gt;  &lt;!-- 使用者資訊攔截器,這是你自定義的攔截器--&gt;   

        &lt;/list&gt;          

    &lt;/property&gt;          

&lt;/bean&gt;     

&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;  

    &lt;property name="messageConverters"&gt;    

            &lt;ref bean="byteArray_hmc" /&gt;    

            &lt;ref bean="string_hmc" /&gt;    

            &lt;ref bean="resource_hmc" /&gt;    

            &lt;ref bean="source_hmc" /&gt;    

            &lt;ref bean="xmlAwareForm_hmc" /&gt;    

            &lt;ref bean="jaxb2RootElement_hmc" /&gt;    

            &lt;ref bean="jackson_hmc" /&gt;    

        &lt;/list&gt;    

    &lt;/property&gt;    

&lt;/bean&gt;    

&lt;bean id="byteArray_hmc" class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="string_hmc" class="org.springframework.http.converter.StringHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="resource_hmc" class="org.springframework.http.converter.ResourceHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="source_hmc" class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="xmlAwareForm_hmc" class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="jaxb2RootElement_hmc" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;  

&lt;bean id="jackson_hmc" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /&gt;&lt;!-- 處理json--&gt;  

要在http://www.iteye.com/網站有注冊帳号才能下載下傳(這不能怪我)

下載下傳次數: 2341

下載下傳次數: 1497

<a href="http://elf8848.iteye.com/blog/875830#">檢視圖檔附件</a>

Spring MVC 教程,快速入門,深入分析

2011-01-16 19:22

浏覽 74510

<a href="http://elf8848.iteye.com/blog/875830#comments">評論(82)</a>

<a href="http://www.iteye.com/wiki/blog/875830" target="_blank">相關推薦</a>

<a></a>

&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;    

    &lt;property name="messageConverters"&gt;      

        &lt;list&gt;      

            &lt;ref bean="byteArray_hmc" /&gt;      

            &lt;ref bean="string_hmc" /&gt;      

            &lt;ref bean="resource_hmc" /&gt;      

            &lt;ref bean="source_hmc" /&gt;      

            &lt;ref bean="xmlAwareForm_hmc" /&gt;      

            &lt;ref bean="jaxb2RootElement_hmc" /&gt;      

            &lt;ref bean="jackson_hmc" /&gt;      

        &lt;/list&gt;      

    &lt;/property&gt;      

&lt;/bean&gt;      

&lt;bean id="byteArray_hmc" class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="string_hmc" class="org.springframework.http.converter.StringHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="resource_hmc" class="org.springframework.http.converter.ResourceHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="source_hmc" class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="xmlAwareForm_hmc" class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="jaxb2RootElement_hmc" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /&gt;&lt;!-- 處理.. --&gt;    

&lt;bean id="jackson_hmc" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /&gt;&lt;!-- 處理json--&gt;   

用這種會報錯,

嚴重: Servlet /SpringMVC threw load() exception

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

直接使用

&lt;mvc:annotation-driven/&gt;

自定義的攔截器又不行了

請問怎麼解決啊