关闭

spring MVC详解(转)

130人阅读 评论(0) 收藏 举报

spring <wbr>MVC详解(转) 

如图 
请求首先通过DispatcherServlet。servlet根据HandlerMapping,来处理请求,并根据请求,来找到Controller,Controller执行完毕后,发送一个ModelAndView,并告诉需要展示哪个视图。根据这个视图,servlet找到这个视图的ViewResolver,并由这个ViewResolver生成对应的view,并输出。 

配置servlet 
springmvc是基于servlet的,因此需要在web.xml配置。 
<servlet> 
<servlet-name>roadrantz</servlet-name> 
<servlet-class>org.springframework.web.servlet.DispatcherServlet 
</servlet-class> 
<load-on-startup>1</load-on-startup> 
</servlet> 

默认情况下,DispatcherServlet会加载这个servletname-servlet.xml文件,将这个文件作为spring的配置文件(淡然可以和全局的加载器,也就是全局的监听器和监听器加载的配置文件结合使用)。如上面我们定义的servlet-name的名字是roadrantz,因此它会加载roadrantz-servlet.xml。 

之后当然是要配置这个servlet对应的映射的了。 
<servlet-mapping> 
<servlet-name>roadrantz</servlet-name> 
<url-pattern>*.htm</url-pattern> 
</servlet-mapping> 

事实上,我们应该把配置分成多个文件。这样,基于springmvc的配置只在servletname-servlet.xml中,和其他部分的配置(如事务管理,数据源等配置则在另外一个地方,因为他们是通用的)是分开的。 

WebApplicationContext 
WebApplicationContext是ApplicationContext的子类它提供了为WEB应用服务的更多功能。 
我们可以通过RequestContextUtils来获取WebApplicationContext 

DispatcherServlet 
会配置如下的bean 
Bean type Explanation 
controllers mvc中的C 
handler mappings 处理器影射器,它会根据请求,查找到实际的请求处理者 
view resolvers 视图解析器 
locale resolver 本地化解析器,提供国际化的支持 
Theme resolver 主题解析器 
multipart file 文件上传解析器 
handler exception resolvers 异常处理器 

DispatcherServlet配置完成后,当相应的请求到达时,处理就开始了。 处理流程是 
1.找到WebApplicationContext并将其绑定到请求的一个属性上, 以便控制器和处理链上的其它处理器能使用WebApplicationContext。 默认的属性名为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE。 

2.将本地化解析器(localResolver)绑定到请求上,这样使得处理链上的处理器在处理请求(准备数据、显示视图等等) 时能进行本地化处理。若不使用本地化解析器,也不会有任何副作用,因此如果不需要本地化解析,忽略它即可。 

3.将主题解析器绑定到请求上,这样视图可以决定使用哪个主题。如果你不需要主题,可以忽略它,不会有任何影响。 

4.如果上传文件解析器被指定,Spring会检查每个接收到的请求是否存在上传文件,如果存在, 这个请求将被封装成MultipartHttpServletRequest以便被处理链中的其它处理器使用 (关于文件上传的更多内容请参考Section 13.8.2, “使用MultipartResolver”)。 

5.找到合适的处理器,执行和这个处理器相关的执行链(预处理器,后置处理器,控制器),以便为视图准备模型数据(用于渲染)。 

6.如果模型数据被返回,就使用配置在WebApplicationContext中的视图解析器显示视图, 否则视图不会被显示。有多种原因可以导致返回的数据模型为空,比如预处理器或后处理器可能截取了请求,这可能是出于安全原因, 也可能是请求已经被处理,没有必要再处理一次。 

DispatcherServlet的初始化参数 
contextClass 实现了WebApplicationContext的类。默认是XmlWebApplicationContext。 
contextConfigLoSctraintgitohnat 与全局的contextConfigLoSctraintgitohnat参数可以共存 
namespace WebApplicationContext的命名空间。默认是[servlet-name]-servlet 


多个配置文件的方式 
1.基于监听器的方式: 
定义监听器 
<listener> 
<listener-class>org.springframework. 
web.context.ContextLoaderListener</listener-class> 
</listener> 
以及配置全局监听器的配置属性。 
注意 
有些比较老的容器,在初始化servlet之前,并不会初始化监听器,因此如果可能会被部署到这样的容器的话,需要将监听器,改成另外一个servlet 
ContextLoaderServlet 
将它置于DispatcherServlet之前。 

不管是监听器还是ContextLoaderServlet,这两个全局的装载器,在没有指定配置文件的情况下,会查找/WEB-INF/applicationContext.xml。 
但我们会有更多的配置文件,可以通过属性contextConfigLocation来设置 
如 
<context-param> 
<param-name>contextConfigLocation</param-name> 
<param-value> 
/WEB-INF/spitter-security.xml 
classpath:service-context.xml 
classpath:persistence-context.xml 
classpath:dataSource-context.xml 
</param-value> 
</context-param> 
这个属性的值,和spring的资源Resource加载方式一样,可以带classpath:,file:,等前缀。 

这里先给出一个非注解方式的使用方式。 
主页 
主页是一个web应用必须有的(这里说的必须,你懂得)。 
当然先需要一个controller了。 
package com.roadrantz.mvc; 
import java.util.List; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.AbstractController; 
import com.roadrantz.service.RantService; 
public class HomePageController extends AbstractController { 
public HomePageController() { 


protected ModelAndView handleRequestInternal( 
HttpServletRequest request, HttpServletResponse response) 
throws Exception { 
List recentRants = rantService.getRecentRants(); 

//定义modelandview,home表示会返回home.jsp(是不是jsp由视图解析器决定)。 
return new ModelAndView("home", 
"rants", recentRants); 


private RantService rantService; 

public void setRantService(RantService rantService) { 
this.rantService = rantService; 




ModelAndView对象 
ModelAndView封装了视图已经模型数据。 
注意,如果一个controller,return类型非null或者非viod,且没有写@ResponseBody注解的,最后都会被封装成ModelAndView,对与返回的一个普通的bean的时候,分装后的ModelAndView如下图 

spring <wbr>MVC详解(转)  

new ModelAndView("home", "rants", recentRants); 
如上,第一个参数是视图名字。之后的参数是以模型对象将被传递给视图。 

下面是配置这个controller 
<bean name="/home.htm" 
class="com.roadrantz.mvc.HomePageController"> 
<property name="rantService" ref="rantService" /> 
</bean> 
这里首先没有使用id,而是使用name,这里的原因是因为有特殊字符/和.id不支持。而使用name。 

当一个请求home.htm(这个请求位于根目录下,如果非根目录是无法访问的,如127.0.0.1/daowole/home.htm是可以访问的,但是127.0.0.1/daowole/abc/home.htm是无法访问的。如果想要它不管通过哪个目录,只要是最后的资源是home.htm都可以访问,可以把bean的name改成name="home.htm",那么127.0.0.1/daowole/abc/home.htm还是127.0.0.1/daowole/home.htm都可以访问了。)的话,那么就会被访问到这里来。这里可以发现我们无需配置HandlerMapping,因为springmvc有一个默认的handlermapping,BeanNameUrlHandlerMapping。它是使用URL模式的基本名字。 

由于上面的的视图使用的是jsp视图,因此直接return一个jsp页面,自然没有问题了。 
而对应jsp视图,springmvc自然还提供了其他配置(相对普通jsp而言),这需要使用到一个jsp的解析器,org.springframework.web.servlet.view.InternalResourceViewResolver。 
<bean id="viewResolver" 
class="org.springframework.web. 
servlet.view.InternalResourceViewResolver"> 
<property name="prefix"> 
<value>/WEB-INF/jsp/</value> 
</property> 
<property name="suffix"> 
<value>.jsp</value> 
</property> 
</bean> 
这个会再controller返回的时候,会拼装前缀和后缀,再查找文件。如果找到,它来处理是自然的。 
home拼装前缀和后缀后就是/WEB-INF/jsp/home.jsp 

对于spring3.0版本的,如果使用了Spring 3.0.4或以上版本的话,可以使用 
<mvc:resources location="" mapping=""/> 
在servletname-servlet.xml文件中。 
这种情况就解决了如果我们把url映射定义为/(这会由springmvc处理所有的请求),那么图片,js等静态资源会被由springmvc处理。它会把mapping指定的路径(ant风格)映射到location中。 
<mvc:resources mapping="/resources 
public class HelloController 
    extends AbstractCommandController { 
... 


<bean id="urlMapping" 
class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping" /> 


SimpleUrlHandlerMapping 

<bean id="simpleUrlMapping" 
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
<property name="mappings"> 
<props> 
<prop key="test.html">homeController</prop> 
</props> 
</property> 
</bean> 
如上,当任何一种方式访问到test.html,都由id=homeController的bean处理 

mappings是一个java.util.Properties类型的。 

ControllerClassNameHandlerMapping使用 

package com.cgodo.daowole.action; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.AbstractController; 

public class SampleController extends AbstractController { 
protected ModelAndView handleRequestInternal(HttpServletRequest arg0, 
HttpServletResponse arg1) throws Exception { 
ModelAndView mav = new ModelAndView("index"); 
mav.addObject("message", "Hello World!"); 

return mav; 


<bean id="urlMapping" 
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /> 
如上,我们可以通过test.html(这里的后缀.html和你的web.xml配置有关)。就能访问。而不需要再增加其他的配置了。 

DefaultAnnotationHandlerMapping 根据@RequestMapping注解要查找action 

对于支持DefaultAnnotationHandlerMapping 版本的spring,如果没有对应 
handlermapping,那么DispatcherServlet会分别建立 
BeanNameUrlHandlerMappin
和 
DefaultAnnotationHandlerMapping 

多个handlemapping同时处理,也是可以的。我们也可以通过order属性。来配置mapping的排序。 
如 
<bean id="beanNameUrlMapping" class="org.springframework.web. 
➥ servlet.handler.BeanNameUrlHandlerMapping"> 
<property name="order"><value>1</value></property> 
</bean> 
<bean id="simpleUrlMapping" class="org.springframework.web. 
➥ servlet.handler.SimpleUrlHandlerMapping"> 
<property name="order"><value>0</value></property> 
<property name="mappings"> 
… 
</property> 
</bean> 
这里的话,SimpleUrlHandlerMapping排序是0,因此它首先被servlet询问,如果这个SimpleUrlHandlerMapping有结果回来(标示它来处理),那么就进行处理,而没有的话,将询问下一个,也就是BeanNameUrlHandlerMapping。 

控制器 

spring <wbr>MVC详解(转)  

如图,spring的控制器,由Controller接口定义。 
可以将控制器归类为6类 
View类型: 
ParameterizableViewController 
UrlFilenameViewControlle
当控制器只需要显示静态视图时。 

Simple类型 
Controller (interface) 
AbstractController 

Throwaway类型 
ThrowawayController 

Multiaction类型 
MultiActionController 
当action中有多个执行代码(方法)。 

Command类型 
BaseCommandController 
AbstractCommandControlle
action可以获取请求的一个或多个参数,并将参数封装成一个对象。还能对参数进行验证。 

Form类型 
AbstractFormController 
SimpleFormController 
拥有表单处理功能。 

Wizard类型 
AbstractWizardFormController 
当一个应用,由多个步骤组成,每一个步骤走完之后,得到一个结果,类似向导。 

AbstractCommandControlle
直接继承AbstractController,自然可以访问到request,来获取参数,完成参数验证,但是这样会让你的action变得复杂。 
package com.cgodo.daowole.action; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.validation.BindException; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.AbstractCommandController; 

import com.cgodo.daowole.model.Page; 

@SuppressWarnings("deprecation") 
public class SampleController extends AbstractCommandController { 

public SampleController() { 
setCommandClass(Page.class); 
setCommandName("page"); 


@SuppressWarnings("unchecked") 
protected ModelAndView handle(HttpServletRequest request, 
HttpServletResponse response, Object command, BindException errors) 
throws Exception { 
ModelAndView mav = new ModelAndView("index", "message", "hello!"); 
@SuppressWarnings("unused") 
Page<String> page = (Page<String>) command; 

return mav; 


如上所示。 
访问 
http://127.0.0.1:8080/daowole/test.html?pageNo=2 
可以发现,pageNo被注入到了command变量中。 

验证 
编写验证类 
package com.cgodo.daowole.action.validator; 

import org.springframework.validation.Errors; 
import org.springframework.validation.Validator; 

import com.cgodo.daowole.model.Page; 

public class PageValidator implements Validator { 

public boolean supports(Class<?> arg0) { 
return arg0.equals(Page.class); 


public void validate(Object command, Errors arg1) { 
Page<String> page = (Page<String>) command; 

if (page.getPageNo() < 2) { 
arg1.rejectValue("pageNO", "request.pageNo", "请输入pageNo"); 




修改bean的定义 
<bean id="homeController" name="home.html" 
class="com.cgodo.daowole.action.SampleController"> 
<property name="formView" value="input" /> 
<property name="successView" value="index" /> 
<property name="validator"> 
<bean class="com.cgodo.daowole.action.validator.PageValidator" /> 
</property> 
</bean> 

SimpleFormController 

package com.roadrantz.mvc; 
import java.util.HashMap; 
import java.util.Map; 
import javax.servlet.http.HttpServletRequest; 
import org.springframework.validation.BindException; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.SimpleFormController; 
import com.roadrantz.domain.Rant; 
import com.roadrantz.domain.Vehicle; 
import com.roadrantz.service.RantService; 
public class AddRantFormController extends SimpleFormController { 
private static final String[] ALL_STATES = { 
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", 
"GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", 
"MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", 
"NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", 
"SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WV", "WI", 
"WY" 
}; 
public AddRantFormController() { 
setCommandClass(Rant.class); 
setCommandName("rant"); 

protected Object formBackingObject(HttpServletRequest request) 
throws Exception { 
Rant rantForm = (Rant) super.formBackingObject(request); 
rantForm.setVehicle(new Vehicle()); 
return rantForm; 

protected Map referenceData(HttpServletRequest request) 
throws Exception { 
Map referenceData = new HashMap(); 
referenceData.put("states", ALL_STATES); 
return referenceData; 

protected ModelAndView onSubmit(Object command, 
BindException bindException) throws Exception { 
Rant rant = (Rant) command; 
rantService.addRant(rant); 
return new ModelAndView(getSuccessView()); 

private RantService rantService; 
public void setRantService(RantService rantService) { 
this.rantService = rantService; 



<bean id="addRantController" 
class="com.roadrantz.mvc.AddRantFormController"> 
<property name="formView" value="addRant" /> 
<property name="successView" value="rantAdded" /> 
<property name="rantService" ref="rantService" /> 
</bean> 

验证 
编写验证类 
package com.roadrantz.mvc; 
import org.apache.oro.text.perl.Perl5Util; 
import org.springframework.validation.Errors; 
import org.springframework.validation.ValidationUtils; 
import org.springframework.validation.Validator; 
import com.roadrantz.domain.Rant; 
public class RantValidator implements Validator { 
public boolean supports(Class clazz) { 
return clazz.equals(Rant.class); 

public void validate(Object command, Errors errors) { 
Rant rant = (Rant) command; 
ValidationUtils.rejectIfEmpty( 
errors, "vehicle.state", "required.state", 
"State is required."); 
ValidationUtils.rejectIfEmpty( 
errors, "vehicle.plateNumber", "required.plateNumber", 
"The license plate number is required."); 
ValidationUtils.rejectIfEmptyOrWhitespace( 
errors, "rantText", "required.rantText", 
"You must enter some rant text."); 
validatePlateNumber( 
rant.getVehicle().getPlateNumber(), errors); 

private static final String PLATE_REGEXP = 
"/[a-z0-9]{2,6}/i"; 
private void validatePlateNumber( 
String plateNumber, Errors errors) { 
Perl5Util perl5Util = new Perl5Util(); 
if(!perl5Util.match(PLATE_REGEXP, plateNumber)) { 
errors.reject("invalid.plateNumber", 
"Invalid license plate number."); 




修改bean的定义。 
<bean id="addRantController" 
class="com.roadrantz.mvc.AddRantFormController"> 
<property name="formView" value="addRant" /> 
<property name="successView" value="rantAdded" /> 
<property name="rantService" ref="rantService" /> 
<property name="validator"> 
<bean class="com.roadrantz.mvc.RantValidator" /> 
</property> 
</bean> 


例子 
package com.cgodo.daowole.service.imp; 

import org.springframework.stereotype.Service; 

import com.cgodo.daowole.service.ITest; 

@Service 
public class MyTest implements ITest { 
public void test() { 




package com.cgodo.daowole.action; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 

import com.cgodo.daowole.service.ITest; 

@Controller 
public class ActionTest { 
private ITest test; 

public ITest getTest() { 
return test; 


@Autowired 
public void setTest(ITest test) { 
this.test = test; 


@RequestMapping(value = "/") 
public String home() { 
System.out.println("HomeController: Passing through..."); 

return "index"; 


@RequestMapping("/input") 
public String input(String input) { 
System.out.println("name is " + input); 
return "index"; 



com.cgodo.daowole.spring.applicationContext包下面 
applicationContext.xml 

<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-2.5.xsd 
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
<!-- 开启注解支持 ,将会对注解进行处理--> 
<context:annotation-config /> 
<!-- 
开启自动代理,自动代理是指Spring会判断一个bean是否使用了一个或多个切面通知,并据此自动生成相应的代理以拦截其方法调用,并且确认通知是否如期进行。 
如果想强制使用CGLIB代理,需要将 <aop:aspectj-autoproxy> 的 proxy-target-class 
属性设为true。 
--> 
<aop:aspectj-autoproxy proxy-target-class="true" /> 
<!-- 扫描的包,spring将自动扫描这些包,根据其的注解配置,自动进行配置 --> 
<context:component-scan 
base-package="com.cgodo.daowole.dao, com.cgodo.daowole.service, com.cgodo.daowole.aop" /> 

<!-- 注解驱动开启,对注解方式的事物进行支持 --> 
<tx:annotation-driven mode="aspectj" /> 

<!-- 数据源配置 --> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close"> 
<property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
<property name="url" 
value="jdbc:mysql://10.13.166.224:3306/daowole?useUnicode=false&amp;autoReconnect=true&amp;characterEncoding=utf-8" /> 
<property name="username" value="root" /> 
<property name="password" value="" /> 
</bean> 

<!-- 事物管理员 --> 
<bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
<property name="dataSource" ref="dataSource" /> 
</bean> 
</beans> 

WEB-INF文件夹下面 
springMVC-servlet.xml 

<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-2.5.xsd 
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd 
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" 
default-> 
<context:component-scan base-package="com.cgodo.daowole.action" /> 
<mvc:annotation-driven /> 

<bean 
class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
<property name="prefix" value="" /> 
<property name="suffix" value=".jsp" /> 
</bean> 
</beans> 

web.xml 

<?xml version="1.0" encoding="UTF-8"?> 
<web-app id="WebApp_ID" version="2.4" 
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 
<display-name>daowole</display-name> 

<!-- <context-param>--> 
<!-- <param-name>contextConfigLocation</param-name>--> 
<!-- <param-value></param-value>--> 
<!-- </context-param>--> 
<!----> 
<!-- <listener>--> 
<!-- 
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
--> 
<!-- </listener>--> 

<servlet> 
<description> 
test</description> 
<display-name>test</display-name> 
<servlet-name>test</servlet-name> 
<servlet-class>com.cgodo.daowole.test.ServletTest</servlet-class> 
</servlet> 

<servlet> 
<servlet-name>springMVC</servlet-name> 
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
<init-param> 
<param-name>contextConfigLocation</param-name> 
<param-value>/WEB-INF/springMVC-servlet.xml, classpath:com/cgodo/daowole/spring/applicationContext/applicationContext.xml</param-value> 
</init-param> 
<load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
<servlet-name>test</servlet-name> 
<url-pattern>/test</url-pattern> 
</servlet-mapping> 

<servlet-mapping> 
<servlet-name>springMVC</servlet-name> 
<url-pattern>home.do" }) 
public String home( 
@RequestParam(value = "name", required = false) String username, 
Model model) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + username); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "index"; 




请求中的参数name必须输入(required = true,如果没有@RequestParam,默认required = false,如果写了@RequestParam,默认required = true) 

另外注意在类得上面有@RequestMapping("/test"),表示,只有再请求是资源位于/test下面才会处理 
比如(应用是daowole) 
127.0.0.1/daowole/abc/home.do 
127.0.0.1/daowole/abc/test/home.do 
127.0.0.1/daowole/ 
127.0.0.1/daowole/abc/ 
将不被处理, 
而 
127.0.0.1/daowole/test/home.do 
127.0.0.1/daowole/test/ 
将被处理 
如果去掉上面的类注解@RequestMapping("/test"),那么 
127.0.0.1/daowole/abc/ 
127.0.0.1/daowole/test/ 
将不被处理 
127.0.0.1/daowole/abc/home.do 
127.0.0.1/daowole/abc/test/home.do 
127.0.0.1/daowole/ 
127.0.0.1/daowole/test/home.do 
将被处理 

另外一个参数是Model,它是模型处理器。 
model.addAttribute(new Page<String>());将根据传入的对象的类型,生成对应的attribute name,比如Page类型生成page,而Account生成account,AccountOther生成accountOther。 

@RequestParam注解并非必须。当请求参数名和方法参数名字不相同的时候,才需要。如果不是用这个注解,那么将自动把请求参数名映射到对应的方法参数名。 

另外我们的model是用的是Model接口,而不是Map<String, Object>,这是因为Model接口提供了更方便的功能。 


package com.cgodo.daowole.action; 

import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestParam; 

import com.cgodo.daowole.model.Page; 

@Controller 
@RequestMapping("/test") 
public class AnnotationAction { 
@RequestMapping( { "/", "home.do" }) 
public String home(String pageSize, Model model, Page<String> page) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 



上面的代码中,首先要知道Page类型里面有一个pageSize属性,另外我们方法中也定义了一个pageSize参数。这个时候如果我们请求中有pageSize参数,那么方法参数的pageSize属性和page对象里面的pageSize属性的值会同时被设置为这个请求参数的值。 

另外需要看的是return "redirect:input.jsp";这里有一个redirect:前缀,表示重定向到input.jsp。 

package com.cgodo.daowole.action; 

import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RequestMapping; 

import com.cgodo.daowole.model.Page; 

@Controller 
@RequestMapping("/my") 
public class AnnotationAction { 
@RequestMapping( { "/", "home.do" }) 
public String home(String pageSize, Model model, Page<String> page) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 


@RequestMapping( { "/{name}/{cask}" }) 
public String home(@PathVariable String name, String pageSize, Model model, 
Page<String> page, @PathVariable String cask) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 



看另一个方法home 
@RequestMapping( { "/{name}/{cask}" }) 
{varName}会将/my/后面的路径转化成参数。 
最后一个{varName}会自动去掉后缀。 
@RequestMapping( { "/{name}/{cask}" })写了两个varName,因此必须存在两个目录级别(相对@RequestMapping("/my")而言)。由于只写了两级varName,因此也必须只有两级,三级的话就无效了。 
PathVariable 默认根据参数名字和请求参数名自动映射(名字相同)。 
可以根据自己的名字 
@RequestMapping( { "/{test}/{cask}" }) 
public String home(@PathVariable("test") String name, String pageSize, Model model, 
Page<String> page, @PathVariable String cask) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 

它也支持ant路径风格 

如果定义了类级别的RequestMapping路径参数风格,在方法级别那可以指定更详细的规则 
package com.cgodo.daowole.action; 

import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RequestMapping; 

@Controller 
@RequestMapping("/owners/{ownerId}") 
public class ControllerTest { 
@RequestMapping(value = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String ownerId, 
@PathVariable String petId, Model model) { 
System.out.println(); 


@RequestMapping(value = "/", headers = "content-type=texthome.do" }) 
public String home(String pageSize, Model model, Page<String> page, 
BindingResult bindingResult, 
@RequestParam(value = "image", required = false) MultipartFile image) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 


@RequestMapping( { "/a/{name}/{cask}" }) 
public String home(@PathVariable String name, String pageSize, Model model, 
Page<String> page, @PathVariable String cask) { 
System.out.println("------------------------------"); 
System.out.println("userName is " + pageSize); 
System.out.println("------------------------------"); 
model.addAttribute(new Page<String>()); 
return "redirect:input.jsp"; 



这里 
@RequestParam(value = "image", required = false) MultipartFile image 
发现@RequestParam去掉,就报错, 
beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.web.multipart.MultipartFile]: 
Specified class is an interface 
而留下这句就不会报错,不知道什么原因。。。 
减少到最小 
@RequestParam 
到这种程度。 

DispatcherServlet的不知道如何处理多部分 
表单数据。我们需要一个multipart解析器来提取出的多重数据 
DispatcherServlet的POST请求,以便它可以给我们的控制器。 
要注册一个Spring multipart解析器,我们只需要声明一个bean, 
实现了MultipartResolver接口。 
spring提供了一个实现 
CommonsMultipartResolver 
<mvc:annotation-driven />后这个类会自动注入。当然我们如果要配置更多的属性,需要自己定义这个bean 
<bean id="multipartResolver" 
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
<property name="maxUploadSize" value="5000000"></property> 
</bean> 
注意这里的bean id是固定的。spring会自动读取一个叫做multipartResolver的bean。如果叫做其他名字是无效的。 

关于action的返回值和参数 
经过@ RequestMapping注解定义的方法,这个方法的参数和返回值定义可以很灵活。下面说的参数可以定义任意数量。 
1.可以在方法中定义Request和Response,类型可以是ServletRequest 或 HttpServletRequest. 
response类似 
2.Session对象,类型HttpSession.session是线程不安全的。可以在定义的AnnotationMethodHandlerAdapter中的参数synchronizeOnSession设置为true,来设置为线程安全的。 
3.org.springframework.web.context.request.WebRequest类型或者org.springframework.web.context.request.NativeWebRequest类型的Servlet/Portlet API. 
回应类似 
4.java.util.Locale 获取当前请求的本地信息。 
5.java.io.InputStream / java.io.Reader类型,可以获取到请求的输入流 
6.java.io.OutputStream / java.io.Writer类型可以获取到回应的输出流。 
7.java.security.Principal 当前的验证用户 
8.在参数之前加入@PathVariable注解。来处理目录影射为参数值 
9.在参数之前加入@RequestParam注解。来处理从参数影射为方法参数值 
10.在参数之前加入@RequestHeader注解。用来将指定的请求头信息影射为方法的参数。 
11.在参数之前加入@RequestBody注解。用来将指定的客户端发送过来的请求参数的数据格式转换成java实体 
12.定义一个HttpEntity<?>类型的变量。将会把请求参数的head和请求内容转换成实体类。 
13.java.util.Map / org.springframework.ui.Model /org.springframework.ui.ModelMap 
这个是存放数据模型的。 
14.命令,或表单对象的实体。会将请求参数转成实体。@InitBinder注解或者HandlerAdapter 定义的时候进行转换设置。 
15.org.springframework.validation.Errors/org.springframework.validation.BindingResult验证结果。 
16.org.springframework.web.bind.support.SessionStatus 会话状态 

需要注意的是,Errors类型和BindingResult类型的参数的排序一定要有规则。 
因为定义的实体模型可能有多个,spring会为每个实体创建org.springframework.validation.Errors/org.springframework.validation.BindingResult 
如果定义的org.springframework.validation.Errors/org.springframework.validation.BindingResult类型排序不对应了,那么可能会无法得到你的预期结果 
@RequestMapping(method = RequestMethod.POST) 
public String processSubmit(@ModelAttribute("pet") Pet pet, 
Model model, BindingResult result) { … } 
这里的result对应的是model,而不是pet。 

@RequestMapping(method = RequestMethod.POST) 
public String processSubmit(@ModelAttribute("pet") Pet pet, 
BindingResult result, Model model) { … } 
这个是有效的。 

控制器的返回结果 
可以是 
1.ModelAndView 包含了@ModelAttribute注解定义的key=@ModelAttribute("a")的value=模型的结果,视图名,命令对象。 
2.Model对象,包含了视图名(RequestToViewNameTranslator类型),模型数据,命令对象,和ModelAttribute注解定义的模型。 
3.Map对象,和Model类似。 
4.View对象,包含了命令对象,@ModelAttribute注解定义的模型。可能还包含了Model对象。 
5.String字符串。一个逻辑视图名。 
6.void 当结果直接写入ServletResponse / HttpServletResponse。requestToViewNameTranslator将自动查找视图。
7.如果这个方法定义了@ResponseBody注解。那么会把返回值转换成这个数据格式,输出给客户端。 
8.HttpEntity<?>类型或者ResponseEntity<?>,会将返回值转换成响应的head和响应内容。 
9.其他任何类型。 

绑定参数 
@RequestParam 

@Controller 
@RequestMapping("/pets") 
@SessionAttributes("pet") 
public class EditPetForm { 
// ... 
@RequestMapping(method = RequestMethod.GET) 
public String setupForm(@RequestParam("petId") int petId, ModelMap model) { 
Pet pet = this.clinic.loadPet(petId); 
model.addAttribute("pet", pet); 
return "petForm"; 



先看@RequestMapping,它指定了影射的关系。 

在看SessionAttributes注解,其作用看后面内容。 

@RequestParam("petId") 
这里定义了从请求参数映射到方法参数的映射关系。直接写一个字符串表示将请求参数的petId映射为方法参数的第一个参数。 

RquestBody注解 
这个可以将http的请求 body转换成指定格式。 
注意 http协议中,Request body只有在post格式提交的数据,才用户请求体(put,head等请求方式,很少使用,我们不考虑)。而get请求方式没有Request Body。详情请了解http协议 

spring <wbr>MVC详解(转)  
如上图 

注意这里的转换和方法的参数名无关系。 
编写如下内容 


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>领钱</title> 
</head> 
<body> 
领钱 
<form action="test/body" method="post"><input 
name="body" value="123" /> <input name="name" value="456" /><input 
type="submit" /></form> 
</body> 
</html> 

package com.cgodo.daowole.action; 

import java.io.IOException; 
import java.io.Writer; 

import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RequestBody; 
import org.springframework.web.bind.annotation.RequestMapping; 

@Controller 
@RequestMapping("/test") 
public class ControllerTest { 
@RequestMapping(value = "/pets/{petId}", params = "myParam=*") 
public void findPet(@PathVariable String ownerId, 
@PathVariable String petId, Model model) { 
System.out.println(); 


@RequestMapping(value = "/body") 
public void handle(@RequestBody() String host, Writer writer) 
throws IOException { 
writer.write(host); 



访问 
http://127.0.0.1:8081/daowole/index.jsp 
并点击提交。请求体将被获得,我们还把请求体答应出去了。 

spring <wbr>MVC详解(转)  

这里的请求体转换是通过 
HttpMessageConverter实现类来完成的。 
基于注解的mvc使用DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter.(spring mvc 3) 
AnnotationMethodHandlerAdapter提供了对RequestBody注解的支持。 
提供实现的转换器 
ByteArrayHttpMessageConverter 转换byte数组 
StringHttpMessageConverter 转换成String 
FormHttpMessageConverter 将请求体转换成一个MultiValueMap<String, String> 
SourceHttpMessageConverter 转换javax.xml.transform.Source.我使用的时候报错,不知道是不是需要添加其他东西的支持 
MarshallingHttpMessageConverter 转换成org.springframework.oxm下面的类 
AnnotationMethodHandlerAdapter默认加上上面的内容的bean 

另外,对于AnnotationMethodHandlerAdapter在处理requestbody注解之前,有request.getParameter(String name);方法的话,会破坏对post的body的处理,也就是会再它处理之前,把request的inputstream读取完毕了。(至于原因查看http协议)。如主题修改拦截器,本地化拦截器都会在它之前执行request.getParameter(String name);。那么就会是都最后得到的requestBody的结果为null。 


@ResponseBody注解 
这个注解可以放在一个方法的声明那,当方法返回时,将返回的内容直接写入到请求的客户端,而不是作为一个视图。 

如 

package com.cgodo.daowole.action; 

import java.io.IOException; 
import java.io.Writer; 

import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.util.MultiValueMap; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RequestBody; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 

@Controller 
@RequestMapping("/test") 
public class ControllerTest { 
@RequestMapping(value = "/pets/{petId}", params = "myParam=*") 
public void findPet(@PathVariable String ownerId, 
@PathVariable String petId, Model model) { 
System.out.println(); 


@RequestMapping(value = "/body") 
public void handle(@RequestBody() MultiValueMap<String, String> host, 
Writer writer) throws IOException { 
writer.write(""); 


@RequestMapping(value = "/responseBody") 
@ResponseBody 
public String responseBody() { 
return "Hello World"; 



responseBody方法使用这个注解。 
将直接输出hello world给客户端。 
http://127.0.0.1:8081/daowole/test/responseBody 

spring <wbr>MVC详解(转)  
当然直接输出的内容可能会照成部分浏览器无法解析的问题。这要看浏览器的严格程度。 

HttpEntity<?> ResponseEntity<?> 
ResponseEntity是HttpEntity子类,专门用于处理响应的。 
和@requestbody和@responsebody类似(既然类似,和他们一样需要post) 


package com.cgodo.daowole.action; 

import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.io.Writer; 

import org.springframework.http.HttpEntity; 
import org.springframework.http.HttpHeaders; 
import org.springframework.http.HttpStatus; 
import org.springframework.http.ResponseEntity; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.util.MultiValueMap; 
import org.springframework.web.bind.annotation.PathVariable; 
import org.springframework.web.bind.annotation.RequestBody; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 

@Controller 
@RequestMapping("/test") 
public class ControllerTest { 
@RequestMapping(value = "/pets/{petId}", params = "myParam=*") 
public void findPet(@PathVariable String ownerId, 
@PathVariable String petId, Model model) { 
System.out.println(); 


@RequestMapping(value = "/body") 
public void handle(@RequestBody() MultiValueMap<String, String> host, 
Writer writer) throws IOException { 
writer.write(""); 


@RequestMapping(value = "/responseBody") 
@ResponseBody 
public String responseBody() { 
return "Hello World"; 


@RequestMapping("/entity") 
public ResponseEntity<String> handle(HttpEntity<String> requestEntity) 
throws UnsupportedEncodingException { 
String requestHeader = requestEntity.getHeaders().getFirst( 
"MyRequestHeader"); 
String requestBody = requestEntity.getBody(); 
// do something with request header and body 
HttpHeaders responseHeaders = new HttpHeaders(); 
responseHeaders.set("MyResponseHeader", "MyValue"); 
return new ResponseEntity<String>("Hello World", responseHeaders, 
HttpStatus.CREATED); 



spring <wbr>MVC详解(转)  

结果如上图 
spring <wbr>MVC详解(转)  

@ModelAttribute注解 
可以用在方法声明上面,或者方法参数声明的时候。注意声明在方法之前的@ModelAttribute注解(假设这个方法没有RequestMapping),将会在@RequestMapping定义了的方法之前执行一遍(如果@ModelAttribute和ModelAttribute和@RequestMapping不在同一个方法),然后再执行匹配的方法。如果@ModelAttribute和@RequestMapping在一个方法都存在。不会在其他方法之前执行。 
@ModelAttribute("types") 
public Collection<String> populatePetTypes() { 
List<String> ss = new ArrayList<String>(); 

return ss; 


@RequestMapping("/model") 
public String processSubmit() { 
return "index"; 

如上populatePetTypes方法是没有的RequestMapping,请求 
http://127.0.0.1:8081/daowole/test/model,先执行 

spring <wbr>MVC详解(转)  

再执行 
spring <wbr>MVC详解(转)  
修改代码 

@ModelAttribute("types") 
@RequestMapping("/model1.do") 
public Collection<String> populatePetTypes() { 
List<String> ss = new ArrayList<String>(); 

return ss; 


@RequestMapping("/model") 
public String processSubmit() { 
return "index"; 

访问http://127.0.0.1:8081/daowole/test/model 
直接进入processSubmit,无需先执行populatePetTypes 

spring <wbr>MVC详解(转)  


http://127.0.0.1:8081/daowole/test/model1.do 
进入populatePetTypes 

spring <wbr>MVC详解(转)  

@SessionAttributes注解 
写在类级别的注解,定义一个session attributes,属性名字为SessionAttributes指定。可以指定多个(数组),也同时可以指定类型。 
@Controller 
@SessionAttributes( { "user" }) 
@RequestMapping("/test") 
public class ControllerTest { 
@RequestMapping("/session") 
@ResponseBody 
public String sessionIn(@ModelAttribute("user") User user) { 
return "index"; 


@RequestMapping("/sessionOut") 
@ResponseBody 
public String sessionOut(HttpSession session) { 
User user = (User) session.getAttribute("user"); 

if (user == null) { 
user = new User(); 
user.setId(1); 
session.setAttribute("user", user); 


return "index"; 



访问sessionOut,然后再访问sessionIn,可以发现sessionIn的user可以访问到sessionOut设置的user 

需要注意的是,@SessionAttributes注解在处理器处理的时候,会根据session.getAttributes的返回内容,来处理一次,也就是,当return = null (处理器是通过request.getSession(false),它不会创建session,如果session=null,直接return null),就抛出异常HttpSessionRequiredException异常。 

而有时候,我们在session存放的对象,并非是必须存在的。解决这个问题有三个方法 
1.这个时候,我们就可以通过 
@ModelAttributes注解写在方法之前,并且这个方法没有@RequestMapping注解,那么这个方法会在之前处理的原理来解决。 

注意,当写在方法上面的@ModelAttribute("user")指定的名字和@SessionAttributes( { "user" })指定的名字中,刚好重合的时候,make方法在一个session中只会被调用一次。 

例子如下 
@SessionAttributes( { "user" }) 
public class ControllerTest { 
private int x = 0; 

@ModelAttribute("user") 
public Object make(HttpSession session) { 
Object user = session.getAttribute("user"); 

if (user == null) { 
user = new User(); 


return user; 


@RequestMapping(value = { "/", "home.do", "index", "index.jsp", 
"index.html", "index.htm" }) 
public String home(@ModelAttribute("user") User user, ModelMap model) 
throws IOException { 
List<String> messages = new ArrayList<String>(); 

messages.add("你没有登录,请先登录!"); 
messages.add("你输入的用户名不存在!"); 
messages.add("无效的账号"); 
model.put("messages", messages); 

return "application/index"; 


上面的这种方法由于会依赖与HttpSession,这个时候这个类又重新依赖于servlet-api的架包了。不太好。 

2. 
我们可以换一种写法,使用ModelMap model,这个样子就能把对jee架包的依赖消除了。 

@ModelAttribute("user") 
public Object make(ModelMap model) { 
Object user = model.get("user"); 

if (user == null) { 
user = new User(); 


return user; 


@CookieValue注解 
@RequestMapping("/cookie") 
@ResponseBody 
public String cookie(@CookieValue("JSESSIONID") String sessionId) { 
return sessionId; 


@RequestHeader注解 
@RequestMapping("/head") 
@ResponseBody 
public String head(@RequestHeader("Accept-Encoding") String head) { 
return head; 


3. 
还有一种方式就是利用 
WebBindingInitializer的功能,实现一个WebBindingInitializer,并且这个东西其实什么也不做,只是生成session的attributes。如 

package com.cgodo.daowole.web.bind; 

import org.springframework.web.bind.WebDataBinder; 
import org.springframework.web.bind.support.WebBindingInitializer; 
import org.springframework.web.context.request.ServletRequestAttributes
import org.springframework.web.context.request.WebRequest; 

public class ClinicBindingInitializer implements WebBindingInitializer { 

public void initBinder(WebDataBinder arg0, WebRequest arg1) { 
//从session 
Object  o = arg1.getAttribute("code", ServletRequestAttributes.SCOPE_SESSION); 

if( o == null) { 
//放入session的值 
arg1.setAttribute("code", new String(), 1); 






WebBindingInitializer 
通过InitBinder注解或者天加一个WebBindingInitializer.的实现类 
@InitBinder写在@Controller的类中的方法上面,这个方法可以接受3个参数,当然这三个参数是灵活的。你需要定义几个都可以 

@InitBinder 
public void initBinder(WebDataBinder binder) { 
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 
dateFormat.setLenient(false); 
binder.registerCustomEditor(Date.class, new CustomDateEditor( 
dateFormat, false)); 


@RequestMapping("/bind") 
@ResponseBody 
public String bind(Date date) { 
return "test"; 

如上,定义中,binder.registerCustomEditor(Date.class, new CustomDateEditor( 
dateFormat, false));指定了Date类型将由CustomDateEditor属性编辑器完成初始化工作。 

WebBindingInitializer实现类实现方式 

package com.cgodo.daowole.web.bind; 

import org.springframework.web.bind.WebDataBinder; 
import org.springframework.web.bind.support.WebBindingInitializer; 
import org.springframework.web.context.request.WebRequest; 

public class ClinicBindingInitializer implements WebBindingInitializer { 

public void initBinder(WebDataBinder arg0, WebRequest arg1) { 
System.out.println(); 



这个时候,就要重写AnnotationMethodHandlerAdapter bean的定义了。 

<!-- <bean--> 
<!-- class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">--> 
<!-- <property name="cacheSeconds" value="0" />--> 
<!-- <property name="webBindingInitializer">--> 
<!-- <bean class="com.cgodo.daowole.web.bind.ClinicBindingInitializer" />--> 
<!-- </property>--> 
<!-- </bean>--> 


注解驱动开启后会注册DefaultAnnotationHandlerMapping, 
默认情况下它生成的默认配置包括了 
interceptors 拦截器 
defaultHandler 默认的hangler mapping 
order 详细查看spring的order属性,Spring 将上下文中可用的映射进行排序,然后选用第一个和请求匹配的处理器。
alwaysUseFullPath 如果这个属性被设成true,Spring 将会使用绝对路径在当前的servlet context中寻找合适的处理器。 这个属性的默认值是false,在这种情况下,Spring会使用当前servlet context中的相对路径。 例如,如果一个servlet在servlet-mapping中用的值是/testing*;q=0.5  
  
firefox:  
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 

spring完成内容协商(content negotiation)的工作是由ContentNegotiatingViewResolver来完成的 


locale 
是由LocaleResolver完成的。 
DispatcherServlet会查找locale解析器。我们可以通过RequestContext.getLocale()方法获取本地化。 

LocaleResolver的实现有 
AcceptHeaderLocaleResolver 
CookieLocaleResolver 
SessionLocaleResolver 

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> 
  <property name="cookieName" value="clientlanguage"/> 
  <property name="cookieMaxAge" value="100000"> 
</bean> 

CookieLocaleResolver的属性 
cookieName,默认是classname + LOCALE,由于是 
CookieLocaleResolver 还有一个属性是defaultLocale。如果没有个它设置默认值,那么在调用它的determineDefaultLocale方法的时候,会有判断,如果是null,就从request.getLocale();获取。 
org.springframework.web.servlet.i18n.CookieLocaleResolver处理的,所以叫org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE 

cookieMaxAge cookie的最大时间 默认 Integer.MAX_INT 
cookiePath cookie有效路径。 默认/ 

另外还提供了一个请求参数拦截器,会根据请求参数,来修改对应的本地化解析器的本地化信息 
LocaleChangeInterceptor 

<bean id="localeChangeInterceptor" 
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
<property name="paramName" value="siteLanguage" /> 
</bean> 

<bean id="localeResolver" 
class="org.springframework.web.servlet.i18n.CookieLocaleResolver" /> 

<bean 
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> 
<property name="interceptors"> 
<list> 
<ref bean="localeChangeInterceptor" /> 
</list> 
</property> 
</bean> 

如果开了 
<mvc:annotation-driven /> 
那么配置应该是 
<mvc:interceptors> 
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
<property name="paramName" value="siteLanguage" /> 
</bean> 
</mvc:interceptors> 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5366次
    • 积分:145
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:48篇
    • 译文:0篇
    • 评论:0条
    文章分类