SpringBoot实战:枚举类型转换问题

1.在controller层中完成service注入

2.调用业务层进行查询所有房间类型标签 

@Tag(name = "标签管理")
@RestController
@RequestMapping("/admin/label")
public class LabelController {

    @Autowired
    private LabelInfoService service;

    @Operation(summary = "(根据类型)查询标签列表")
    @GetMapping("list")
    public Result<List<LabelInfo>> labelList(@RequestParam(required = false) ItemType type) {
        //添加查询过滤条件
        LambdaQueryWrapper<LabelInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //type类型不为空,获取该类型的所有信息,由于涉及类型转换,需要手动配置converter
        lambdaQueryWrapper.eq(type != null, LabelInfo::getType, type);
        List<LabelInfo> list = service.list(lambdaQueryWrapper);
        return Result.ok(list);
    }

 转换问题

上述接口的功能是根据type(公寓/房间),查询标签列表。由于这个type字段在数据库、实体类、前后端交互的过程中有多种不同的形式,因此在请求和响应的过程中,type字段会涉及到多次类型转换。

数据库中type类型

+-------------+--------------+
| Field       | Type         |
+-------------+--------------+
| id          | bigint       |
| type        | tinyint      |
| name        | varchar(255) |
| create_time | timestamp    |
| update_time | timestamp    |
| is_deleted  | tinyint      |
+-------------+--------------+

 实体类中type字段为ItemType类型

@Schema(description = "标签信息表")
@TableName(value = "label_info")
@Data
public class LabelInfo extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Schema(description = "类型")
    @TableField(value = "type")
    private ItemType type;

    @Schema(description = "标签名称")
    @TableField(value = "name")
    private String name;
}

ItemType枚举类

public enum ItemType {

    APARTMENT(1, "公寓"),
    ROOM(2, "房间");

    private Integer code;
    private String name;

    ItemType(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

前后端数据交互中type类型为数字

 数据类型转换过程及原理

`WebDataBinder`依赖于[`Converter`]实现类型转换,若Controller方法声明的`@RequestParam`参数的类型不是`String`,`WebDataBinder`就会自动进行数据类型转换。SpringMVC提供了常用类型的转换器,例如`String`到`Integer`、`String`到`Date`,`String`到`Boolean`等等,其中也包括`String`到枚举类型,但是`String`到枚举类型的默认转换规则是根据实例名称("APARTMENT")转换为枚举对象实例(ItemType.APARTMENT)。若想实现`code`属性到枚举对象实例的转换,需要自定义`Converter

WebDataBinder枚举类型转换

方法一:

步骤1、自定义Converter实体类实现Converter接口,并重写接口的方法

步骤2、自定义WebMvcConfiguration实体类实现WebMvcConfiguration接口,并重写addFormatters方法,在方法内将定义的Converter实体类添加到容器中

//自定义converter,完成枚举类型向string类型转换
@Component
public class StringToItemTypeConverter implements Converter<String, ItemType> {
    @Override
    public ItemType convert(String source) {

        //获取所有的ItemType枚举类型
        ItemType[] values = ItemType.values();
        for (ItemType itemType : values) {
            if (itemType.getCode().equals(Integer.valueOf(source))) {
                return itemType;
            }
        }

        throw new IllegalArgumentException("code非法");
    }
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private StringToItemTypeConverter converter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(this.converter);
    }
}

局限性

我们有很多的枚举类型都需要考虑类型转换这个问题,按照上述思路,我们需要为每个枚举类型都定义一个Converter,并且每个Converter的转换逻辑都完全相同,针对这种情况,我们使用[`ConverterFactory`]接口更为合适,这个接口可以将同一个转换逻辑应用到一个接口的所有实现类,因此我们可以定义一个`BaseEnum`接口,然后另所有的枚举类都实现该接口,然后就可以自定义`ConverterFactory`,集中编写各枚举类的转换逻辑了。

 方法二:

 步骤一:实现接口ConverterFactory接口,并重写getConverter方法,由该方法实现所有子类枚举类型转换

 步骤二:自定义WebMvcConfiguration实体类实现WebMvcConfiguration接口,并重写addFormatters方法,在方法内将定义的ConverterFactory实体类添加到容器中

//完成String向BaseEnum转换,当String需要向BaseEnum的子类进行转换时,
//ConverterFactory会自动调用getConverter方法,并将需要转换的子类传入,此时可通过字节码加载所有的枚举常量进行比较
@Component
public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        //通过字节码加载出所有的枚举常量
        return new Converter<String, T>() {
            @Override
            public T convert(String source) {
                T[] enumConstants = targetType.getEnumConstants();
                for (T enumConstant : enumConstants) {
                    if (enumConstant.getCode().equals(Integer.parseInt(source))) {
                        return enumConstant;
                    }
                }
                throw new IllegalArgumentException("code:" + source + "非法");
            }
        };
    }
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private StringToBaseEnumConverterFactory stringToBaseEnumConverterFactory;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(stringToBaseEnumConverterFactory);
    }
}

TypeHandler枚举类型转换

Mybatis预置的`TypeHandler`可以处理常用的数据类型转换,例如`String`、`Integer`、`Date`等等,其中也包含枚举类型,但是枚举类型的默认转换规则是枚举对象实例(ItemType.APARTMENT)和实例名称("APARTMENT")相互映射。若想实现`code`属性到枚举对象实例的相互映射,需要自定义`TypeHandler`。不过MybatisPlus提供了一个[通用的处理枚举类型的TypeHandler。其使用十分简单,只需在`ItemType`枚举类的`code`属性上增加一个注解`@EnumValue`,Mybatis-Plus便可完成从`ItemType`对象到`code`属性之间的相互映射 

public enum ItemType {

    APARTMENT(1, "公寓"),
    ROOM(2, "房间");

    @EnumValue
    private Integer code;
    private String name;

    ItemType(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

 HTTPMessageConverter枚举类型转换

 HttpMessageConverter`依赖于Json序列化框架(默认使用Jackson)。其对枚举类型的默认处理规则也是枚举对象实例(ItemType.APARTMENT)和实例名称("APARTMENT")相互映射。不过其提供了一个注解`@JsonValue`,同样只需在`ItemType`枚举类的`code`属性上增加一个注解`@JsonValue`,Jackson便可完成从`ItemType`对象到`code`属性之间的互相映射。

@Getter
public enum ItemType {

    APARTMENT(1, "公寓"),
    ROOM(2, "房间");

    @EnumValue
    @JsonValue
    private Integer code;
    private String name;

    ItemType(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

dm-verity hashtree的结构

参考了&#xff1a;实现 dm-verity | Android Open Source Project (google.cn)。基于这个添加了一层原始数据&#xff0c;便于理解。 结构图如下&#xff1a; 对hashtree结构图的解释&#xff1a; dev data&#xff1a;表示我们的分区数据。这里我们将dev data按照指定的大…

【JAVA poi-tl-ext 富文本转word】

富文本转word 环境使用poi-tl-ext的原因富文本转word代码 环境 jdk 1.8 <dependency><groupId>io.github.draco1023</groupId><artifactId>poi-tl-ext</artifactId><version>0.4.16</version> </dependency>poi-tl-ext已经包…

学习C++,应该循序渐进的看哪些书?

学习C是一个循序渐进的过程&#xff0c;需要根据自己的基础和目标来选择合适的书籍。以下是一个推荐的学习路径&#xff0c;包含了从入门到进阶的书籍&#xff1a; 1. 入门阶段 《C Primer Plus 第6版 中文版》 推荐理由&#xff1a;这本书同样适合C零基础的学习者&#xff0…

中国蚁剑的安装(附文件)

1.下载压包&#xff08;注意两个都要下载&#xff09; 我先挂几个月&#xff0c;后续怕找不到的话&#xff0c;就自己保存网盘 链接:https://pan.baidu.com/s/1bhBe6a1_5VFYUY35XG1N9Q?pwdx9gp 提取码:x9gp 链接:https://pan.baidu.com/s/1u8CMkOORRVpCI2zJysJPQQ?pwdx9gp …

java Web学习笔记(三)

文章目录 1. 前置知识2. Vue使用vite构建项目SFC入门使用ref和.value体会响应式数据&#xff08;使用ES6和setup&#xff09; 3. Vue视图渲染技术及其语法模板语法&#xff1a;命令插值表达式渲染双标><中的文本&#xff08;还挺可爱&#xff09;属性渲染命令事件渲染命令…

内网对抗-基石框架篇域树林域森林架构信任关系多域成员层级信息收集环境搭建

知识点&#xff1a; 1、基石框架篇-域树&域林架构-权限控制-用户和网络 2、基石框架篇-域树&域林架构-环境搭建-准备和加入 3、基石框架篇-域树&域林架构-信息收集-手工和工具1、工作组(局域网) 将不同的计算机按照功能分别列入不同的工作组。想要访问某个部门的…

24/7/12总结

axios Axios 是一个基于 promise 网络请求库&#xff0c;作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。 get请求: <script>function…

WordPress 主题技巧:给文章页增加“谁来过”模块。

模块功能&#xff1a; 我个人目前在做一个电影类的网站&#xff0c;在开发文章页的模版时候&#xff0c;突然觉得给文章页增加一个“谁对本电影感兴趣”的功能模块可能会比较有趣&#xff0c;这个功能有点类似于‘足迹’的感觉&#xff0c;用户可以通过这个功能&#xff0c;发…

C# Winform 系统方案目录的管理开发

在做一个中等复杂程度项目时&#xff0c;我们通常有系统全局配置&#xff0c;还要有对应的方案目录的管理和更新。 比如我们有如下需求&#xff1a;开发一个方案管理&#xff0c;可以新建、打开和保存方案&#xff0c;同时还需要保存方案中的各种文件。我设计的采用目录管理和…

短视频SEO矩阵系统:源码开发与部署全攻略

在数字化时代&#xff0c;短视频已成为人们获取信息、娱乐休闲的重要方式。随着短视频平台的兴起&#xff0c;如何让自己的内容在众多视频中脱颖而出&#xff0c;成为每个创作者和内容运营者关注的焦点。本文将为您深入解析短视频SEO矩阵系统的源码开发与部署&#xff0c;助您在…

Flink异常:org/apache/hadoop/hive/ql/parse/SemanticException

在flink项目中跑 上面这段代码出现如下这个异常&#xff0c; java.lang.NoClassDefFoundError: org/apache/thrift/TException 加上下面这个依赖后不报错 <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId…

PostgreSQL(二十二)缓冲区管理器

目录 一、缓冲区概述 1、缓冲区结构 2、buffer_tag结构 3、Backend进程读取操作 4、写脏块 二、缓冲区管理器结构 1、第一层&#xff1a;Buffer Table layer&#xff08;缓冲区表层&#xff09; 2、第二层&#xff1a;Buffer Descriptor Layer&#xff08;缓冲区描述层…

有必要把共享服务器升级到VPS吗?

根据自己的需求来选择是否升级&#xff0c;虚拟专用服务器 (VPS) 是一种托管解决方案&#xff0c;它以低得多的成本提供专用服务器的大部分功能。使用 VPS&#xff0c;您的虚拟服务器将与在其上运行的其他虚拟服务器共享硬件服务器的资源。但是&#xff0c;与传统的共享托管&am…

用python识别二维码(python实例二十三)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.识别二维码 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&…

Hadoop3:HDFS-通过配置黑白名单对集群进行扩缩容,并实现数据均衡(实用)

一、集群情况介绍 我的本地虚拟机&#xff0c;一共有三个节点&#xff0c;hadoop102、hadoop103、hadoop104 二、白名单 创建白名单文件whitelist&#xff0c;通过白名单的配置&#xff0c;只允许集群包含102和103两台机器可以存储数据&#xff0c;104无法存储数据。 需求 …

数据结构(4.2)——朴素模式匹配算法

字符串模式匹配 在主串中找到模式串相同的子串&#xff0c;并返回其所在的位置。 子串和模式串的区别 子串&#xff1a;主串的一部分&#xff0c;一定存在 模式串&#xff1a;不一定能在主串中找到 字符串模式匹配 朴素模式匹配算法 主串长度为n&#xff0c;模式串长度为…

js 请求blob:https:// 图片

方式1 def get_file_content_chrome(driver, uri):result driver.execute_async_script("""var uri arguments[0];var callback arguments[1];var toBase64 function(buffer){for(var r,nnew Uint8Array(buffer),tn.length,anew Uint8Array(4*Math.ceil(t/…

Oracle数据库加密与安全

Wallet简介&#xff1a; Oracle Wallet(即内部加密技术TDE( Transparent DataEncryption&#xff09; TDE是 Oracle10gR2中推出的一个新功能,使用时要保证Oracle版本是在10gR2或者以上 Wallet配置&#xff1a; 1.创建一个新目录&#xff0c;并指定为Wallet目录 /home/oracle…

根据脚手架archetype快速构建spring boot/cloud项目

1、找到archetype&#xff0c;并从私仓下载添加archetype到本地 点击IDEA的file&#xff0c;选择new project 选择maven项目&#xff0c;勾选create from archetype 填写archetype信息&#xff0c;&#xff08;repository填写私仓地址&#xff09; 2、选择自定义的脚手架arche…

torch之从.datasets.CIFAR10解压出训练与测试图片 (附带网盘链接)

前言 从官网上下载的是长这个样子的 想看图片&#xff0c;咋办咧&#xff0c;看下面代码 import torch import torchvision import numpy as np import os import cv2 batch_size 50transform_predict torchvision.transforms.Compose([torchvision.transforms.ToTensor(),…