SpringMVC @ResponseBody处理流程
来源:互联网 发布:autodesk公司的软件 编辑:程序博客网 时间:2024/06/06 12:57
SpringMVC的Controller方法的返回值大体有两种:
1. ModelAndView(没有使用@ResponseBody
注解)
2. 直接输出到响应流的数据(使用@ResponseBody
注解,没有视图解析的步骤)
/** * 指示方法返回值直接绑定到 HTTP Response Body 的注解 */@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ResponseBody {}
@ResponseBody
注解的处理类org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
,
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
SpringMVC是如何找到该处理器的:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler { //... private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>(); //... @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; } //...}
RequestResponseBodyMethodProcessor的supportsReturnType方法为:
@Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } //第一个在类上查找该注解,第二个在方法上查找该注解
因为我们使用了@ResponseBody 注解,所以以上方法返回true
HandlerMethodReturnValueHandlerComposite可以认为是HandlerMethodReturnValueHandler的包装器类。
我们知道RequestMappingHandlerAdapter是处理请求的适配器,也就是请求之后处理具体逻辑的执行,关系到哪个类的哪个方法以及转换器等工作。
RequestMappingHandlerAdapter在进行handle的时候,会委托给HandlerMethod(具体由子类ServletInvocableHandlerMethod处理)的invokeAndHandle方法进行处理,这个方法又转接给HandlerMethodReturnValueHandlerComposite处理。
RequestResponseBodyMethodProcessor
继承自org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor
@ResponseBody 的真正处理程序在AbstractMessageConverterMethodProcessor
里的writeWithMessageConverters
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object outputValue; Class<?> valueType; Type declaredType; if (value instanceof CharSequence) { outputValue = value.toString(); valueType = String.class; declaredType = String.class; } else { outputValue = value; valueType = getReturnValueType(outputValue, returnType); declaredType = getGenericType(returnType); } if (isResourceType(value, returnType)) { outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes"); if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null) { Resource resource = (Resource) value; try { List<HttpRange> httpRanges = inputMessage.getHeaders().getRange(); outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value()); outputValue = HttpRange.toResourceRegions(httpRanges, resource); valueType = outputValue.getClass(); declaredType = RESOURCE_REGION_LIST_TYPE; } catch (IllegalArgumentException ex) { outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength()); outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); } } } HttpServletRequest request = inputMessage.getServletRequest(); List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request); List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType); if (outputValue != null && producibleMediaTypes.isEmpty()) { throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType); } Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { if (requestedType.isCompatibleWith(producibleType)) { compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (compatibleMediaTypes.isEmpty()) { if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return; } List<MediaType> mediaTypes = new ArrayList<>(compatibleMediaTypes); MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null; for (MediaType mediaType : mediaTypes) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> converter : this.messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); if (outputValue != null) { addContentDispositionHeader(inputMessage, outputMessage); if (genericConverter != null) { genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage); } else { ((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage); } if (logger.isDebugEnabled()) { logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + converter + "]"); } } return; } } } if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); } }
private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException { List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request)); return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes); }
获得请求信息头里的Accept属性,如果为空则返回*/*
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, @Nullable Type declaredType) { Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (!CollectionUtils.isEmpty(mediaTypes)) { return new ArrayList<>(mediaTypes); } else if (!this.allSupportedMediaTypes.isEmpty()) { List<MediaType> result = new ArrayList<>(); for (HttpMessageConverter<?> converter : this.messageConverters) { if (converter instanceof GenericHttpMessageConverter && declaredType != null) { if (((GenericHttpMessageConverter<?>) converter).canWrite(declaredType, valueClass, null)) { result.addAll(converter.getSupportedMediaTypes()); } } else if (converter.canWrite(valueClass, null)) { result.addAll(converter.getSupportedMediaTypes()); } } return result; } else { return Collections.singletonList(MediaType.ALL); } }
this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
private static List<MediaType> getAllSupportedMediaTypes(List<HttpMessageConverter<?>> messageConverters) { Set<MediaType> allSupportedMediaTypes = new LinkedHashSet<>(); for (HttpMessageConverter<?> messageConverter : messageConverters) { allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); } List<MediaType> result = new ArrayList<>(allSupportedMediaTypes); MediaType.sortBySpecificity(result); return Collections.unmodifiableList(result); }
allSupportedMediaTypes
保存了容器内所有的HttpMessageConverter
支持的媒体类型
List<MediaType> requestedMediaTypes
保存了客户端需要的哪一种类型的数据(Accept)。 List<MediaType> producibleMediaTypes
也即保存了该容器可以产生的 Content-Type 类型的数据。
哪一个HttpMessageConverter可以处理你的Controller方法返回的对象,则把该HttpMessageConverter支持的媒体类型返回。
writeWithMessageConverters 方法的作用也就是选择合适的HttpMessageConverter,按照合适的 MediaType ,把数据写入到输出流。
参考:
https://my.oschina.net/lichhao/blog/172562
http://www.cnblogs.com/fangjian0423/p/springMVC-xml-json-convert.html
http://blog.csdn.net/fw0124/article/details/48280083
- SpringMVC @ResponseBody处理流程
- SpringMVC @ResponseBody 415错误处理
- SpringMVC @ResponseBody 415错误处理
- SpringMVC @ResponseBody 415错误处理
- SpringMVC @ResponseBody 415错误处理
- SpringMVC 3.x @ResponseBody 415错误处理
- SpringMVC使用@ResponseBody处理Ajax请求
- SpringMVC RequestBody ResponseBody处理Json数据
- SpringMVC ResponseBody 日期类型Json 处理
- SpringMVC @ResponseBody
- @ResponseBody-------springMVC
- springMVC ResponseBody
- SpringMVC @responsebody
- springmvc处理流程
- SpringMVC处理流程
- SpringMVC请求处理流程
- SpringMVC的处理流程
- SpringMVC 请求处理流程
- Unity 游戏帧率优化,设置分辨率
- KindEditor用法介绍
- 面向对象--this关键字
- JavaScript 相等和绝对相等(===)
- UDP套接字编程
- SpringMVC @ResponseBody处理流程
- OGNL学习
- 最简单的嵌入式Linux下ntp实现
- 皮尔逊相关度系数原理,以及java实现
- 解决科大讯飞11210错误
- 5.2
- 数组中的逆序对
- 机器学习学习笔记--迁移学习
- Java通过apache poi 读取excel(.xlsx)文件,并通过MyBbtis插入数据库中