响应

为了测试方便,我们编写了一个简单的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 {

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);。

为了测试方便,我们把其他的所有消息转换器屏蔽掉

测试代码:

@Controller

public 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, 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 mediaTypes = getSupportedMediaTypes();

return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null);

}

以上方法用来获得默认的Content-Type

@Override

public List getSupportedMediaTypes() {

return Collections.unmodifiableList(this.supportedMediaTypes);

}

getSupportedMediaTypes 方法获得属性supportedMediaTypes 保存的媒体类型。

supportedMediaTypes 是一个List集合

private List supportedMediaTypes = Collections.emptyList();

可见可以通过AbstractHttpMessageConverter 的子类来设置该属性。

那么既然是一个setter方法,我们也可以自行注入进去的(会覆盖构造函数的设置内容)。

text/plain;charset=UTF-8

text/plain;charset=UTF-8

text/plain;charset=UTF-8

如代码所示,默认取第一个mediaTypes.get(0)。

public void setSupportedMediaTypes(List supportedMediaTypes) {

Assert.notEmpty(supportedMediaTypes, "MediaType List must not be empty");

this.supportedMediaTypes = new ArrayList(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 属性作为默认的字符集。

java contenttype_SpringMVC Content-Type解析相关推荐

  1. Error while extracting response for type [] and content type [],json返回值被解析为xml

    在使用restTemplate请求restful接口时,在特定情况下总会将返回的json数据解析为xml数据然后处理,接着就会爆出标题中的错误: Error while extracting resp ...

  2. Java POI WPS另存为的XLSX Excel报错Package should contain a content type part [M1.13]

    最近在写项目的时候,使用到了POI对表格的处理,在通过文件流创建工作簿的时候,出现异常,异常信息是:Package should contain a content type part [M1.13] ...

  3. poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]

    导入excel文件POI解析 时报错: FileInputStream file = new FileInputStream(new File("G:\\TestData\\test.xls ...

  4. 报错Content type ‘multipart/form-data;boundary=----WebKitFormBoundaryTz0sivpVO7U0H70m;charset=UTF-8‘ n

    最近在做一个图片上传,遇到这了这种情况,在入参 body 中同时传入文件和其它参数信息结果出现如题异常. 特别在此记录解决办法,以供大家参考. method="post"必须事po ...

  5. restTemplate http请求报错:no suitable HttpMessageConverter found for response type and content type

    报错信息: org.springframework.web.client.UnknownContentTypeException: Could not extract response: no sui ...

  6. Maven报错解决:Element 'dependency' cannot have character [children], because the type's content type is

    在用maven的时候遇到报错: Element 'dependency' cannot have character [children], because the type's content ty ...

  7. Spring Boot——[Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]解决方案

    问题描述 2020-02-13 19:32:04.322 WARN 109508 --- [p-nio-80-exec-4] .m.m.a.ExceptionHandlerExceptionResol ...

  8. eclipse 设置 content type 编码格式

    前言 Eclipse Version: 2019-12 (4.14.0) 操作 打开Preferences.菜单路径为:Window–> Preferences 在搜索框中输入:content ...

  9. java docx文档解析_带有docx4j的Java Word(.docx)文档

    java docx文档解析 几个月前,我需要创建一个包含许多表和段落的动态Word文档. 过去,我曾使用POI来实现此目的,但是我发现它很难使用,并且在创建更复杂的文档时对我来说效果不佳. 因此,对于 ...

  10. transactionManager 以及datasource type解析

    transactionManager 以及datasource type解析 transactionManager 在 MyBatis 中有两种事务管理器类型(也就是 type="[JDBC ...

最新文章

  1. 解决eclipse中egit中的cannot open git-upload-pack问题
  2. 宏观与量子的恩怨情仇
  3. python3.5安装-linux安装python3.5.1
  4. Oracle归档已满的处理办法
  5. poj2823 线段树模板题 点修改(也可以用单调队列)
  6. DDoS(Distributed Denial of Service,分布式拒绝服务)
  7. MapReduce 计算框架如何运作
  8. 3月30日见!荣耀30S外观“偷跑”:经典蝶羽纹理设计
  9. IBM MQ 创建以及常见问题
  10. LeetCode(709)——转换成小写字母(JavaScript)
  11. java https双向验证_Https双向验证与Springboot整合测试-人来人往我只认你
  12. Android Java(2015-6-18 15:28、2016-1-30 21:18、2016-5-31 11:20)
  13. 用迭代法求a的平方根
  14. 使用pytorch获取bert词向量 将字符转换成词向量
  15. @Transactional 失效的几种情况
  16. kubernetes健康检查配置解析
  17. 计算机国二表情包,哈哈哈!设计师专用表情包合集(二)
  18. 北京考虑分时分区单双号限行预期效果遭质疑-北京-分时分区-单双号限行
  19. spring boot+vue个人博客七:打包部署,多节点部署方案
  20. 天津大学计算机网络专业排名,2019计算机考研天津大学先进网络技术与应用重点实验室简介...

热门文章

  1. 计算机文化基础证书丢了,计算机文化基础 文档的打印与保护 3.8.1 防止文档内容丢失.pptx...
  2. 带经纬度的水印相机_这个国庆节,元道经纬相机做交警人员的好帮手
  3. 29 顺时针打印矩阵(四-画图让抽象问题形象化)
  4. springcloud- FeginClient 调用统一拦截添加请求头 RequestInterceptor ,被调用服务获取请求头...
  5. pgsql merge方法
  6. HDU 2639 Bone Collector II (dp)
  7. [实战]挖掘CSRF姿势
  8. win7 下 qwt安装教程
  9. 转: JavaScript判断浏览器类型及版本
  10. 单链表插入、删除操作单步解析(十三)