rest-apiV2.0.0升级为simplest-api开源框架生态之simplest-jpa发布

什么是 simplest

simplest 追求存粹简单和极致。

旨在为项目快速开发提供一系列的基础能力,方便用户根据项目需求快速进行功能拓展

不在去关心一些繁琐。重复工作,而是把重点聚焦到业务。

前言

程序 10 年。作为一个多年程序。深知每个项目和程序,都有很多重复性工作要做。
入行近 10 年,我写过很多程序,也写死过很多程序。。。。。

见证互联网黄金时代,到如今的萎靡。幸运是我还在程序员大军中。和你们一起奋斗!

我的故事 <<程序员三时>> 公众号 期待与你交流。希望给迷茫你一点启发和帮助。

相关仓库

项目简介gitee 地址github 地址
simplest-api前后端分离项目基于 simplest-api 可以快速构建基于 Web Json API 格式的统一通讯交互https://gitee.com/daTouY/simplest-api/tree/main/https://github.com/coder-amiao/simplest-api
simplest-jpa基于 QueryDSL 语法灵活强大的 QueryWrapper,链式 QueryChain 强大自由组合查询器,像写原生 SQL 一样基于 Java API 查询数据,优雅极致。https://gitee.com/daTouY/simplest-jpahttps://github.com/coder-amiao/simplest-jpa
simplest-boot业务通用生态核心组件https://gitee.com/daTouY/simplest-boot.githttps://github.com/coder-amiao/simplest-boot
simplest-admin基于 RABC 权限模型,功能丰富最新技术栈 Vue3.3 + Vite4 + TS + Pinia + Element-Plus 管理后台脚手架。开箱即用,可定制的代码生成模板,让你只需专注于业务开发。https://gitee.com/daTouY/simplest-admin.githttps://github.com/coder-amiao/simplest-admin

Simplest开发文档

这里主要介绍simplest-jpa 使用

快速开始

项目 pom 中引入依赖

<dependency><groupId>cn.soboys</groupId><artifactId>simplest-jpa-spring-boot-starter</artifactId><version>1.0.1</version>
</dependency><!-- MySQL -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version>
</dependency>

在 SpringBoot 启动类或者配置类上通过 @EnableJPAQuery注解开启 simplest-jpa

@SpringBootApplication
@EnableJPAQuery
public class SpringbootJpaApplication {public static void main(String[] args) {SpringApplication.run(SpringbootJpaApplication.class, args);}}

到此你项目中就可以使用所有的功能了。

数据库配置

在项目中配置对应数据库连接

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/rest-admin?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghaiusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.zaxxer.hikari.HikariDataSourcehikari:minimum-idle: 10maximum-pool-size: 20idle-timeout: 600000max-life-time: 1800000jpa:hibernate:naming:implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImplddl-auto: update # 控制是否可以基于程序中Entity的定义自动创建或者修改DB中表结构show-sql: true #控制是否打印运行时的SQL语句与参数信息database-platform: org.hibernate.dialect.MySQLDialect #数据库方言open-in-view: trueproperties:hibernate:enable_lazy_load_no_trans: true

定义对应entity 对应数据库表。JPA 会自动帮你生成数据库。

package cn.soboys.springbootjpa.entity;import cn.soboys.springbootjpa.entity.base.BaseEntity;
import cn.soboys.springbootjpa.entity.dto.TitleVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;/*** @author 公众号 程序员三时* @version 1.0* @date 2023/7/19 10:44* @webSite https://github.com/coder-amiao* 内容分类*/
@Data
@Entity
@Table(name = "cms_category")
public class Category extends BaseEntity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;/*** 标题*/@Column(nullable = false, length = 64)@Schema(description = "标题")private String title;/*** @Embedded 用户映射数据库表到一个实体vo。*/@Embedded@Schema(description = "标题信息")private TitleVo titleVo;/*** 描述*/@Schema(description = "描述")private String described;/*** 图标*/@Column( length = 32)@Schema(description = "图标",maxLength = 32)private String icon;/*** 图片*/@Column( length = 32)@Schema(description = "图片",maxLength = 32)private String pic;/**** 引用关系不填写。默认对应主键。*/@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE},fetch = FetchType.LAZY)@JoinTable(name = "cms_module_relation",joinColumns = @JoinColumn(name = "resource_id"),inverseJoinColumns = @JoinColumn(name = "module_id"))private Set<Module> modules=new HashSet<>();/*** 额外其他属性* @Transient 解绑和数据联系。属于实体类属性*/@Transientprivate String other;}

生成对应查询EntityPath

基于 QueryDSL 的APT 技术 在 maven 的 pom.xml 中引入对应的插件

<plugin><!--因为QueryDsl是类型安全的,所以还需要加上Maven APT plugin,使用 APT 自动生成Q类:--><groupId>com.mysema.maven</groupId><artifactId>apt-maven-plugin</artifactId><version>1.1.3</version><executions><execution><phase>generate-sources</phase><goals><goal>process</goal></goals><configuration><outputDirectory>target/generated-sources/java</outputDirectory><processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor></configuration></execution></executions>
</plugin>

然后通过 maven 编译项目。

会在你指定目录生成对应查询EntityPaht实体

简单查询

  1. 编写自己的Repository 继承通用BaseRepository
package cn.soboys.springbootjpa.repository;import cn.soboys.simplestjpa.BaseRepository;
import cn.soboys.springbootjpa.entity.Category;
import org.springframework.stereotype.Repository;/*** @author 公众号 程序员三时* @version 1.0* @date 2023/7/19 12:02* @webSite https://github.com/coder-amiao* 数据库 dao层。*/
@Repository
public interface CategoryRepository extends BaseRepository<Category, Long{}
  1. 编写自己的Service 继承通用Service
package cn.soboys.springbootjpa.service;import cn.soboys.simplestjpa.IService;
import cn.soboys.springbootjpa.entity.Category;
import org.springframework.data.jpa.repository.Query;/*** @author 公众号 程序员三时* @version 1.0* @date 2023/7/19 17:08* @webSite https://github.com/coder-amiao*/
public interface ICategoryService extends IService<Category,Long> {}

实现类

package cn.soboys.springbootjpa.service.impl;import cn.soboys.simplestjpa.ServiceImpl;
import cn.soboys.springbootjpa.entity.Category;
import cn.soboys.springbootjpa.repository.CategoryRepository;
import cn.soboys.springbootjpa.service.ICategoryService;
import org.springframework.stereotype.Service;/*** @author 公众号 程序员三时* @version 1.0* @date 2023/7/20 14:46* @webSite https://github.com/coder-amiao*/
@Service
public class CategoryServerImpl extends ServiceImpl<CategoryRepository, Category, Long> implements ICategoryService {}

这样你 service 有基础所有操作数据增删改查的方法

package cn.soboys.springbootjpa;import cn.soboys.simplestjpa.UpdateWrapper;
import cn.soboys.springbootjpa.entity.Category;
import cn.soboys.springbootjpa.entity.QCategory;
import cn.soboys.springbootjpa.entity.dto.QTitleVo;
import cn.soboys.springbootjpa.service.ICategoryService;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAUpdateClause;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.text.StrUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;
import java.util.List;
import java.util.Optional;/*** @author 公众号 程序员三时* @version 1.0* @date 2023/7/26 21:54* @webSite https://github.com/coder-amiao*/
@SpringBootTest
@Slf4j
public class ServiceTest {@Autowiredprivate ICategoryService categoryService;@Testvoid countByExample() {Category category = new Category();//category.setTitle("测试");long count = categoryService.count(Example.of(category));log.info("条件count{}", count);}@Testvoid getById() {Optional<Category> category = categoryService.getByIdOpt(6l);if (category.isPresent()) {log.info(category.get().toString());}}@Testvoid getOne() {QCategory qCategory = QCategory.category;QTitleVo vo=QTitleVo.titleVo;Predicate query=vo.subTitle.eq("batch1");Category category = categoryService.getOne(query);log.info(category.toString());}@Testvoid getPageQuery() {QCategory qCategory = QCategory.category;PageRequest pageRequest = PageRequest.of(0, 20); //第一页从零开始Predicate query = qCategory.title.like("%" + "batch" + "%");Page<Category> categoryList = categoryService.page(pageRequest, query);log.info("数量{}", categoryList.getContent().size());}@Testvoid getPage() {QCategory qCategory = QCategory.category;// categoryService.getJPAQueryFactory().select().where(qCategory.)}@Testvoid save() {Category c = new Category();// c.setTitle("保存");categoryService.save(c);}@Testvoid deleteById() {categoryService.removeById(6l);}@Testvoid deleteAll() {List<Long> ids = new ArrayList<>();ids.add(6l);ids.add(7l);Boolean flag = categoryService.removeByIds(ids);}/*** 实体ID对应存在更新否则添加*/@Testvoid saveOrUpdate() {Category c = new Category();// c.setTitle("保存");categoryService.saveOrUpdate(c);}@Test@Rollback(value = false)@Transactionalvoid updateChain() {QCategory qCategory = QCategory.category;categoryService.updateChain(qCategory).set(qCategory.title, "测试jpa").where(qCategory.id.eq(6l)).execute();}@Test@Rollback(value = false)@Transactionalvoid update() {QCategory qCategory = QCategory.category;JPAUpdateClause updateWrapper = UpdateWrapper.of(qCategory);updateWrapper.set(qCategory.title, "bh").where(qCategory.id.eq(6l));Boolean flag = categoryService.update(updateWrapper);log.info("更新{}", flag);}@Test@Rollback(value = false)@Transactionalvoid updateIgnoreNull() {Category category = new Category();category.setId(6l);// category.setSubTitle("忽略");//Category category1 = categoryService.update(category, true);  //会自动忽略实体空属性。//category.setTitle("");Category category1 = categoryService.update(category, true, new String[]{"title"});  //自定义不忽略字段,log.info("更新{}", category1);}@Testvoid selectQueryChain() {QCategory qCategory = QCategory.category;List<String> categoryList = categoryService.queryChain().select(qCategory.title).from(qCategory).fetch();log.info("返回条数{}", categoryList.size());}@Testvoid selectQuery() {QCategory qCategory = QCategory.category;BooleanBuilder booleanBuilder = new BooleanBuilder();String subTitle = "88";if (StrUtil.isNotEmpty(subTitle)) {booleanBuilder.and(qCategory.described.eq("88"));}long id = 6l;if (!StrUtil.isBlankIfStr(id)) {booleanBuilder.and(qCategory.id.eq(6l));}List<Category> categories = categoryService.list(booleanBuilder);log.info("返回条数{}", categories.size());}}

Simplest-JPA

simplest-jpa内置名为 BaseRepository 接口,它实现了基本的增删改查功能以及分页查询功能。 和对应Service

新增数据

Service 提供了save,saveBatch,saveOrUpdate 方法

  • save(T entity)插入实体类数据,不忽略 null 值。
  • saveBatch(Collection<T> entities) 批量插入实体类数据
  • saveOrUpdate(T entity) 插入或者更新,若主键有值,则更新,若没有主键值,则插入,插入或者更新都不会忽略 null 值。
  • saveOrUpdateSelective(T entity)插入或者更新,若主键有值,则更新,若没有主键值,则插入,更新会忽略 null 值。

删除数据

Service 提供了remove,removeAll,removeById,removeByIds 方法

  • removeById(ID id) 根据主键删除数据
  • removeById(Collection<? extends ID> ids) 根据多个主键批量删除数据
  • remove(Collection<T> entities) 根据多个实体(实体需要有主键)进行批量删除
  • remove(T entity) 根据实体条件进行删除

更新数据

Service 提供了update 多个重载方法

  • update(T entity) 查询条件 根据实体 ID 更新。不会忽略 null 值
  • update(T entity, Boolean ignore) 查询条件根据实体 ID 更新。自定义忽略 nul 值
  • update(T entity, Boolean ignore, String[] ignoreProperties) 自定义忽略实体字段属性
  • update(JPAUpdateClause query) 根据查询条件来更新数据。
@Test
@Rollback(value = false)
@Transactional
void update() {QCategory qCategory = QCategory.category;JPAUpdateClause updateWrapper = UpdateWrapper.of(qCategory);updateWrapper.set(qCategory.title, "bh").where(qCategory.id.eq(6l));Boolean flag = categoryService.update(updateWrapper);log.info("更新{}", flag);
}

updateChain

updateChain是一个对 UpdateWrapper 等进行封装的一个工具类,方便用户用于进行链式操作。

@Test
@Rollback(value = false)
@Transactional
void updateChain() {QCategory qCategory = QCategory.category;categoryService.updateChain(qCategory).set(qCategory.title, "测试jpa").where(qCategory.id.eq(6l)).execute();
}

Simplest-JPA 查询和分页查询

基础查询

simplest-jpaService提供了如下的功能用于查询数据库的数据

  • getById(ID id) 根据主键查询数据。
  • getByIdOpt(ID id)根据主键查询数据。返回Optional类型
  • getOne(Example<T> example) 根据查询条件来查询 1 条数据。
  • getOne(Predicate query) 根据查询条件来查询 1 条数据。
  • getOneOpt(Example<T> example)根据查询条件来查询 1 条数据。返回Optional类型查询到多条匹配数据时,会抛 NonUniqueResultException
  • listByIds(Collection<ID> ids) 根据数据主键查询数据集合。
  • list(Predicate query)根据查询条件查询数据集合。
  • list(Example query) 根据查询条件查询数据集合。
  • list()查询所有数据。
  • count(Predicate query) 根据查询条件查询数据数量。
  • count(Example<T> example) 根据查询条件查询数据数量。
  • exists(Predicate query) 根据查询条件判断数据是否存在。
  • existsById(ID id) 根据 ID 判断是否存在

分页查询

  • page(Pageable page)分页查询所有数据。
  • page(Pageable page, Predicate query) 根据查询条件分页查询数据。

链式查询

simplest-jpa 中,内置了 queryChain 和 updateChain 用于对数据进行链式查询操作和链式数据操作(修改和删除)。

  • queryChain:链式查询
  • updateChain:链式更新

queryChain 示列

@Test
void selectQueryChain() {QCategory qCategory = QCategory.category;List<String> categoryList = categoryService.queryChain().select(qCategory.title).from(qCategory).fetch();log.info("返回条数{}", categoryList.size());
}

条件查询

@Test
void selectQueryChainWhere() {QCategory qCategory = QCategory.category;List<String> categoryList=  categoryService.queryChain().select(qCategory.title).from(qCategory).where(qCategory.id.eq(1l)).fetch();log.info("返回条数{}", categoryList.size());
}

分页查询

@Test
void selectQueryChainWhere() {QCategory qCategory = QCategory.category;List<String> categoryList = categoryService.queryChain().select(qCategory.title).from(qCategory).where(qCategory.id.eq(1l)).limit(1).fetch();log.info("返回条数{}", categoryList.size());
}

updateChain 示例

@Test
@Rollback(value = false)
@Transactional
void updateChain() {QCategory qCategory = QCategory.category;categoryService.updateChain(qCategory).set(qCategory.title, "测试jpa").where(qCategory.id.eq(6l)).execute();
}

queryChain 的方法

  • fetch() 获取多条数据 懒加载模式
  • fetchAll() 获取多条数据 忽略懒加载
  • fetchOne() 获取一条数据 多条会报错
  • fetchFirst() 查询第一条数据
  • fetchCount() 查询数据条数

灵活的 QueryWrapper

在 增删改 和 查询和分页 章节中,我们随时能看到 QueryWrapper 的身影,QueryWrapper 是用于构造 Sql 的 强有力工具,也是 simplest-jpa 的亮点和特色。

QueryWrapper 的使用

@SpringBootTest
@Slf4j
public class JpaQueryDSLTest {@Autowiredprivate ICategoryService categoryService;@Autowiredprivate JPAQueryFactory queryWrapper;/*** select() 和 fetch() 的常用写法* 使用fetch()查询时,数据库没有符合该条件的数据时,返回的是空集合,而不是null*//*** 查询字段-select()*/@Testpublic void fetchColum() {QCategory qCategory = QCategory.category;List<String> a = queryWrapper.select(qCategory.title).from(qCategory).fetch();log.info("返回数量{}", a.size());}/*** 查询实体-selectFrom()*/@Testpublic void fetchEntity() {QCategory qCategory = QCategory.category;List<Category> categories = queryWrapper.selectFrom(qCategory).fetch();log.info("返回数量{}", categories.size());}/*** 查询并将结果封装至dto中*/@Testpublic void fetchDto() {QCategory qCategory = QCategory.category;List<CategoryDto> categoryDtos = queryWrapper.select(Projections.bean(CategoryDto.class, qCategory.title)).from(qCategory).fetch();log.info("返回数量{}", categoryDtos.size());}/*** 去重查询-selectDistinct()*/@Testpublic void fetchDistinct() {QCategory qCategory = QCategory.category;List<String> c = queryWrapper.selectDistinct(qCategory.title).from(qCategory).fetch();log.info("返回数量{}", c.size());}/*** 获取首个查询结果-fetchFirst() 单条记录 limit 1*/@Testpublic void fetchFirst() {QCategory qCategory = QCategory.category;Category category = queryWrapper.selectFrom(qCategory).fetchFirst();log.info("返回数量{}", category.toString());}/*** 获取唯一查询结果-fetchOne()* 当fetchOne()根据查询条件从数据库中查询到多条匹配数据时,会抛`NonUniqueResultException`*/@Testpublic void fetchOne() {QCategory qCategory = QCategory.category;Category category = queryWrapper.selectFrom(qCategory).fetchOne();log.info("返回数量{}", category.toString());}/*** where 子句查询条件的常用写法*/@Testpublic void fetchWhere() {QCategory qCategory = QCategory.category;List<Category> categories = queryWrapper.selectFrom(qCategory).where(qCategory.title.eq("更新").and(qCategory.subTitle.like('%' + "测试" + '%'))).fetch();log.info("返回数量{}", categories.size());}/*** where 动态条件查询*//*** 使用QueryDSL提供的BooleanBuilder来进行查询条件管理。*/@Testpublic void fetchWhereDynamic() {QCategory qCategory = QCategory.category;BooleanBuilder builder = new BooleanBuilder();String title = "a";if (StrUtil.isNotEmpty(title)) {builder.and(qCategory.title.eq(title));}String subTitle = "";if (StrUtil.isNotEmpty(subTitle)) {builder.and(qCategory.subTitle.eq(subTitle));}List<Category> categories = queryWrapper.selectFrom(qCategory).where(builder).fetch();log.info("返回数量{}", categories.size());}/*** 复杂的查询关系*/@Testpublic void fetchWhereDynamicComplex() {QCategory qCategory = QCategory.category;BooleanBuilder builder = new BooleanBuilder();builder.or(qCategory.id.eq(1l));String title = "a";if (StrUtil.isNotEmpty(title)) {builder.and(qCategory.title.eq(title));}String subTitle = "";if (StrUtil.isNotEmpty(subTitle)) {builder.and(qCategory.subTitle.eq(subTitle));}List<Category> categories = queryWrapper.selectFrom(qCategory).where(builder).fetch();log.info("返回数量{}", categories.size());}/*** 自定义封装查询的结果集* JPAQueryFactory查询工厂的select方法可以将Projections方法返回的QBean作为参数,通过Projections的bean方法来构建返回的结果集映射到实体内,有点像Mybatis内的ResultMap的形式,不过内部处理机制肯定是有着巨大差别的!* <p>* bean方法第一个参数需要传递一个实体的泛型类型作为返回集合内的单个对象类型,如果QueryDSL查询实体内的字段与DTO实体的字段名字不一样时,可以采用as方法来处理,为查询的结果集指定的字段添加别名,这样就会自动映射到DTO实体内。*//*** 使用Projections的Bean方法*/@Testpublic void fetchBean() {QCategory qCategory = QCategory.category;QModule qModule = QModule.module;List<CategoryDto> categoryDtos = queryWrapper.select(Projections.bean(CategoryDto.class, qCategory.title, qModule.code)).from(qCategory, qModule).fetch();log.info("返回数量{}", categoryDtos.size());}/*** 使用Projections的fields方法*/@Testpublic void fetchFields() {QCategory qCategory = QCategory.category;List<CategoryDto> categoryDtos = queryWrapper.select(Projections.fields(CategoryDto.class, qCategory.title)).from(qCategory).fetch();log.info("返回数量{}", categoryDtos.size());}/*** 使用集合的stream转换* 从方法开始到fetch()结束完全跟QueryDSL没有任何区别,采用了最原始的方式进行返回结果集,但是从fetch()获取到结果集后处理的方式就有所改变了。* <p>* fetch()方法返回的类型是泛型List(List),List继承了Collection,完全存在使用Collection内非私有方法的权限,通过调用stream方法可以将集合转换成Stream泛型对象,该对象的map方法可以操作集合内单个对象的转换,具体的转换代码可以根据业务逻辑进行编写。* <p>* 在map方法内有个lambda表达式参数tuple,通过tuple对象get方法就可以获取对应select方法内的查询字段。* ————————————————*/@Testpublic void selectWithStream() {QCategory qCategory = QCategory.category;List<CategoryDto> categoryDtos = queryWrapper.select(qCategory.title, qCategory.subTitle).from(qCategory).fetch().stream().map(tuple -> {CategoryDto c = new CategoryDto();c.setTitle(tuple.get(qCategory.title));return c;}).collect(Collectors.toList());log.info("返回数量{}", categoryDtos.size());}@Testpublic void findByQuery() {QCategory qCategory = QCategory.category;//该Predicate为querydsl下的类,支持嵌套组装复杂查询条件BooleanBuilder builder = new BooleanBuilder();String title = "a";if (StrUtil.isNotEmpty(title)) {builder.and(qCategory.title.eq(title));}String subTitle = "";if (StrUtil.isNotEmpty(subTitle)) {builder.and(qCategory.subTitle.eq(subTitle));}List<Category> c = categoryService.list(builder);log.info("条数{}",c.size());}@Testpublic void findByQueryWrapper(){QCategory qCategory = QCategory.category;JPAQueryFactory queryWrapper=QueryWrapper.of();List<String> c = queryWrapper.selectDistinct(qCategory.title).from(qCategory).fetch();log.info("返回数量{}", c.size());}}

实例

  1. 单表查询
@Service
@Transactional
public class UserService {@Autowiredprivate JPAQueryFactory queryFactory;/*** attention:* Details:查询user表中的所有记录*/public List<User> findAll(){QUser quser = QUser.user;return queryFactory.selectFrom(quser).fetch();}/*** Details:单条件查询*/public User findOneByUserName(final String userName){QUser quser = QUser.user;return queryFactory.selectFrom(quser).where(quser.name.eq(userName)).fetchOne();}/*** Details:单表多条件查询*/public User findOneByUserNameAndAddress(final String userName, final String address){QUser quser = QUser.user;return queryFactory.select(quser).from(quser) // 上面两句代码等价与selectFrom.where(quser.name.eq(userName).and(quser.address.eq(address)))// 这句代码等同于where(quser.name.eq(userName), quser.address.eq(address)).fetchOne();}/*** Details:使用join查询*/public List<User> findUsersByJoin(){QUser quser = QUser.user;QUser userName = new QUser("name");return queryFactory.selectFrom(quser).innerJoin(quser).on(quser.id.intValue().eq(userName.id.intValue())).fetch();}/*** Details:将查询结果排序*/public List<User> findUserAndOrder(){QUser quser = QUser.user;return queryFactory.selectFrom(quser).orderBy(quser.id.desc()).fetch();}/*** Details:Group By使用*/public List<String> findUserByGroup(){QUser quser = QUser.user;return queryFactory.select(quser.name).from(quser).groupBy(quser.name).fetch();}/*** Details:删除用户*/public long deleteUser(String userName){QUser quser = QUser.user;return queryFactory.delete(quser).where(quser.name.eq(userName)).execute();}/*** Details:更新记录*/public long updateUser(final User u, final String userName){QUser quser = QUser.user;return queryFactory.update(quser).where(quser.name.eq(userName)).set(quser.name, u.getName()).set(quser.age, u.getAge()).set(quser.address, u.getAddress()).execute();}/*** Details:使用原生Query*/public User findOneUserByOriginalSql(final String userName){QUser quser = QUser.user;Query query = queryFactory.selectFrom(quser).where(quser.name.eq(userName)).createQuery();return (User) query.getSingleResult();}/***分页查询所有的实体,根据uIndex字段排序** @return*/public QueryResults<User> findAllPage(Pageable pageable) {QUser user = QUser.user;return jpaQueryFactory.selectFrom(user).orderBy(user.uIndex.asc()).offset(pageable.getOffset())   //偏移量,计算:offset = ( 当前页 - 1) * 每页条数,这里直接使用的是Pageable中的Offset.limit(pageable.getPageSize())  //每页大小.fetchResults();    //获取结果,该结果封装了实体集合、分页的信息,需要这些信息直接从该对象里面拿取即可}/*** 部分字段映射查询* 投影为UserRes,lambda方式(灵活,类型可以在lambda中修改)** @return*/public List<UserDTO> findAllUserDto(Pageable pageable) {QUser user = QUser.user;List<UserDTO> dtoList = jpaQueryFactory.select(user.username,user.userId,user.nickName,user.birthday).from(user).offset(pageable.getOffset()).limit(pageable.getPageSize()).fetch().stream().map(tuple -> UserDTO.builder().username(tuple.get(user.username)).nickname(tuple.get(user.nickName)).userId(tuple.get(user.userId).toString()).birthday(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tuple.get(user.birthday))).build()).collect(Collectors.toList());return dtoList;}/*** 部分字段映射查询* 投影为UserRes,自带的Projections方式,不能转换类型,但是可以使用as转换名字** @return*/public List<UserDTO> findAllDto2() {QUser user = QUser.user;List<UserDTO> dtoList = jpaQueryFactory.select(Projections.bean(UserDTO.class,user.username,user.userId,user.nickName,user.birthday)).from(user).fetch();return dtoList;}}
  1. 多表查询
/*** @Description 查询全部* @Author 程序员三时* @Date  10:53* @return java.util.List<com.cs.querydsl.model.Loc>**/
@Override
public List<Loc> findAll(Loc loc) {// 使用 QueryDSL 进行查询QLoc qLoc = QLoc.loc1;QUser qUser = QUser.user;// 定于获取条件BooleanBuilder booleanBuilder = new BooleanBuilder();// 要查询的条件if(!StringUtils.isEmpty(loc.getLoc())){// 放入要查询的条件信息booleanBuilder.and(qLoc.loc.contains(loc.getLoc()));}//连接查询条件(Loc.id = User.id )booleanBuilder.and(qLoc.id.eq(qUser.id));// 使用 QueryDSL 进行多表联合查询QueryResults<Tuple> listResult = queryFactory.select(QLoc.loc1,QUser.user).from(qLoc, qUser)//查询两表.where(booleanBuilder).fetchResults();//遍历 java8 自带流转换成集合List<Loc> collect = listResult.getResults().stream().map(tuple -> {Loc lcs = tuple.get(qLoc);return lcs;}).collect(Collectors.toList());return collect;
}部分字段映射的投影查询:当使用`@ManyToOne`、`@ManyToMany`建立关联时:/*** 根据部门的id查询用户的基本信息+用户所属部门信息,并且使用UserDeptDTO进行封装返回给前端展示* @param departmentId* @return*/
public List<UserDeptDTO> findByDepatmentIdDTO(int departmentId) {QUser user = QUser.user;QDepartment department = QDepartment.department;//直接返回return jpaQueryFactory//投影只去部分字段.select(user.username,user.nickName,user.birthday,department.deptName,department.createDate).from(user)//联合查询.join(user.department, department).where(department.deptId.eq(departmentId)).fetch()//lambda开始.stream().map(tuple ->//需要做类型转换,所以使用map函数非常适合UserDeptDTO.builder().username(tuple.get(user.username)).nickname(tuple.get(user.nickName)).birthday(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tuple.get(user.birthday))).deptName(tuple.get(department.deptName)).deptBirth(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tuple.get(department.createDate))).build()).collect(Collectors.toList());
}当使用id建立关联时:
/*** 根据部门的id查询用户的基本信息+用户所属部门信息,并且使用UserDeptDTO进行封装返回给前端展示** @param departmentId* @return*/
public List<UserDeptDTO> findByDepatmentIdDTO(int departmentId) {QUser user = QUser.user;QDepartment department = QDepartment.department;//直接返回return jpaQueryFactory//投影只去部分字段.select(user.username,user.nickName,user.birthday,department.deptName,department.createDate).from(user, department)//联合查询.where(user.departmentId.eq(department.deptId).and(department.deptId.eq(departmentId))).fetch()//lambda开始.stream().map(tuple ->//需要做类型转换,所以使用map函数非常适合UserDeptDTO.builder().username(tuple.get(user.username)).nickname(tuple.get(user.nickName)).birthday(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tuple.get(user.birthday))).deptName(tuple.get(department.deptName)).deptBirth(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tuple.get(department.createDate))).build()).collect(Collectors.toList());
}使用 Projections 自定义返回 Bean/*** Details:方式一:使用Bean投影*/
public List<PersonIDCardDto> findByDTOUseBean(){Predicate predicate = (QPerson.person.id.intValue()).eq(QIDCard.iDCard.person.id.intValue());return queryFactory.select(Projections.bean(PersonIDCardDto.class, QIDCard.iDCard.idNo, QPerson.person.address, QPerson.person.name)).from(QIDCard.iDCard, QPerson.person).where(predicate).fetch();
}/*** Details:方式二:使用fields来代替setter*/
public List<PersonIDCardDto> findByDTOUseFields(){Predicate predicate = (QPerson.person.id.intValue()).eq(QIDCard.iDCard.person.id.intValue());return queryFactory.select(Projections.fields(PersonIDCardDto.class, QIDCard.iDCard.idNo, QPerson.person.address, QPerson.person.name)).from(QIDCard.iDCard, QPerson.person).where(predicate).fetch();
}/*** Details:方式三:使用构造方法,注意构造方法中属性的顺序必须和构造器中的顺序一致*/
public List<PersonIDCardDto> findByDTOUseConstructor(){Predicate predicate = (QPerson.person.id.intValue()).eq(QIDCard.iDCard.person.id.intValue());return queryFactory.select(Projections.constructor(PersonIDCardDto.class, QPerson.person.name, QPerson.person.address, QIDCard.iDCard.idNo)).from(QIDCard.iDCard, QPerson.person).where(predicate).fetch();
}

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

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

相关文章

通用商城项目(中)

金山编译器出问题了。下面段落标号全出问题了&#xff0c;排版也出问题了。懒得改了。 使用对象存储OSS&#xff0c;保存品牌logo 新建Module&#xff0c;提供上传、显示服务 有些不明所以的&#xff0c;按照steinliving-commodity配置了一通pom.xml 新建application.yml&…

实现邮箱管理之gmail邮箱、office365(Azure)邮箱之披荆斩棘问题一览

要进行Office365邮箱的授权对接&#xff0c;你需要先申请一个应用&#xff0c;并获取授权访问令牌。 以下是一个简单的步骤&#xff1a; 登录 Azure 门户&#xff1a;https://portal.azure.com/创建一个新的应用程序&#xff0c;或者使用现有的应用程序。要创建新的应用程序&…

从0到1开发go-tcp框架【3-读写协程分离、引入消息队列、进入连接管理器、引入连接属性】【基础篇完结】

从0到1开发go-tcp框架【3-读写协程分离、引入消息队列、进入连接管理器、引入连接属性】 1 读写协程分离[v0.7] 添加一个Reader和Writer之间通信的channel添加一个Writer goroutineReader由之前直接发送给客户端改为发送给通信channel启动Reader和Writer一起工作 zinx/znet/co…

【Golang 接口自动化05】使用yml管理自动化用例

目录 YAML 基本语法 对象&#xff1a;键值对的集合(key:value) 数组&#xff1a;一组按顺序排列的值 字面量&#xff1a;单个的、不可再分的值&#xff08;数字、字符串、布尔值&#xff09; yml 格式的测试用例 定义yml文件 创建结构体 读取yml文件中的用例数据 调试…

【1.3】Java微服务:Spring Cloud版本说明

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…

【后端面经】微服务构架 (1-6) | 隔离:如何确保心悦会员体验无忧?唱响隔离的鸣奏曲!

文章目录 一、前置知识1、什么是隔离?2、为什么要隔离?3、怎么进行隔离?A) 机房隔离B) 实例隔离C) 分组隔离D) 连接池隔离 与 线程池隔离E) 信号量隔离F) 第三方依赖隔离二、面试环节1、面试准备2、基本思路3、亮点方案A) 慢任务隔离B) 制作库与线上库分离三、章节总结 …

深度学习各层负责什么内容?

1、深度学习——神经网络简介 深度学习(Deep Learning)(也称为深度结构学习【Deep Structured Learning】、层次学习【Hierarchical Learning】或者是深度机器学习【Deep Machine Learning】)是一类算法集合&#xff0c;是机器学习的一个分支。 深度学习方法近年来&#xff0c…

元宇宙虚拟展厅的特点是什么呢?优势有哪些?

元宇宙是一个很广阔的虚拟世界&#xff0c;它可以创造出更为丰富、沉浸式的体验&#xff0c;这种全新的体验为展览和艺术领域带来了更多的可能性&#xff0c;元宇宙虚拟展厅以其多样化、互动性、沉浸式展示的特点&#xff0c;带领大家进入一个虚拟现实的全新世界。 元宇宙虚拟展…

MACOM EDI 需求分析

MACOM 是一家全球性半导体公司&#xff0c;专注于设计和制造高性能射频、微波和光电元件&#xff0c;其产品被广泛应用于通信、航空航天、国防、工业和医疗等领域。随着 MACOM 的不断发展&#xff0c;传统数据传输方式效率较低&#xff0c;无法满足 MACOM 的需求。为了提高企业…

使用自适应去噪在线顺序极限学习机预测飞机发动机剩余使用寿命(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

代理模式--静态代理和动态代理

1.代理模式 定义&#xff1a;代理模式就是代替对象具备真实对象的功能&#xff0c;并代替真实对象完成相应的操作并且在不改变真实对象源代码的情况下扩展其功能&#xff0c;在某些情况下&#xff0c;⼀个对象不适合或者不能直接引⽤另⼀个对象&#xff0c;⽽代理对象可以在客户…

【前端知识】React 基础巩固(三十六)——RTK中的异步操作

React 基础巩固(三十六)——RTK中的异步操作 一、RTK中使用异步操作 引入RTK中的createAsyncThunk&#xff0c;在extraReducers中监听执行状态 import { createSlice, createAsyncThunk } from "reduxjs/toolkit"; import axios from "axios";export cons…

Spring事务传播机制、实现方式、失效场景即原理

贴一篇源码分析的好文章&#xff1a;https://blog.csdn.net/qq_30905661/article/details/114400417 本质&#xff1a; 一个事务对应一个数据库连接。 通过 this 来调用某个带有 Transactional 注解的方法时&#xff0c;这个注解是失效的&#xff0c;可以看做这个方法&#x…

安防视频汇聚平台EasyCVR视频广场面包屑侧边栏支持拖拽操作

智能视频监控平台EasyCVR能在复杂的网络环境中&#xff0c;将海量设备实现集中统一接入与汇聚管理&#xff0c;实现视频的处理与分发、录像与存储、按需调阅、平台级联等。 TSINGSEE青犀视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协…

2023年中职组“网络安全”赛项吉安市竞赛任务书

2023年中职组“网络安全”赛项 吉安市竞赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 服务加固…

MYSQL进阶-事务

什么是数据库事务&#xff1f; 事务是一个不可分割的数据库操作序列&#xff0c;也是数据库并发控制的基本单位&#xff0c;其执 行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上 的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务最…

使用express搭建后端服务

目录 1 创建工程目录2 初始化3 安装express依赖4 启动服务5 访问服务总结 上一篇我们利用TDesign搭建了前端服务&#xff0c;现在的开发讲究一个前后端分离&#xff0c;后端的话需要单独搭建服务。后端服务的技术栈还挺多&#xff0c;有java、php、python、nodejs等。在众多的技…

2023-08-03 LeetCode每日一题(删除注释)

2023-08-03每日一题 一、题目编号 722. 删除注释二、题目链接 点击跳转到题目位置 三、题目描述 给一个 C 程序&#xff0c;删除程序中的注释。这个程序source是一个数组&#xff0c;其中source[i]表示第 i 行源码。 这表示每行源码由 ‘\n’ 分隔。 在 C 中有两种注释风…

【图论】强连通分量

一.定义 强连通分量&#xff08;Strongly Connected Components&#xff0c;简称SCC&#xff09;是图论中的一个概念&#xff0c;用于描述有向图中的一组顶点&#xff0c;其中任意两个顶点之间都存在一条有向路径。换句话说&#xff0c;对于图中的任意两个顶点u和v&#xff0c;…