spring下HttpMessageConverter核心代码详解

来源:互联网 发布:达示数据 编辑:程序博客网 时间:2024/05/17 06:56

使用spring的小伙伴肯定对下面的配置特别了解:

    <mvc:annotation-driven>        <mvc:message-converters register-defaults="false">            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />            <bean class="org.springframework.http.converter.StringHttpMessageConverter">                <property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />            </bean>            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">                <property name="supportedMediaTypes">                    <list>                        <value>text/plain;charset=UTF-8</value>                        <value>application/json;charset=UTF-8</value>                    </list>                </property>            </bean>        </mvc:message-converters>    </mvc:annotation-driven>

再看下下面的controller代码:


    @GetMapping(value = "/get-person", produces = MediaType.APPLICATION_JSON_VALUE)    public @ResponseBody Person getPerson() throws IOException {    Person per = new Person("Bill","Gates");    return per;    }
responsebody注解的作用是告诉spring框架使用HttpMessageConverter来将getPerson方法返回的Person对象使用mvc:message-converters注解里面配置的消息转换器将返回值经过相应的转换后传递给前端。

这里面就离不开AbstractMessageConverterMethodProcessor这个抽象类,下面我们来看下该类相关代码:

protected <T> void writeWithMessageConverters(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);}HttpServletRequest request = inputMessage.getServletRequest();
//获取前端传递的多媒体类型List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
//获取该方法支持返回的的多媒体类型,对于getPerson方法来说只有application/json一种类型List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);if (outputValue != null && producibleMediaTypes.isEmpty()) {throw new IllegalArgumentException("No converter found for return value of type: " + valueType);}Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();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<MediaType>(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) {
//去除权衡因子:比如对application/json;q=0.8来说,调用removeQualityValue后返回application/jsonselectedMediaType = selectedMediaType.removeQualityValue();
/*接下来的代码的作用就是从mvc:message-converters配置的消息转换器中选择一个可以处理返回值为
Person类且支持返回类型为application/json的转换器,如果找不到则抛出
‘HttpMediaTypeNotAcceptableException’异常,找到则调用相应转换器的write方法将Person对象
按照json格式处理后写入返回消息的body中*/for (HttpMessageConverter<?> messageConverter : this.messageConverters) {if (messageConverter instanceof GenericHttpMessageConverter) {if (((GenericHttpMessageConverter) messageConverter).canWrite(declaredType, valueType, selectedMediaType)) {outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),inputMessage, outputMessage);if (outputValue != null) {addContentDispositionHeader(inputMessage, outputMessage);((GenericHttpMessageConverter) messageConverter).write(outputValue, declaredType, selectedMediaType, outputMessage);if (logger.isDebugEnabled()) {logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +"\" using [" + messageConverter + "]");}}return;}}else if (messageConverter.canWrite(valueType, selectedMediaType)) {outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),inputMessage, outputMessage);if (outputValue != null) {addContentDispositionHeader(inputMessage, outputMessage);((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);if (logger.isDebugEnabled()) {logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +"\" using [" + messageConverter + "]");}}return;}}}if (outputValue != null) {throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);}}


0 0
原创粉丝点击