SpringMVC的消息转换器
SpringMVC的消息转换器(Message Converter)是Spring框架中用于处理HTTP请求和响应体与Java对象之间转换的组件。它们使得开发人员可以轻松地将HTTP请求的数据映射到方法参数,并将返回的对象转换为HTTP响应。
工作原理
当一个HTTP请求到达Spring MVC应用程序时,框架会根据请求的内容类型(Content-Type
)和接受类型(Accept
)来选择合适的消息转换器。例如,如果客户端发送了一个JSON格式的POST请求,那么Spring MVC会选择MappingJackson2HttpMessageConverter
来将请求体反序列化为Java对象。同样地,当方法返回一个Java对象并需要将其发送给客户端时,Spring MVC会使用相应的消息转换器来序列化这个对象。
常见的内置转换器
在SpringMVC中,消息转换器通常通过HttpMessageConverter
接口实现。Spring MVC提供了多种内置的消息转换器来支持不同的媒体类型,例如JSON、XML等。以下是几个常见的内置转换器:
MappingJackson2HttpMessageConverter
:用于支持JSON格式的HTTP消息,依赖于Jackson库。MappingJackson2XmlHttpMessageConverter
:用于支持XML格式的HTTP消息,同样依赖于Jackson库。StringHttpMessageConverter
:用于处理纯文本字符串的HTTP消息。FormHttpMessageConverter
:用于处理表单数据(application/x-www-form-urlencoded或multipart/form-data),包括标准表单和文件上传。ByteArrayHttpMessageConverter
:用于处理二进制数据,比如图片或文件下载。Jaxb2RootElementHttpMessageConverter
:基于JAXB API,用于XML数据的序列化和反序列化。SourceHttpMessageConverter
:用于处理基于javax.xml.transform.Source的XML消息。ResourceHttpMessageConverter
:用于处理资源文件,如文件下载
配置消息转换器
你可以通过以下几种方式配置消息转换器:
-
通过Java配置类
如果你正在使用基于Java的配置,可以通过实现
WebMvcConfigurer
接口并重写configureMessageConverters
方法来添加自定义的消息转换器:@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加默认的消息转换器WebMvcConfigurer.super.configureMessageConverters(converters);// 添加自定义的消息转换器converters.add(new CustomHttpMessageConverter());} }
-
通过Spring XML配置
如果你还在使用XML配置,则可以在配置文件中定义
<mvc:message-converters>
元素:<mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/><!-- 其他自定义的消息转换器 --></mvc:message-converters> </mvc:annotation-driven>
-
自动配置(Spring Boot)
在Spring Boot中,框架会根据类路径上的库自动配置合适的消息转换器。例如,如果Jackson库在类路径上,Spring Boot会自动注册
MappingJackson2HttpMessageConverter
。
自定义消息转换器
为了创建自定义的消息转换器,你需要实现HttpMessageConverter<T>
接口,其中T
是你想要转换的对象类型。这个接口有三个主要的方法需要实现:
boolean canRead(Class<?> clazz, MediaType mediaType)
:判断是否能够读取指定类型的对象。boolean canWrite(Class<?> clazz, MediaType mediaType)
:判断是否能够写入指定类型的对象。List<MediaType> getSupportedMediaTypes()
:返回支持的媒体类型列表。T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
:从HTTP输入消息中读取并转换为对象。void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
:将对象转换为HTTP输出消息。
一旦实现了上述接口,就可以将其添加到SpringMVC的配置中,以便框架知道在处理特定类型的HTTP消息时使用哪个转换器。除了实现HttpMessageConverter<T>
接口外,你还可以通过配置类或XML文件控制哪些转换器被使用,以及它们的优先级顺序。这对于确保正确处理不同类型的消息非常重要。
自定义消息转换器实例
1. 创建业务对象
首先,我们需要一个Java类来表示我们要序列化和反序列化的数据模型。这里我们创建一个简单的CustomObject
:
public class CustomObject {private Long id;private String name;// Getters and Setterspublic Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "CustomObject{" +"id=" + id +", name='" + name + '\'' +'}';}
}
2. 实现自定义消息转换器
接下来,我们将创建一个自定义的消息转换器,用于处理特定媒体类型的数据。假设我们的自定义媒体类型是application/vnd.example.v1+json
。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;import java.io.IOException;
import java.util.Collections;public class CustomJsonHttpMessageConverter extends AbstractHttpMessageConverter<CustomObject> {private final ObjectMapper objectMapper = new ObjectMapper();public CustomJsonHttpMessageConverter() {// 支持的媒体类型super(new MediaType("application", "vnd.example.v1+json"));}@Overrideprotected boolean supports(Class<?> clazz) {// 指定转换器支持的类型return CustomObject.class.isAssignableFrom(clazz);}@Overrideprotected CustomObject readInternal(Class<? extends CustomObject> clazz, HttpInputMessage inputMessage)throws IOException, HttpMessageNotReadableException {// 读取并反序列化为CustomObjectreturn objectMapper.readValue(inputMessage.getBody(), clazz);}@Overrideprotected void writeInternal(CustomObject object, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {// 序列化CustomObject到输出流中objectMapper.writeValue(outputMessage.getBody(), object);}
}
3. 配置消息转换器
为了使Spring MVC知道使用我们自定义的消息转换器,我们需要在配置类中注册它。下面是如何在基于Java的配置中做到这一点:
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加自定义的消息转换器converters.add(new CustomJsonHttpMessageConverter());// 如果需要保留默认的消息转换器,可以这样添加// WebMvcConfigurer.super.configureMessageConverters(converters);}
}
4. 控制器层
现在,我们可以创建一个控制器来使用这个自定义的消息转换器:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/custom")
public class CustomController {@PostMapping(consumes = "application/vnd.example.v1+json", produces = "application/vnd.example.v1+json")public CustomObject createCustomObject(@RequestBody CustomObject customObject) {// 处理业务逻辑...System.out.println("Received: " + customObject);return customObject; // 返回相同的对象作为响应}@GetMapping(value = "/{id}", produces = "application/vnd.example.v1+json")public CustomObject getCustomObject(@PathVariable Long id) {// 模拟查询操作CustomObject obj = new CustomObject();obj.setId(id);obj.setName("Example Object " + id);return obj;}
}
5. 异常处理
当消息转换过程中发生错误时,Spring MVC会抛出HttpMessageNotReadableException
或HttpMessageNotWritableException
。你可以通过全局异常处理器来捕获这些异常并返回友好的错误信息给客户端。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(HttpMessageNotReadableException.class)public ResponseEntity<String> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {return new ResponseEntity<>("Error reading message: " + ex.getMessage(), HttpStatus.BAD_REQUEST);}@ExceptionHandler(HttpMessageNotWritableException.class)public ResponseEntity<String> handleHttpMessageNotWritable(HttpMessageNotWritableException ex) {return new ResponseEntity<>("Error writing message: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);}
}
6. 全局配置与性能优化
如果你有多个自定义转换器或者想要对所有转换器进行一些全局配置(比如设置日期格式),你可以在配置类中做进一步的调整。此外,对于高流量的应用程序,考虑使用缓存或异步处理以提高性能。
例如,你可以配置Jackson的ObjectMapper
以更好地控制JSON的序列化和反序列化行为:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class JacksonConfig {@Beanpublic ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();mapper.registerModule(new JavaTimeModule()); // 支持Java 8时间API// 这里还可以设置其他全局配置选项return mapper;}
}
然后,在你的自定义消息转换器中注入这个ObjectMapper
bean:
import org.springframework.beans.factory.annotation.Autowired;public class CustomJsonHttpMessageConverter extends AbstractHttpMessageConverter<CustomObject> {private final ObjectMapper objectMapper;@Autowiredpublic CustomJsonHttpMessageConverter(ObjectMapper objectMapper) {super(new MediaType("application", "vnd.example.v1+json"));this.objectMapper = objectMapper;}// ... 省略其他方法 ...
}
这将确保所有的CustomJsonHttpMessageConverter
实例都使用同一个配置过的ObjectMapper
,从而简化了配置并且提高了代码的一致性。
7. 配置与自定义
使用@ConfigurationProperties
进行配置
对于复杂的配置需求,可以使用@ConfigurationProperties
来创建一个配置类,从而将配置属性外部化。例如,如果你想要为Jackson ObjectMapper
配置多个属性,你可以这样做:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class JacksonConfig {@Bean@ConfigurationProperties(prefix = "spring.jackson")public ObjectMapper objectMapper() {return new ObjectMapper();}
}
在application.properties
或application.yml
中添加相应的配置项:
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=UTC
# 更多配置...
自定义序列化器和反序列化器
有时默认的行为可能不符合业务需求,这时可以通过实现自定义的序列化器和反序列化器来调整数据处理方式。以日期格式为例,如果想要统一处理Java 8的时间类型,可以注册JavaTimeModule
模块:
@Bean
public Module javaTimeModule() {return new JavaTimeModule();
}
还可以通过继承JsonSerializer
和JsonDeserializer
来创建更加定制化的逻辑。
8. 性能优化
缓存ObjectMapper
确保ObjectMapper
实例是单例且线程安全的,因为它不是线程安全的。通常情况下,Spring会为你管理这一点,但如果你手动创建了ObjectMapper
,则需要特别注意。
异步处理
为了提高响应速度,尤其是在处理大文件或复杂对象时,可以考虑使用异步的消息转换。Spring MVC支持异步请求处理,允许你在后台线程池中执行耗时任务而不阻塞主线程。
@GetMapping("/async/{id}")
public CompletableFuture<CustomObject> getCustomObjectAsync(@PathVariable Long id) {return CompletableFuture.supplyAsync(() -> {// 模拟耗时操作try { Thread.sleep(1000); } catch (InterruptedException e) {}CustomObject obj = new CustomObject();obj.setId(id);obj.setName("Async Example Object " + id);return obj;});
}
9. 安全性考虑
内容协商(Content Negotiation)
确保你的应用程序正确地实现了内容协商机制,以防止攻击者利用不期望的内容类型发起攻击。可以通过设置白名单来限制允许的内容类型,并确保所有转换器都只处理经过验证的媒体类型。
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.favorPathExtension(false).favorParameter(true).parameterName("mediaType").ignoreAcceptHeader(true).useRegisteredExtensionsOnly(true).defaultContentType(MediaType.APPLICATION_JSON).mediaType("json", MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML);
}
数据验证
始终对输入的数据进行验证,即使是在序列化和反序列化之后。这可以帮助防止诸如注入攻击等安全问题。
10. Spring Boot集成
在Spring Boot中,许多配置已经被简化并自动化。你只需要确保所需的库(如Jackson)存在于类路径上,框架就会自动配置合适的消息转换器。此外,Spring Boot还提供了额外的功能,比如自动发现和注册转换器。
# application.yml
spring:jackson:serialization:write-dates-as-timestamps: falsedeserialization:fail-on-unknown-properties: false
11. 日志记录
启用详细的日志记录有助于调试和监控消息转换过程中的任何问题。可以在application.properties
中配置日志级别:
logging.level.org.springframework.web=DEBUG
logging.level.com.fasterxml.jackson=DEBUG
12. 测试
编写单元测试和集成测试来验证消息转换器的行为是否符合预期非常重要。JUnit和MockMvc可以帮助你模拟HTTP请求并检查转换结果。
@WebMvcTest
class CustomControllerTest {@Autowiredprivate MockMvc mockMvc;@Testvoid shouldReturnDefaultMessage() throws Exception {mockMvc.perform(get("/custom/1").accept(MediaType.parseMediaType("application/vnd.example.v1+json"))).andExpect(status().isOk()).andExpect(content().contentType("application/vnd.example.v1+json")).andExpect(jsonPath("$.name").value("Example Object 1"));}
}
使用注解控制消息转换
在控制器层,你可以使用一些注解来控制消息转换的行为,比如@RequestBody
和@ResponseBody
:
@RequestBody
:用于将HTTP请求体的内容映射到方法参数,并使用适当的HttpMessageConverter
进行反序列化。@ResponseBody
:用于指示方法的返回值应该被直接写入HTTP响应体,而不是解析为视图。
此外,还有@RestController
注解,它是一个组合注解,等价于同时使用@Controller
和@ResponseBody
,简化了RESTful服务的开发。
相关文章:

SpringMVC的消息转换器
SpringMVC的消息转换器(Message Converter)是Spring框架中用于处理HTTP请求和响应体与Java对象之间转换的组件。它们使得开发人员可以轻松地将HTTP请求的数据映射到方法参数,并将返回的对象转换为HTTP响应。 工作原理 当一个HTTP请求到达Spr…...

Chrome 浏览器下载安装教程,保姆级教程
大家好,今天我们来聊一聊如何在国内下载和安装最新版本的 Chrome 浏览器。由于众所周知的原因,Google 的网站在国内是被屏蔽的,因此很多朋友在下载 Chrome 浏览器 时会遇到困难。其实,不必担心,今天我将为大家带来一份…...

ElasticSearch系列(一)
一.了解ES、倒排索引、es的一些概念、安装es、kibana 二.DSL;索引库操作 三.Java RestClient:索引库操作 一、了解ES、倒排索引、es的一些概念、安装es、kibana kibana、logstash、beats Elasticserach 存储,计算 ,搜索数据 –…...

C++技巧:map和vector
一,map是有序的,unordered_map是无序的 在C中,std::map 和 std::unordered_map 是两种不同的容器,它们都用于存储键值对,但是它们的底层实现和性能特性有所不同。以下是它们的详细介绍: std::map std::m…...

中建海龙:科技助力福城南产业片区绿色建筑发展
在快速发展的城市化进程中,绿色建筑以其环保、节能、可持续的特点日益受到重视。作为建筑工业化领域的领军企业,中建海龙科技有限公司(简称“中建海龙”)凭借其卓越的科技实力和创新举措,在推动绿色建筑发展方面做出了…...

模块化通讯管理机在物联网系统中的应用
安科瑞刘鸿鹏 摘要 随着能源结构转型和智能化电网的推进,电力物联网逐渐成为智能电网的重要组成部分。本文以安科瑞ANet系列智能通信管理机为例,探讨其在电力物联网中的应用,包括数据采集、规约转换、边缘计算、远程控制等技术实践&#…...

建立一个Macos载入image的实例含界面
前言 为了方便ios程序的开发,有时候需要先用的Macos平台进行一些功能性的程序开发。 作为对比和参考。 1、创建一个MacOS的App 2、主界面控件的增加 添加的控件方法与ios相同,也是再用commandshiftL(CtrlShiftL),就会弹出控件…...

Redis List列表
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 Redis List列表 收录于专栏[redis] 本专栏旨在分享学习Redis的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 概述 常用命令 LPUSH …...

继承与多态 - 继承机制、虚函数、纯虚函数
引言 C 是一种支持面向对象编程(OOP)的编程语言,继承和多态是 OOP 的两个核心概念。通过继承,我们可以创建新的类,这些新类可以重用现有类的代码,并且可以根据需要进行扩展或修改。多态则允许我们编写更加…...

【QT】C++线程安全的单例模板
模板代码 #pragma once #include <mutex> #include <atomic>// CRTP基类模板 Curiously Recurring Template Parttern—奇异递归模板模式。 template <typename T> class SingletonCRTP { public:// 禁止拷贝构造和赋值操作SingletonCRTP(const SingletonCR…...

node.js内置模块之---EventEmitter 类
EventEmitter 类什么作用 EventEmitter 类的主要方法 EventEmitter 类什么作用 在 Node.js 中,EventEmitter 是一个非常核心的类,它提供了一种事件驱动的机制。几乎所有的 Node.js 核心模块(如 fs, http, net 等)都采用了事件驱…...

SWM221系列芯片之电机应用及控制
经过对SWM221系列的强大性能及外设资源,TFTLCD彩屏显示及控制进行了整体介绍后,新迎来我们的电控篇---SWM221系列芯片之电机应用及控制。在微控制器市场面临性能、集成度与成本挑战的当下,SWM221系列芯片以其卓越性能与创新设计,受…...

单片机-静动态数码管实验
P0控制数码管 ,P0低电平 P1,P2,P3高电平 1、静态数码管 需求:数码管显示0,即让p0端口输出数字0的段码0x3f(共阴) #include "reg52.h" typedef unsigned int u16; typedef unsigned char u8; //数码管显示数字的数组 共阴极 …...

Fabric环境部署
官方下载文档:A Blockchain Platform for the Enterprise — Hyperledger Fabric Docs main documentation 1.1 创建工作目录 将Fabric代码按照GO语言的推荐方式进行存放,创建目录结构并切换到该目录下。具体命令如下: mkdir -p ~/go/src/g…...

VisualRules规则引擎语法介绍
VisualRules规则引擎是一款用于处理复杂业务规则的引擎,广泛应用于金融、保险、医疗等领域。它通过将业务逻辑从代码中分离出来,以可配置的方式管理和执行规则。以下是VisualRules规则引擎的基本语法和使用方法: 1. 规则定义 规则通常由 条件…...

enzymejest TDD与BDD开发实战
一、前端自动化测试需要测什么 1. 函数的执行逻辑,对于给定的输入,输出是否符合预期。 2. 用户行为的响应逻辑。 - 对于单元测试而言,测试粒度较细,需要测试内部状态的变更与相应函数是否成功被调用。 - 对于集成测试而言&a…...

Statistic for ML
statistical concept 統計學概念 免費完整內容 PMF and CDF PMF定義的值是P(Xx),而CDF定義的值是P(X < x),x為所有的實數線上的點。 probability mass function (PMF) 概率質量函數 p X ( x ) P ( X x ) pX(x)P(Xx) pX(x)P(Xx) 是離散隨機變數…...

Django 中数据库迁移命令
在 Django 中,python manage.py makemigrations、python manage.py sqlmigrate polls 0003 和 python manage.py migrate 是与数据库迁移相关的重要命令。它们的作用和对应内容如下: 1. python manage.py makemigrations 功能: 此命令会根据你的模型文…...

【机器学习】 卷积神经网络 (CNN)
文章目录 1. 为什么需要 CNN2. CNN 的架构3. 卷积层4. 池化层5. CNN 的应用 1. 为什么需要 CNN 前提:利用前置知识,去掉全连接神经网络中的部分参数,提升学习效率。本质:在 DNN 之前加上 CNN,先去除不必要的参数&…...

Linux中操作中的无痕命令history技巧
当我们需要查看Linux下的操作记录时,就可以用history命令来查看历史记录 1、关闭history记录功能,如果不想让别人看到自己在Linux上的操作命令,可以用这个命令 set o history 2、打开history记录功能 set -o history3、清空记录 histor…...

在CE自动汇编里调用lua函数
CE自动汇编模板里有一个是调用lua函数,但是关于如何使用的资料很少,结果问AI也是各种错误回答,还各种误导... 下面是32位游戏的例子: loadlibrary(luaclient-i386.dll) luacall(openLuaServer(CELUASERVER))CELUA_ServerName: d…...

如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone
概括 近期iOS 13.5的更新以及苹果公司发布的iPhone SE在众多iOS用户中引起了不小的轰动。此外,不少变化,如暴露通知 API、Face ID 增强功能以及其他在 COVID-19 期间与公共卫生相关的新功能,吸引了 iPhone 用户尝试新 iPhone 并更新到最…...

欧科云链研究院:ChatGPT 眼中的 Web3
编辑|OKG Research 转眼间,2024年已经进入尾声,Web3 行业经历了热闹非凡的一年。今年注定也是属于AI的重要一年,OKG Research 决定拉上 ChatGPT 这位“最懂归纳的AI拍档”,尝试把一整年的研究内容浓缩成精华。我们一共…...

行为模式2.命令模式------灯的开关
行为型模式 模板方法模式(Template Method Pattern)命令模式(Command Pattern)迭代器模式(Iterator Pattern)观察者模式(Observer Pattern)中介者模式(Mediator Pattern…...

Kerberos用户认证-数据安全-简单了解-230403
hadoop安全模式官方文档:https://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/SecureMode.html kerberos是什么 kerberos是计算机网络认证协议,用来在非安全网络中,对个人通信以安全的手段进行身份认证。 概念&#…...

【Multisim用74ls92和90做六十进制】2022-6-12
缘由Multisim如何用74ls92和90做六十进制-其他-CSDN问答 74LS92、74LS90参考...

滴滴工作流引擎Turbo与logicFlow研究
目录 logicFlow turbo 工作流引擎很多,也都提供了前端UI库,但是太过于冗杂了,元数据表都几十个,logincFlow和Turbo的组合提供了轻量化方式,turbo后端代码只有5个元数据表,logicFlow也提供了bpm的相关扩展功能,但缺点是turbo社区不活跃,logicFlow个人认为跟echarts这种…...

AE Pinnacle 10x6 kW DeviceNet MDXL User r Manual
AE Pinnacle 10x6 kW DeviceNet MDXL User r Manual...

Flutter Android修改应用名称、应用图片、应用启动画面
修改应用名称 打开Android Studio,打开对应项目的android文件。 选择app下面的manifests->AndroidManifest.xml文件,将android:label"bluetoothdemo2"中的bluetoothdemo2改成自己想要的名称。重新启动或者重新打包,应用的名称…...

Nginx rewrite 执行顺序(草稿,下次继续编辑)
个人结论: 1.server层ngx_http_rewrite_module模块相关指令按照配置顺序依次执行; 2.server层执行完break指令后,该层级所有跟ngx_http_rewrite_module模块相关的指令都不再被执行,但是不影响其他模块(例如:https://zhuanlan.zhihu.com/p/357…...