首页 > 其他分享 >扩展SpringMVC框架的消息转化器

扩展SpringMVC框架的消息转化器

时间:2023-08-09 20:47:12浏览次数:39  
标签:框架 SpringMVC 扩展 public 对象 消息 new 转换器 class

1、消息转化器

请求和响应都有对应的body,而这个body就是需要关注的主要数据。

请求体与请求的查询参数或者表单参数是不同的,请求体的表述一般就是一段字符串,而查询参数可以看作url的一部分,这两个是位于请求报文的不同地方。表单参数可以按照一定格式放在请求体中,也可以放在url上作为查询参数。总之可以把请求体看作客户端通过请求报文捎带的字符串。

响应体则是浏览器渲染页面的依据,对于一个普通html页面得响应,响应体就是这个html页面的源代码。

请求体和响应体都是需要配合Content-Type头部使用的,这个头部主要用于说明body中得字符串是什么格式的,比如:text,json,xml等。对于请求报文,只有通过此头部,服务器才能知道怎么解析请求体中的字符串,对于响应报文,浏览器通过此头部才知道应该怎么渲染响应结果,是直接打印字符串还是根据代码渲染为一个网页。

还有一个与body有关的头部是Accept,这个头部标识了客户端期望得到什么格式的响应体。服务器可根据此字段选择合适的结果表述。

对于HttpServletRequest和HttpServletResponse,可以分别调用getInputStream和getOutputStream来直接获取body。但是获取到的仅仅只是一段字符串。

而对于java来说,处理一个对象肯定比处理一个字符串要方便得多,也好理解得多。所以根据Content-Type头部,将body字符串转换为java对象是常有的事。反过来,根据Accept头部,将java对象转换客户端期望格式的字符串也是必不可少的工作。

 

对于消息转换器的调用,都是在RequestResponseBodyMethodProcessor类中完成的。它实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口,分别实现了处理参数和处理返回值的方法。

而要动用这些消息转换器,需要在特定的位置加上@RequestBody和@ResponseBody。
下面是源码不一定看,但是要看自定义消息转换器。

/**
 * RequestResponseBodyMethodProcessor.class
 */
···
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }

    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }
···

对返回值的消息转换来说:

/**
 * RequestResponseBodyMethodProcessor.class
 */
···
public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException;

大致流程为:
1.根据返回值获取其类型,其中MethodParameter封装了方法对象,可获去方法返回值类型。

1 /**
2  * AbstractMessageConverterMethodProcessor.class
3  */
4 ···
5             outputValue = value;
6             valueType = getReturnValueType(outputValue, returnType);
7             declaredType = getGenericType(returnType);

2.根据request的Accept和HandellerMapping的produces属性经过比对、排序从而得到最应该转换的消息格式(MediaType)。

 1 /**
 2  * AbstractMessageConverterMethodProcessor.class
 3  */
 4 ···
 5         List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
 6         List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
 7         Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
 8 ···
 9 //匹配
10 ···
11         List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
12         MediaType.sortBySpecificityAndQuality(mediaTypes);
13 
14         MediaType selectedMediaType = null;
15 ···
16 //选择最具体的MediaType
17 ···

3.遍历所有已配置的消息转换器,调用其canWrite方法,根据返回值类型(valueType)和消息格式(MediaType)来检测是否可以转换。

 1 /**
 2  * AbstractMessageConverterMethodProcessor.class
 3  */
 4 ···
 5 for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
 6 ···
 7      if (messageConverter.canWrite(valueType, selectedMediaType)){
 8 ···
 9         ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
10 ···
11      }
12 }

4.若有对应的转换器,则执行消息转换,即write方法。在write方法中,将返回值被转换后得到的字符串写在Response的输出流中。若找不到对应的转换器,则抛出HttpMediaTypeNotAcceptableException异常,浏览器会收到一个406 Not Acceptable状态码。

2、自定义消息转换器

除了spring提供的9个默认的消息转换器,还可以添加自定义的消息转换器,或者更换消息转换器的实现。

一个自定义消息转换器的例子:
对象映射器:

 1 /**
 2  * 此类是对象映射器:
 3  * 基于jackson将Java对象转为json,或者将json转为Java对象
 4  * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 5  * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 6  * 这里将数据类型转为其他类型解决一些数字偏大的从而导致js四舍五入出现精度不高的行为,所以下面有我们有一种将long类型的转化为string类型。
 7  */
 8 public class JacksonObjectMapper extends ObjectMapper {
 9 
10     public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
11     public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
12     public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
13 
14     public JacksonObjectMapper() {
15         super();
16         //收到未知属性时不报异常
17         this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
18 
19         //反序列化时,属性不存在的兼容处理
20         this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
21 
22 
23         SimpleModule simpleModule = new SimpleModule()
24                 .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
25                 .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
26                 .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
27 
28                 .addSerializer(BigInteger.class, ToStringSerializer.instance)
29                 //将long转化为字符串
30                 .addSerializer(Long.class, ToStringSerializer.instance)
31                 .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
32                 .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
33                 .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
34 
35         //注册功能模块 例如,可以添加自定义序列化器和反序列化器
36         this.registerModule(simpleModule);
37     }
38 }

 

扩展mvc框架的消息转换器,配置SpringMVC使用我们自定义的jackson对象转换器:

 1 @Slf4j
 2 @Configuration
 3 public class WebMvcConfig extends WebMvcConfigurationSupport {
 4     /*设置静态资源的映射*/
 5 
 6     @Override
 7     protected void addResourceHandlers(ResourceHandlerRegistry registry) {
 8         log.info("开始进行对静态资源的映射");
 9         registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
10         registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
11 
12     }
13 
14     /**
15      * 扩展mvc框架的消息转换器,不使用它默认的转换器,使用这个转换器,就能按照
16      * JacksonObjectMapper的对象映射器来进行对象之间转换。
17      * @param converters
18      */
19     @Override
20     protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
21         log.info("扩展消息转换器");
22         //创建消息转换器对象
23         MappingJackson2HttpMessageConverter messageConverter=new MappingJackson2HttpMessageConverter();
24         //设置对象转换器,底层使用Jackson将Java对象转为json
25         messageConverter.setObjectMapper(new JacksonObjectMapper());
26         //将上面的消息转换器对象追加到mvc框架的转换器集合中,第一个参数是设置优先级,最先使用这个消息转换器。
27         converters.add(0,messageConverter);
28     }
29 }          

作者:JerryL_
链接:https://www.jianshu.com/p/2f633cb817f5

标签:框架,SpringMVC,扩展,public,对象,消息,new,转换器,class
From: https://www.cnblogs.com/xdqx/p/17617934.html

相关文章

  • SpringMVC支持跨域访问详解
    跨站HTTP请求(Cross-siteHTTPrequest)是指发起请求的资源所在域不同于该请求所指向资源所在的域的HTTP请求。这里有域名的不同,端口号的不同。很多浏览器在发起跨域访问时是会询问用户是否需要发送该请求,或者干脆不发送跨域访问请求。(最好的办法是不使用ajax之类的,不要在前端......
  • 智慧工地源码,基于Vue+Spring Cloud +UniApp框架开发
    源码技术架构:微服务+JavaVue+SpringCloud+UniApp+MySql智慧工地管理平台是依托物联网、互联网、AI、可视化建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。智慧工地管理平台功能包括:劳务实名制管理系统、监测系统、区域安......
  • 微前端框架哪个好?QianKun还是MicroApp
    在当前云原生微服务、业务中台、低代码平台等IT架构下,不再是传统的烟囱式应用系统建设,而是打破企业业务部门竖井,建立企业级的信息化平台(数据中台、业务中台),那么对业务开发的解耦和聚合将成为关键技术,目前对于系统后端已有成熟的微服务架构,基于SpringBoot开发微服务,通过SpringCloud......
  • 山东布谷科技直播程序源码使用Redis进行服务器横向扩展
    当今,直播程序源码平台作为新媒体时代主流,受到了世界各地人民的喜爱,这也使得直播程序源码平台用户数量的庞大,也难免会出现大量用户同时访问服务器,使服务器过载的情况,当服务器承受不住的时候,可能就会造成服务器崩溃,为了应对这一问题,直播程序源码的开发人员在开发服务器的时候就要去使......
  • Pytorch框架CV开发-从入门到实战
    点击下载:Pytorch框架CV开发-从入门到实战课程分享,视频+源码+数据集下载!提取码:bbvaPyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序。它主要由Facebookd的人工智能小组开发,不仅能够实现强大的GPU加速,同时还支持动态神经网络,这一点是现在很多主流框架如......
  • 山东布谷科技直播程序源码使用Redis进行服务器横向扩展
    当今,直播程序源码平台作为新媒体时代主流,受到了世界各地人民的喜爱,这也使得直播程序源码平台用户数量的庞大,也难免会出现大量用户同时访问服务器,使服务器过载的情况,当服务器承受不住的时候,可能就会造成服务器崩溃,为了应对这一问题,直播程序源码的开发人员在开发服务器的时候就要去......
  • GreatSQL从单机到MGR扩展纪实
    一、前言原有的业务系统跑在MySQL主从架构中,高可用通过脚本完成,但存在切换数据丢失和切换不及时风险,调研了高可用更稳定的MGR后,准备入手一试。本篇文章主要记录GreatSQL从单机扩展到MGR的详细过程,遇到的问题及解决方法。二、基础环境服务器角色如下IP端口主机名作用......
  • 第六节:框架版本升级和Vuex改造为Pinia
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • Springmvc展示oss的图片
    公开权限的图片展示首先确定思路,存储在oss中的图片有两种权限模式,一种是公开的,这种直接通过url对应到具体某张图片即可显示。格式如下:http://<yourBucketName>.<yourEndpoint>/<yourObjectName>?x-oss-process=image/<yourAction>,<yourParamValue>具体例子http://image-demo.oss-c......
  • python 测试框架中的数据库连接类(mysql示例)
     1.数据库信息yaml文件conf_env.yamlhost:doname:demo.pab.com.cnport:80database:host:"db.fat.qa.pab.com.cn"user:"deploy"password:"thess"dbname:"testdb"charset:"utf8"2.与数据库yaml文件同级目录,创建配置conf......