上一篇文章 springMVC源码分析--HttpMessageConverter(二)之参数read操作中我们已经简单介绍了参数值转换的read操作,接下来我们介绍一下返回值的处理操作。同样返回值的操作操作也是在HandlerMethodReturnValueHandler中处理的,可以参考之前的springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)
springmvc读写的过程.png简单的返回值处理示例使用@ResponseBody进行注解:
@ResponseBody
@RequestMapping("/get")
public Object get(){
Product product = new Product();
product.setDescription("hello springMVC RestFul");
product.setId(10);
product.setName("springMVC");
product.setPrice(10);
return product; //在页面中返回json数据
}
这里返回值是一个Product对象,但真正浏览器获取的数据是json数据,处理的过程就是在HttpMessageConverter中实现的 。
配置一下消息处理使用FastJSON处理的配置
普通的spring项目的话,用xml配置
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<array>
<value>text/html;charset=UTF-8</value>
</array>
</property>
<property name="features">
<array>
<value>WriteMapNullValue</value>
<value>WriteNullStringAsEmpty</value>
<!-- 全局关闭循环引用检查,最好是不要关闭,不然有可能会StackOverflowException -->
<!-- <value>DisableCircularReferenceDetect</value> -->
</array>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
如果springboot的话
public class FastJsonHttpMessageConverterEx extends FastJsonHttpMessageConverter{
public FastJsonHttpMessageConverterEx(){
//在这里配置fastjson特性(全局设置的)
FastJsonConfig fastJsonConfig = new FastJsonConfig();
//fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); //自定义时间格式
//fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue); //正常转换null值
//fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); //关闭循环引用
this.setFastJsonConfig(fastJsonConfig);
}
@Override
protected boolean supports(Class<?> clazz) {
return super.supports(clazz);
}
}
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
.....
@Bean
public FastJsonHttpMessageConverterEx fastJsonHttpMessageConverterEx(){
return new FastJsonHttpMessageConverterEx();
}
}
这样返回值的处理操作就是使用FastJsonHttpMessageConverter来进行处理,将返回值转为json数据返回。
返回值的处理是在HandlerMethodReturnValueHandlerComposite中handleReturnValue中实现的。
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
接下来是在子类RequestResponseBodyMethodProcessor的handleReturnValue中处理操作
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
在RequestResponseBodyMethodProcessor的父类AbstractMessageConverterMethodProcessor的writeWithMessageConverters中处理操作
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
this.writeWithMessageConverters(value, returnType, inputMessage, outputMessage);
}
接下来就是通过职责链模式选择HttpMessageConverter的实现类来进行数据转换操作。
会调用converter的write()方法,write()方法又会调用writeInternal()方法
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object outputValue;
Class valueType;
Object declaredType;
if(value instanceof CharSequence) {
outputValue = value.toString();
valueType = String.class;
declaredType = String.class;
} else {
outputValue = value;
valueType = this.getReturnValueType(value, returnType);
declaredType = this.getGenericType(returnType);
}
HttpServletRequest request = inputMessage.getServletRequest();
List requestedMediaTypes = this.getAcceptableMediaTypes(request);
List producibleMediaTypes = this.getProducibleMediaTypes(request, valueType, (Type)declaredType);
if(outputValue != null && producibleMediaTypes.isEmpty()) {
throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
} else {
LinkedHashSet compatibleMediaTypes = new LinkedHashSet();
Iterator mediaTypes = requestedMediaTypes.iterator();
MediaType selectedMediaType;
Iterator var14;
MediaType messageConverter;
while(mediaTypes.hasNext()) {
selectedMediaType = (MediaType)mediaTypes.next();
var14 = producibleMediaTypes.iterator();
while(var14.hasNext()) {
messageConverter = (MediaType)var14.next();
if(selectedMediaType.isCompatibleWith(messageConverter)) {
compatibleMediaTypes.add(this.getMostSpecificMediaType(selectedMediaType, messageConverter));
}
}
}
if(compatibleMediaTypes.isEmpty()) {
if(outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
} else {
ArrayList mediaTypes1 = new ArrayList(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(mediaTypes1);
selectedMediaType = null;
var14 = mediaTypes1.iterator();
while(var14.hasNext()) {
messageConverter = (MediaType)var14.next();
if(messageConverter.isConcrete()) {
selectedMediaType = messageConverter;
break;
}
if(messageConverter.equals(MediaType.ALL) || messageConverter.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if(selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
//匹配消息数据转换器
var14 = this.messageConverters.iterator();
while(var14.hasNext()) {
HttpMessageConverter messageConverter1 = (HttpMessageConverter)var14.next();
if(messageConverter1 instanceof GenericHttpMessageConverter) {
if(((GenericHttpMessageConverter)messageConverter1).canWrite((Type)declaredType, valueType, selectedMediaType)) {
outputValue = this.getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, messageConverter1.getClass(), inputMessage, outputMessage);
if(outputValue != null) {
this.addContentDispositionHeader(inputMessage, outputMessage);
//进行消息转换成配置的格式 ,调用write方法
((GenericHttpMessageConverter)messageConverter1).write(outputValue, (Type)declaredType, selectedMediaType, outputMessage);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter1 + "]");
}
}
return;
}
} else if(messageConverter1.canWrite(valueType, selectedMediaType)) {
outputValue = this.getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, messageConverter1.getClass(), inputMessage, outputMessage);
if(outputValue != null) {
this.addContentDispositionHeader(inputMessage, outputMessage);
//进行消息转换成配置的格式 ,调用write方法
messageConverter1.write(outputValue, selectedMediaType, outputMessage);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter1 + "]");
}
}
return;
}
}
}
if(outputValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
}
}
write()方法又会调用writeInternal()方法
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
this.addDefaultHeaders(headers, t, contentType);
if(outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage)outputMessage;
streamingOutputMessage.setBody(new Body() {
public void writeTo(final OutputStream outputStream) throws IOException {
//调用writeInternal()
AbstractHttpMessageConverter.this.writeInternal(t, new HttpOutputMessage() {
public OutputStream getBody() throws IOException {
return outputStream;
}
public HttpHeaders getHeaders() {
return headers;
}
});
}
});
} else {
this.writeInternal(t, outputMessage);
outputMessage.getBody().flush();
}
}
最终会选择FastJsonHttpMessageConverter 的write方法中进行处理操作,就是将数据转换为json写到输出流中
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
ByteArrayOutputStream outnew = new ByteArrayOutputStream();
try {
HttpHeaders ex = outputMessage.getHeaders();
SerializeFilter[] globalFilters = this.fastJsonConfig.getSerializeFilters();
ArrayList allFilters = new ArrayList(Arrays.asList(globalFilters));
boolean isJsonp = false;
Object value = this.strangeCodeForJackson(object);
if(value instanceof FastJsonContainer) {
FastJsonContainer len = (FastJsonContainer)value;
PropertyPreFilters filters = len.getFilters();
allFilters.addAll(filters.getFilters());
value = len.getValue();
}
if(value instanceof MappingFastJsonValue) {
isJsonp = true;
value = ((MappingFastJsonValue)value).getValue();
} else if(value instanceof JSONPObject) {
isJsonp = true;
}
int len1 = this.writePrefix(outnew, object);
//只要加了@ResponseBody这里fastjson会将返回值转换为json字符串
len1 += JSON.writeJSONString(outnew, this.fastJsonConfig.getCharset(), value, this.fastJsonConfig.getSerializeConfig(), (SerializeFilter[])allFilters.toArray(new SerializeFilter[allFilters.size()]), this.fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE, this.fastJsonConfig.getSerializerFeatures());
len1 += this.writeSuffix(outnew, object);
if(isJsonp) {
ex.setContentType(APPLICATION_JAVASCRIPT);
}
if(this.fastJsonConfig.isWriteContentLength()) {
ex.setContentLength((long)len1);
}
outnew.writeTo(outputMessage.getBody());
} catch (JSONException var14) {
throw new HttpMessageNotWritableException("Could not write JSON: " + var14.getMessage(), var14);
} finally {
outnew.close();
}
}
插入一些小知识
@ResponseBody
作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
所以从上面的writeInternal方法,我们可以知道,当我们使用@ResponseBody这个注解时,会自动调用JSON.writeJSONString这个方法,这个方法和toJSONString() 方法类似,里面会带上我们在Spring里面配置的属性。
附一种不好的编程习惯:
在加了@ResponseBody注解的Controller中使用
String result = JSON.toJSONString(obj);
return result;
这种情况就相当于JSON.toJSONString() 这句话执行了两次。
springMVC默认提供了很多参数和结果值处理器,包括如下:
(1)MappingJackson2HttpMessageConverter
(2)GsonHttpMessageConverter
(3)ByteArrayHttpMessageConverter
(4)ObjectToStringHttpMessageConverter
(5)ProtobufHttpMessageConverter
(6)ResourceHttpMessageConverter
(7)StringHttpMessageConverter
(8)AllEncompassingFormHttpMessageConverter
参考文章:
http://blog.csdn.net/qq924862077/article/details/55271959
http://blog.csdn.net/weixiaodedao/article/details/51790790
网友评论