spring boot jpa 进行通用多条件动态查询和更新 接口
原因: jpa 没有类似于mybatis的那种 拼接sql的方式 想动态更新 需要使用
CriteriaUpdate的方式 去一直拼接,其实大多数场景只要传入一个非空实体类,去动态拼接sql
1.定义实体类 继承一个统一的类型
@Data
@ToString
@Entity
@Table(name = "sys_user")
@DynamicInsert
@JsonIgnoreProperties(ignoreUnknown = true)
@EntityListeners(SysUserListener.class)
public class SysUser extends BaseEntity {
// ... @Schema(description = "用户ID")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long userId; // ... @Schema(description = "用户账号")
@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
@Column(name = "user_name")
private String userName; }
2. java 反射 拿到id 和值 作为 更新的 主键
package com.ricoh.srcb.system.service; import com.ricoh.srcb.system.entity.domain.SysMenu;
import com.ricoh.srcb.system.framework.web.domain.BaseEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.ObjectUtils; import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; @Service
@Slf4j
public abstract class GenericService<T extends BaseEntity> { @PersistenceContext
private EntityManager entityManager; /**
* Updates the given entity by setting non-null fields.
*
* @param entity The entity to update.
* @return The number of rows affected by the update.
*/
public int baseUpdate(T entity) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaUpdate<T> criteriaUpdate = criteriaBuilder.createCriteriaUpdate(entityClass());
Root<T> root = criteriaUpdate.from(entityClass()); Field idField = getIdFieldAndValue(entity).getKey();
Object idValue = getIdFieldAndValue(entity).getValue(); if (ObjectUtils.isEmpty(idValue)) {
throw new RuntimeException("jpa update id not null");
}
criteriaUpdate.where(criteriaBuilder.equal(root.get(idField.getName()), idValue));
boolean hasFieldsToUpdate = false; Field[] fields = entity.getClass().getDeclaredFields(); for (Field field : fields) {
boolean annotationPresent = field.isAnnotationPresent(Column.class);
if (!idField.getName().equals(field.getName())&&annotationPresent) { // Exclude the id field
try {
field.setAccessible(true);
Object value = field.get(entity);
if (ObjectUtils.isNotEmpty(value)) {
criteriaUpdate.set(field.getName(), value);
hasFieldsToUpdate = true;
}
} catch (IllegalAccessException e) {
throw new RuntimeException("Error accessing field: " + field.getName(), e);
}
}
} if (!hasFieldsToUpdate) {
throw new IllegalArgumentException("No fields to update");
}
log.info("update table {} ,sql:{}", entity.getClass().getName(), criteriaUpdate);
return entityManager.createQuery(criteriaUpdate).executeUpdate();
} private Map.Entry<Field, Object> getIdFieldAndValue(T entity) {
for (Field field : entity.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Id.class)) {
field.setAccessible(true);
try {
Object value = field.get(entity);
return new AbstractMap.SimpleEntry<>(field, value);
} catch (IllegalAccessException e) {
throw new RuntimeException("Error accessing @Id field.", e);
}
}
}
throw new IllegalStateException("No @Id field found in entity class.");
} /**
* Finds an entity by its ID.
*
* @param id The ID of the entity to find.
* @return The found entity or null if not found.
*/
/**
* Finds entities based on non-null fields of the provided entity.
*
* @param queryEntity The entity used as a template for query conditions.
* @return A list of entities that match the query conditions.
*/
public List<T> findByCriteria(T queryEntity) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass());
Root<T> root = criteriaQuery.from(entityClass()); List<Predicate> predicates = new ArrayList<>(); Field[] fields = entityClass().getDeclaredFields(); for (Field field : fields) {
try {
field.setAccessible(true);
Object value = field.get(queryEntity);
if (ObjectUtils.isNotEmpty(value)) {
predicates.add(criteriaBuilder.equal(root.get(field.getName()), value));
}
} catch (IllegalAccessException e) {
throw new RuntimeException("Error accessing field: " + field.getName(), e);
}
} criteriaQuery.where(predicates.toArray(new Predicate[0]));
return entityManager.createQuery(criteriaQuery).getResultList();
} private Class<T> entityClass() {
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) superClass;
Type entityType = parameterizedType.getActualTypeArguments()[0];
if (entityType instanceof Class) {
return (Class<T>) entityType;
} else {
throw new IllegalArgumentException("Expected a class type for the generic parameter but got " + entityType);
}
} else {
throw new IllegalArgumentException("Expected a ParameterizedType but got " + superClass);
}
} public abstract List<SysMenu> selectMenuList(SysMenu menu, Long userId);
}
3.service 进行 继承这个类 进行通用查询和更新
@Service
public class SysMenuServiceImpl extends GenericService<SysMenu> implements ISysMenuService {
@Override
@Transactional
public Boolean updateRole(SysRole role) {
// 修改角色信息
baseUpdate(role);
return insertRoleMenu(role) > 0 ? true : false;
}
}
spring boot jpa 进行通用多条件动态查询和更新 接口的更多相关文章
- Spring Boot JPA的查询语句
文章目录 准备工作 Containing, Contains, IsContaining 和 Like StartsWith EndsWith 大小写不敏感 Not @Query Spring Boo ...
- Spring Boot Jpa 多条件查询+排序+分页
事情有点多,于是快一个月没写东西了,今天补上上次说的. JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将 ...
- spring boot JPA中实体类常用注解
spring boot jpa中的注解很多,参数也比较多.没必要全部记住,但是经常查看官方文档也比较麻烦,记录一下一些常用的注解.通过一些具体的例子来帮助记忆. @Entity @Table(name ...
- Spring boot JPA 用自定义主键策略 生成自定义主键ID
最近学习Spring boot JPA 学习过程解决的一些问题写成随笔,大家一起成长.这次遇到自定义主键的问题 package javax.persistence; public enum Gener ...
- Spring Boot JPA 连接数据库
本文将介绍怎样在Spring Boot project中加入JPA作为持久化方式. 改动 pom.xml 依赖 与上一篇介绍的 jdbc 不同的是 spring-boot-starter-jdbc 改 ...
- Spring boot Jpa添加对象字段使用数据库默认值
Spring boot Jpa添加对象字段使用数据库默认值 jpa做持久层框架,项目中数据库字段有默认值和非空约束,这样在保存对象是必须保存一个完整的对象,但在开发中我们往往只是先保存部分特殊的字段其 ...
- spring boot jpa 使用update 报错解决办法
在spring boot jpa 中自定义sql,执行update操作报错解决办法: 在@Query(...)上添加 @Modifying@Transactional注解
- Spring Boot(五):Spring Boot Jpa 的使用
在上篇文章Spring Boot(二):Web 综合开发中简单介绍了一下 Spring Boot Jpa 的基础性使用,这篇文章将更加全面的介绍 Spring Boot Jpa 常见用法以及注意事项. ...
- Spring Boot + JPA(hibernate 5) 开发时,数据库表名大小写问题
(转载)Spring Boot + JPA(hibernate 5) 开发时,数据库表名大小写问题 这几天在用spring boot开发项目, 在开发的过程中遇到一个问题hibernate在执 ...
- Spring Boot Jpa 的使用
Spring Boot Jpa 介绍 首先了解 Jpa 是什么? Jpa (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范.它为 Java 开发人员提供了一种 ...
随机推荐
- [Py] Failed to import pydot. You must install pydot and graphviz for `pydotprint` to work
当通过常规命令安装 pip install pydot 和 brew install graphviz 之后,在代码中 import pydot 依旧不生效. 比如:在 tensorflow 使用 t ...
- [Go] 有了 cast 组件, golang 类型转换从此不再困扰
在 golang 中,参数和返回值之间往往涉及 int.string.[].map 等之间的转换. 如果是手动去处理,一容易出错,二不能兼容多数类型,比较麻烦. 使用 cast,能够让代码更健壮.可维 ...
- [Go] 让 go build 生成的可执行文件对 Mac、linux、Windows 平台一致
要做到这一点,使用的是交叉编译选项. CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go CGO_ENABLED=0 GOOS=windows ...
- WinForm 下的高性能笔迹方法
在 WPF 中可以通过 StylusPlugIn 的方式快速从触摸线程拿到触摸数据,而 WinForms 没有这个机制,但是可以通过 Microsoft.Ink 组件和 WPF 相同在 RealTim ...
- MQ消息积压,把我整吐血了
前言 我之前在一家餐饮公司待过两年,每天中午和晚上用餐高峰期,系统的并发量不容小觑. 为了保险起见,公司规定各部门都要在吃饭的时间轮流值班,防止出现线上问题时能够及时处理. 我当时在后厨显示系统团队, ...
- Vue3:Cannot read properties of null (reading 'isCE')
Cannot read properties of null (reading 'isCE') 这个问题是在vue3中引入elementui的列表框时出现的.经过网上查询,有说是装了两个vue版本 ...
- java学习之旅(day.12)
异常机制(Exception) 异常指程序运行中出现的不期而至的各种状况 异常分类: 检查性异常:用户输入错误引起的异常 运行时异常:写的时候未报错,但一运行就会报错, 错误(error):错误不是异 ...
- pyqt5 子线程如何操作主线程GUI
一.简介 在使用pyqt5编写gui时遇到两个问题,会导致界面崩溃,今天就围绕这两个问题来简单说明和改进. 1.在主线程中使用while无限循环会导致界面崩溃 2.在子线程中操作主线程gui会导致界面 ...
- Spring 对 Junit4,Junit5 的支持上的运用
1. Spring 对 Junit4,Junit5 的支持上的运用 @ 目录 1. Spring 对 Junit4,Junit5 的支持上的运用 每博一文案 2. Spring对Junit4 的支持 ...
- FolkMq v1.4.6 发布(可以内嵌的消息中间件)
功能简表 角色 功能 生产者(客户端) 发布消息.定时消息(或叫延时).顺序消息.可过期消息.事务消息.支持 Qos0.Qos1 消费者(客户端) 订阅.取消订阅.消费-ACK(自动.手动) 服务端 ...