百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

SpringBoot 实现JPA的save方法不更新null属性

liebian365 2024-10-23 13:52 26 浏览 0 评论

作者:yizhiwazi
链接:https://www.jianshu.com/p/4931fbc52ea1

序言:直接调用原生Save方法会导致null属性覆盖到数据库,使用起来十分不方便。本文提供便捷方法解决此问题。

核心思路

如果现在保存某User对象,首先根据主键查询这个User的最新对象,然后将此User对象的非空属性覆盖到最新对象。

核心代码

直接修改通用JpaRepository的实现类,然后在启动类标记此实现类即可。

一、通用CRUD实现类
public class SimpleJpaRepositoryImpl extends SimpleJpaRepository {

 private final JpaEntityInformation entityInformation;
 private final EntityManager em;

 @Autowired
 public SimpleJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
 super(entityInformation, entityManager);
 this.entityInformation = entityInformation;
 this.em = entityManager;
 }

 /**
 * 通用save方法 :新增/选择性更新
 */
 @Override
 @Transactional
 public  S save(S entity) {
 //获取ID
 ID entityId = (ID) entityInformation.getId(entity);
 Optional optionalT;
 if (StringUtils.isEmpty(entityId)) {
 String uuid = UUID.randomUUID().toString();
 //防止UUID重复
 if (findById((ID) uuid).isPresent()) {
 uuid = UUID.randomUUID().toString();
 }
 //若ID为空 则设置为UUID
 new BeanWrapperImpl(entity).setPropertyValue(entityInformation.getIdAttribute().getName(), uuid);
 //标记为新增数据
 optionalT = Optional.empty();
 } else {
 //若ID非空 则查询最新数据
 optionalT = findById(entityId);
 }
 //获取空属性并处理成null
 String[] nullProperties = getNullProperties(entity);
 //若根据ID查询结果为空
 if (!optionalT.isPresent()) {
 em.persist(entity);//新增
 return entity;
 } else {
 //1.获取最新对象
 T target = optionalT.get();
 //2.将非空属性覆盖到最新对象
 BeanUtils.copyProperties(entity, target, nullProperties);
 //3.更新非空属性
 em.merge(target);
 return entity;
 }
 }

 /**
 * 获取对象的空属性
 */
 private static String[] getNullProperties(Object src) {
 //1.获取Bean
 BeanWrapper srcBean = new BeanWrapperImpl(src);
 //2.获取Bean的属性描述
 PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();
 //3.获取Bean的空属性
 Set properties = new HashSet<>();
 for (PropertyDescriptor propertyDescriptor : pds) {
 String propertyName = propertyDescriptor.getName();
 Object propertyValue = srcBean.getPropertyValue(propertyName);
 if (StringUtils.isEmpty(propertyValue)) {
 srcBean.setPropertyValue(propertyName, null);
 properties.add(propertyName);
 }
 }
 return properties.toArray(new String[0]);
 }
}

二、启动类
@EnableJpaRepositories(value = "com.hehe.repository", repositoryBaseClass = SimpleJpaRepositoryImpl.class)
@SpringBootApplication
public class JpaApplication {

 public static void main(String[] args) {
 SpringApplication.run(JpaApplication.class, args);
 }
}

三、实体类和通用Save

@Entity
@Table(name = "T_USER")
@JsonIgnoreProperties({"handler","hibernateLazyInitializer"})
public class User {
 @Id
 private String userId;
 private String username;
 private String password;
 //省略GET/SET
}
public interface UserRepository extends JpaRepository {
}

四、配置文件 application.yml
spring:
 datasource:
 url: jdbc:mysql://localhost:3306/socks?useSSL=false
 username: root
 password: root
 driver-class-name: com.mysql.jdbc.Driver

五、数据库脚本
drop table if exists t_user;
create table t_user (
 user_id varchar(50),
 username varchar(50),
 password varchar(50)
);

insert into t_user values ('1', 'admin', 'admin');
insert into t_user values ('2', 'yizhiwazi', '123456');

六、测试代码
@RestController
public class UserController {

 @Autowired
 private UserRepository userRepository;

 @RequestMapping("/")
 public User get() {

 userRepository.save(new User("1", "", null));

 return userRepository.findById("1").get();
 }
}

整体结构图

在实际项目中,可以直接复制SimpleJpaRepositoryImpl使用,并不影响原有的其它API。

相关推荐

深度解密epoll 如何工作的?(epoll基本处理流程)

epoll...

大乐透第19082期:头奖开出7注1000万分落六地 奖池41亿元

2019年7月17日晚开奖的体彩超级大乐透第19082期开奖号码为:前区06、18、20、21、31,后区03、04。本期大乐透前区号码五区比为1:0:3:0:1,二区和四区号码没有给出。当期前区和值...

【开奖】4月27日周六:福彩、体彩(2021年4月27日体彩开奖结果)

4月27日开奖福彩3D第2019110期:61222选5第2019110期:0812202122排列3第19110期:303排列5第19110期:30305大乐透第19047期:0304...

“红狒狒”落户哈尔滨铁路局(哈尔滨铁路红肠)

这几天,“红人”“红狒狒”在牡丹江机务段可引起了不小的轰动,众粉丝争相与其拍照留念,在该段人气爆棚!“红狒狒”到底何许人也?“红狒狒”,中文名:和谐3D型电力机车;绰号:红狒狒、番茄;制造商:大连机...

2D、3D、2.5D,做游戏还是搞噱头?玩家都晕了

前言游戏类型就像某种潮流,一种流行罢,另一种接棒成为主流。前两年的新作大多以“开放世界”为标签,在追求纯沙盒的过程中打造出一些细致的分类,比如说“类GTA沙盒”。诚然,纯碎的沙盒游戏并不多见,业内只有...

《战神4》PC版宣传片发布 GTX 1070即可60帧畅玩

在今年10月的时候索尼PlayStation官方正式宣布圣莫尼卡2018年的《战神4》将于2022年1月14日推出PC版本,官方在今天公布了一段PC版宣传片,并且公开了游戏的配置需求。下面让我们一起来...

男星深情好丈夫形象崩塌,半夜搂美女坐大腿,举止亲密

近日,于晓光被拍到深夜在酒吧玩,结束后与一名女子一起上车离开。上车后,女子直接坐在了他腿上,他也顺势搂着美女,美女满脸笑容地坐在他腿上玩手机离开。可能有人会好奇,于晓光是谁呢?于晓光是韩国艺人秋瓷炫的...

d3d12dll丢失怎么修复?d3d12dll加载失败怎么解决?

  d3d12.dll丢失怎么修复?d3d12.dll加载失败怎么解决?很多朋友想要运行游戏的时候都会遇到这个问题,这种情况该怎么办呢?今天系统之家小编给朋友们讲讲具体的解决方法,操作其实还蛮简单的。...

许多玩家反馈《生化4RE》PC一直崩溃 无法进入游戏

今日(3月24日),卡普空《生化危机4:重制版》正式发售,然而有部分PC玩家遇到了游戏崩溃等问题。很多玩家在贴吧发帖称游戏遇到了严重的崩溃问题,且经常反复,报错代码普遍为FatalD3Derror...

微软正式推出适用于WSL Linux的D3D12 GPU视频加速技术

今天,微软正式向WindowsSubsystemforLinux(WSL)用户发布了Direct3D12GPU视频加速支持。在微软通过WSL允许在Linux下使用Open...

《怪物猎人:崛起》曙光系统报错“Fatal d3d error”的解决办法

《怪物猎人:崛起》曙光系统报错“Fatald3derror”的解决办法不少小伙伴反应《怪物猎人:崛起》DLC曙光预载以后打不开游戏,出现了Fatald3derror类似的错误代码,这类问题的解...

Mac+双屏,前端程序员的专业配置 - Loctek 乐歌 D3D 双屏电脑显示器支架

做FE也有一段日子了,电脑屏幕每天在设计稿、浏览器、IDE、即时通讯工具、Terminal、邮箱之间切换。虽然mac的工作区带来了很多灵活,但是依然略显不足。于是入手支架,把公司配的电脑和显示器发挥起...

RPC 的原理和简单使用(rpc详解)

RPC的概念RPC,RemoteProcedureCall,翻译成中文就是远程过程调用,是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数。在调用的...

大厂开源的golang微服务rpc框架 — kitex

提前rpc估计所有的开发同学都知道,不知道的也无所谓,毕竟我也好几年没用了,今天带大家在复习一下。RPC(RemoteProcedureCall):远程过程调用,...

干货!一文掌握Protobuf所有语言所有用法,快收藏

说实话,Protobuf这个库,让人相见时难别亦难,东风无力百花残,每次等到要用它的时候,总感觉还没有完全掌握它的用法,而实际上等去百度或者谷歌的时候,教程都是多么的凌乱不堪。学会它,最直接关系到的,...

取消回复欢迎 发表评论: