九,自定义转换器详细操作(附+详细源码解析)

九,自定义转换器详细操作(附+详细源码解析)

文章目录

  • 九,自定义转换器详细操作(附+详细源码解析)
  • 1. 基本介绍
  • 2. 准备工作
  • 3. 自定义转换器操作
  • 4. 自定义转换器的注意事项和细节
  • 5. 总结:
  • 6. 最后:

Spring Boot 定义对象参数支持自动封装

  1. 在开发中,Spring Boot 在响应客户端请求时,也支持自定义对象参数
  2. 完成自动类型转换与格式化
  3. 支持级联封装

1. 基本介绍

  1. Spring Boot 在响应客户端请求时,将提交的数据封装成对象时,使用了内置的转换器。
  2. Spring Boot也支持自定义转换器,这个内置的转换器在debug的时候,可以看到,后面给大家演示,提供了 124个内置转换器,看下源码 GenericConverter ——> ConvertiblePair

在这里插入图片描述

2. 准备工作

在 pom.xml 文件当中配置相关的 jar 依赖。如下图所示:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rainbowsea</groupId><artifactId>springboot_parameters</artifactId><version>1.0-SNAPSHOT</version><!--    导入SpringBoot 父工程-规定写法--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.3</version></parent><!--    导入web项目场景启动器:会自动导入和web开发相关的jar包所有依赖【库/jar】--><!--    后面还会在说明spring-boot-starter-web 到底引入哪些相关依赖--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>

对应需要测试的 Bean 对象/POJO对象,两个 Car 和 Monster ,这里我们使用上 Lombok 插件,关于 Lombok的详细内容,大家可以移步至:✏️✏️✏️ 六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率-CSDN博客

在这里插入图片描述

package com.rainbowsea.springboot.bean;import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
public class Car {private String name;private Double price;
}
package com.rainbowsea.springboot.bean;import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Date;@Data
@NoArgsConstructor
public class Monster {private Integer id;private String name;private Integer age;private Boolean isMarried;private Date birth;private Car car;
}

创建对应的controller 控制器,对应的请求路径的处理。

在这里插入图片描述


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;//@RestController //  @Controller + @ResponseBody
@Controller
public class ParameterController {// 处理添加 monster 的方法@PostMapping("/savemonster")@ResponseBodypublic String saveMonster(Monster monster) {System.out.println("monster-" + monster);return "success";}
}

对应前端 ,浏览器提交数据的 表单 html 页面的编写内容。

自定义转换器关联 Car 对象,使用 , 号间隔。

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>添加妖怪</title>
</head>
<body>
<h1>添加妖怪-坐骑[测试封装POJO:]</h1>
<form action="/savemonster" method="post">编号: <input name="id" value="100"><br/>姓名: <input name="name" value="牛魔王"><br/>年龄: <input name="age" value="500"><br/>婚否: <input name="isMarried" value="true"><br/>生日: <input name="birth" value="2000/11/11"><br/>
<!--使用自定义转换器关联Car,字符串整体提交,使用,号间隔-->坐骑: <input name="car" value="避水金晶兽,666.6">
<!--    坐骑名称: <input name="car.name" value="法拉利"><br/>坐骑价格: <input name="car.price" value="999"><br/>--><input type="submit" value="保存"></form>
</body>
</html>

编写 Spring Boot 的应用程序的启动场景

在这里插入图片描述

package com.rainbowsea.springboot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class,args);}
}

3. 自定义转换器操作

编写 自定义转换器:将 前端的“String ”类型的数据转换为 后端“Car” 类型的数据 。

在这里插入图片描述

在这里插入图片描述

package com.rainbowsea.springboot.config;import com.rainbowsea.springboot.bean.Car;
import com.rainbowsea.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration // 标志配置类
public class WebConfig {@Bean // 注如到 ioc容器当中public WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 老师解读* 1. 在addFormatters方法中,增加一个自定义的转换器* 2. 增加自定义转换器 String->car* 3. 增加的自定义转换器会注册到converters容器中* 4. converters 底层结构时 ConcurrentHashMap 内置了124个转换器* 5. 一会老师会使用 debug 来看到这些转换器*/registry.addConverter(new Converter<String, Car>() { // 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Car convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils) 或者 ObjectUtils 工具类都行。if(!ObjectUtils.isEmpty(source)) {Car car = new Car();String[] split = source.split(",");car.setName(split[0]);car.setPrice(Double.parseDouble(split[1]));  // 将String类型的数据转换为 Double 类型的数据return car;}return null;}});}}}
}

运行测试:

在这里插入图片描述

上面是使用了 匿名的内部类 ,我们也可以不使用匿名内部类,分开来写也是可以的。

在这里插入图片描述

package com.rainbowsea.springboot.config;import com.rainbowsea.springboot.bean.Car;
import com.rainbowsea.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration // 标志配置类
public class WebConfig {@Bean // 注如到 ioc容器当中public WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 老师解读* 1. 在addFormatters方法中,增加一个自定义的转换器* 2. 增加自定义转换器 String->car* 3. 增加的自定义转换器会注册到converters容器中* 4. converters 底层结构时 ConcurrentHashMap 内置了124个转换器* 5. 一会老师会使用 debug 来看到这些转换器*/Converter<String,Car> converter = new Converter<String, Car>() { // 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Car convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {Car car = new Car();String[] split = source.split(",");car.setName(split[0]);car.setPrice(Double.parseDouble(split[1]));return car;}return null;}};// 添加自定义的转换器registry.addConverter(converter);}}}
}

运行测试:

在这里插入图片描述

注意:自定义转换器可以添加多个,默认 Spring Boot 内置的转换器是 124 个

这里,我们再添加一个转换器:将 前端的"Spring ’ 类型的数据,转换成 Monster 类型的数据,这里主要演示的是,可以添加多个自定义转换器,所以,自定义转换器内部的业务,我就不处理编写的,直接返回 null了。

在这里插入图片描述

package com.rainbowsea.springboot.config;import com.rainbowsea.springboot.bean.Car;
import com.rainbowsea.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration // 标志配置类
public class WebConfig {@Bean // 注如到 ioc容器当中public WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 老师解读* 1. 在addFormatters方法中,增加一个自定义的转换器* 2. 增加自定义转换器 String->car* 3. 增加的自定义转换器会注册到converters容器中* 4. converters 底层结构时 ConcurrentHashMap 内置了124个转换器* 5. 一会老师会使用 debug 来看到这些转换器*/Converter<String,Car> converter = new Converter<String, Car>() { // 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Car convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {Car car = new Car();String[] split = source.split(",");car.setName(split[0]);car.setPrice(Double.parseDouble(split[1]));return car;}return null;}};// 第2个自定义转换器// 还可以增加更多的转换器Converter<String,Monster> converter2 = new Converter<String, Monster>() { //// 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Monster convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {Monster monster = new Monster();String[] split = source.split(",");return monster;}return null;}};// 添加自定义的转换器registry.addConverter(converter);registry.addConverter(converter2);}}}
}

这里我们进行一个 Debug 进行追踪源码:看看是不是真的添加上了2个我们自己编写的转换器,记住Spring Boot 默认是 124个,这里我们添加了 2个就是 126个了

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4. 自定义转换器的注意事项和细节

从上面的我们的Debug分析可以知道的 Spring Boot 是使用 Map集合存储我们的转换器的,而对应 Map 当中的 key 就是我们转换的内容信息

=在这里插入图片描述

而 Map 集合当中 key 是唯一的不可以重复的,所以,当我们自定义了多个转换内容类型是重复(一样)的 转换器的时候,会覆盖掉,我们前面转换内容信息一样的 转换器。

如下:我们再定义一个“将 前端的“String ”类型的数据转换为 后端“Car” 类型的数据 的转换器”。

在这里插入图片描述

package com.rainbowsea.springboot.config;import com.rainbowsea.springboot.bean.Car;
import com.rainbowsea.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration // 标志配置类
public class WebConfig {@Bean // 注如到 ioc容器当中public WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addFormatters(FormatterRegistry registry) {/*** 老师解读* 1. 在addFormatters方法中,增加一个自定义的转换器* 2. 增加自定义转换器 String->car* 3. 增加的自定义转换器会注册到converters容器中* 4. converters 底层结构时 ConcurrentHashMap 内置了124个转换器* 5. 一会老师会使用 debug 来看到这些转换器*/Converter<String,Car> converter = new Converter<String, Car>() { // 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Car convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {Car car = new Car();String[] split = source.split(",");car.setName(split[0]);car.setPrice(Double.parseDouble(split[1]));return car;}return null;}};// 添加转换器converter3 重复了Converter<String,Car> converter3 = new Converter<String, Car>() { // 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Car convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {System.out.println("source-" + source);}return null;}};// 第2个自定义转换器// 还可以增加更多的转换器Converter<String,Monster> converter2 = new Converter<String, Monster>() { //// 第一个参数是要转换的类型,第二个参数是想要转换成什么类型@Overridepublic Monster convert(String source) {  // source 就是传入的字符串,避水金晶兽// 这里就加入你的自定义的转换业务处理//if(StringUtils)if(!ObjectUtils.isEmpty(source)) {Monster monster = new Monster();String[] split = source.split(",");return monster;}return null;}};// 添加自定义的转换器registry.addConverter(converter);registry.addConverter(converter2);registry.addConverter(converter3);}};}
}

在这里插入图片描述

从上述结果上来看,我们可以十分清楚的明白了。

因为:因为Spring Boot是用 Map存储我们的转换器的,而Map其中的 key 存储的是我们转换器的内容信息,Spring Boot以我们转换的内容信息,作为 key 唯一,不可重复。所以一旦我们出现了,转换内容信息是一样的转换器,那么前面的转换器会被最后一个重复的转换器给替换掉。

5. 总结:

  1. Spring Boot 内置有 124 个转换器。我们可以自定义多个转换器。
  2. Spring Boot是用 Map 存储我们的转换器的,而Map其中的 key 存储的是我们转换器的内容信息,Spring Boot以我们转换的内容信息,作为 key 唯一,不可重复。所以一旦我们出现了,转换内容信息是一样的转换器,那么前面的转换器会被最后一个重复的转换器给替换掉。
  3. 实际开发中 Spring Boot 内置的 124个转换器,以及Spring Boot的自动封装对象的机制,足够我们实际开发中使用了。

6. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

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

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

相关文章

电脑怎么限制软件上网?推荐三个超详细的小妙招(软件上网权限管理)

想要控制电脑上哪些软件可以上网、哪些不能&#xff1f;不管是为了保护隐私、节省流量&#xff0c;还是提高工作效率&#xff0c;限制软件上网都是非常实用的小妙招&#xff01; 今天给大家带来三个超详细的招数&#xff0c;帮助你轻松管理软件的上网权限。让那些不该上网的应…

云计算第四阶段----CLOUD 01-03

CLOUD Day01 一、虚拟化平台搭建 虚拟化技术产品介绍 #黄线标注的&#xff0c;都是比较主流且常用的虚拟化平台。 虚拟化与云计算的关系 虚拟化是一种技术&#xff0c;它允许在单个物理服务器上创建和运行多个虚拟机&#xff08;VMs&#xff09;&#xff0c;每个虚拟机都有其…

python编程知识(实现数据加密和解密)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

JavaScript使用高德API显示地图

前言 在JavaScript中&#xff0c;使用Leaflet库显示地图是一种常见的做法。Leaflet是一个开源的JavaScript库&#xff0c;用于在Web应用程序中创建互动地图。它非常轻量级&#xff0c;易于使用&#xff0c;并且提供了多种功能&#xff0c;使开发者能够轻松地将地图集成到他们的…

银行结算业务

1.1 银行本票 银行本票是由银行签发的,承诺自己在见票时无条件支付票款给收款人或持票人的业务。银行本票按票面划分为定额本票和不定额本票,按币种划分为人民币银行本票和外币银行本票。人民币银行本票仅在同一交换区域内使用,资金清算利用当地人民银行组织的资金清算形式…

vite+vue3+typescript+elementPlus前端实现电子证书查询系统

实现背景&#xff1a;之前电子证书的实现是后端实现的&#xff0c;主要采用GD库技术&#xff0c;在底图上添加文字水印和图片水印实现的。这里采用前端技术实现电子证书的呈现以及点击证书下载&#xff0c;优点是&#xff1a;后端给前端传递的是一组数据&#xff0c;不需要传证…

数据分析训练模型后输出模型评估报告

数据分析训练模型后输出模型评估报告 1、模型评估指标 1.1、概念: A:n个正样本,检测到是真值的数量 B:m个负样本,检测到是真值的数量 C:n个正样本,检测到假值的数量 D:m个负样本,检测到假值的数量 1.2、准确率(Accuracy) 正确预测的样本数量与总样本数量的比值。…

笔记整理—内核!启动!—kernel部分(1)从汇编阶段到start_kernel

kernel起始与ENTRY(stext)&#xff0c;和uboot一样&#xff0c;都是从汇编阶段开始的&#xff0c;因为对于kernel而言&#xff0c;还没进行栈的维护&#xff0c;所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。 内核起始部分代码被解压代码调用&#xff0c…

Pinterest账号被封?试试这几种解封方法

Pinterest作为一个充满创意与灵感的视觉社交平台&#xff0c;吸引着大量用户和企业前来展示、收藏和分享他们的作品。然而&#xff0c;如同其他社交媒体平台一样&#xff0c;Pinterest也设立了一套严格的使用规则和监测机制&#xff0c;以保障平台内容的质量和用户的良好体验。…

Helm Deploy Online Rancher v2.9.1

文章目录 准备安装查看下载 准备 $ kubectl get node NAME STATUS ROLES AGE VERSION kube-master01 Ready control-plane 19d v1.29.5 kube-node01 Ready <none> 19d v1.29.5 kube-node02 Ready <none&…

SpringBoot+Redis极简整合

1 前言 Redis是现在最受欢迎的NoSQL数据库之一&#xff0c;下面将以最简洁的代码演示&#xff0c;在SpringBoot中使用redis。 2 下载安装Redis 2.1 下载 Redis3.x windows安装版下载地址 2.2 安装到任意位置 一直Next到完即可。 2.3 启动 打开安装目录&#xff0c;点击…

Bootstrap前端框架Glyphicons字体图标

115工具网收集提供Bootstrap前端框架Glyphicons字体图标库对照表​​​​​​​&#xff0c;Bootstrap前端UI,Glyphicons字体图标调用,Bootstrap按钮字体图标对照表,包括250多个来自Glyphicon Halflings的字体图标.项目中引用Bootstrap相关文件后即可直接调用下列图标class&quo…

HTML生日蛋糕

目录 写在前面 完整代码 代码分析 系列文章 写在最后 写在前面 HTML实现的生日蛋糕来喽&#xff0c;小编亲测&#xff0c;发给好友可以直接打开哦。在代码的第183行可以写下对朋友的祝福&#xff0c;快拿去送给你的好朋友吧&#xff01; 完整代码 <!DOCTYPE html>…

整合Redis和RedisCacheManger

整合redis springboot在现在的版本中操作Redis数据库用到了lettuce&#xff0c;而不是Jedis&#xff0c;他们各有各的特点。Jedis以Redis命令作为方法名称&#xff0c;学习成本低&#xff0c;简单实用。但是Jedis实例是线程不安全的&#xff0c;多线程环境下需要基于连接池来使…

VSCode安装配置C语言(保姆级教程)

目录 引言 一、VS Code的卸载 1.卸载VS Code应用 ​编辑2.删除安装的插件 3.删除配置的信息 二、VS Code的安装 1.下载vscode 2.安装VS Code 三、VS Code配置C语言环境 1.安装插件 2.下载MinGW 3.添加路径 4.确认gcc位置 ​四、运行C语言程序 ​总结 引言 Vi…

揭开面纱--机器学习

一、人工智能三大概念 1.1 AI、ML、DL 1.1.1 什么是人工智能? AI&#xff1a;Artificial Intelligence 人工智能 AI is the field that studies the synthesis and analysis of computational agents that act intelligently AI is to use computers to analog and instead…

MASt3R:从3D的角度来实现图像匹配(更新中)

Abstract 图像匹配是 3D 视觉中所有性能最佳算法和pipeline的核心组件。 然而&#xff0c;尽管匹配从根本上来说是一个 3D 问题&#xff0c;与相机姿态和场景几何结构有内在联系&#xff0c;但它通常被视为一个 2D 问题。因为匹配的目标是建立 2D 像素字段之间的对应关系&#…

STM32的GPIO使用

一、使用流程 1.使用RCC开启GPIO时钟 2.使用GPIO_Init 函数初始化GPIO 3.使用输出或输入函数控制GPIO口 二、RCC的常用函数 函数内容可通过这两个文件进行查看&#xff1a; RCC常用函数如下&#xff1a; void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalS…

我与Linux的爱恋:yum和vim以及gcc的使用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 ​1.Linux软件包管理器yum2.Linux开发工具3.Linux编译器 vimvim的基本概念vim的基本操作vim正常模式命令集vim末行模式命令集vim操作总结批量化注释批量化去注释简…

2024国赛数学建模A题B题C题D题E题思路资料模型

开始在本帖实时更新2024国赛数学建模赛题思路代码&#xff0c;文章末尾获取&#xff01; 持续更新参考思路