SpringBoot中一行代码解决字符串向枚举类型转换的问题
1. 场景
在WEB开发,客户端和服务端传输的数据中经常包含一些这样的字段:字段的值只包括几个固定的字符串。 这样的字段意味着我们需要在数据传输对象(Data Transfer Object, DTO)中对该字段进行校验以避免客户端传输的非法数据持久化到我们的系统中。
public record UserCreateDto(String userName,// userType的值为NORMAL, SILVER_CARD, GOLD_CARD, String userType) {}
我们可以采用多种办法验证userType的正确性,如:
方法一:利用Validation和正则表达式进行验证
public record UserCreateDto(String userName,// userType的值为NORMAL, SILVER_CARD, GOLD_CARD@Pattern(regexp = "^NORMAL$|^SILVER_CARD$|^GOLD_CARD$")String userType) {
}
方法二:在代码中写validate方法,在使用到DTO代码中调用validate方法
public record UserCreateDto(String userName,// userType的值为NORMAL, SILVER_CARD, GOLD_CARDString userType) {public void validate() {if (List.of("NORMAL", "SILVER_CARD", "GOLD_CARD").contains(userType)) {return;}throw new IllegalArgumentException("userType must be NORMAL, SILVER_CARD, GOLD_CARD");}
}
比较这两种方法,两种方法各有优缺点:
| 优点 | 缺点 | |
|---|---|---|
| 方法一 | 在DTO创建时(即参数的入口处)就可以验证数据的有效性 | 在@Pattern中使用字符串常量不方便,意味着开发者很难在整个代码中使用统一的自定义常量,为后期的修改带来不便 |
| 方法二 | 开发者可以在整个代码中使用统一的自定义常量,方便后续的修改 | 需要开发者主动调用validate方法,容易遗漏调用 |
2. 面向对象的解决办法
可能你早已想到用枚举来解决上述场景中的问题,没错,在面向对象编程中,枚举是解决这种问题的最好的解决办法。
public enum UserType {NORMAL, SILVER_CARD, GOLD_CARD
}public record UserCreateDto(String userName,// userType的值为NORMAL, SILVER_CARD, GOLD_CARD@NotNullUserType userType) {
}
枚举让我们的参数具有类型约束,并且具有可复用性和易修改等特性。
但是在SpringBoot中默认是不支持String到Enum的转换(读者可以尝试一下,不管客户端传入的userType正确与否,在DTO中userType值均为null )。
为了解决这个问题很多开发者都是通过自定义Conveter来进行String到Enum的转换的。如此常见的场景,作为开发者的我们都能想到使用统一的Converter,难到作为框架的开发者想不到?
3. 一行代码解决String到Enum的转换问题
先上解决方案。
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {// 通过ApplicationConversionService向应用中注入ConverterApplicationConversionService.configure(registry);}
就是这么简单,在应用中自定义WebMvcConfigurer,覆写addFormatters方法,并通过ApplicationConversionService向应用中注入String到Enum的Converter。
4. 原理分析
通过分析ApplicationConversionService的时序图,我们可以看到ApplicationConversionService最终通过DefaultConversonService调用ConverterRegister向应用注册了StringToEnumConverterFactory,从名字可以看出来StringToEnumConverterFactory就是负责String向Enum转换的。

StringToEnumConverterFactory的代码如下:
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {@Overridepublic <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {return new StringToEnum(ConversionUtils.getEnumType(targetType));}private static class StringToEnum<T extends Enum> implements Converter<String, T> {private final Class<T> enumType;StringToEnum(Class<T> enumType) {this.enumType = enumType;}@Override@Nullablepublic T convert(String source) {if (source.isEmpty()) {// It's an empty enum identifier: reset the enum value to null.return null;}return (T) Enum.valueOf(this.enumType, source.trim());}}
}
可以看出,StringToEnumConverterFactory中也是通过Enum的valueOf方法完成String到Enum的转换的。
5. 方案的不足
采用Spring框架提供的StringToEnum Converter带给我们便利性的同时,也存在一些约束,如:
- Enum中实例的大小写必须和字符串的大小写一致,如字符串是小写的normal、silver_card、gold_card,Enum定义的实例也必须是normal、silver_card、gold_card,这个可能并不符合代码规范(通常Enum的实例都要球全大写);
- 字符串中包含一些特殊字符是Java命名规范不允许的,如中划线。
因此,选用哪种方法完成字符串到Enum的转换还要根据实际的应用场景出发。
相关文章:
SpringBoot中一行代码解决字符串向枚举类型转换的问题
1. 场景 在WEB开发,客户端和服务端传输的数据中经常包含一些这样的字段:字段的值只包括几个固定的字符串。 这样的字段意味着我们需要在数据传输对象(Data Transfer Object, DTO)中对该字段进行校验以避免客户端传输的非法数据持…...
Praat之基频分析
Praat之基频分析 测量基频F0的方法 自相关 Autocorrelation(易出现pitch-halving\pitch-double)窄带谱图 Narrowband spectrogram(第一谐波就是基频)倒谱分析 Cepstral analysis测量声门波 glottal pluse(通过波形&a…...
乡村企业门户网站
技术:Java、JSP等摘要:随着时代的发展,电脑与Internet已经进入我们的生活。信息时代的来临,知识经济的扩张,网站已越来越靠近我们的生活。据CNNIC报告显示,中国上网用户有6800万。通过Internet来经营运作一…...
Deploy Workshop|DIY部署环境,让OceanBase跑起来
2023 年 3 月 25 日,我们将在北京开启首次 OceanBase 开发者大会,与开发者共同探讨单机分布式、云原生、HTAP 等数据库前沿趋势,分享全新的产品 Roadmap,交流场景探索和最佳实践,此外,OceanBase 开源技术全…...
【CPP】定义一个类
一:当实现一个类的时候,编译器都做了什么 前言:当我们实现一个类的时候,编译器为我们做了什么;在对类进行操作的时候,有哪些特殊的成员函数可以帮助我们更好的操纵类; class A {A();//默认构造…...
谷歌广告投放步骤流程是什么?一文带你全方位了解实操细节
谷歌,大家都不陌生吧,一个人们很常用的搜索引擎。而谷歌还可以打广告,即谷歌广告,那这跟跨境电商有什么关心呢?东哥告诉大家,关系大了去了,毕竟如果用户搜索与我们相关的关键词,就有…...
TypeScript 怎么去查找类型定义的?
TypeScript 怎么去查找类型定义的?类型文件分类第三方库的类型自定义类型结论类型文件分类 我们项目中的类型文件分为两种:一类是第三方库的类型,一类是在项目中的自定义类型。 第三方库的类型 (1)Jquery࿱…...
NPM包管理器
文章目录一、NPM包管理器1、简介2、安装NPM3、使用npm管理项目3.1项目初始化3.2修改npm镜像3.3 npm install命令的使用3.4其它命令一、NPM包管理器 1、简介 什么是NPM NPM全称Node Package Manager,是Node.js包管理工具,是全球最大的模块生态系统&…...
IT英语记录
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言1、Classification2、Logistic Regression3、网络相关3.1 WAN(Wide Area Network)、LAN(Local Area Network)网络…...
SRS4.0 源码分析- RTC模块相关类
前言 本文介绍SRS4.0涉及RTC模块的C类,主要包括RTC Server和Session相关的。 SrsGoApiRtcPlay 处理webrtc client的播放请求,解析client的offer,并且生成server的answer,并且为这次请求创建一个session。SrsRtcServer 监听udp端…...
数位DP
数位dp的题目一般会问,某个区间内,满足某种性质的数的个数。 利用前缀和,比如求区间[l,r]中的个数,转化成求[0,r]的个数 [0,l-1]的个数。利用树的结构来考虑(按位分类讨论) 1081. 度的数量 #include<…...
剑指offer(一)-链表
(一)找出链表的环的入口结点 JZ23 链表中环的入口结点 中等 通过率:36.78% 时间限制:1秒 空间限制:64M 知识点链表哈希双指针 描述 给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点…...
CDH大数据平台入门篇之搭建与部署
一、CDH介绍 1.CDH 是一个强大的商业版数据中心管理工具 提供了各种能够快速稳定运行的数据计算框架,如Spark; 使用Apache Impala做为对HDFS、HBase的高性能SQL查询引擎; 使用Hive数据仓库工具帮助用户分析数据; 提供CM安装HBas…...
Spark Join
Spark Join关联形式内关联外关联左外关联右外关联全外关联左半/逆关联关联机制NLJSMJHJ分发模式Join 选择等值 Join不等值 JoinJoin 按照关联形式(Join Types)划分 : 内关联、外关联、左关联、右关联 Join 按实现机制划分 : NLJ (Nested Loop Join) 、S…...
数字的转化规则?
数字的转化规则?js将字符串转换为数字的方式有哪些?1. 使用 parseInt()2. 使用 Number()3. 使用一元运算符 ()4.使用parseFloat()5. 使用 Math.floor()和Math.ceil()6.乘以数字7. 双波浪号 (~~) 运算符其它值到数字的转化规则1.Undefined 类型2.Null 类型…...
MySQL面试题-锁相关
目录 1.MySQL 锁的类型有哪些呢? 2.如何使用全局锁 3.如果要全库只读,为什么不使用set global readonlytrue的方式? 4.表级锁和行级锁有什么区别? 5.行级锁的使用有什么注意事项? 6.InnoDB 有哪几类行锁ÿ…...
Windows 终端编译 C代码
E:\My_SoftWare\Window gcc\windowbianji\mingw64\bin 此电脑--》属性--》系统--》高级系统设置--》环境变量--》Path--》新建--》粘贴路径 E:\My_SoftWare\Window gcc\windowbianji\mingw64\bin 打开命令终端 E: 回车 dir 显示所有文件 cd E:\My_SoftWare\Window gcc\C_co…...
SpringCloud:Feign的使用及配置
目录 Feign的使用及配置 1、Feign替代RestTemplate 2、使用Fegin步骤 3、自定义配置 4、Feign使用优化 5、Feign的最佳实践方式 Feign的使用及配置 1、Feign替代RestTemplate RestTemplate方式远程调用的问题 问题: 1、代码可读性差,编程体验不同…...
Parquet学习与使用之BloomFilter的应用
写在前面 最近在自己做自定义的OLAP系统,文件格式上用的是Parquet,但是发现Parquet各个API的示例代码很少。所以就打算把这个系列的文章写一下。 1. Parquet的Filter Parquet的过滤支持两大类,一类是基于Footer中的元数据进行RowGroup级别…...
95%置信区间计算-理解
机器学习中做多次试验后,需要计算指标的95%置信区间。 假设做了10次试验,计算得出的某指标分别为{x1,…,x10} 其均值为μ(x1...x10)/10\mu(x1 ... x10)/10μ(x1...x10)/10 方差σ∑(xi−μ)2/10\sigma\sum(x_i -\mu)^2/10σ∑(xi−μ)2/10 95%置信…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
