Mybatis自定义TypeHandler,直接存储枚举类对象

在这篇文章中,我们已经知道如何使用枚举类直接接受前端的数字类型参数,省去了麻烦的转换。如果数据库需要保存枚举类的code,一般做法也是代码中手动转换,那么能不能通过某种机制,省去转换,达到代码中直接保存枚举对象,但是数据库中保存的却是code值呢。即我们的整体目标如下

数字
枚举类
数字
前端
后端-枚举类接收
Mybatis-枚举类接收
数据库保存数字类型

实际上Mybatis对枚举类有一定的支持,在官网中看到对枚举类的支持有两种:EnumTypeHandler和EnumOrdinalTypeHandler。前者是保存枚举的name,后置是保存枚举的ordinal值。这两个都不满足我们的需求,仿照它们,我们洗一个自己的TypeHandler。

自定义枚举TypeHandler

还是使用原先的数据对象

public class Product {private Status status;private String name;// getter and setter
}// BaseEnumDeserial 见https://blog.csdn.net/weixin_41535316/article/details/142426433
@JsonDeserialize(using = BaseEnumDeserial.class)
public interface BaseEnum {Integer getCode();
}
pu
blic enum Status implements BaseEnum {ON_LINE(1000, "在线"),OFF_LINE(2000, "下线");private int code;private String desc;Status(int code, String desc) {this.code = code;this.desc = desc;}public static Status getByCode(int code) {final Status[] values = Status.values();for (int i = 0; i < values.length; i++) {if (values[i].code == code) {return values[i];}}throw new RuntimeException("不合法的code值");}@Overridepublic Integer getCode() {return code;}
}

配置数据库连接

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/stu?serverTimezone=GMT&useSSL=falseusername: rootpassword: root
mybatis:# 自定义的typeHandler所在包位置type-handlers-package: com.example.mybatis.typehandlemapper-locations: classpath:mapper/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

创建表

    CREATE TABLE `product`  (`name` varchar(255) NULL,`status` integer NULL);

创建Mapper


@Mapper
public interface ProductMapper {int insert(Product product);Product getByName(String name);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis.mapper.ProductMapper"><resultMap id="product" type="com.example.mybatis.entity.Product"><result property="status" jdbcType="INTEGER" column="status"/><result property="name" jdbcType="VARCHAR" column="name"/></resultMap><insert id="insert" parameterType="com.example.mybatis.entity.Product">insert into product(name, status) values(#{name}, #{status})</insert><select id="getByName" parameterType="string" resultType="com.example.mybatis.entity.Product">select name, status from product where name = #{name}</select>
</mapper>

定义接口

    @AutowiredProductMapper productMapper;@PostMapping("/insertProduct")@ResponseBodypublic void insertProduct(@RequestBody Product product) {System.out.println(product.getStatus());System.out.println(product.getName());final int insert = productMapper.insert(product);System.out.println(insert);System.out.println("ok");}@GetMapping("/getProduct")@ResponseBodypublic void getProduct(@RequestParam String name) {final Product product = productMapper.getByName(name);System.out.println(product.getStatus());System.out.println(product.getName());System.out.println("ok");}

定义通用TypeHandler

通用TypeHandler同样面临在运行时怎么确定要转成哪种具体枚举类的问题,不同于jackson的运行时创建反序列化器,Mybatis是在项目启动时创建了所有的TypeHandler,且对于枚举类,会根据具体对象创建出不同的TypeHandler。
通用TypeHandler如下:

@MappedTypes(BaseEnum.class)
@MappedJdbcTypes(value = {JdbcType.SMALLINT,JdbcType.TINYINT,JdbcType.INTEGER}, includeNullJdbcType = true)
public class BaseEnumTypeHandler<T extends BaseEnum> extends BaseTypeHandler<BaseEnum> {private final Class<T> type;private final T[] enums;/*** 对于枚举,会优先使用Constructor<?> c = typeHandlerClass.getConstructor(Class.class);* 获取构造函数,如果没有,会获取午无参构造函数,这样就可以为同一个接口下的不同实现类创建不同的TypeHandler了*/public BaseEnumTypeHandler(Class<T> clazz) {this.type = clazz;enums = type.getEnumConstants();}/*** 这里时设置参数 i是参数位置,parameter是外层传入的真实值,可以处理后再存入数据库*/@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, BaseEnum parameter, JdbcType jdbcType) throws SQLException {ps.setInt(i, parameter.getCode());}/*** rs.getInt(columnName)拿到了数据库中保存的值,处理后得到返回给上层的类型 T*/@Overridepublic T getNullableResult(ResultSet rs, String columnName) throws SQLException {final int code = rs.getInt(columnName);for (int i = 0; i < enums.length; i++) {if (enums[i].getCode() == code) {return enums[i];}}return null;}@Overridepublic T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {final int code = rs.getInt(columnIndex);for (int i = 0; i < enums.length; i++) {if (enums[i].getCode() == code) {return enums[i];}}return null;}@Overridepublic T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {final int code = cs.getInt(columnIndex);for (int i = 0; i < enums.length; i++) {if (enums[i].getCode() == code) {return enums[i];}}return null;}
}

例如我们有两个枚举类Status和GenderEnum都继实现了BaseEnum接口,Mybatis会创建两个BaseEnumTypeHandler。
在这里插入图片描述
另外需要注意的是,如果数据库中的枚举是NULL,那么ResultSet 的getInt()方法会返回0,而不是NULL。所以我们的枚举类最好不要使用0作为一个有意义的code值。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PowerMill 2025简体中文版百度云资源分享下载

如大家所了解的&#xff0c;PowerMill是一款专业的CAM&#xff08;计算机辅助制造&#xff09;软件。主要用于加工行业&#xff0c;可以帮助用户进行高效、精准的加工工艺设计和数控编程&#xff0c;以达到生产部件的高精度和高质量。 对于初次接触的小伙伴来说&#xff0c;目…

k均值vs高斯混合模型

K均值&#xff08;K-means&#xff09;和高斯混合模型&#xff08;Gaussian Mixture Model, GMM&#xff09;是常用的聚类算法。 K均值是非概率模型&#xff0c;根据&#xff08;欧氏&#xff09;距离判断&#xff0c;类比最小距离分类器&#xff08;分类&#xff09;。高斯混…

240922-chromadb的基本使用

A. 基本使用 ChromaDB 是一个专门为向量数据库和嵌入查询优化的数据库。它可以与嵌入模型结合使用&#xff0c;存储和查询高维向量数据&#xff0c;通常用于大规模语义搜索、推荐系统等领域。 以下是使用 ChromaDB 的步骤&#xff1a; 1. 安装 ChromaDB 你可以通过 pip 安装…

96. UE5 GAS RPG 实现闪电链技能(一)

闪电链有一个施法的过程&#xff0c;就是在按键按下的过程&#xff0c;会在按下的过程一直持续造成伤害&#xff0c;一直等到条件不满足&#xff08;技能键位抬起&#xff0c;蓝量不足&#xff0c;被眩晕&#xff09;时&#xff0c;将结束技能&#xff0c;并退出技能状态。 所以…

【WSL迁移】将WSL2迁移到D盘

首先查看WSL状态&#xff1a;wsl -l -v 以压缩包的形式导出到其他盘。 wsl --export Ubuntu D:\Ubuntu_WSL\ubuntu.tar 注销原有的linux系统 wsl --unregister Ubuntu 导入系统到D盘 wsl --import Ubuntu D:\Ubuntu_WSL D:\Ubuntu_WSL\Ubuntu.tar 恢复默认用户 Ubuntu co…

如何保护您的机器学习模型

在计算机技术领域&#xff0c;很少有领域像人工智能(AI)和机器学习(ML)一样受到如此多的关注。这门学科位于计算机科学和数据分析的交叉点&#xff0c;已成为移动应用程序、语音助手、欺诈交易检测、图像识别、自动驾驶甚至医疗诊断不可或缺的一部分。 背景介绍由于机器学习模型…

数据结构与算法——Java实现 9.习题——删除链表倒数节点

目录 19. 删除链表的倒数第 N 个结点 方法1 通过链表长度直接删除 方法2 递归加入哨兵节点 ListNode 方法3 快慢指针法 苦难&#xff0c;区区挫折罢了&#xff0c;而我必定站在幸福的塔尖 —— 24.9.22 19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第…

预付费计量系统整体概念

1.预付费计量系统整体概念 A Payment Metering System is a collective infrastructure that supports the contractual relationship between a supplier of goods or services and a customer. It includes processes, functions, data elements, system entities (devices a…

鸿蒙 OS 开发零基础快速入门教程

视频课程: 东西比较多, 这里主要分享一些代码和案例. 开关灯效果案例: 开灯 开关灯效果案例: 关灯 Column 和 Row 的基本用法 Entry Component struct Index {State message: string 张三;build() {// 一行内容Row() {// 一列内容Column() {// 文本内容Text(this.mess…

IDEA创建Web项目(详细版)

目录 1 新建Web项目 步骤如下 1 打开idea,选择新建项目 2 点击创建 3 点击项目结构&#xff0c;选择添加模块 ---web 2 配置Tomcat 步骤如下 1 点击Edit Configurations&#xff08;编辑配置&#xff09; 1.1 右上角当前文件下 选择编辑配置 1.2 点击菜单栏中run 选…

宝塔linux 安装code-server指定对应的端口无法访问

这个一般就是nginx搞的鬼&#xff0c;如果服务正常启动&#xff0c;就是访问不了&#xff1b;大概就是宝塔安装的nginx配置没有代理code-server服务对应的端口&#xff0c;一般就是nginx配置文件的问题 安装默认的nginx会有一个配置文件 直接拉到最后会有一行这个&#xff0c…

Linux 文件系统(下)

目录 一.文件系统 1.文件在磁盘上的存储方式 a.盘面、磁道和扇区 b.分区和分组 2.有关Block group相关字段详解 a.inode编号 b.inode Table&#xff08;节点表&#xff09; c.Data blocks&#xff08;数据区&#xff09; d.小结 二.软硬链接 1.软链接 a.软链接的创建…

springboot启动流程之总体流程梳理

springboot的启动流程相当复杂&#xff0c;我们需要先把控整体流程&#xff0c;后面会有若干文章一一讲解springboot启动流程中的重要的细节&#xff0c;springboot的启动经过了一些一系列的处理&#xff0c;我们先看看整体过程的流程图 篇幅有限&#xff0c;我们这里先聊聊实…

N叉树的前序与后续遍历(含两道leetcode题)

文章目录 589. N 叉树的前序遍历递归法迭代法 590. N 叉树的后序遍历递归法迭代法 589. N 叉树的前序遍历 589. N 叉树的前序遍历 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由…

CSP-S 2024 提高组初赛第一轮初赛试题及答案解析

完整试题&#xff0c;CSP-S-2024 CSP-S 2024 提高组初赛第一轮初赛试题及答案解析 一、 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1 在 Linux 系统中&#xff0c;如果你想显示当前工作目录的…

哔哩哔哩自动批量删除抽奖动态解析篇(一)

本文的分析过程可能需要读者了解一点前后端数据交互和逆向分析的思路和基础&#xff0c;由于本人是新手&#xff0c;自己也处于摸索学习阶段&#xff0c;说的不对或者不好的地方敬请谅解。 一、删除动态流程分析 B站每条动态无论是转发他人的动态还是自己原创发布的动态都有一…

蓝桥杯1.小蓝的漆房

样例输入 2 5 2 1 1 2 2 1 6 2 1 2 2 3 3 3样例输出 1 2 import math import os import sys tint(input())#执行的次数 for j in range(t):n,kmap(int,input().split())#n为房间数 k为一次能涂的个数alist(map(int,input().split()))#以列表的形式存放房间的颜色maxvaluemath…

MySQL数据库的增删改查以及基本操作分享

1、登录MySQL数据库 首先找到你安装MySQL数据库的目录&#xff0c;然后在终端打开该目录&#xff0c;输入以下命令 mysql -u root -p然后输入密码就可以登录数据库了&#xff0c;看到如下页面就是登陆成功了 ***注意在终端操纵数据库时所有语句写完之后一定要加 &#xff1…

【基础算法总结】模拟篇

目录 一&#xff0c;算法介绍二&#xff0c;算法原理和代码实现1576.替换所有的问号495.提莫攻击6.Z字形变换38.外观数列1419.数青蛙 三&#xff0c;算法总结 一&#xff0c;算法介绍 模拟算法本质就是"依葫芦画瓢"&#xff0c;就是在题目中已经告诉了我们该如何操作…

【记录】大模型|Windows 下 Hugging Face 上的模型的通用极简调用方式之一

这篇文是参考了这篇&#xff0c;然后后来自己试着搭了一下&#xff0c;记录的全部过程&#xff1a;【翻译】Ollama&#xff5c;如何在 Ollama 中运行 Hugging Face 中的模型_ollama 导入 huggingface-CSDN 博客 另外还参考了这篇&#xff1a;无所不谈,百无禁忌,Win11 本地部署无…