什么是 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-jpa https://github.com/coder-amiao/simplest-jpa
simplest-admin 基于 RABC 权限模型,功能丰富最新技术栈 Vue3.3 + Vite4 + TS + Pinia + Element-Plus 管理后台脚手架。开箱即用,可定制的代码生成模板,让你只需专注于业务开发。 https://gitee.com/daTouY/simplest-admin.git https://github.com/coder-amiao/simplest-admin
simplest-boot 业务通用生态核心组件 https://gitee.com/daTouY/simplest-boot.git https://github.com/coder-amiao/simplest-boot

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/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 10
maximum-pool-size: 20
idle-timeout: 600000
max-life-time: 1800000 jpa:
hibernate:
naming:
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
ddl-auto: update # 控制是否可以基于程序中Entity的定义自动创建或者修改DB中表结构
show-sql: true #控制是否打印运行时的SQL语句与参数信息
database-platform: org.hibernate.dialect.MySQLDialect #数据库方言
open-in-view: true
properties:
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 解绑和数据联系。属于实体类属性
*/
@Transient
private 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 {
@Autowired
private ICategoryService categoryService; @Test
void countByExample() {
Category category = new Category();
//category.setTitle("测试");
long count = categoryService.count(Example.of(category));
log.info("条件count{}", count);
} @Test
void getById() {
Optional<Category> category = categoryService.getByIdOpt(6l);
if (category.isPresent()) {
log.info(category.get().toString());
}
} @Test
void getOne() {
QCategory qCategory = QCategory.category;
QTitleVo vo=QTitleVo.titleVo;
Predicate query=vo.subTitle.eq("batch1");
Category category = categoryService.getOne(query);
log.info(category.toString());
} @Test
void 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());
} @Test
void getPage() {
QCategory qCategory = QCategory.category; // categoryService.getJPAQueryFactory().select().where(qCategory.)
} @Test
void save() {
Category c = new Category();
// c.setTitle("保存");
categoryService.save(c);
} @Test
void deleteById() {
categoryService.removeById(6l);
} @Test
void deleteAll() {
List<Long> ids = new ArrayList<>();
ids.add(6l);
ids.add(7l);
Boolean flag = categoryService.removeByIds(ids);
} /**
* 实体ID对应存在更新否则添加
*/
@Test
void saveOrUpdate() {
Category c = new Category();
// c.setTitle("保存");
categoryService.saveOrUpdate(c);
} @Test
@Rollback(value = false)
@Transactional
void updateChain() {
QCategory qCategory = QCategory.category;
categoryService.updateChain(qCategory)
.set(qCategory.title, "测试jpa")
.where(qCategory.id.eq(6l)).execute();
} @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);
} @Test
@Rollback(value = false)
@Transactional
void 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);
} @Test
void selectQueryChain() {
QCategory qCategory = QCategory.category;
List<String> categoryList = categoryService.queryChain()
.select(qCategory.title)
.from(qCategory).fetch();
log.info("返回条数{}", categoryList.size());
} @Test
void 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 { @Autowired
private ICategoryService categoryService; @Autowired
private JPAQueryFactory queryWrapper; /**
* select() 和 fetch() 的常用写法
* 使用fetch()查询时,数据库没有符合该条件的数据时,返回的是空集合,而不是null
*/ /**
* 查询字段-select()
*/
@Test
public void fetchColum() {
QCategory qCategory = QCategory.category;
List<String> a = queryWrapper
.select(qCategory.title)
.from(qCategory)
.fetch();
log.info("返回数量{}", a.size());
} /**
* 查询实体-selectFrom()
*/
@Test
public void fetchEntity() {
QCategory qCategory = QCategory.category;
List<Category> categories = queryWrapper.selectFrom(qCategory).fetch();
log.info("返回数量{}", categories.size()); } /**
* 查询并将结果封装至dto中
*/
@Test
public 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()
*/
@Test
public void fetchDistinct() {
QCategory qCategory = QCategory.category;
List<String> c = queryWrapper
.selectDistinct(qCategory.title)
.from(qCategory)
.fetch();
log.info("返回数量{}", c.size());
} /**
* 获取首个查询结果-fetchFirst() 单条记录 limit 1
*/
@Test
public void fetchFirst() {
QCategory qCategory = QCategory.category;
Category category = queryWrapper
.selectFrom(qCategory)
.fetchFirst();
log.info("返回数量{}", category.toString());
} /**
* 获取唯一查询结果-fetchOne()
* 当fetchOne()根据查询条件从数据库中查询到多条匹配数据时,会抛`NonUniqueResultException`
*/
@Test
public void fetchOne() {
QCategory qCategory = QCategory.category;
Category category = queryWrapper
.selectFrom(qCategory)
.fetchOne();
log.info("返回数量{}", category.toString());
} /**
* where 子句查询条件的常用写法
*/
@Test
public 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来进行查询条件管理。
*/
@Test
public 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()); } /**
* 复杂的查询关系
*/
@Test
public 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方法
*/
@Test
public 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方法
*/
@Test
public 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方法内的查询字段。
* ————————————————
*/
@Test
public 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());
} @Test
public 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());
} @Test
public 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 { @Autowired
private 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();
}

rest-apiV2.0.0升级为simplest-api开源框架生态之simplest-jpa发布的更多相关文章

  1. 【实践】如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统)

    如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统) 一.环境配置 1. Python3.7.x(注:我用的是3.7.3.安 ...

  2. NetCore 3.0 中使用Swagger生成Api说明文档及升级报错原因

    认识Swagger Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参 ...

  3. Linux下Oracle 10.2.0.1升级到10.2.0.4总结

    最近部署测试环境时,将测试环境ORACLE数据库从10.2.0.1升级到了10.2.0.4,顺便整理记录一下升级过程. 实验环境: 操作系统:Oracle Linux Server release 5 ...

  4. WPF NET5 Prism8.0的升级指南

    前言 ​ 曾经我以学习的目的写了关于在.NET Core3.1使用Prism的系列文章.NET Core 3 WPF MVVM框架 Prism系列文章索引,也谢谢大家的支持,事实上当初的版本则是Pri ...

  5. NGINX Ingress控制器1.0.0升级迁移文档(翻译)

    Ingress 是什么 Ingress 是对k8s集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP. Ingress 可以提供负载均衡.SSL 终结和基于名称的虚拟托管. 最近 ...

  6. Apache ShardingSphere 5.0.0 内核优化及升级指南

    经过近两年时间的优化和打磨,Apache ShardingSphere 5.0.0 GA 版终于在本月正式发布,相比于 4.1.1 GA 版,5.0.0 GA 版在内核层面进行了大量的优化.首先,基于 ...

  7. MVC3.0 项目升级到 MVC4.0

    按照 http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253806 的步骤 第一步:修改web.config 注意,默认的MVC3网站 ...

  8. 系统补丁更新导致MVC3.0.0升级到3.0.1的问题解决

    在更新了系统补丁之后,会不知觉的将MVC3.0.0升级到MVC3.0.1的问题,解决的思路如下: 1.全部MVC引用使用NuGet进行包的管理. 2.单独把MVC库抽离出来,然后放在单独的项目文件夹, ...

  9. Asp.net Core 1.0.1升级到Asp.net Core 1.1.0 Preview版本发布到Windows Server2008 R2 IIS中的各种坑

    Asp.net Core 1.0.1升级到Asp.net Core 1.1.0后,程序无法运行了 解决方案:在project.json中加入runtime节点 "runtimes" ...

  10. web2.0最全的国外API应用集合

    web2.0最全的国外API应用集合 原文地址:http://www.buguat.com/post/98.html 2.0时代,越来越多的API被大家广泛应用,如果你还不了解API是何物,请看这里的 ...

随机推荐

  1. 驱动开发:通过MDL映射实现多次通信

    在前几篇文章中LyShark通过多种方式实现了驱动程序与应用层之间的通信,这其中就包括了通过运用SystemBuf缓冲区通信,运用ReadFile读写通信,运用PIPE管道通信,以及运用ASYNC反向 ...

  2. MySQL WorkBench更换界面成中文的方法

    菜单页面更换 文章目录 菜单页面更换 汉化文件的xml文件我放在下面的网盘中了 1.找到MySQL的安装位置, 总结 汉化文件的xml文件我放在下面的网盘中了 1.找到MySQL的安装位置, 具体安装 ...

  3. 做了个vscode 小插件,用于修改window 的颜色以区分同时打开的不同工作区,快用起来吧!

    Coralize marketplace/coralize 以高效且便捷的方式自定义Visual Studio Code工作区窗口的状态栏.标题栏以及活动边栏等颜色!这将对那些需要同时打开多个vsco ...

  4. nginx配置文件编写及日志文件相关操作

    nginx配置文件编写及日志文件相关操作 目录 nginx配置文件编写及日志文件相关操作 nginx主配置文件扩展详解 部署nginx网站 注意事项 Nginx虚拟主机 nginx配置虚拟主机的三种方 ...

  5. uniapp开发企业微信应用中的定位问题记录

    项目背景:开发工具为HBuilderX,框架为uniapp,开发移动端的Web应用,在企业微信中使用(自建应用),Web开发的应用,不是小程序. 需求点:获取用户当前的位置信息,技术流程包括以下几个环 ...

  6. 【深入浅出 Yarn 架构与实现】6-4 Container 生命周期源码分析

    本文将深入探讨 AM 向 RM 申请并获得 Container 资源后,在 NM 节点上如何启动和清理 Container.将详细分析整个过程的源码实现. 一.Container 生命周期介绍 Con ...

  7. Python中json.dump()和json.dumps()的区别

    一.图解 json.dumps(dict, indent):将Python对象转换成json字符串 json.dump(dict, file_pointer):将Python对象写入json文件 二. ...

  8. pycharm eslint 关闭

    pycharm 关闭eslint 文件->设置->语言和框架->JavaScript->代码质量工具->ESLint

  9. phpstudy-sqlilabs-less-4

    题目:GET - Error based - Double Quotes - String              基于错误的GET双引号字符型注入 可能的注入点(不全) ' " ) ') ...

  10. 从0搭建Vue3组件库(十三):引入Husky规范git提交

    为什么要引入 husky? 虽然我们项目中引入了prettier和eslint对代码格式进行了校验,但是多人开发的时候难免依然会有人提交不符合规范的代码到仓库中,如果我们拉取到这种代码还得慢慢对其进行 ...