SpringMVC Content-Type解析
来源:互联网 发布:手机桌面图标整理软件 编辑:程序博客网 时间:2024/05/19 04:53
响应
为了测试方便,我们编写了一个简单的HttpMessageConverter
package cn.bjut.converter;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.nio.charset.Charset;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;import org.springframework.http.converter.AbstractHttpMessageConverter;import org.springframework.util.StreamUtils;public class MyStringHttpMessageConverter extends AbstractHttpMessageConverter<String> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public MyStringHttpMessageConverter() { this(DEFAULT_CHARSET); } public MyStringHttpMessageConverter(Charset defaultCharset) { super(defaultCharset, MediaType.TEXT_PLAIN, MediaType.ALL); } @Override public boolean supports(Class<?> clazz) { return String.class == clazz; } @Override protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException { Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType()); return StreamUtils.copyToString(inputMessage.getBody(), charset); } @Override protected Long getContentLength(String str, MediaType contentType) { Charset charset = getContentTypeCharset(contentType); try { return (long) str.getBytes(charset.name()).length; } catch (UnsupportedEncodingException ex) { // should not occur throw new IllegalStateException(ex); } } @Override protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException { Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType()); StreamUtils.copy(str, charset, outputMessage.getBody()); } private Charset getContentTypeCharset(MediaType contentType) { if (contentType != null && contentType.getCharset() != null) { return contentType.getCharset(); } else { return getDefaultCharset(); } }}
以上代码(修改自StringHttpMessageConverter
),我们把DEFAULT_CHARSET
即默认的字符集改为UTF-8
。并通过构造器传递给父类AbstractHttpMessageConverter
的defaultCharset
属性 super(defaultCharset, MediaType.TEXT_PLAIN, MediaType.ALL);
。
为了测试方便,我们把其他的所有消息转换器屏蔽掉
<mvc:annotation-driven> <mvc:message-converters register-defaults="false"> <bean class="cn.bjut.converter.MyStringHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven>
测试代码:
@Controllerpublic class TestController { @RequestMapping("/test") @ResponseBody public String test() { return "你大爷"; }}
debug走起
调用堆栈如下图所示:
响应头的设置在AbstractHttpMessageConverter
类中
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { final HttpHeaders headers = outputMessage.getHeaders(); addDefaultHeaders(headers, t, contentType); //... }
经测试outputMessage.getHeaders();
获得的HttpHeaders
始终都是空。HttpHeaders实际上就是个Map,用来保存Http Header public class HttpHeaders implements MultiValueMap<String, String>, Serializable
所以真正的处理在addDefaultHeaders
方法中。
/** * 在输出消息中设置响应头 * MediaType: 形如 text/plain 的媒体类型*/protected void addDefaultHeaders(HttpHeaders headers, T t, MediaType contentType) throws IOException{ if (headers.getContentType() == null) { MediaType contentTypeToUse = contentType; // 判断媒体类型是否包含通配符* if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) { // contentTypeToUse = getDefaultContentType(t); } // 判断媒体类型是不是 application/octet-stream else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) { MediaType mediaType = getDefaultContentType(t); contentTypeToUse = (mediaType != null ? mediaType : contentTypeToUse); } if (contentTypeToUse != null) { // 判断媒体类型是否包含字符集(一般的媒体类型形如: "text/plain;charset=UTF-8") if (contentTypeToUse.getCharset() == null) { // 设置默认字符集 this.defaultCharset Charset defaultCharset = getDefaultCharset(); if (defaultCharset != null) { // 组建媒体类型(一般就形成了: "text/plain;charset=UTF-8") contentTypeToUse = new MediaType(contentTypeToUse, defaultCharset); } } // 将 Content-Type 添加到Http Header headers.setContentType(contentTypeToUse); } } if (headers.getContentLength() < 0 && !headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) { Long contentLength = getContentLength(t, headers.getContentType()); if (contentLength != null) { // 将 Content-Length 添加到Http Header headers.setContentLength(contentLength); } } }
protected MediaType getDefaultContentType(T t) throws IOException { List<MediaType> mediaTypes = getSupportedMediaTypes(); return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null); }
以上方法用来获得默认的Content-Type
@Override public List<MediaType> getSupportedMediaTypes() { return Collections.unmodifiableList(this.supportedMediaTypes); }
getSupportedMediaTypes
方法获得属性supportedMediaTypes
保存的媒体类型。
supportedMediaTypes
是一个List集合 private List<MediaType> supportedMediaTypes = Collections.emptyList();
可见可以通过AbstractHttpMessageConverter
的子类来设置该属性。
那么既然是一个setter方法,我们也可以自行注入进去的(会覆盖构造函数的设置内容)。
<mvc:annotation-driven> <mvc:message-converters register-defaults="false"> <bean class="cn.bjut.converter.MyStringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/plain;charset=UTF-8</value> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
如代码所示,默认取第一个mediaTypes.get(0)
。
public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) { Assert.notEmpty(supportedMediaTypes, "MediaType List must not be empty"); this.supportedMediaTypes = new ArrayList<MediaType>(supportedMediaTypes); }
如上面的代码所示,如果我们自行配置supportedMediaTypes
则会覆盖掉通过构造函数添加进来的。
所以说addDefaultHeaders
方法添加默认Http Headers也就是添加Content-Type
与 Content-Length
请求
关于SpringMVC如何获得请求的Content-Type
在以上MyStringHttpMessageConverter
类中:
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException { Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType()); return StreamUtils.copyToString(inputMessage.getBody(), charset); }
private Charset getContentTypeCharset(MediaType contentType) { if (contentType != null && contentType.getCharset() != null) { return contentType.getCharset(); } else { return getDefaultCharset(); } }
如上面代码所示,如果我们在发出请求时没有携带Content-Type
请求头则使用AbstractHttpMessageConverter
里的defaultCharset
属性作为默认的字符集。
- SpringMVC Content-Type解析
- springmvc与content-type
- springmvc http content-type
- springmvc梳理8----Content-Type
- springmvc 设置content-type为 application/json
- 关于SpringMVC content-type的那些事
- content-type
- Content Type
- content-type
- Content-Type
- Content-Type
- Content-Type
- Content-Type
- Content-Type
- Content-Type
- content type
- Content-Type
- content-type
- 编写代码模拟手机与SIM卡的组合关系。
- 销毁指定Activity的方法
- Android碎片知识
- opencv 对于矩形框的操作
- 并查集
- SpringMVC Content-Type解析
- Keras深度学习框架配置
- oracle用户管理详解
- 【LCA基础】poj 1470 Closest Common Ancestors
- h5图片上传和压缩
- samba的一些错误处理
- python函数、参数、模块
- zookeeper客户端zkCli.sh常用命令
- 自学Web前端第一天---初识HTML