spring mvc 的文档学习

Spring 4.1..6文档笔记

Spring mvc

Mvc框架围绕着一个DispatcherServlet设计,它用来分发处理请求,配合着处理映射,视图解析,语言,时间区,主题解析,支持文件上传。默认的处理由@Controller  and @RequestMapping来支持。Spring3.0控制器机制也支持创建Restful类型的网站,通过@PathVariable等一系列注解来声明

Springmvc视图解析很灵活,一个控制器负责准备数据和选择的视图名组成的模板映射,或者直接将数据写到响应流,完成请求。

 

 

 

DispatcherServlet是一个Servlet继承了HttpServlet基类。你需要映射请求用DispatcherServlet来处理

<web-app>

    <servlet>

        <servlet-name>example</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>example</servlet-name>

        <url-pattern>/example/*</url-pattern>

    </servlet-mapping>

</web-app>

上面配置中所有以/example开头的请求都会由DispatcherServlet的实例example处理,同样相等的在a Servlet 3.0+environment环境中,可以用以下的代码代替上面的xml中的内容。

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override

    public void onStartup(ServletContext container) {

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());

        registration.setLoadOnStartup(1);

        registration.addMapping("/example/*");

    }

}

 

WebApplicationInitializer由mvc提供的接口,保证的的类被检测并自动初始化Servlet 3容器,一个抽象类实现了AbstractDispatcherServletInitializer接口使得注册DispatcherServlet更容易?(不怎么了解)

上下文关系图

 

 

初始化dispatcherServlet,寻找应用中WEB-INF目录中的[servlet-name]-servlet.xml。

 

考虑一下的web.xml中的配置

<web-app>

    <servlet>

        <servlet-name>golfing</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>golfing</servlet-name>

        <url-pattern>/golfing/*</url-pattern>

    </servlet-mapping>

</web-app>

以上的配置对应的你的应用中得有一个/WEB-INF/golfing-servlet.xml对用的配置文件。

也可以只有一个根目录下的上下文文件包含了初始化的参数,指定具体的servlet配置路径

 

<web-app>

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/root-context.xml</param-value>

    </context-param>

    <servlet>

        <servlet-name>dispatcher</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>

            <param-name>contextConfigLocation</param-name>

            <param-value></param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>dispatcher</servlet-name>

        <url-pattern>/*</url-pattern>

    </servlet-mapping>

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

</web-app>

WebApplicationContext是ApplicationContext的扩展,有一些其他的特性。可以来解析主题,并且知道了哪个servlet相关(有一个和ServletContext的连接)。

Dispatcherservlet用特殊的bean来处理请求返回视图,你可以通过配置选择一些ben在web上下文中,也可以使用默认的一系列bean。

HandlerMapping 匹配请求和一系列的前后处理(处理拦截器)。

HandlerAdapter 帮助DispatcherServlet调用映射的处理器

HandlerExceptionResolver 将异常对应到视图

ViewResolver 解析逻辑的基于字符串的视图名到实际的视图类型

LocaleResolver & LocaleContextResolver 提供国际化的视图

ThemeResolver 在应用中提供个性化的布局资源(css,jpg)

MultipartResolver 处理多媒体请求,如处理文件上传来自表单

FlashMapManager 储存输入,输出 FlashMap,传递属性组从一个请求到另一个请求在重定向中

 

默认的DispatcherServlet配置保存在org.springframework.web.servlet的DispatcherServlet.properties文件中

 

DispatcherServlet处理请求的顺序

1.应用上下文查找并绑定请求中的信息作为属性,提供以后的处理器或其他使用

2.Locale resolver 解析方言在处理请求中(渲染视图,准备数据)使用

3.The theme resolver 请求中使视图决定要使用哪些主题

4.a multipart file resolver 请求中检查多媒体,找到了,请求被包装成MultipartHttpServletRequest,待后续处理

5.寻找合适的处理器,找到了处理器相关的执行链(前处理,后处理,控制器),来处理业务和数据

6.如果业务实体返回,视图被渲染;无返回不处理视图

 

 

DispatcherServlet 初始化参数组

contextClass 实现了WebApplicationContext,初始化servlet使用的上下文,默认使用XmlWebApplicationContext

contextConfigLocation 根据字符串标识的一个或多个上下文类名,或者是位置信息来配置,最后的起作用。

Namespace WebApplicationContext命名空间,默认是 [servlet-name]-servlet

 

 

实现Controllers

解析用户输入,转变为model,通过view展示给user

 

使用注解@RequestMapping, @RequestParam, @ModelAttribute(Spring2.5)

@Controller

public class HelloWorldController {

 

    @RequestMapping("/helloWorld")

    public String helloWorld(Model model) {

        model.addAttribute("message", "Hello World!");

        return "helloWorld";

    }

}

 

定义控制器 @Controller

自动检测注解控制器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:p="http://www.springframework.org/schema/p"

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

    xsi:schemaLocation="

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

        http://www.springframework.org/schema/beans/spring-beans.xsd

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

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

    <context:component-scan base-package="org.springframework.samples.petclinic.web"/>

    <!-- ... -->

</beans>

请求映射@RequestMapping

URLS到对应的实体类或特定处理方法

Controller

@RequestMapping("/appointments")

public class AppointmentsController {

 

    private final AppointmentBook appointmentBook;

 

    @Autowired

    public AppointmentsController(AppointmentBook appointmentBook) {

        this.appointmentBook = appointmentBook;

    }

 

    @RequestMapping(method = RequestMethod.GET)

    public Map<String, Appointment> get() {

        return appointmentBook.getAppointmentsForToday();

    }

 

    @RequestMapping(value="/{day}", method = RequestMethod.GET)

    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {

        return appointmentBook.getAppointmentsForDay(day);

    }

 

    @RequestMapping(value="/new", method = RequestMethod.GET)

    public AppointmentForm getNewForm() {

        return new AppointmentForm();

    }

 

    @RequestMapping(method = RequestMethod.POST)

    public String add(@Valid AppointmentForm appointment, BindingResult result) {

        if (result.hasErrors()) {

            return "appointments/new";

        }

        appointmentBook.addAppointment(appointment);

        return "redirect:/appointments";

    }

}

@RequestMapping 类上, 表示控制器类中方法和url相关

               方法上,表示方法和不同URLS相关

@Controller

public class ClinicController {

 

    private final Clinic clinic;

 

    @Autowired

    public ClinicController(Clinic clinic) {

        this.clinic = clinic;

    }

 

    @RequestMapping("/")

    public void welcomeHandler() {

    }

 

    @RequestMapping("/vets")

    public ModelMap vetsHandler() {

        return new ModelMap(this.clinic.getVets());

    }

}

可以用@RequestMapping(method=GET)缩小动作范围

 

 

有时候一个控制器需要运行时用AOP代理装饰,比如在控制器上用@Transactional,这种情况下使用基于类的代理

 

 

Spring MVC 3.1中支持@RequestMapping methods的类

RequestMappingHandlerMapping 是3.1中唯一一个地方决定请求处理的方法,RequestMappingHandlerAdapter 是实际调用方法。

 

在3.1之前,类型和方法级别的请求映射由两个阶段检查,先是DefaultAnnotationHandlerMapping,然后实际方法调用是AnnotationMethodHandlerAdapter。

 

@PathVariable在方法参数上绑定URI模板变量的值

 

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)

public String findOwner(@PathVariable String ownerId, Model model) {

    Owner owner = ownerService.findOwner(ownerId);

    model.addAttribute("owner", owner);

    return "displayOwner";

}

url模板“/owners/{ownerId}”表面变量是ownerId,当控制器处理这个请求时,URI中合适地方发现的值设置为ownerId的值,比如,当一个请求来自/owners/fred时,ownerId的值是fred。

 

或者你可以在参数注解中明确指定变量名,如下:@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)

public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {

    // implementation omitted

}

 

一个方法参数中,可以有多个@PathVariable;

@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)

public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

    Owner owner = ownerService.findOwner(ownerId);

    Pet pet = owner.getPet(petId);

    model.addAttribute("pet", pet);

    return "displayPet";

}

 

还有一种路径中参数变量的请求方式URL/owners/42/pets/21.

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

 

    @RequestMapping("/pets/{petId}")

    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

        // implementation omitted

    }

 

}

路径参数可以使任何简单类型int,long,Date等,Spring自动转化类型或者失败时表现TypeMismatchException异常

@RequestMapping支持URI模板中变量表达式的使用,如{varName:regex},第一部分是变量名,第二部分是匹配表达式,比如:

/spring-web/spring-web-3.0.5.jar

@RequestMapping("/spring-web/{symbolicName:[a-z-]}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]}")

    public void handle(@PathVariable String version, @PathVariable String extension) {

        // ...

    }

}

 

 

请求路径匹配规则

默认MVC执行文件后缀匹配,匹配路径/person也适合匹配/person.*;

 

Matrix Variables

模型变量:在URL中eg: "/cars;color=red;year=2012",以;或,分割,Eg: "color=red,green,blue" 或"color=red;color=green;color=blue";

 

// GET /pets/42;q=11;r=22

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)

public void findPet(@PathVariable String petId, @MatrixVariable int q) {

 

    // petId == 42

    // q == 11

 

}

用注解指定这种变量之间值得映射关系:

// GET /owners/42;q=11/pets/21;q=22

 

@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)

public void findPet(

        @MatrixVariable(value="q", pathVar="ownerId") int q1,

        @MatrixVariable(value="q", pathVar="petId") int q2) {

 

    // q1 == 11

    // q2 == 22

 

}

可以指定默认值代替路径中的变量值

// GET /pets/42

 

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)

public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

 

    // q == 1

 

}

将值传入Map类型的参数中

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

 

@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)

public void findPet(

        @MatrixVariable Map<String, String> matrixVars,

        @MatrixVariable(pathVar="petId"") Map<String, String> petMatrixVars) {

 

    // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]

    // petMatrixVars: ["q" : 11, "s" : 23]

 

}

 

 

默认配置中<mvc:annotation-driven>有一个属性enable-matrix-variables 为false,如果要使用这种变量需要设置为true:

 

<?xml version="1.0" encoding="UTF-8"?>

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

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

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

    xsi:schemaLocation="

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

        http://www.springframework.org/schema/beans/spring-beans.xsd

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

        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

 

    <mvc:annotation-driven enable-matrix-variables="true"/>

</beans>

 

 

@RequestMapping中参数consumes指定媒体类型,来匹配请求头中content-Type中相同的媒体类型

@Controller

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

public void addPet(@RequestBody Pet pet, Model model) {

    // implementation omitted

}

 

又如Content-Type :text/plain

@RequestMapping中produces属性指定相应请求响应头中content-type类型

@Controller

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json")

@ResponseBody

public Pet getPet(@PathVariable String petId, Model model) {

    // implementation omitted

}

 

请求参数和请求头值

@RequestMapping params  "myParam", "!myParam", or "myParam=myValue"

指定参数,非指定参数,指定参数值

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

 

    @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")

    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

        // implementation omitted

    }

 

}

 

@Controller

@RequestMapping("/owners/{ownerId}")

public class RelativePathUriTemplateController {

 

    @RequestMapping(value = "/pets", method = RequestMethod.GET, headers="myHeader=myValue")

    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {

        // implementation omitted

    }

 

}

 

@RequestMapping匹配的处理方法参数类型

 支持的方法参数类型

请求或相应对象(servlet API)veg: ServletRequest, HttpServletRequest;

Session 对象(servlet API)httpSesion类型,展现session,这样的参数永远不会为空(session可能非线程安全,尤其在servlet环境中,如果多个请求同时操作一个会话,可以设置RequestMappingHandlerAdapter's "synchronizeOnSession" flag to "true";

org.springframework.web.context.request.WebRequest or org.springframework.web.context.request.NativeWebRequest请求参数或属性通过,与本地Servlet/Portlet API无关;

java.util.Locale 当前请求的现场,由配置环境中的LocaleResolver / LocaleContextResolver决定;

java.util.TimeZone当前请求,由LocaleContextResolver决定;

java.io.InputStream / java.io.Reader 请求内容,由Servlet API暴露原始值;

java.io.OutputStream / java.io.Writer,响应内容,由Servlet API暴露原始值;

org.springframework.http.HttpMethod 请求动作,get,post,delete,head,opitions…..;

java.security.Principal包含目前已授权的用户;

@PathVariable URL模板中变量对应参数;

@MatrixVariable URL路径片段中的name-value对对应的参数类型;

@RequestParam 访问特殊的servlet请求参数,参数值自动转化为方法参数类型;

@RequestHeader访问特殊的servlet请求头,参数值自动转化为方法参数类型;

@RequestBody 访问http请求体参数注解,参数值转换为参数定义类型通过httpMessageConverter;

@RequestPart访问"multipart/form-data"请求部分的注解;

HttpEntity<?> 访问servlet请求http的请求头和内容,请求流转化为实体通过HttpMessageConverter;

java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap 充实model暴露给web视图;

org.springframework.web.servlet.mvc.support.RedirectAttributes 明确重定向的属性集合,在server端缓存属性方便重定向后二次请求的需要;

RedirectAttributes 不通过model如果方法返回带有 “redirect:”前缀的视图名或RedirectView;

org.springframework.validation.Errors / org.springframework.validation.BindingResult 校验结果为前处理或form对象;

org.springframework.web.bind.support.SessionStatus处理表单过程完成状态的标志,如果成功就清理会话属性(@SessionAttributes指定);

org.springframework.web.util.UriComponentsBuilder准备当前请求的url生成器。;

 

 

无效的参数顺序(@ModelAttribute("pet") Pet pet, Model model, BindingRes

有效的参数顺序 (@ModelAttribute("pet") Pet pet, BindingResult result, Model model)

 

支持的方法返回类型

ModelAndView 对象,包含数据模型和@ModelAttribute注解访问的方法结果

Model 包含视图对象名(RequestToViewNameTranslator决定),命令对象充实的数据,结果(ModelAttribute标注方法返回相关数据)

Map 放弃数据模型的对象,包含视图名(RequestToViewNameTranslator)和充实后的数据模型;

View 命令对象返回的数据模型和@ModelAttribute涉及的数据访问方法,处理方法可以通过Model参数来充实数据模型

String  逻辑视图名的值,命令对象决定的数据模型和@ModelAttribute涉及的数据访问方法,a Model参数标记的处理方法;

Void 如果自己处理响应(直接返回数据,定义参数ServletResponse/HttpServletResponse)或者由RequestToViewNameTranslator决定,(不是定义响应参数在处理方法签名中)

 

如果方法是由@ResponseBody标记的,返回方式写入响应http身体,返回值转变为定义的参数类型(通过HttpMessageConverters

HttpEntity<?>or ResponseEntity<?>  访问servlet响应http头或内容,实体将转化为响应流(HttpMessageConverters

 

HttpHeaders 作为返回响应 没有身体

 

Callable<?>返回,Spring mvc管理线程,应用异步处理返回结果

DeferredResult<?>自己选择线程处理返回结果值

ListenableFuture<?> 同上

 

任何其他返回类型都是被当作数据模型的一个属性暴露给视图,@ModelAttribute在方法级上做标记

 

请求参数到方法参数的绑定 @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";

    }

 

    // ...

 

}

自动转化参数非string类型,可以设置默认参数值

 

 

请求体和@RequestBody注解的对象相映射

方法参数和http请求体的值绑定

@RequestMapping(value = "/something", method = RequestMethod.PUT)

public void handle(@RequestBody String body, Writer writer) throws IOException {

    writer.write(body);

}

转化通过HttpMessageConverter将请求消息转化为对象 并且将对象转化为响应体 ,RequestMappingHandlerAdapter支持@RequestBody,HttpMessageConverters支持对象的转化

 

如果要进行xml的转化,需要MarshallingHttpMessageConverter通过确定的org.springframework.oxm下的 Marshaller和Unmarshaller实现

 

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

    <property name="messageConverters">

        <util:list id="beanList">

            <ref bean="stringHttpMessageConverter"/>

            <ref bean="marshallingHttpMessageConverter"/>

        </util:list>

    </property

</bean>

 

<bean id="stringHttpMessageConverter"

        class="org.springframework.http.converter.StringHttpMessageConverter"/>

 

<bean id="marshallingHttpMessageConverter"

        class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">

    <property name="marshaller" ref="castorMarshaller" />

    <property name="unmarshaller" ref="castorMarshaller" />

</bean>

 

<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>

 

一个@RequestBody注解的方法参数可以用@Valid,表示用确定的Validator实例来验证

 

将响应体和对应的方法相关联@ResponseBody

标记方法表示返回的对象将直接写入http响应体(不会被方法模型代替,或视图名打断)

@RequestMapping(value = "/something", method = RequestMethod.PUT)

@ResponseBody

public String helloWorld() {

    return "Hello World";

}

 

上例中文本会写入响应流中

@RequestBody,相同,HttpMessageConverter转换返回对象为响应体。

 

@RestController在映射的方法上,,将@ResponseBody和@Controller联合起来。

 

使用HttpEntity

@RequestBody and @ResponseBody用来访问请求体和响应体,而且可以访问请求和响应头(httpEntity and ResponseEntity)

@RequestMapping("/something")

public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {

//请求头值  

  String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));

//读取请求体作为字节数组

    byte[] 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);

}

@ModelAttribute 在方法上和方法参数上

添加一个或多个model属性,不是直接与请求相关联,而是在关联之前调用。

/ Add one attribute

// The return value of the method is added to the model under the name "account"

// You can customize the name via @ModelAttribute("myAccount")

 

@ModelAttribute

public Account addAccount(@RequestParam String number) {

    return accountManager.findAccount(number);

}

 

// Add multiple attributes

 

@ModelAttribute

public void populateModel(@RequestParam String number, Model model) {

    model.addAttribute(accountManager.findAccount(number));

    // add more ...

}

 

@ModelAttribute注解的方法用来构成哪些下拉框值得属性,或者构成一个对象用来在html表单中展示

在方法上使用@ModelAttribute有两种方式,第一种,增加一个参数并且返回。第二种,接收一个Model,加入多个属性。

一个controller可以有多个@ModelAttribute标记的方法,这些方法都在映射url之前被调用

@ModelAttribute可以用在@RequestMapping注解的方法上,RequestMapping注解方法的返回时一个model的属性而不是一个视图名。

 

 

在方法参数中使用@ModelAttribute 注解

参数由model而来,如果不在model中,则先实例化后加入model.model中后,参数fields由所有请求匹配的名字中获得。者叫做数据绑定,一个有用的机制使你避免从field中一个个解析

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)

public String processSubmit(@ModelAttribute Pet pet) { }

 

Pet的实例从哪来:

已在model中(使用了SessionAttributes

已在model中由于使用了(@ModelAttribute)在同一个controller

基于URI template变量和类型转换

实例化使用自己默认的构造器

 

 

@ModelAttribute标记的方法是一种普遍的方法来传递数据库中的值,可以选择性的存储在请求或者使用@SessionAttributes。一些情况中使用URI template variable and a type converter.恢复属性更方便

@RequestMapping(value="/accounts/{account}", method = RequestMethod.PUT)

public String save(@ModelAttribute("account") Account account) {

 

}

上例中model属性account匹配uri template同名变量,如果你注册Converter<String, Account>可以将string型的account值转为account实例

 

数据绑定中可能有没有匹配的错误,检查这种错误加上BindingResult参数

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)

public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {

 

    if (result.hasErrors()) {

        return "petForm";

    }

 

    // ...

 

}

 

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)

public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {

 

    new PetValidator().validate(pet, result);

    if (result.hasErrors()) {

        return "petForm";

    }

 

    // ...

 

}

 

 

 

@Valid校验参数绑定

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)

public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {

 

    if (result.hasErrors()) {

        return "petForm";

    }

 

    // ...

 

}

 

 

@SessionAttributes在请求之中存储model属性在http会话中

特定的处理器处理SessionAttributes定义的session。列出model属性名或属性类型(显示的存储在session或一些会话的存储)当作随后请求的支持者

 

@Controller

@RequestMapping("/editPet.do")

@SessionAttributes("pet")

public class EditPetForm {

    // ...

}

 

 

指定重请求和短时间存储的属性

默认的一些model属性被暴露在uri template的重请求url的变量中,这些参数被保存下来在集合或队列中。

 

@CookieValue 来映射cookie values

可以将方法参数与http cookie绑定

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

http请求获得的cookie值

@RequestMapping("/displayHeaderInfo.do")

public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {

    //...

}

由名字来映射

请求头属性和@RequestHeader注解的参数绑定

Host                    localhost:8080

Accept                  text/html,application/xhtml+xml,application/xml;q=0.9

Accept-Language         fr,en-gb;q=0.7,en;q=0.3

Accept-Encoding         gzip,deflate

Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive              300

 

 

 

@RequestMapping("/displayHeaderInfo.do")

public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,

        @RequestHeader("Keep-Alive") long keepAlive) {

    //...

}

上例中通过映射将相同名字对应的值映射到方法参数中

@RequestHeader 用在Map<String, String>, MultiValueMap<String, String>, or HttpHeaders 中会获得所有的头中的值。

请求中的值包括请求参数,路径变量,请求头,cookie值转化为对应的方法参数类型

 

最近修改的响应内容的缓存

一个@RequestMapping标注的方法可能要去支持最近修改的请求去促进内容的缓存

一个应用就是请求通过计算最近修改时间查看web资源是否发生了变化,状态304没有发生变化

@RequestMapping

public String myHandleMethod(WebRequest webRequest, Model model) {

 

    long lastModified = // 1. application-specific calculation

 

    if (request.checkNotModified(lastModified)) {

        // 2. shortcut exit - no further processing necessary

        return null;

    }

 

    // 3. or otherwise further request processing, actually preparing content

    model.addAttribute(...);

    return "myViewName";

}

 

 

 

@ControllerAdvice通知controllers

方法级别的注解使用,通知实现的类通过路径扫描自动检测相关的实现类;当使用MVC namespace  mvc  java config

 

@ControllerAdvice注解的classes能包含@ExceptionHandler, @InitBinder, and @ModelAttribute 注解的方法

 

// Target all Controllers annotated with @RestController

@ControllerAdvice(annotations = RestController.class)

public class AnnotationAdvice {}

 

// Target all Controllers within specific packages

@ControllerAdvice("org.example.controllers")

public class BasePackageAdvice {}

 

// Target all Controllers assignable to specific classes

@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})

public class AssignableTypesAdvice {}

 

 

 

 

Jackson Serialization View Support

有时能够过滤对象上下文序列化到http响应体中。为了使用这种功能通过springmvc提供的Jackson’s Serialization Views.

@ResponseBody controller方法上使用或者控制方法返回ResponseEntity,简单的在类参数上使用注解@JsonView,指定具体的view类或者要使用的接口

 

@RestController

public class UserController {

 

    @RequestMapping(value = "/user", method = RequestMethod.GET)

    @JsonView(User.WithoutPasswordView.class)

    public User getUser() {

        return new User("eric", "7!jd#h23");

    }

}

 

public class User {

 

    public interface WithoutPasswordView {};

    public interface WithPasswordView extends WithoutPasswordView {};

 

    private String username;

    private String password;

 

    public User() {

    }

 

    public User(String username, String password) {

        this.username = username;

        this.password = password;

    }

 

    @JsonView(WithoutPasswordView.class)

    public String getUsername() {

        return this.username;

    }

 

    @JsonView(WithPasswordView.class)

    public String getPassword() {

        return this.password;

    }

}

 

控制器依赖视图解析,简单的添加序列化的视图类到model

 

@Controller

public class UserController extends AbstractController {

 

    @RequestMapping(value = "/user", method = RequestMethod.GET)

    public String getUser(Model model) {

        model.addAttribute("user", new User("eric", "7!jd#h23"));

        model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);

        return "userView";

    }

}

Jackson JSONP Support

为了使jsonp支持@responseBody标记的或者返回 ResponseEntity的方法,定义一个@ControllerAdvice bean 继承AbstractJsonpResponseBodyAdvice 类。

@ControllerAdvice

public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

 

    public JsonpAdvice() {

        super("callback");

    }

}

 

JSONP自动使得请求有参数(名字为jsoupcallback,这些名字能够自定义通过jsonpParameterNames属性

Asynchronous Request Processing

Spring MVC 3.2 介绍 Servlet 3的异步请求过程,不是返回一个值,一个controller返回java.util.concurrent.Callable,并且产生一个返回结果通过另一线程,同时主要的servlet容器线程被释放,并允许处理其他请求。Spring mvc调用 the callable在另一个线程中(TaskExecutor的帮助),当callable返回时,将请求分派给Servlet容器简单处理callable返回的值,以下是一个例子

@RequestMapping(method=RequestMethod.POST)

public Callable<String> processUpload(final MultipartFile file) {

 

    return new Callable<String>() {

        public String call() throws Exception {

            // ...

            return "someView";

        }

    };

 

}

第二种选择是返回一个DeferredResult的实例。这种情况下返回值也会被一个线程处理,spring mvc并不知道这个线程,比如返回可能是对一个JMS信息事件的响应,一个定时任务等:

@RequestMapping("/quotes")

@ResponseBody

public DeferredResult<String> quotes() {

    DeferredResult<String> deferredResult = new DeferredResult<String>();

    // Save the deferredResult in in-memory queue ...

    return deferredResult;

}

 

// In some other thread...

deferredResult.setResult(data);

}

没有servlet3异步处理特性的了解是很难明白这一点,了解一下基础的事实

ServletRequest通过request.startAsync()的调用使得进入异步的模式。做事的是servlet和一些filters,可以退出,响应依然打开,允许其他线程完成处理

调用后返回异步的上下文,可以供以后异步的处理,例如提供dispatch方法,可以调用来分发请求返回servlet 容器。异步分发类似forward跳转,只是从应用的一个线程到container的另一个线程,然而forward是同步发生在同一个线程中。

ServletRequest可以访问DispatcherType,,可以用来区分servletfilter(在最初的请求处理线程中)

Callable异常请求处理:Controller返回Callable对象;spring mvc开始异常处理提交callabletaskExecutor(不同的线程处理);DispatcherServlet和所有Filter退出请求处理现场,响应依然打开;calalble产生结果,spring 分发请求回到servlet容器;DispatcherServlet再次被调用处理异步产生的结果(处理callable

 

 

Exception Handling for Async Requests

当返回callable时引起异常怎么处理?@ExceptionHandler注解的方法在同一个控制器中或者一个配置的实例HandlerExceptionResolver

当使用DeferredResult时选择它的setErrorResult(Object)方法,提供一个异常或其他对象。用@ExceptionHandler标记的方法在同一个controller或者一个HandlerExceotionResolver实例处理异常

拦截异步请求(Intercept)

一个存在的HandlerInterceptor实现AsyncHandlerInterceptor,提供另外的方法afterConcurrentHandlingStarted。这个方法被调用在异常处理开始之后,初始的请求处理线程退出。可以参考AsyncHandlerInterceptor javadocs

DeferredResult提供其他异步请求生命周期的调用,有方法onTimeout(Runnable),onCompletion(Runnable),分别是在超时或者完成后调用。超时事件可以设置DeferredResult为一些其他值,完成调用是final型,它的结果不能再设置

 

 

处理映射handler mappings

下例示例如何配置一个拦截器

 

<beans>

    <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

        <property name="interceptors">

            <bean class="example.MyInterceptor"/>

        </property>

    </bean>

<beans>

 

HandlerInterceptor拦截请求

<beans>

    <bean id="handlerMapping"

            class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

        <property name="interceptors">

            <list>

                <ref bean="officeHoursInterceptor"/>

            </list>

        </property>

    </bean>

 

    <bean id="officeHoursInterceptor"

            class="samples.TimeBasedAccessInterceptor">

        <property name="openingTime" value="9"/>

        <property name="closingTime" value="18"/>

    </bean>

<beans>

package samples;

 

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

 

    private int openingTime;

    private int closingTime;

 

    public void setOpeningTime(int openingTime) {

        this.openingTime = openingTime;

    }

 

    public void setClosingTime(int closingTime) {

        this.closingTime = closingTime;

    }

 

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,

            Object handler) throws Exception {

        Calendar cal = Calendar.getInstance();

        int hour = cal.get(HOUR_OF_DAY);

        if (openingTime <= hour && hour < closingTime) {

            return true;

        }

        response.sendRedirect("http://host.com/outsideOfficeHours.html");

        return false;

    }

}

任何请求处理被拦截TimeBasedAccessInterceptor,如果当前日期是工作时间之外,用户重定向到静态html页面,只有在规定时间内才能访问

 

解析视图,

两个接口ViewResolver提供视图名和视图的映射,View将请求交给对应的视图技术

 Resolving views with the ViewResolver interface

 

 

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

    <property name="prefix" value="/WEB-INF/jsp/"/>

    <property name="suffix" value=".jsp"/>

</bean>

 

<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">

    <property name="order" value="1"/>

    <property name="location" value="/WEB-INF/views.xml"/>

</bean>

 

<!-- in views.xml -->

 

<beans>

    <bean name="report" class="org.springframework.example.ReportExcelView"/>

</beans>

 

 

重定向view

@RequestMapping(value = "/files/{path}", method = RequestMethod.POST)

public String upload(...) {

    // ...

    return "redirect:files/{path}";

}

 

创建urls

提供创建加密的URI使用UriComponentsBuilder and UriComponents.

 

UriComponents uriComponents = UriComponentsBuilder.fromUriString(

        "http://example.com/hotels/{hotel}/bookings/{booking}").build();

 

URI uri = uriComponents.expand("42", "21").encode().toUri();

Note that UriComponents is immutable and the expand() and encode() operations return new instances if necessary.

You can also expand and encode using individual URI components:

UriComponents uriComponents = UriComponentsBuilder.newInstance()

        .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()

        .expand("42", "21")

        .encode();

 

 

servlet环境中ServletUriComponentsBuilder提供静态工厂方法从servlet 请求中获得可用的url信息

HttpServletRequest request = ...

 

// Re-use host, scheme, port, path and query string

// Replace the "accountId" query param

 

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request)

        .replaceQueryParam("accountId", "{id}").build()

        .expand("123")

        .encode();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


转载于:https://my.oschina.net/iioschina/blog/670595

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值