spring boot json和xml,xhtml转换器选择

当我们的地址以json和xml结尾时,spring boot会选择对应的转换器来进行转换
比如,输入

http://ip:port/hello.json   结果返回json格式的{"code":100,"msg":"hello"}

http://ip:port/hello.xml   结果返回xml格式的

<xml>

   <code>100</code>

   <msg>hello</msg>

</xml

首先,系统在初始化的时候,通常会加载json和xml两种格式

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport

	protected Map<String, MediaType> getDefaultMediaTypes() {
		Map<String, MediaType> map = new HashMap<String, MediaType>(4);
		if (romePresent) {
			map.put("atom", MediaType.APPLICATION_ATOM_XML);
			map.put("rss", MediaType.APPLICATION_RSS_XML);
		}
		if (jaxb2Present || jackson2XmlPresent) {
			map.put("xml", MediaType.APPLICATION_XML);
		}
		if (jackson2Present || gsonPresent) {
			map.put("json", MediaType.APPLICATION_JSON);
		}
		return map;
	}

如果DefaultMediaTypes中找不到的话,他就会去MimeMappings中查找

那么其它的类型在哪里呢,org.springframework.boot.context.embedded.MimeMappings

static {

MimeMappings mappings = new MimeMappings();

mappings.add("abs", "audio/x-mpeg");

mappings.add("ai", "application/postscript");

mappings.add("aif", "audio/x-aiff");

mappings.add("aifc", "audio/x-aiff");

                 .....太多了,不copy了

mappings.add("xhtml", "application/xhtml+xml");

所以这也是为什么xhtml最终可以输出xml格式

在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();
                //这里从request中获取支MediaType(header或uri末尾)
		List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
		List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

		if (outputValue != null && producibleMediaTypes.isEmpty()) {
			throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
		}

....


	if (selectedMediaType != null) {
			selectedMediaType = selectedMediaType.removeQualityValue();
                        //循环去匹配对应的convert转换器
			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;
				}
			}
		}

PathExtensionContentNegotiationStrategy 关键字获取

可以看到这里截取了URI末尾的关键字(json or xml  or xhtml ...)

	protected String getMediaTypeKey(NativeWebRequest webRequest) {
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		if (request == null) {
			logger.warn("An HttpServletRequest is required to determine the media type key");
			return null;
		}
		String path = this.urlPathHelper.getLookupPathForRequest(request);
		String extension = UriUtils.extractFileExtension(path);
		return (StringUtils.hasText(extension) ? extension.toLowerCase(Locale.ENGLISH) : null);
	}

AbstractMappingContentNegotiationStrategy

	public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, String key)
			throws HttpMediaTypeNotAcceptableException {

		if (StringUtils.hasText(key)) {
                        //从getDefaultMediaTypes()中寻找匹配
			MediaType mediaType = lookupMediaType(key);
			if (mediaType != null) {
				handleMatch(key, mediaType);
				return Collections.singletonList(mediaType);
			}
                        //从servletContext中寻找(我用的是内嵌tomcat,所以用的是MimeMappings)
			mediaType = handleNoMatch(webRequest, key);
			if (mediaType != null) {
				addMapping(key, mediaType);
				return Collections.singletonList(mediaType);
			}
		}
		return Collections.emptyList();
	}

猜你喜欢

转载自yxjajl.iteye.com/blog/2409647