what is simplest
simplest pursues simplicity and perfection.
It aims to provide a series of basic capabilities for the rapid development of projects, so that users can quickly expand functions according to project needs
Don't care about some cumbersome things anymore. Duplicate work, but focus on business.
foreword
Program 10 years. as a multi-year program. Knowing that every project and program, there is a lot of repetitive work to do.
I have been in the industry for nearly 10 years, I have written many programs, and I have written many programs to death. . . . .
Witness the golden age of the Internet to the present sluggishness. Fortunately, I am still in the army of programmers. Fight with you!
My story <<Programmer Three Hours>> The official account is looking forward to communicating with you. I hope to give you some inspiration and help when you are confused.
related warehouse
project | Introduction | gitee address | github address |
---|---|---|---|
simplest-api | The front-end and back-end separation project is based on the simplest-api, which can quickly build a unified communication interaction based on the Web Json API format | https://gitee.com/daTouY/simplest-api/tree/main/ | https://github.com/coder-amiao/simplest-api |
simplest-jpa | Based on the flexible and powerful QueryWrapper of QueryDSL syntax, the chained QueryChain is powerful and free to combine queryers, and queries data based on Java API like writing native SQL, which is extremely elegant. | https://gitee.com/daTouY/simplest-jpa | https://github.com/coder-amiao/simplest-jpa |
simplest-boot | Business common ecological core components | https://gitee.com/daTouY/simplest-boot.git | https://github.com/coder-amiao/simplest-boot |
simplest-admin | Based on the RABC permission model, it is rich in functions and the latest technology stack Vue3.3 + Vite4 + TS + Pinia + Element-Plus management background scaffolding. Out-of-the-box, customizable code generation templates allow you to focus on business development. | https://gitee.com/daTouY/simplest-admin.git | https://github.com/coder-amiao/simplest-admin |
Simplest
development documentation
Here we mainly introduce simplest-jpa
the use of
quick start
Introduce dependencies in project 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>
Enable simplest-jpa via the @EnableJPAQuery annotation on the SpringBoot startup class or configuration class
@SpringBootApplication
@EnableJPAQuery
public class SpringbootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootJpaApplication.class, args);
}
}
At this point you can use all the functions in your project.
database configuration
Configure the corresponding database connection in the project
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
Define the corresponding entity corresponding to the database table. JPA will automatically generate the database for you.
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;
}
Generate corresponding query EntityPath
The APT technology based on QueryDSL introduces the corresponding plug-in in pom.xml of maven
<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>
Then compile the project via maven.
The corresponding query EntityPaht entity will be generated in the directory you specify
simple query
- Write your own
Repository
inherit genericBaseRepository
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{
}
- Write your own
Service
inherit commonService
layer
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> {
}
Implementation class
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 {
}
In this way, your service has the basic method of adding, deleting, modifying and checking all operational data
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 has a built-in named BaseRepository
interface, which implements the basic addition, deletion, modification and query functions and paging query functions. and correspondingService
new data
Service
provides the save
method _saveBatch
saveOrUpdate
save(T entity)
Insert entity class data without ignoringnull
the value.saveBatch(Collection<T> entities)
Batch insert entity class datasaveOrUpdate(T entity)
Insert or update, if the primary key has a value, then update, if there is no primary key value, then insert, insert or update will not ignore the null value.saveOrUpdateSelective(T entity)
Insert or update, if the primary key has a value, then update, if there is no primary key value, then insert, update will ignore the null value.
delete data
Service
Provides the remove
, removeAll
, methodremoveById
removeByIds
removeById(ID id)
Delete data based on primary keyremoveById(Collection<? extends ID> ids)
Delete data in batches based on multiple primary keysremove(Collection<T> entities)
Batch delete based on multiple entities (entities need to have a primary key)remove(T entity)
Delete based on entity conditions
update data
Service
Provides update
multiple overloaded methods
update(T entity)
The query condition is updated based on the entity ID. null values are not ignoredupdate(T entity, Boolean ignore)
The query condition is updated based on the entity ID. Custom ignore nul valueupdate(T entity, Boolean ignore, String[] ignoreProperties)
Custom ignore entity field attributesupdate(JPAUpdateClause query)
Update data based on query conditions.
@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
It is a tool class that encapsulates UpdateWrapper, etc., which is convenient for users to perform chain operations.
@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 queries and paging queries
basic query
Simplest-jpa provides Service
the following functions for querying database data
getById(ID id)
Query data based on primary key.getByIdOpt(ID id)
Query data based on primary key. returnOptional
typegetOne(Example<T> example)
Query 1 piece of data according to the query condition.getOne(Predicate query)
Query 1 piece of data according to the query condition.getOneOpt(Example<T> example)
Query 1 piece of data according to the query condition. When the returnOptional
type query finds multiple matching data, a NonUniqueResultException will be thrownlistByIds(Collection<ID> ids)
Query the data collection according to the data primary key.list(Predicate query)
Query data collection according to query conditions.list(Example query)
Query data collection according to query conditions.list()
Query all data.count(Predicate query)
Query the amount of data based on query conditions.count(Example<T> example)
Query the amount of data based on query conditions.exists(Predicate query)
Determine whether the data exists according to the query conditions.existsById(ID id)
Determine whether it exists according to the ID
Paging query
page(Pageable page)
Query all data in pages.page(Pageable page, Predicate query)
Query data in pages according to query conditions.
chain query
In simplest-jpa
, built-in queryChain and updateChain are used to perform chained query operations and chained data operations (modify and delete) on data.
- queryChain: chain query
- updateChain: chain update
queryChain demonstration
@Test
void selectQueryChain() {
QCategory qCategory = QCategory.category;
List<String> categoryList = categoryService.queryChain()
.select(qCategory.title)
.from(qCategory)
.fetch();
log.info("返回条数{}", categoryList.size());
}
conditional query
@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());
}
Paging query
@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 example
@Test
@Rollback(value = false)
@Transactional
void updateChain() {
QCategory qCategory = QCategory.category;
categoryService.updateChain(qCategory)
.set(qCategory.title, "测试jpa")
.where(qCategory.id.eq(6l)).execute();
}
method of queryChain
fetch()
Get multiple data lazy loading modefetchAll()
Get multiple pieces of data and ignore lazy loadingfetchOne()
Getting more than one piece of data will report an errorfetchFirst()
Query the first datafetchCount()
Query the number of data
Flexible QueryWrapper
In the addition, deletion, query and paging chapters, we can see at any time QueryWrapper
, QueryWrapper
it is a powerful tool for constructing Sql, and it is also simplest-jpa
the highlight and feature of .
Use of 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());
}
}
example
- single table query
@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;
}
}
- multi-table query
/**
* @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();
}