本文接上一篇文章,介绍@RequestMapping中的headers属性,并进一步研究produces属性以及和它配对的consumes属性。
首先看看讲解用到的类:
- package org.springframework.samples.mvc.simple;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- @Controller
- public class SimpleControllerRevisited {
- @RequestMapping(value="/simple/revisited", method=RequestMethod.GET, headers="Accept=text/plain")
- public @ResponseBody String simple() {
- return "Hello world revisited!";
- }
- }
package org.springframework.samples.mvc.simple; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class SimpleControllerRevisited { @RequestMapping(value="/simple/revisited", method=RequestMethod.GET, headers="Accept=text/plain") public @ResponseBody String simple() { return "Hello world revisited!"; } }
header是HTTP协议中的一个概念,一般翻译成头域,为了不陷入讲解理论的泥潭,我们使用Firefox的firebug看一下header到底是什么,还记得HelloWorld那一篇文章的例子么?访问http://localhost:8080/web/simple,浏览器显示Hello World!,与本例唯一的区别就是@RequestMapping没有加headers, 打开firebug,在"网络"这一栏看到有一行记录URL "GET simple",Status "200 OK",Domain "localhost:8080"等信息,展开,有三列数据,分别为Headers,Response,HTML,看Headers这列,
Request Headers:
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Encoding: gzip, deflate
- Accept-Language: en-us,en;q=0.5
- Connection: keep-alive
- Host: localhost:8080
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: en-us,en;q=0.5 Connection: keep-alive Host: localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Response Headers:
- Content-Length: 12
- Content-Type: text/html
- Server: Jetty(7.2.0.v20101020)
Content-Length: 12 Content-Type: text/html Server: Jetty(7.2.0.v20101020)
Request Headers中有个Accept,它是由浏览器发出的,表示浏览器认为它可以支持的格式,并不是真的只能支持这些格式,而Response Headers中有个Content-Type,这个值是服务端(如Servlet)封装到Respose的Headers中的。
访问例子程序的URL:http://localhost:8080/web/simple/revisited,
Request Headers:
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Encoding: gzip, deflate
- Accept-Language: en-us,en;q=0.5
- Connection: keep-alive
- Host: localhost:8080
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: en-us,en;q=0.5 Connection: keep-alive Host: localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Response Headers:
- Content-Length: 22
- Content-Type: text/plain
- Server: Jetty(7.2.0.v20101020)
Content-Length: 22 Content-Type: text/plain Server: Jetty(7.2.0.v20101020)
Response Headers中的Content-Type变成了text/plain,因为RequestMapping的headers设置了Accept=text/plain。
注意这个Accept和Request Headers中的Accept没有半点关系,它跟Response Headers的Content-Type有关。
我们已经数次提及Content-Type了,其实@RequestMapping的headers属性除了Accept外也有Content-Type:
- @RequestMapping(value="/simple/revisited2", method=RequestMethod.GET, headers="Content-Type=text/plain")
- public @ResponseBody String simple2() {
- return "Hello world 2 revisited!";
- }
@RequestMapping(value="/simple/revisited2", method=RequestMethod.GET, headers="Content-Type=text/plain") public @ResponseBody String simple2() { return "Hello world 2 revisited!"; }
访问http://localhost:8080/web/simple/revisited2,发现浏览器上返回HTTP状态码为415的出错页面:
- HTTP ERROR 415
- Problem accessing /web/simple/revisited2. Reason:
- Unsupported Media Type
- Powered by Jetty://
HTTP ERROR 415 Problem accessing /web/simple/revisited2. Reason: Unsupported Media Type Powered by Jetty://
这是因为headers="Content-Type=text/plain"的含义是
它必须要求Request Headers里的Content-Type为"text/plain"才能执行该方法,
看firebug的Request Headers:
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Encoding: gzip, deflate
- Accept-Language: en-us,en;q=0.5
- Connection: keep-alive
- Host: localhost:8080
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: en-us,en;q=0.5 Connection: keep-alive Host: localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
没有Content-Type属性,不光这个,前面的那个Request Headers也没有Content-Type,其实GET方式访问的URL的Request Header里压根就没有Content-Type(我原来也不知道,直到我搜索到了这篇文章)! 所以我们只能使用POST方式测试这个特性,很遗憾,我暂时没有找到如何通过浏览器地址栏的方式来POST提交,但是,想到了上一篇文章附录中的RestTemplate,可以写个Java小程序模拟一下,在SimpleControllerRevisited中增加一个方法:
- @RequestMapping(value="/simple/revisited3", method=RequestMethod.POST, headers="Content-Type=text/plain")
- public @ResponseBody String simple3() {
- return "Hello world 3 revisited!";
- }
@RequestMapping(value="/simple/revisited3", method=RequestMethod.POST, headers="Content-Type=text/plain") public @ResponseBody String simple3() { return "Hello world 3 revisited!"; }
写个RestTemplate的小程序:
- package org.springframework.samples.mvc.simple;
- import org.springframework.http.HttpStatus;
- import org.springframework.http.MediaType;
- import org.springframework.http.ResponseEntity;
- import org.springframework.web.client.RestTemplate;
- public class SimpleControllerRevisitedTest {
- public static void main(String[] args) {
- testPost();
- }
- public static void testPost() {
- RestTemplate template = new RestTemplate();
- ResponseEntity<String> entity = template.postForEntity(
- "http://localhost:8080/web/simple/revisited3", null, String.class);
- String body = entity.getBody();
- MediaType contentType = entity.getHeaders().getContentType();
- System.out.println("contentType:[" + contentType + "]");
- HttpStatus statusCode = entity.getStatusCode();
- System.out.println("statusCode:[" + statusCode + "]");
- }
- }
package org.springframework.samples.mvc.simple; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; public class SimpleControllerRevisitedTest { public static void main(String[] args) { testPost(); } public static void testPost() { RestTemplate template = new RestTemplate(); ResponseEntity<String> entity = template.postForEntity( "http://localhost:8080/web/simple/revisited3", null, String.class); String body = entity.getBody(); MediaType contentType = entity.getHeaders().getContentType(); System.out.println("contentType:[" + contentType + "]"); HttpStatus statusCode = entity.getStatusCode(); System.out.println("statusCode:[" + statusCode + "]"); } }
执行,报错:
- DEBUG: org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/web/simple/revisited3"
- DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*]
- WARN : org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/web/simple/revisited3" resulted in 415 (Unsupported Media Type); invoking error handler
- Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
- at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76)
- at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
- at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
- at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
- at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:302)
- at org.springframework.samples.mvc.simple.SimpleControllerRevisitedTest.testPost(SimpleControllerRevisitedTest.java:16)
- at org.springframework.samples.mvc.simple.SimpleControllerRevisitedTest.main(SimpleControllerRevisitedTest.java:11)
DEBUG: org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/web/simple/revisited3" DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*] WARN : org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/web/simple/revisited3" resulted in 415 (Unsupported Media Type); invoking error handler Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76) at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401) at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:302) at org.springframework.samples.mvc.simple.SimpleControllerRevisitedTest.testPost(SimpleControllerRevisitedTest.java:16) at org.springframework.samples.mvc.simple.SimpleControllerRevisitedTest.main(SimpleControllerRevisitedTest.java:11)
还是报415 Unsupported Media Type,
这说明Content-Type并不是text-plain,那么到底是什么呢?新写一个方法,去掉headers属性,仅保留POST:
- @RequestMapping(value="/simple/revisited4", method=RequestMethod.POST)
- public @ResponseBody String simple4() {
- return "Hello world 4 revisited!";
- }
@RequestMapping(value="/simple/revisited4", method=RequestMethod.POST) public @ResponseBody String simple4() { return "Hello world 4 revisited!"; }
将SimpleControllerRevisitedTest中的URL改为http://localhost:8080/web/simple/revisited4, 查看服务端打印的日志(注意访问前一个URL时,服务端是不打印此日志的,因为Request Header中的Content-Type就不满足要求,直接拒掉了):
- DEBUG: org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Reading [[B] as "application/x-www-form-urlencoded" using [org.springframework.http.converter.ByteArrayHttpMessageConverter@1d05c9a1]
DEBUG: org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Reading [[B] as "application/x-www-form-urlencoded" using [org.springframework.http.converter.ByteArrayHttpMessageConverter@1d05c9a1]
发现使用POST方式,Request Headers中的Content-Type为"application/x-www-form-urlencoded",
那么再增加一个方法:
- @RequestMapping(value="/simple/revisited5", method=RequestMethod.POST, headers="Content-Type=application/x-www-form-urlencoded")
- public @ResponseBody String simple5() {
- return "Hello world 5 revisited!";
- }
@RequestMapping(value="/simple/revisited5", method=RequestMethod.POST, headers="Content-Type=application/x-www-form-urlencoded") public @ResponseBody String simple5() { return "Hello world 5 revisited!"; }
将SimpleControllerRevisitedTest中的URL改为http://localhost:8080/web/simple/revisited5,
- DEBUG: org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/web/simple/revisited5"
- DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*]
- DEBUG: org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/web/simple/revisited5" resulted in 200 (OK)
- DEBUG: org.springframework.web.client.RestTemplate - Reading [java.lang.String] as "text/plain;charset=ISO-8859-1" using [org.springframework.http.converter.StringHttpMessageConverter@5f326484]
- contentType:[text/plain;charset=ISO-8859-1]
- statusCode:[200]
DEBUG: org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/web/simple/revisited5" DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*] DEBUG: org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/web/simple/revisited5" resulted in 200 (OK) DEBUG: org.springframework.web.client.RestTemplate - Reading [java.lang.String] as "text/plain;charset=ISO-8859-1" using [org.springframework.http.converter.StringHttpMessageConverter@5f326484] contentType:[text/plain;charset=ISO-8859-1] statusCode:[200]
从程序运行结果看,一切OK(注意不要被这个日志中的contentType弄混了,这个contentType是Response的Headers里的)。
总结一下,@RequestMapping中的headers有两种写法,
一种是:headers="Accept=text/plain",
另一种是:headers="Content-Type=application/x-www-form-urlencoded",
Accept指定的格式为Response Headers的Content-Type的格式,
Content-Type指定的格式为Reqeust Headers必须要满足的格式,
否则将被SpringMVC直接拒绝掉,并返回415的HTTP状态码。
大家可能会想,@RequestMapping的headers属性搞这么复杂干嘛?Spring团队应该是听到了社区群众的呼声,或者他们自己都觉得晕?因此在Spring 3.1 M2发布的时候,他们做了改进,SpringSource的Team Blog上有一篇文章 SPRING 3.1 M2: SPRING MVC ENHANCEMENTS,说道了Spring 3.1 M2版本针对以前版本的编程模型改进(programming model improvement),将第四点和第五点简而言之就是:
@RequestMapping中
headers="Content-Type=application/json"被consumes="application/json"替换了,
headers="Accept=application/json"被produces="application/json"替换了。
现在应该对上一篇文章中,我写道
理解了,任何一个框架都是不断的在发展和完善的,如果能在学习的过程中,知道一点框架的变迁史,将会对我们的理解产生莫大的好处。
相关推荐
在Java Web开发中,Spring MVC框架是一个非常流行的用于构建企业级应用的模型-视图-控制器(MVC)架构。这个压缩包“Spring MVC 文件上传下载 后端 - Java.zip”很可能包含了关于如何在Spring MVC中实现文件上传和...
Spring Web MVC是Spring框架的核心组件之一,它为构建基于Java的Web应用程序提供了模型-视图-控制器(MVC)架构。本篇将深入探讨Spring Web MVC的重要概念、工作原理以及实际应用。 一、Spring MVC概述 Spring MVC...
Spring MVC 是一个强大的Java Web开发框架,用于构建可维护、高性能和灵活的Web应用程序。它在Spring框架的基础上,为处理HTTP请求提供了模型-视图-控制器(MVC)架构。在Spring MVC中实现文件的上传和下载是常见的...
在Spring MVC框架中,Ajax(Asynchronous JavaScript and XML)是一种常用的技术,用于在不刷新整个页面的情况下与服务器进行异步通信。本章将探讨如何在Spring MVC中集成和使用Ajax,以及涉及的上传和下载功能,...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。在本教程中,我们将深入探讨 Spring MVC 的核心概念、配置以及如何...
Spring MVC 是一个基于 Java 的模型-视图-控制器(MVC)架构,是 Spring 框架的一部分,用于构建Web应用程序。它提供了丰富的功能,帮助开发者处理HTTP请求、数据绑定、视图渲染等任务,使得开发过程更加简洁高效。...
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。在Spring MVC中,开发者可以利用模型-视图-控制器(MVC)架构模式来分离业务逻辑、数据处理和...
在Spring MVC框架中,文件上传和下载是常见的功能需求,特别是在构建Web应用程序时。这篇博客“spring mvc文件上传下载实例”将引导我们如何在Spring MVC项目中实现这两个功能。 首先,我们需要理解Spring MVC的...
在IT行业中,Spring MVC是一个广泛使用的Java框架,用于构建基于模型-视图-控制器(MVC)模式的Web应用程序。本文将深入探讨Spring MVC在文件上传和下载方面的应用,以及如何结合FineUploader和jQuery实现这一功能。...
在Spring MVC框架中,文件上传是一项常见的功能,它允许用户通过Web表单上传文件到服务器。Spring MVC通过集成Apache Commons FileUpload库实现了这一功能。在本文中,我们将深入探讨如何配置和使用Spring MVC进行...
在现代Web开发中,Spring MVC和ExtJS是两个常见的技术,用于构建强大的后端和前端应用。本篇文章将深入探讨如何使用Spring MVC 3与ExtJS进行数据交互,特别是通过JSON格式来实现这一过程。 首先,Spring MVC 3引入...
Spring MVC 是一个强大的Java Web开发框架,用于构建高效、可维护的Web应用程序。在这个主题中,我们将深入探讨Spring MVC如何支持文件的上传和下载功能,这对于任何交互式Web应用都是必不可少的部分。 首先,让...
Spring MVC 是一个基于Java的轻量级Web应用框架,它为构建Web应用程序提供了一种模型-视图-控制器(MVC)的编程模型。在Spring MVC中,DispatcherServlet扮演着核心角色,它作为整个Web应用的前端控制器,负责接收...
在实际开发中,通常会结合使用`@RequestMapping`和其他注解,如`@ControllerAdvice`(全局异常处理)、`@ResponseBody`(将方法返回值直接转换为HTTP响应体)等,构建出功能丰富的Spring MVC应用程序。 通过理解并...
在Spring MVC框架中,集成测试是确保应用程序各个组件协同工作的关键步骤。`Rest Assured`和`MockMvc`是两种常用的工具,它们可以帮助开发者高效地完成这个任务。本篇文章将详细探讨如何使用这两个库进行Spring MVC...
Spring MVC 是一个强大的Java web开发框架,用于构建可维护、模块化且松散耦合的Web应用程序。在Spring MVC中,文件的上传和下载是常见的功能需求,这涉及到客户端与服务器之间的数据传输。本篇文章将深入探讨Spring...
在`pom.xml`文件中添加Spring Web依赖,因为CORS功能是基于Spring MVC的: ```xml <groupId>org.springframework.boot <artifactId>spring-boot-starter-web ``` 2. 配置CORS: 可以通过两种方式配置...
在IT行业中,Spring MVC是一个广泛使用的Java框架,用于构建Web应用程序。它提供了处理HTTP请求、渲染视图以及处理用户输入的强大功能。在这个场景下,我们关注的是Spring MVC如何实现文件的上传与下载功能,这对于...
Spring Boot以其简洁的配置和强大的功能集深受开发者喜爱,它简化了开发过程,特别是对于构建RESTful API和Web服务。以下是你需要了解的关键知识点: 1. **Spring Boot基础知识**: - Spring Boot是Spring框架的...