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.mzph.cn/web/53353.shtml

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

相关文章

【Unity-UGUI组件拓展】| Image 组件拓展,支持FIlled和Slice功能并存

🎬【Unity-UGUI组件拓展】| Image 组件拓展,支持FIlled和Slice功能并存一、组件介绍二、组件拓展方法三、完整代码💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏…

博睿谷IT认证-订阅试学习

在这个信息爆炸的时代&#xff0c;拥有一张IT认证证书&#xff0c;就像拿到了职场晋升的通行证。博睿谷&#xff0c;作为IT认证培训的佼佼者&#xff0c;帮你轻松拿下华为、Oracle等热门认证。下面&#xff0c;让我们一起看看博睿谷如何助你一臂之力。 学习时间&#xff0c;你说…

将阮一峰老师的《ES6入门教程》的源码拷贝本地运行和发布

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 阮一峰老师的《ES6入门教程》应该是很多同学学习 ES6 知识的重要参考吧&#xff0c;应该也有很多同学在看该文档的时候&#xff0c;想知道这个教程的前端源码是怎么实现的&#xff0c;也可能有同学下载…

移动技术开发:ListView水果列表

1 实验名称 ListView水果列表 2 实验目的 掌握自定义ListView控件的实现方法 3 实验源代码 布局文件代码&#xff1a; activity_main.xml: <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.androi…

远程连接MySQL并操作

配置MySQL开发环境 如果你使用的是基于Debian的系统&#xff08;如Ubuntu&#xff09;&#xff0c;可以在终端通过如下步骤安装MySQL开发包。 更新软件包列表 运行以下命令以确保你拥有最新的软件包列表。 sudo apt-get update安装libmysqlclient-dev开发包 执行以下命令以…

【Java注解】

Java注解&#xff08;Annotation&#xff09;让其他程序根据注解信息来决定怎么执行该程序。 是Java 5中引入的一种特殊类型的注释&#xff0c;它可以被用来为代码添加元数据&#xff0c;即关于代码的数据。 注解不会改变程序的逻辑&#xff0c;但它们可以被其他程序使用&…

Datawhale X 南瓜书 task02学习笔记

算法原理引入 样本点通常应该在模型的2侧&#xff0c;原因&#xff1a;在实际中&#xff0c;因为某种不可控的因素&#xff0c;测出来的样本点肯定是有误差的。如果样本数据点都在模型上&#xff0c;则说明在建立模型时&#xff0c;把误差也考虑进去了&#xff0c;这就是我们说…

【技术解析】消息中间件MQ:从原理到RabbitMQ实战(深入浅出)

文章目录 【技术解析】消息中间件MQ&#xff1a;从原理到RabbitMQ实战(深入浅出)1.简介1.1 什么是消息中间件1.2 传统的http请求存在那些缺点1.3 Mq应用场景有那些1.4 为什么需要使用mq1.5 Mq与多线程之间区别1.6 Mq消息中间件名词1.7主流mq区别对比1.8 Mq设计基础知识 2.Rabbi…

前端框架Vue、React、Angular、Svelte对比

在对比 React、Vue.js、Angular 和 Svelte 时&#xff0c;除了在高层次的特性上有显著差异&#xff0c;它们在核心设计理念和底层实现机制上也有明显的不同。为了清晰地理解这些框架&#xff0c;我们可以从以下几个方面来分析它们的核心不同点和底层不同点。 1. 框架类型和设计…

Golang | Leetcode Golang题解之第415题字符串相加

题目&#xff1a; 题解&#xff1a; func addStrings(num1 string, num2 string) string {add : 0ans : ""for i, j : len(num1) - 1, len(num2) - 1; i > 0 || j > 0 || add ! 0; i, j i - 1, j - 1 {var x, y intif i > 0 {x int(num1[i] - 0)}if j &g…

ChatGPT 4o 使用指南 (9月更新)

首先基础知识还是要介绍得~ 一、模型知识&#xff1a; GPT-4o&#xff1a;最新的版本模型&#xff0c;支持视觉等多模态&#xff0c;OpenAI 文档中已经更新了 GPT-4o 的介绍&#xff1a;128k 上下文&#xff0c;训练截止 2023 年 10 月&#xff08;作为对比&#xff0c;GPT-4…

深度学习自编码器 - 去噪自编码器篇

序言 在深度学习的广阔天地中&#xff0c;自编码器作为一种强大的无监督学习工具&#xff0c;通过重构输入数据的方式&#xff0c;不仅实现了数据的有效压缩&#xff0c;还探索了数据的内在表示。而去噪自编码器&#xff08; Denoising Autoencoder, DAE \text{Denoising Auto…

软件设计师——操作系统

&#x1f4d4;个人主页&#x1f4da;&#xff1a;秋邱-CSDN博客☀️专属专栏✨&#xff1a;软考——软件设计师&#x1f3c5;往期回顾&#x1f3c6;&#xff1a;C: 类和对象&#xff08;上&#xff09;&#x1f31f;其他专栏&#x1f31f;&#xff1a;C语言_秋邱 一、操作系统…

VGG16模型实现新冠肺炎图片多分类

1. 项目简介 本项目的目标是通过深度学习模型VGG16&#xff0c;实现对新冠肺炎图像的多分类任务&#xff0c;以帮助医疗人员对患者的影像进行快速、准确的诊断。新冠肺炎自爆发以来&#xff0c;利用医学影像如X光和CT扫描进行疾病诊断已成为重要手段之一。随着数据量的增加&am…

华为---以太网静态路由配置使用下一跳通信正常,而使用出接口无法通信

目录 1. 实验环境 2. 结果测试 3. 分析验证 3.1 以太网静态路由配置使用下一跳跨网段通信抓包分析 3.2 以太网静态路由配置使用出接口跨网段通信抓包分析 3.3 以太网静态路由配置使用出接口无法跨网段通信问题解决办法 1. 实验环境 以太网静态路由配置使用下一跳跨网段通…

网络丢包定位记录(二)

网卡驱动丢包 查看&#xff1a;ifconfig eth1/eth0 等接口 1.RX errors: 表示总的收包的错误数量&#xff0c;还包括too-long-frames错误&#xff0c;Ring Buffer 溢出错误&#xff0c;crc 校验错误&#xff0c;帧同步错误&#xff0c;fifo overruns 以及 missed pkg 等等。 …

Maven的详细解读和配置

目录 一、Maven 1.1 引言 1.2 介绍 1.3 下载安装 1.3.1 解压 1.3.2 配置环境变量 1.3.3 测试 1.4 仓库[了解] 1.5 Maven配置 1.5.1 修改仓库位置 1.5.2 设置镜像 二、IDEA - MAVEN 2.1 idea关联maven 2.2 为新项目设置 2.2 创建java项目[重点] 2.3 java项目结构…

Go-知识-定时器

Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…

特征工程与交叉验证在机器学习中的应用

数据入口&#xff1a;学生考试表现影响因素数据集 - Heywhale.com 本数据集提供了关于影响学生考试成绩的多种因素的全面概述。数据集包含了有关学习习惯、出勤率、家长参与、资源获取等方面的信息。 数据说明 字段名说明Hours_Studied每周学习的小时数Attendance出勤率&…

(笔记自用)位运算总结+LeetCode例题:颠倒二进制位+位1的个数

一.位运算总结: 在解题之前理解一下为什么需要位运算&#xff1f;它的本质是什么&#xff1f; 力扣上不少位运算相关的题&#xff0c;并且很多题也会用到位运算的技巧。这又是为什么&#xff1f; 位运算的由来 在计算机里面&#xff0c;任何数据最终都是用数字来表示的&…