SpringMVC常用注解

Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、

视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。处理器是你的应用中注解了@Controller和@RequestMapping的类和方法,

Spring为处理器方法提供了极其多样灵活的配置。Spring 3.0以后提供了@Controller注解机制、@PathVariable注解以及一些其他的特性,

你可以使用它们来进行RESTful web站点和应用的开发。

在Spring Web MVC中,你可以使用任何对象来作为命令对象或表单返回对象,而无须实现一个框架相关的接口或基类。Spring的数据绑定非常灵活:比如,

它会把数据类型不匹配当成可由应用自行处理的运行时验证错误,而非系统错误。你可能会为了避免非法的类型转换在表单对象中使用字符串来存储数据,

但无类型的字符串无法描述业务数据的真正含义,并且你还需要把它们转换成对应的业务对象类型。有了Spring的验证机制,意味着你再也不需这么做了,

并且直接将业务对象绑定到表单对象上通常是更好的选择。

Spring的视图解析也是设计得异常灵活。控制器一般负责准备一个Map模型、填充数据、返回一个合适的视图名等,同时它也可以直接将数据写到响应流中。

视图名的解析高度灵活,支持多种配置,包括通过文件扩展名、Accept内容头、bean、配置文件等的配置,甚至你还可以自己实现一个视图解析器ViewResolver。

模型(MVC中的M,model)其实是一个Map类型的接口,彻底地把数据从视图技术中抽象分离了出来。你可以与基于模板的渲染技术直接整合,

如JSP、Velocity和Freemarker等,或者你还可以直接生成XML、JSON、Atom以及其他多种类型的内容。Map模型会简单地被转换成合适的格式,

比如JSP的请求属性(attribute),一个Velocity模板的模型等。

1 @Controller

@Controller注解可以认为是被标注类的原型(stereotype),表明了这个类所承担的角色。

分派器(DispatcherServlet)会扫描所有注解了@Controller的类,检测其中通过@RequestMapping注解配置的方法

2 @RequestMapping

你可以使用@RequestMapping注解来将请求URL,如/appointments等,映射到整个类上或某个特定的处理器方法上。一般来说,

类级别的注解负责将一个特定(或符合某种模式)的请求路径映射到一个控制器上,

同时通过方法级别的注解来细化映射,即根据特定的HTTP请求方法(“GET”“POST”方法等)、HTTP请求中是否携带特定参数等条件,将请求映射到匹配的方法上。

例如:

@Controller

@RequestMapping("/appointments")

public class AppointmentsController {

private final AppointmentBook appointmentBook;

@Autowired

public AppointmentsController(AppointmentBook appointmentBook) {

this.appointmentBook = appointmentBook;

}

@RequestMapping(method = RequestMethod.GET)

public Map get() {

return appointmentBook.getAppointmentsForToday();

}

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

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

return appointmentBook.getAppointmentsForDay(day);

}

@RequestMapping(path = "/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注解。第一次使用点是作用于类级别的,它指示了所有/appointments开头的路径都会被映射到控制器下。

get()方法上的@RequestMapping注解对请求路径进行了进一步细化:它仅接受GET方法的请求。这样,一个请求路径为/appointments、HTTP方法为GET的请求,

将会最终进入到这个方法被处理。add()方法也做了类似的细化,而getNewForm()方法则同时注解了能够接受的请求的HTTP方法和路径。这种情况下,

一个路径为appointments/new、HTTP方法为GET的请求将会被这个方法所处理。getForDay()方法则展示了使用@RequestMapping注解的另一个技巧:URI模板。

2.1 URI模板

URI模板是一个类似于URI的字符串,只不过其中包含了一个或多个的变量名。当你使用实际的值去填充这些变量名的时候,模板就退化成了一个URI。

在URI模板的RFC提议中定义了一个URI是如何进行参数化的。比如说,一个这个URI模板http://www.example.com/users/{userId}就包含了一个变量名userId。

将值fred赋给这个变量名后,它就变成了一个URI:http://www.example.com/users/fred

2.2 @PathVariable

在Spring MVC中你可以在方法参数上使用@PathVariable注解,将其与URI模板中的参数绑定起来:

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

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

Owner owner = ownerService.findOwner(ownerId);

model.addAttribute("owner", owner);

return "displayOwner";

}

URI模板"/owners/{ownerId}"指定了一个变量,名为ownerId。当控制器处理这个请求的时候,ownerId的值就会被URI模板中对应部分的值所填充。

比如说,如果请求的URI是/owners/fred,此时变量ownerId的值就是fred.

2.2.1 为了处理@PathVariables注解,Spring MVC必须通过变量名来找到URI模板中相对应的变量。你可以在注解中直接声明:

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

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

// 具体的方法代码…

}

或者,如果URI模板中的变量名与方法的参数名是相同的,则你可以不必再指定一次。只要你在编译的时候留下debug信息,Spring MVC就可以自动匹配URL模板中与方法参数名相同的变量名。

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

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

// 具体的方法代码…

}

2.2.2 一个方法可以拥有任意数量的@PathVariable注解:

@RequestMapping(path="/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";

}

2.2.3 URI模板可以从类级别和方法级别的 @RequestMapping 注解获取数据。因此,像这样的findPet()方法可以被类似于/owners/42/pets/21这样的URL路由并调用到:

@Controller

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

public class RelativePathUriTemplateController {

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

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

// 方法实现体这里忽略

}

}

2.3 带正则表达式的URI模板

有时候你可能需要更准确地描述一个URI模板的变量,比如说这个URL:"/spring-web/spring-web-3.0.5.jar。你要怎么把它分解成几个有意义的部分呢?

@RequestMapping注解支持你在URI模板变量中使用正则表达式。语法是{varName:regex},其中第一部分定义了变量名,第二部分就是你所要应用的正则表达式。比如下面的代码样例:

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

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

// 代码部分省略...

}

}

2.4 Path Patterns

除了URI模板外,@RequestMapping注解还支持Ant风格的路径模式(如/myPath/*.do等)。不仅如此,还可以把URI模板变量和Ant风格

的glob组合起来使用(比如/owners/*/pets/{petId}这样的用法等)。

2.5 路径样式的匹配(Path Pattern Comparison)

2.5.1 当一个URL同时匹配多个模板(pattern)时,我们将需要一个算法来决定其中最匹配的一个。

2.5.2 URI模板变量的数目和通配符数量的总和最少的那个路径模板更准确。举个例子,/hotels/{hotel}/*这个路径拥有一个URI变量和一个通配符,

而/hotels/{hotel}/**这个路径则拥有一个URI变量和两个通配符,因此,我们认为前者是更准确的路径模板。

2.5.3 如果两个模板的URI模板数量和通配符数量总和一致,则路径更长的那个模板更准确。举个例子,/foo/bar*就被认为比/foo/*更准确,因为前者的路径更长。

2.5.4 如果两个模板的数量和长度均一致,则那个具有更少通配符的模板是更加准确的。比如,/hotels/{hotel}就比/hotels/*更精确。

2.5.5 默认的通配模式/**比其他所有的模式都更“不准确”。比方说,/api/{a}/{b}/{c}就比默认的通配模式/**要更准确

2.5.6 前缀通配(比如/public/**)被认为比其他任何不包括双通配符的模式更不准确。比如说,/public/path3/{a}/{b}/{c}就比/public/**更准确

2.6 带占位符的路径模式(path patterns)

@RequestMapping注解支持在路径中使用占位符,以取得一些本地配置、系统配置、环境变量等。这个特性有时很有用,比如说控制器的映射路径需要通过配置来定制的场景。

如果想了解更多关于占位符的信息,可以参考PropertyPlaceholderConfigurer这个类的文档。

2.7 后缀模式匹配(Suffix Pattern Matching)

Spring MVC默认采用".*"的后缀模式匹配来进行路径匹配,因此,一个映射到/person路径的控制器也会隐式地被映射到/person.*。

这使得通过URL来请求同一资源文件的不同格式变得更简单(比如/person.pdf,/person.xml)。

你可以关闭默认的后缀模式匹配,或者显式地将路径后缀限定到一些特定格式上for content negotiation purpose。我们推荐这样做,

这样可以减少映射请求时可以带来的一些二义性,比如请求以下路径/person/{id}时,路径中的点号后面带的可能不是描述内容格式,

比如/person/joe@email.com vs /person/joe@email.com.json。而且正如下面马上要提到的,后缀模式通配以及内容协商有时可能会被黑客用来进行攻击,

因此,对后缀通配进行有意义的限定是有好处的。

2.8 矩阵变量

使用 @MatrixVariable 注解

2.8.1 原来的URI规范RFC 3986中允许在路径段落中携带键值对,但规范没有明确给这样的键值对定义术语。有人叫“URI路径参数”,也有叫“矩阵URI”的。

后者是Tim Berners-Lee首先在其博客中提到的术语,被使用得要更加频繁一些,知名度也更高些。而在Spring MVC中,我们称这样的键值对为矩阵变量。

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

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

public void findPet(

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

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

// q1 == 11

// q2 == 22

}

2.8.2 如果要允许矩阵变量的使用,你必须把RequestMappingHandlerMapping类的removeSemicolonContent属性设置为false。该值默认是true的。

MVC的Java编程配置和命名空间配置都提供了启用矩阵变量的方式。

如果你是使用Java编程的方式,“MVC Java高级定制化配置”一节描述了如何对RequestMappingHandlerMapping进行定制。

而使用MVC的命名空间配置时,你可以把元素下的enable-matrix-variables属性设置为true。该值默认情况下是配置为false的。

2.9 可消费的媒体类型

你可以指定一组可消费的媒体类型,缩小映射的范围。这样只有当请求头中 Content-Type 的值与指定可消费的媒体类型中有相同的时候,请求才会被匹配。比如下面这个例子:

@Controller

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

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

// 方法实现省略

}

指定可消费媒体类型的表达式中还可以使用否定,比如,可以使用 !text/plain 来匹配所有请求头 Content-Type 中不含 text/plain 的请求。

同时,在MediaType类中还定义了一些常量,比如APPLICATION_JSON_VALUE、APPLICATION_JSON_UTF8_VALUE等,推荐更多地使用它们。

@Controller

@RequestMapping(path = "/pets", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)

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

// 方法实现省略

}

consumes 属性提供的是方法级的类型支持。与其他属性不同,当在类型级使用时,方法级的消费类型将覆盖类型级的配置,而非继承关系。

2.10 可生产的媒体类型

你可以指定一组可生产的媒体类型,缩小映射的范围。这样只有当请求头中 Accept 的值与指定可生产的媒体类型中有相同的时候,请求才会被匹配。

而且,使用 produces 条件可以确保用于生成响应(response)的内容与指定的可生产的媒体类型是相同的。举个例子:

@Controller

@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)

@ResponseBody

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

// 方法实现省略

}

produces 属性提供的是方法级的类型支持。与其他属性不同,当在类型级使用时,方法级的消费类型将覆盖类型级的配置,而非继承关系。

2.11 请求参数与请求头的值

你可以筛选请求参数的条件来缩小请求匹配范围,比如"myParam"、"!myParam"及"myParam=myValue"等。前两个条件用于筛选存在/不存在某些请求参数的请求,

第三个条件筛选具有特定参数值的请求。下面有个例子,展示了如何使用请求参数值的筛选条件:

@Controller

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

public class RelativePathUriTemplateController {

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

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

// 实际实现省略

}

}

同样,你可以用相同的条件来筛选请求头的出现与否,或者筛选出一个具有特定值的请求头:

@Controller

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

public class RelativePathUriTemplateController {

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

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

// 方法体实现省略

}

}

3 定义@RequestMapping注解的处理方法(handler method)

3.1 使用@RequestParam将请求参数绑定至方法参数

@Controller

@RequestMapping("/pets")

@SessionAttributes("pet")

public class EditPetForm {

// ...

@RequestMapping(method = RequestMapping.GET)

public String setupForm(@RequestParam("petId") int petId, ModelMap model) {

Pet pet = this.clinic.loadPet(petId);

model.addAttribute("pet", pet);

return "petForm";

}

// ,..

}

若参数使用了该注解,则该参数默认是必须提供的,但你也可以把该参数标注为非必须的:只需要将@RequestParam注解的required属性设置为false即可(比如,@RequestParam(path="id", required=false))。

若所注解的方法参数类型不是String,则类型转换会自动地发生。详见"方法参数与类型转换"一节

若@RequestParam注解的参数类型是Map或者MultiValueMap,则该Map中会自动填充所有的请求参数。

3.2 使用@RequestBody注解映射请求体

方法参数中的@RequestBody注解暗示了方法参数应该被绑定了HTTP请求体的值。举个例子:

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

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

writer.write(body);

}

3.3 使用@ResponseBody注解映射响应体

@ResponseBody注解与@RequestBody注解类似。@ResponseBody注解可被应用于方法上,标志该方法的返回值应该被直接写回到HTTP响应体中去(而不会被被放置到Model中或被解释为一个视图名)。举个例子:

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

@ResponseBody

public String helloWorld() {

return "Hello World"

}

上面的代码结果是文本Hello World将被写入HTTP的响应流中。

与@RequestBody注解类似,Spring使用了一个HttpMessageConverter来将返回对象转换到响应体中。

3.4 使用@RestController注解创建REST控制器

当今让控制器实现一个REST API是非常常见的,这种场景下控制器只需要提供JSON、XML或其他自定义的媒体类型内容即可。

你不需要在每个@RequestMapping方法上都增加一个@ResponseBody注解,更简明的做法是,给你的控制器加上一个@RestController的注解。

@RestController是一个原生内置的注解,它结合了@ResponseBody与@Controller注解的功能。

3.5 对方法使用@ModelAttribute注解

@ModelAttribute注解可被应用在方法或方法参数上

3.5.1 被注解于方法上时的用法

注解在方法上的@ModelAttribute说明了方法的作用是用于添加一个或多个属性到model上。这样的方法能接受与@RequestMapping注解相同的参数类型,

只不过不能直接被映射到具体的请求上。在同一个控制器中,注解了@ModelAttribute的方法实际上会在@RequestMapping方法之前被调用。以下是几个例子:

// 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表单渲染所需要的命令对象,比如Account等。

留意@ModelAttribute方法的两种风格。在第一种写法中,方法通过返回值的方式默认地将添加一个属性;在第二种写法中,方法接收一个Model对象,

然后可以向其中添加任意数量的属性。你可以在根据需要,在两种风格中选择合适的一种。

一个控制器可以拥有数量不限的@ModelAttribute方法。同个控制器内的所有这些方法,都会在@RequestMapping方法之前被调用。

@ModelAttribute方法也可以定义在@ControllerAdvice注解的类中,并且这些@ModelAttribute可以同时对许多控制器生效。具体的信息可以参考使用@ControllerAdvice辅助控制器。

属性名没有被显式指定的时候又当如何呢?在这种情况下,框架将根据属性的类型给予一个默认名称。举个例子,若方法返回一个Account类型的对象,

则默认的属性名为"account"。你可以通过设置@ModelAttribute注解的值来改变默认值。当向Model中直接添加属性时,请使用合适的重载方法addAttribute(..)-即,带或不带属性名的方法。

@ModelAttribute注解也可以被用在@RequestMapping方法上。这种情况下,@RequestMapping方法的返回值将会被解释为model的一个属性,而非一个视图名

3.5.2 在方法参数上使用@ModelAttribute注解

注解在方法参数上的@ModelAttribute说明了该方法参数的值将由model中取得。如果model中找不到,那么该参数会先被实例化,然后被添加到model中。

在model中存在以后,请求中所有名称匹配的参数都会填充到该参数中。这在Spring MVC中被称为数据绑定,一个非常有用的特性,节约了你每次都需要手动从表格数据中转换这些字段数据的时间。

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

public String processSubmit(@ModelAttribute Pet pet) { }

以上面的代码为例,这个Pet类型的实例可能来自哪里呢?有几种可能:

它可能因为@SessionAttributes注解的使用已经存在于model中——详见"在请求之间使用@SessionAttributes注解,使用HTTP会话保存模型数据"一节

它可能因为在同个控制器中使用了@ModelAttribute方法已经存在于model中——正如上一小节所叙述的

它可能是由URI模板变量和类型转换中取得的(下面会详细讲解)

它可能是调用了自身的默认构造器被实例化出来的

@ModelAttribute方法常用于从数据库中取一个属性值,该值可能通过@SessionAttributes注解在请求中间传递。在一些情况下,使用URI模板变量和类型转换的方式来取得一个属性是更方便的方式。这里有个例子:

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

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

}

上面这个例子中,model属性的名称("account")与URI模板变量的名称相匹配。如果你配置了一个可以将String类型的账户值转换成Account类型实例的转换器Converter,那么上面这段代码就可以工作的很好,而不需要再额外写一个@ModelAttribute方法。

下一步就是数据的绑定。WebDataBinder类能将请求参数——包括字符串的查询参数和表单字段等——通过名称匹配到model的属性上。

成功匹配的字段在需要的时候会进行一次类型转换(从String类型到目标字段的类型),然后被填充到model对应的属性中。

如何在控制器层来定制数据绑定的过程,在这一节 "定制WebDataBinder的初始化"中提及。

进行了数据绑定后,则可能会出现一些错误,比如没有提供必须的字段、类型转换过程的错误等。若想检查这些错误,

可以在注解了@ModelAttribute的参数紧跟着声明一个BindingResult参数:

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

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

if (result.hasErrors()) {

return "petForm";

}

// ...

}

拿到BindingResult参数后,你可以检查是否有错误。有时你可以通过Spring的表单标签来在同一个表单上显示错误信息。

BindingResult被用于记录数据绑定过程的错误,因此除了数据绑定外,你还可以把该对象传给自己定制的验证器来调用验证。

这使得数据绑定过程和验证过程出现的错误可以被搜集到一处,然后一并返回给用户:

@RequestMapping(path = "/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";

}

// ...

}

又或者,你可以通过添加一个JSR-303规范的@Valid注解,这样验证器会自动被调用。

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

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

if (result.hasErrors()) {

return "petForm";

}

// ...

}

3.6 使用@SessionAttributes注解,使用HTTP会话保存模型数据

类型级别的@SessionAttributes注解声明了某个特定处理器所使用的会话属性。通常它会列出该类型希望存储到session或converstaion中的model属性名或model的类型名,一般是用于在请求之间保存一些表单数据的bean。

以下的代码段演示了该注解的用法,它指定了模型属性的名称

@Controller

@RequestMapping("/editPet.do")

@SessionAttributes("pet")

public class EditPetForm {

// ...

}

3.7 使用"application/x-www-form-urlencoded"数据

对于不是使用的浏览器的客户端,我们也推荐使用这个注解来处理请求。但当请求是一个HTTP PUT方法的请求时,有一个事情需要注意。

浏览器可以通过HTTP的GET方法或POST方法来提交表单数据,非浏览器的客户端还可以通过HTTP的PUT方法来提交表单。这就设计是个挑战,

因为在Servlet规范中明确规定,ServletRequest.getParameter*()系列的方法只能支持通过HTTP POST方法的方式提交表单,而不支持HTTP PUT的方式。

为了支持HTTP的PUT类型和PATCH类型的请求,Spring的spring-web模块提供了一个过滤器HttpPutFormContentFilter。你可以在web.xml文件中配置它:

httpPutFormFilter

org.springframework.web.filter.HttpPutFormContentFilter

httpPutFormFilter

dispatcherServlet

dispatcherServlet

org.springframework.web.servlet.DispatcherServlet

上面的过滤器将会拦截内容类型(content type)为application/x-www-form-urlencoded、HTTP方法为PUT或PATCH类型的请求,然后从请求体中读取表单数据,

把它们包装在ServletRequest中。这是为了使表单数据能够通过ServletRequest.getParameter*()系列的方法来拿到。

因为HttpPutFormContentFilter会消费请求体的内容,因此,它不应该用于处理那些依赖于其他application/x-www-form-urlencoded转换器的PUT和PATCH请求,

这包括了@RequestBodyMultiValueMap和HttpEntity>。

3.8 使用@CookieValue注解映射cookie值

@CookieValue注解能将一个方法参数与一个HTTP cookie的值进行绑定。

看一个这样的场景:以下的这个cookie存储在一个HTTP请求中:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的代码演示了拿到JSESSIONID这个cookie值的方法:

@RequestMapping("/displayHeaderInfo.do")

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

//...

}

若注解的目标方法参数不是String类型,则类型转换会自动进行。

这个注解可以注解到处理器方法上,在Servlet环境和Portlet环境都能使用。

3.9 使用@RequestHeader注解映射请求头属性

@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

以下的代码片段展示了如何取得Accept-Encoding请求头和Keep-Alive请求头的值:

@RequestMapping("/displayHeaderInfo.do")

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

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

//...

}

参考文档:http://7xvpsh.com1.z0.glb.clouddn.com/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容