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:用于处理资源文件,如文件下载

配置消息转换器

     你可以通过以下几种方式配置消息转换器:

  1. 通过Java配置类

     

    如果你正在使用基于Java的配置,可以通过实现WebMvcConfigurer接口并重写configureMessageConverters方法来添加自定义的消息转换器:

    @Configuration
    public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加默认的消息转换器WebMvcConfigurer.super.configureMessageConverters(converters);// 添加自定义的消息转换器converters.add(new CustomHttpMessageConverter());}
    }
  2. 通过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>
  3. 自动配置(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会抛出HttpMessageNotReadableExceptionHttpMessageNotWritableException。你可以通过全局异常处理器来捕获这些异常并返回友好的错误信息给客户端。

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.propertiesapplication.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();
}

还可以通过继承JsonSerializerJsonDeserializer来创建更加定制化的逻辑。

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服务的开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/65964.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python使用AprilTag 3

python使用AprilTag 3 最近想测试一下AprilTag精度&#xff0c;看看能不能用的上。 1 安装 法1&#xff1a;github源码编译安装&#xff08;放弃&#xff09; 一开始找到了AprilTag 3的官方github网址https://github.com/AprilRobotics/apriltag&#xff0c;但是按着操作下…

小程序学习07—— uniapp组件通信props和$emit和插槽语法

目录 一 父组件向子组件传递消息 1.1 props &#xff08;a&#xff09;传递静态或动态的 Prop &#xff08;b&#xff09;单向数据流 二 子组件通知父组件 2.1 $emit &#xff08;a&#xff09;定义自定义事件 &#xff08;b&#xff09;绑定自定义事件 三 插槽语法…

纵览!报表控件 Stimulsoft Reports、Dashboards 和 Forms 2025.1 新版本发布!

Stimulsoft 2025.1 新版发布&#xff0c;旨在增强您创建报告、仪表板和 PDF 表单的体验&#xff01;此最新版本为您带来了许多改进和新功能&#xff0c;使数据处理更加高效和用户友好。亮点包括对 .NET 9 的支持、Microsoft Analysis Services 的新数据适配器、发布向导中适用于…

Unity Pico 应用失去焦点后,追踪功能被禁用(原生 UI 界面弹出)

在 Unity 中&#xff0c;如果正在使用新的输入系统&#xff0c;任何触发 OnApplicationFocus(false) 的事件都可能会禁用追踪功能。 负责此功能的组件是附加到主摄像机的 "Tracked Pose Driver (Input System)" 组件。由于非输入系统版本不是新输入系统的一部分&…

面试准备备备备

职业技能 放到简历的黄金位置&#xff08;HR刷选简历的重要参考&#xff09; 基本准则&#xff1a;写在简历上的必须能聊&#xff0c;不然就别写 参考公式&#xff1a;职业技能 必要技术 其他技术 针对性的引导面试官&#xff08;让他问一些你想让他问的&#xff09; 寻找合…

多光谱图像的处理和分析方法有哪些?

一、预处理方法 1、辐射校正&#xff1a; 目的&#xff1a;消除或减少传感器本身、大气条件以及太阳光照等因素对多光谱图像辐射亮度值的影响&#xff0c;使得图像的辐射值能够真实反映地物的反射或发射特性。 方法&#xff1a;包括传感器校正和大气校正。传感器校正主要是根…

艾体宝方案丨全面提升API安全:AccuKnox 接口漏洞预防与修复

一、API 安全&#xff1a;现代企业的必修课 在现代技术生态中&#xff0c;应用程序编程接口&#xff08;API&#xff09;扮演着不可或缺的角色。从数据共享到跨平台集成&#xff0c;API 成为连接企业系统与外部服务的桥梁。然而&#xff0c;伴随云计算的普及与微服务架构的流行…

多个DataV遍历生成

DataV是数据可视化工具 与Echart类似 相对Echart图标边框 装饰可选官网DataV 安装 npm install kjgl77/datav-vue3main.ts import DataVVue3 from kjgl77/datav-vue3 app.use(DataVVue3)多个DataV遍历生成 Vue3viteDataV为例:<template><div w50rem h25rem flex&qu…

小程序租赁系统的优势与应用探索

内容概要 小程序租赁系统&#xff0c;听起来很高大上&#xff0c;但实际上它比你想象的要实用得多&#xff01;设想一下&#xff0c;几乎所有的租赁需求都能通过手机轻松解决。这种系统的便捷性体现在让用户随时随地都能发起租赁请求&#xff0c;而不再受制于传统繁琐的手续。…

driftingblues2

修改网卡配置信息 首先kali终端运行以下命令查看靶机ip 这里我们发现并没有查到靶机的ip&#xff0c;这时我们重启靶机 打开靶机&#xff0c;按下e键&#xff0c;进入到如下界面 将ro替换为rw signie init/bin/bash 替换完毕后&#xff0c;按下Ctrl键X键&#xff0c;进入如下…

Redis 使用redisTemplate获取某个规则下的key的全量数据(示例Set结构)

如下是redis中存储的数据结构 我想取key以favorites:结尾的所有数据 Redis 的 SCAN 命令用于迭代数据库中的键&#xff0c;支持通过模式过滤结果。模式规则基于 Redis 的通配符匹配语法&#xff0c;类似于文件名匹配规则&#xff1a; *&#xff1a;匹配零个或多个字符。?&…

1月2日作业

工人管理系统 #include<myhead.h> #include<sqlite3.h> sqlite3 * creat_sqlite()//创建数据库并返回数据库句柄 {const char *p"./my.db";sqlite3 *ppDb;if(sqlite3_open(p,&ppDb)!SQLITE_OK)//调用数据库提供的第三方库函数{printf("打开数据…

职场常用Excel基础03-自定义排序

大家好&#xff0c;今天和大家一起分享一下excel中的自定义排序~ 通过排序&#xff0c;用户可以快速地对表格中的数据进行整理&#xff0c;以便更直观地观察趋势、查找特定信息或为后续的数据分析做准备。除了标准的升序和降序排序外&#xff0c;Excel还提供了强大的自定义排序…

计算机网络-L2TP Over IPSec基础实验

一、概述 上次我们进行了标准L2TP的配置&#xff0c;但是在最后我们在进行业务流量访问时看到流量是没有进行加密的&#xff0c;这就导致可能得安全风险&#xff0c;所以这里其实可以退像GRE那样调用IPSec框架来进行加密保护。 拓扑 数据不加密 现在需要配置IPSec&#xff0c;然…

C#控件开发4—仪表盘

目录 思路&#xff08;GDI绘图&#xff09;1.定义属性2.绘制图形3.最后生成&#xff08;自定义各种监控值显示&#xff09;End 如何让温度、湿度、压力等有量程的监控值如仪表盘&#xff08;DashBoard&#xff09;一样显示&#xff1f; 思路&#xff08;GDI绘图&#xff09; 定…

ThinkPHP 8高效构建Web应用-第一个简单的MVC应用示例

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 我们先实现一…

数字化供应链创新解决方案在零售行业的应用研究——以开源AI智能名片S2B2C商城小程序为例

摘要&#xff1a; 在数字化转型的浪潮中&#xff0c;零售行业正经历着前所未有的变革。特别是在供应链管理方面&#xff0c;线上线下融合、数据孤岛、消费者需求多样化等问题日益凸显&#xff0c;对零售企业的运营效率与市场竞争力构成了严峻挑战。本文深入探讨了零售行业供应…

RabbitMQ - 4 ( 22000 字 RabbitMQ 入门级教程 )

一&#xff1a; RabbitMQ 高级特性 前面主要讲解了 RabbitMQ 的概念和应用。RabbitMQ 实现了 AMQP 0-9-1 规范&#xff0c;并在此基础上进行了多项扩展。在 RabbitMQ 官方网站中详细介绍了其特性&#xff0c;我们将其中一些重要且常用的特性挑选出来进行讲解。 1.1 消息确认 …

mac m2 安装 docker

文章目录 安装1.下载安装包2.在downloads中打开3.在启动台打开打开终端验证 修改国内镜像地址小结 安装 1.下载安装包 到官网下载适配的安装包&#xff1a;https://www.docker.com/products/docker-desktop/ 2.在downloads中打开 拖过去 3.在启动台打开 选择推荐设置 …

QT--------网络

实现思路 主机信息查询&#xff1a; 使用 QHostInfo 类可以查询主机名和 IP 地址信息。QNetworkInterface 类可以获取本地网络接口的信息&#xff0c;包括 IP 地址、子网掩码、广播地址等。 TCP 通信&#xff1a; 使用 QTcpServer 类实现 TCP 服务器端程序设计。使用 QTcpSock…