java中当model实体类类继承一个basemodel类时,使用@ResponseBody 解析失败,怎么处理

springmvc(6)
转自:http://blog.csdn.net/fw0124/article/details/
Spring3.1开始使用新的HandlerMapping 和 HandlerAdapter 来支持@Contoller 和@RequestMapping注解处理:处理器映射RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter组合来代替Spring2.5 开始的处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter。
HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain 对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象;
HandlerAdapter:HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。
配合@ResponseBody注解,以及HTTP Request Header中的Accept属性,Controller返回的对象可以自动被转换成对应的XML或者JSON数据。
先看一个例子,只需要简单的几步,就可以返回XML数据。(本文使用版本 4.1.6,并使用maven做项目构建)
1)在配置文件中添加
2)添加以下几个java类
3) 在Eclipse中使用Jetty插件启动Web Server,然后在浏览器中访问:
非常简单!Spring是怎么实现这个转换的呢?我们先了解下Spring的消息转换机制。
在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。
我们可以用下面的图,简单描述一下这个过程。
这里最关键的就是&mvc:annotation-driven/&,加了这句配置,Spring会调用org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser来解析。
在这个类的parse(Element, ParserContext)方法中,分别实例化了RequestMappingHandlerMapping,RequestMappingHandlerAdapter等诸多类。
RequestMappingHandlerAdapter是请求处理的适配器,我们重点关注它的messageConverters属性。
1)RequestMappingHandlerAdapter在调用handle()的时候,会委托给ServletInvocableHandlerMethod的invokeAndHandle()方法进行处理,这个方法又调用HandlerMethodReturnValueHandlerComposite类进行处理。
HandlerMethodReturnValueHandlerComposite维护了一个HandlerMethodReturnValueHandler列表。
由于我们使用了@ResponseBody注解,getReturnValueHandler就会返回RequestResponseBodyMethodProcessor的实例。
2)之后RequestResponseBodyMethodProcessor.handleReturnValue()方法会被调用。此方法会调用AbstractMessageConverterMethodProcessor.writeWithMessageConverters()。它会根据request header中的Accept属性来选择合适的message converter.
3)&messageConverters中有如下的6个converter. 它们是从哪里来的呢?前面提到,AnnotationDrivenBeanDefinitionParser.parse(Element, ParserContext)方法中,分别实例化了RequestMappingHandlerMapping,RequestMappingHandlerAdapter以及messageConverters属性。
需要关注org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter这个类,就是它实现了返回对象到XML的转换。
4)看一下getMessageConverters()中的处理。有5个message converter是一定会加进来的。
然后再看,这里jaxb2Present为true, 因此Jaxb2RootElementHttpMessageConverter被添加到messageConverters中。
5)看一下jaxb2Present的定义,原来javax.xml.bind.Binder这个类是JDK中包含的类,所以jaxb2Present=true。
6)我们看一下Jaxb2RootElementHttpMessageConverter的canWrite()方法。返回true的条件有两个
a) 返回对象的类具有XmlRootElement注解;
b) 请求头中的Accept属性包含application/xml。
7) 在chrome中打开开发者工具,可以看到请求头中确实包含了Accept=application/xml
接下来我们看看如果想要返回JSON数据,应该怎么做?
根据上面的分析,首先我们需要添加一个支持JSON的message converter. 前面分析getMessageConverters()代码的时候,看到
然后再来看看jackson2Present和gsonPresent的定义。
所以我们只要把Jackson2或者GSON加入工程的class path,Spring就会自动把GsonHttpMessageConverter加进来。
1)我们在POM中添加以下依赖
2)在XmlOrJsonController.java中添加getEmployeeJson()方法
和getEmployeeXml()相比,这里唯一的不同是返回对象变成了Employee,因为Employee类上没有@XmlRootElement注解,所以Spring不会选择Jaxb2RootElementHttpMessageConverter。又因为Accept属性中包含了*/*,表示接受任意格式返回数据,所以GsonHttpMessageConverter的canWrite()方法返回true.这样Spring就会选择MappingJackson2HttpMessageConverter或者GsonHttpMessageConverter来进行数据转换。
至此,我们知道请求头中的Accept属性是一个很关键的东西,我们可以根据这个在Controller中写一个方法,根据Accept的值自动返回XML或者JSON数据。
因为浏览器的Accept值不方便修改,我们自己写客户端来调用。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14163次
排名:千里之外
原创:23篇
转载:33篇
(1)(3)(1)(2)(2)(2)(7)(7)(1)(2)(5)(12)(11)springMVC(3)
Spring3.1开始使用新的HandlerMapping 和 HandlerAdapter 来支持@Contoller 和@RequestMapping注解处理:处理器映射RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter组合来代替Spring2.5 开始的处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter。
HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain 对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象;
HandlerAdapter:HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。
配合@ResponseBody注解,以及HTTP Request Header中的Accept属性,Controller返回的对象可以自动被转换成对应的XML或者JSON数据。
先看一个例子,只需要简单的几步,就可以返回XML数据。(本文使用版本 4.1.6,并使用maven做项目构建)
1)在配置文件中添加
2)添加以下几个java类
3) 在Eclipse中使用Jetty插件启动Web Server,然后在浏览器中访问:
非常简单!Spring是怎么实现这个转换的呢?我们先了解下Spring的消息转换机制。
在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。
我们可以用下面的图,简单描述一下这个过程。
这里最关键的就是&mvc:annotation-driven/&,加了这句配置,Spring会调用org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser来解析。
在这个类的parse(Element, ParserContext)方法中,分别实例化了RequestMappingHandlerMapping,RequestMappingHandlerAdapter等诸多类。
RequestMappingHandlerAdapter是请求处理的适配器,我们重点关注它的messageConverters属性。
1)RequestMappingHandlerAdapter在调用handle()的时候,会委托给ServletInvocableHandlerMethod的invokeAndHandle()方法进行处理,这个方法又调用HandlerMethodReturnValueHandlerComposite类进行处理。
HandlerMethodReturnValueHandlerComposite维护了一个HandlerMethodReturnValueHandler列表。
由于我们使用了@ResponseBody注解,getReturnValueHandler就会返回RequestResponseBodyMethodProcessor的实例。
2)之后RequestResponseBodyMethodProcessor.handleReturnValue()方法会被调用。此方法会调用AbstractMessageConverterMethodProcessor.writeWithMessageConverters()。它会根据request header中的Accept属性来选择合适的message converter.
3)&messageConverters中有如下的6个converter. 它们是从哪里来的呢?前面提到,AnnotationDrivenBeanDefinitionParser.parse(Element, ParserContext)方法中,分别实例化了RequestMappingHandlerMapping,RequestMappingHandlerAdapter以及messageConverters属性。
需要关注org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter这个类,就是它实现了返回对象到XML的转换。
4)看一下getMessageConverters()中的处理。有5个message converter是一定会加进来的。
然后再看,这里jaxb2Present为true, 因此Jaxb2RootElementHttpMessageConverter被添加到messageConverters中。
5)看一下jaxb2Present的定义,原来javax.xml.bind.Binder这个类是JDK中包含的类,所以jaxb2Present=true。
6)我们看一下Jaxb2RootElementHttpMessageConverter的canWrite()方法。返回true的条件有两个
a) 返回对象的类具有XmlRootElement注解;
b) 请求头中的Accept属性包含application/xml。
7) 在chrome中打开开发者工具,可以看到请求头中确实包含了Accept=application/xml
接下来我们看看如果想要返回JSON数据,应该怎么做?
根据上面的分析,首先我们需要添加一个支持JSON的message converter. 前面分析getMessageConverters()代码的时候,看到
然后再来看看jackson2Present和gsonPresent的定义。
所以我们只要把Jackson2或者GSON加入工程的class path,Spring就会自动把GsonHttpMessageConverter加进来。
1)我们在POM中添加以下依赖
2)在XmlOrJsonController.java中添加getEmployeeJson()方法
和getEmployeeXml()相比,这里唯一的不同是返回对象变成了Employee,因为Employee类上没有@XmlRootElement注解,所以Spring不会选择Jaxb2RootElementHttpMessageConverter。又因为Accept属性中包含了*/*,表示接受任意格式返回数据,所以GsonHttpMessageConverter的canWrite()方法返回true.这样Spring就会选择MappingJackson2HttpMessageConverter或者GsonHttpMessageConverter来进行数据转换。
至此,我们知道请求头中的Accept属性是一个很关键的东西,我们可以根据这个在Controller中写一个方法,根据Accept的值自动返回XML或者JSON数据。
因为浏览器的Accept值不方便修改,我们自己写客户端来调用。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:119次
排名:千里之外SpringMVC中出现 400 Bad Request 错误(用@ResponseBody处理aja
今天开发过程中,在SpringMVC中的Action中处理前台ajax请求传过来的json数据直接转成对应的实体类时出错:400 Bad Request,后台也不报错,400指的的是请求无效(
&&&&&&& 今天开发过程中,在SpringMVC中的Action中处理前台ajax请求传过来的json数据直接转成对应的实体类时出错:400 Bad Request,后台也不报错,400指的的是请求无效(请求有语法问题或者不能满足请求),调试了好长时间才解决了,,特意记录下来,并和大家一同分享一下。
&&&&&&&&出现这个错误的原因一般最常见的就是后台的实体类bean与前台穿过的类型不匹配,我的就是,因为的javabean中有定义了Date类型和int类型的成员变量,导致转化器在把json数据转化成bean时不能转化,其实如果用JSONObject.toBean方法转化时,这种情况也会报错的。
&&&&&&&我的解决办法就是把实体类的javabean里边的类型都改成string类型了,在配置SQL语句时用to-date或者to_number转化的。
&&&&&&& 其实还可以在实体类中定义Date和int类型对应的字符串类型成员变量,这样前台的表单中field或者name与之对应上即可,这样也成功转成实体类了,不过转成之后,得在java中把它字符串类型的转成对应的Date或者int类型赋给相应的成员变量即可。
&&&&&&&在就是还有一种方法就是在对应的实体类的对应的非字符串类型的变量的setter方法中传入string类型的,然后在里边用SimpleDateFormat或者Integer进行转化。
&&&&&& 最后还有一种方法比较简单,就是实体类的日期属性上加@DateTimeFormat(pattern=&yyyy-MM-dd&)注解。
&&&&&&&网上我看了一些有关问题,看网友们还有一些其他原因导致这个错误的,特总结归纳了一下方便网友们参考:
1、log4j的配置文件里错误将部分log打为Info级别所致
2、传参数的时候,参数名使用了关键字“name”(我试了试,我的没报错正常)
3、本来要返回json的却忘了加@RequestBody
4、ajax请求的连接后边忘了加参数
5、前台传参时参数的顺序与后台实体类的各个属性的顺序不一致(我试了试,我的顺序改变无影响)
转载请注明―作者:Java我人生(陈磊兴)&&&原文出处:
&&&&&& 最后,认真看过的网友们,大神们,如有感觉我这个程序猿有哪个地方说的不对或者不妥或者你有很好的


你最喜欢的61252人阅读
spring(12)
Java(39)
接上一篇文章讲述处理@RequestMapping的方法参数绑定之后,详细介绍下@RequestBody、@ResponseBody的具体用法和使用时机;同时对曾经看的一篇文章中讲述的某些部分进行澄清 (文章地址:)。
@RequestBody
&&& & i) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
&&& & ii) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
&&& application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);&&& multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);&&& 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
B) PUT方式提交时, 根据request header Content-Type的值来判断:
&&& application/x-www-form-urlencoded, 必须;&&& multipart/form-data, 不能处理;&&& 其他格式, 必须;
说明:request的body部分的数据编码格式由header部分的Content-Type指定;
@ResponseBody
& & & 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:
&&&&& 返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
HttpMessageConverter
* Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
public interface HttpMessageConverter&T& {
* Indicates whether the given class can be read by this converter.
* @param clazz the class to test for readability
* @param mediaType the media type to read, can be {@code null} if not specified.
* Typically the value of a {@code Content-Type} header.
* @return {@code true} {@code false} otherwise
boolean canRead(Class&?& clazz, MediaType mediaType);
* Indicates whether the given class can be written by this converter.
* @param clazz the class to test for writability
* @param mediaType the media type to write, can be {@code null} if not specified.
* Typically the value of an {@code Accept} header.
* @return {@code true} {@code false} otherwise
boolean canWrite(Class&?& clazz, MediaType mediaType);
* Return the list of {@link MediaType} objects supported by this converter.
* @return the list of supported media types
List&MediaType& getSupportedMediaTypes();
* Read an object of the given type form the given input message, and returns it.
* @param clazz the type of object to return. This type must have previously been passed to the
* {@link #canRead canRead} method of this interface, which must have returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
T read(Class&? extends T& clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableE
* Write an given object to the given output message.
* @param t the object to write to the output message. The type of this object must have previously been
* passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param contentType the content type to use when writing. May be {@code null} to indicate that the
* default content type of the converter must be used. If not {@code null}, this media type must have
* previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
* returned {@code true}.
* @param outputMessage the message to write to
* @throws IOException in case of I/O errors
* @throws HttpMessageNotWritableException in case of conversion errors
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableE
该接口定义了四个方法,分别是读取数据时的 canRead(), read() 和 写入数据时的canWrite(), write()方法。
在使用 &mvc:annotation-driven /&标签配置时,默认配置了RequestMappingHandlerAdapter(注意是RequestMappingHandlerAdapter不是AnnotationMethodHandlerAdapter,详情查看Spring 3.1 document
“16.14&Configuring Spring MVC”章节),并为他配置了一下默认的HttpMessageConverter:
ByteArrayHttpMessageConverter converts byte arrays.
StringHttpMessageConverter converts strings.
ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.
SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.
FormHttpMessageConverter converts form data to/from a MultiValueMap&String, String&.
Jaxb2RootElementHttpMessageConverter converts Java objects to/from XML — added if JAXB2 is present on the classpath.
MappingJacksonHttpMessageConverter converts to/from JSON — added if Jackson is present on the classpath.
AtomFeedHttpMessageConverter converts Atom feeds — added if Rome is present on the classpath.
RssChannelHttpMessageConverter converts RSS feeds — added if Rome is present on the classpath.
ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;
StringHttpMessageConverter:&& 负责读取字符串格式的数据和写出二进制格式的数据;
ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;&
FormHttpMessageConverter:&&&&&& 负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
MappingJacksonHttpMessageConverter:& 负责读取和写入json格式的数据;
SouceHttpMessageConverter:&&&&&&&&&&&&&&&&&& 负责读取和写入 xml 中javax.xml.transform.Source定义的数据;
Jaxb2RootElementHttpMessageConverter:& 负责读取和写入xml 标签格式的数据;
AtomFeedHttpMessageConverter:&&&&&&&&&&&&& 负责读取和写入Atom格式的数据;
RssChannelHttpMessageConverter:&&&&&&&&&& 负责读取和写入RSS格式的数据;
当使用@RequestBody和@ResponseBody注解时,RequestMappingHandlerAdapter就使用它们来进行读取或者写入相应格式的数据。
HttpMessageConverter匹配过程:
@RequestBody注解时: 根据Request对象header部分的Content-Type类型,逐一匹配合适的HttpMessageConverter来读取数据;
spring 3.1源代码如下:
private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType)
throws Exception {
MediaType contentType = inputMessage.getHeaders().getContentType();
if (contentType == null) {
StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType()));
String paramName = methodParam.getParameterName();
if (paramName != null) {
builder.append(' ');
builder.append(paramName);
throw new HttpMediaTypeNotSupportedException(
&Cannot extract parameter (& + builder.toString() + &): no Content-Type found&);
List&MediaType& allSupportedMediaTypes = new ArrayList&MediaType&();
if (this.messageConverters != null) {
for (HttpMessageConverter&?& messageConverter : this.messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
if (messageConverter.canRead(paramType, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug(&Reading [& + paramType.getName() + &] as \&& + contentType
+&\& using [& + messageConverter + &]&);
return messageConverter.read(paramType, inputMessage);
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
@ResponseBody注解时: 根据Request对象header部分的Accept属性(逗号分隔),逐一按accept中的类型,去遍历找到能处理的HttpMessageConverter;
源代码如下:
private void writeWithMessageConverters(Object returnValue,
HttpInputMessage inputMessage, HttpOutputMessage outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException {
List&MediaType& acceptedMediaTypes = inputMessage.getHeaders().getAccept();
if (acceptedMediaTypes.isEmpty()) {
acceptedMediaTypes = Collections.singletonList(MediaType.ALL);
MediaType.sortByQualityValue(acceptedMediaTypes);
Class&?& returnValueType = returnValue.getClass();
List&MediaType& allSupportedMediaTypes = new ArrayList&MediaType&();
if (getMessageConverters() != null) {
for (MediaType acceptedMediaType : acceptedMediaTypes) {
for (HttpMessageConverter messageConverter : getMessageConverters()) {
if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
messageConverter.write(returnValue, acceptedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType == null) {
contentType = acceptedMediaT
logger.debug(&Written [& + returnValue + &] as \&& + contentType +
&\& using [& + messageConverter + &]&);
this.responseArgumentUsed =
for (HttpMessageConverter messageConverter : messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
MappingJacksonHttpMessageConverter 调用了 objectMapper.writeValue(OutputStream stream, Object)方法,使用@ResponseBody注解返回的对象就传入Object参数内。若返回的对象为已经格式化好的json串时,不使用@RequestBody注解,而应该这样处理:
1、response.setContentType(&application/ charset=UTF-8&);
2、response.getWriter().print(jsonStr);
直接输出到body区,然后的视图为void。
参考资料:
1、 Spring 3.1 Doc:
spring-3.1.0/docs/spring-framework-reference/html/mvc.html
2、Spring 3.x MVC 入门4 -- @ResponseBody & @RequestBody
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:454175次
积分:3909
积分:3909
排名:第6817名
原创:67篇
转载:52篇
评论:80条
(5)(7)(10)(3)(2)(4)(6)(1)(1)(1)(1)(1)(1)(1)(3)(1)(1)(1)(1)(1)(5)(3)(1)(4)(2)(1)(1)(3)(7)(3)(1)(3)(3)(7)(1)(5)(6)(4)(1)(4)(2)}

我要回帖

更多关于 responsebody 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信