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 开发人员提供了一种 ...
随机推荐
- RedShift到MaxCompute迁移实践指导
简介: 本文主要介绍Amazon Redshift如何迁移到MaxCompute,主要从语法对比和数据迁移两方面介绍,由于Amazon Redshift和MaxCompute存在语法差异,这篇文章讲解 ...
- ARMS企业级场景被集成场景介绍
简介: ARMS企业级场景被集成场景介绍 通过本次最佳实践内容,您可以看到ARMS OpenAPI可以灵活的被集成到客户链路监控场景,并对其进行可视化图形展示监控信息. 1. 背景信息 应用实时监控服 ...
- [Mobi] frida Hook 略知一二: frida-CLI, frida-server
Frida 是一款基于 python + javascript 的 hook 框架,主流平台都支持,由于是基于脚本的交互,因此相比 xposed 和 substrace cydia 更加便捷. 使用时 ...
- [FAQ] Composer, Content-Length mismatch
1. $ composer config repos.packagist composer https://php.cnpkg.org$ composer config cache-files-max ...
- vue-苟曰的老板不发工资230行原创js代码写个扫雷小游戏
上gif: 1.开局提示动画 2.游戏中状态提示 3.开挂模式提示 4.计时器 5.游戏模式扫雷成功,蓝色进度条表示当次扫雷的完成度 6.若当次时间小于最佳记录,则更新最佳记录,如果最佳记录小于设置的 ...
- 如何加速C++文件的编译速度?
一.为什么慢? 重要的一个原因是C++的基本 头文件-源文件的编译模型: 每个源文件为一个编译单元 头文件数量多,可能会包含上百甚至上千个头文件 存在重复解析,每个编译单元中,这些头文件都要从硬盘里读 ...
- Docker服务搭建个人音乐播放器Koel(及马里奥游戏)
Koel简介 Koel是一种简单的基于Web的个人音频流服务,用客户端的Vue和服务器端的Laravel编写.针对Web开发人员,Koel采用了一些更现代的Web技术来完成其工作 搭建步骤 docke ...
- 逆向wechat
本篇博客园地址https://www.cnblogs.com/bbqzsl/p/18171552 计划来个wechat的逆向系列,包括主程序WeChat,以及小程序RadiumWMPF. 开篇,对We ...
- Java面试题:Spring Bean线程安全?别担心,只要你不写并发代码就好了!
Spring中的Bean是否线程安全取决于Bean的作用域(scope).Spring提供了几种不同的Scope,其中包括Singleton.Prototype.Request.Session.Glo ...
- Pytorch:以单通道(灰度图)加载图片
以单通道(灰度图)加载图片 如果我们想以单通道加载图片,设置加载数据集时的transform参数如下即可: from torchvision import datasets, transforms t ...