美文网首页
HttpMessageConverter工作细节

HttpMessageConverter工作细节

作者: 风亡小窝 | 来源:发表于2017-11-22 16:58 被阅读74次

在使用springMVC的@ResponseBody注解和配置HttpMessageConverter时遇到很多奇怪的问题。例如返回字符串为什么被加了双引号?
http://www.jianshu.com/p/88712c5ad54b

看两个类

  1. AbstractHttpMessageConverter
    .canRead()
    .canWrite()
    子类.support()
  1. AbstractMessageConverterMethodProcessor
    .writeWithMessageConverters
    .getProducibleMediaTypes
    .getAcceptableMediaTypes
/**
* Writes the given return type to the given output message.
*
* @param returnValue the value to write to the output message
* @param returnType the type of the value
* @param inputMessage the input messages. Used to inspect the {@code Accept} header.
* @param outputMessage the output message to write to
* @throws IOException thrown in case of I/O errors
* @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated by {@code Accept} header on
* the request cannot be met by the message converters
*/
@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T returnValue,
                                            MethodParameter returnType,
                                            ServletServerHttpRequest inputMessage,
                                            ServletServerHttpResponse outputMessage)
      throws IOException, HttpMediaTypeNotAcceptableException {

  Class<?> returnValueClass = returnValue.getClass();

  HttpServletRequest servletRequest = inputMessage.getServletRequest();
  List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
  List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);

  Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
  for (MediaType r : requestedMediaTypes) {
      for (MediaType p : producibleMediaTypes) {
          if (r.isCompatibleWith(p)) {
              compatibleMediaTypes.add(getMostSpecificMediaType(r, p));
          }
      }
  }
  if (compatibleMediaTypes.isEmpty()) {
      throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
  }

  List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
  // 根据q值进行排序,q值可以认为是优先级
  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<?> messageConverter : messageConverters) {
          if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
              ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
              if (logger.isDebugEnabled()) {
                  logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
                          messageConverter + "]");
              }
              return;
          }
      }
  }
  throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
}
/**
 * 返回所有messageConverter能生产的类型
 */
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> returnValueClass) {
    Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    if (!CollectionUtils.isEmpty(mediaTypes)) {
        return new ArrayList<MediaType>(mediaTypes);
    }
    else if (!allSupportedMediaTypes.isEmpty()) {
        List<MediaType> result = new ArrayList<MediaType>();
        // 重点
        for (HttpMessageConverter<?> converter : messageConverters) {
            if (converter.canWrite(returnValueClass, null)) {
                result.addAll(converter.getSupportedMediaTypes());
            }
        }
        return result;
    }
    else {
        return Collections.singletonList(MediaType.ALL);
    }
}

/**
 * 获取游览器接受的媒体类型
 */
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;
}

相关文章

网友评论

      本文标题:HttpMessageConverter工作细节

      本文链接:https://www.haomeiwen.com/subject/svkovxtx.html