一.七个Repository接口:
- Repository (org.springframework.data.repository)
这是一个标识接口 - CrudRepository (org.springframework.data.repository)
<S extends T> S save(S var1);
<S extends T> Iterable<S> saveAll(Iterable<S> var1);
Optional<T> findById(ID var1);
boolean existsById(ID var1);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> var1);
long count();
void deleteById(ID var1);
void delete(T var1);
void deleteAll(Iterable<? extends T> var1);
void deleteAll();
- PagingAndSortingRepository (org.springframework.data.repository)
Iterable<T> findAll(Sort var1);
Page<T> findAll(Pageable var1);
- QueryByExampleExecutor (org.springframework.data.repository.query)
<S extends T> Optional<S> findOne(Example<S> var1);
<S extends T> Iterable<S> findAll(Example<S> var1);
<S extends T> Iterable<S> findAll(Example<S> var1, Sort var2);
<S extends T> Page<S> findAll(Example<S> var1, Pageable var2);
<S extends T> long count(Example<S> var1);
<S extends T> boolean exists(Example<S> var1);
- JpaRepository (org.springframework.data.jpa.repository)
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
- JpaSpecificationExecutor (org.springframework.data.jpa.repository)
Optional<T> findOne(@Nullable Specification<T> var1);
List<T> findAll(@Nullable Specification<T> var1);
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
List<T> findAll(@Nullable Specification<T> var1, Sort var2);
long count(@Nullable Specification<T> var1);
- QueryDslPredicateExecutor (org.springframework.data.jpa.repository)
两个实现类:SimpleJpaRepository (org.springframework.data.jpa.repository.support)
QueryDslJpaRepository (org.springframework.data.jpa.repository.support)
结构如图:
正常情况下只要写一个接口继承JpaRepository和JpaSpecificationExecutor就够用了。在导入的包里有现成的JpaRepositoryImplementation可以用
package org.springframework.data.jpa.repository.support;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
void setRepositoryMethodMetadata(CrudMethodMetadata var1);
default void setEscapeCharacter(EscapeCharacter escapeCharacter) {
}
}
二.搭建底层
- 新建一个基础DO
import java.io.Serializable;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ToString
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Data
public class JpaDO implements Serializable {
@Id
private ID id;
}
- 新建一个继承JpaRepositoryImplementation的repository,可以在这里自己定义方法
import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;
public interface JpaRepository<T extends JpaDO, ID> extends JpaRepositoryImplementation<T, ID> {
T create(T entity);
}
- 新建repository的实现类
import javax.persistence.EntityManager;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
public class JpaRepositoryImpl<T extends JpaDO, ID> extends SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {
private EntityManager em;
private Class<T> domainClass;
public JpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.domainClass = entityInformation.getJavaType();
this.em = entityManager;
}
public JpaRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.domainClass = domainClass;
this.em = entityManager;
}
@Override
public T create(T entity) {
em.persist(entity);
return entity;
}
}
- 元数据模型
在pom.xml中添加插件,再compile生成。
<build>
<plugins>
<!-- JPA辅助实体 -->
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.0.5</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.4.3.Final</version>
</dependency>
</dependencies>
</plugin>
<!-- 源码 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
三.实战
- 新建application.yml
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/XXX?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
username: root
password: root
sql-script-encoding: utf-8
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQL8Dialect
open-in-view: false
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
enable_lazy_load_no_trans: true
- 新建一个statuDO,继承JpaDO
import java.util.Date;
import javax.persistence.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.hel.all.utils.resources.UtilEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@EqualsAndHashCode(callSuper = true)
public abstract class StatusDO extends JpaDO<String> {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date insDate;
@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
private Date updateDate;
@Enumerated(EnumType.STRING)
@Column
private UtilEnum.Status status = UtilEnum.Status.ENABLED;
}
- 新建一个User实体类,继承StatuDO
import java.util.Set;
import javax.persistence.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@Entity
@Table(name = "a_user")
@DynamicInsert
@DynamicUpdate
@EqualsAndHashCode
@ToString
public class UserDO extends StatusDO {
@Transient
public static final String PREFIX_ID = "US";
/**
* 用户名
*/
@Column(length = 20, nullable = false, unique = true)
private String name;
/**
* 性别
*/
@Enumerated(EnumType.STRING)
private EntityEnum.Sex sex;
/**
* 账号
*/
@Column(length = 20)
private String account;
/**
* 密码
*/
@Password
@Column(length = 20, nullable = false)
private String password;
- 新建UserDAO
import org.springframework.stereotype.Repository;
@Repository
public interface UserDAO extends JpaRepository<UserDO, String> {}
- 新建配置文件
@Configuration
@EnableJpaAuditing
@EntityScan(basePackages = {"com.hel.server.bs.entity"})
@EnableJpaRepositories(basePackages = {"com.hel.server.bs.repository"},
repositoryBaseClass = JpaRepositoryImpl.class)
public class JpaConfig {}
- 新建UserService
public interface UserService {
Optional<UserDO> create(UserDO userDO);
Optional<UserDO> update(UserDO userDO);
}
- 新建UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private Snowflake snowflake;
@Autowired
private UserDAO userDAO;
@Transactional(rollbackFor = Exception.class)
@Override
public Optional<UserDO> create(UserDO userDO) {
Assert.isNull(userDO.getId(), "");
Assert.hasText(userDO.getName(), "");
userDO.setId(snowflake.nextId(UserDO.PREFIX_ID));
userDO.setRole(EntityEnum.Role.VISITOR);
if (Objects.isNull(userDO.getSex())) {
userDO.setSex(EntityEnum.Sex.NONE);
}
userDO.setAccount(userDO.getEmail());
return Optional.ofNullable(userDAO.create(userDO));
}
@Transactional(rollbackFor = Exception.class)
@Override
public Optional<UserDO> update(UserDO userDO) {
Assert.hasText(userDO.getId(), "");
return Optional.ofNullable(userDAO.update(userDO));
}
}
进阶:动态查询
当一个实体有多个查询条件时,每个条件写一个查询方法是不现实的,这里就用到动态查询。主要用到JpaSpecificationExecutor
的List<T> findAll(@Nullable Specification<T> var1);
使用过程中会将Specification进行封装。
- 先在底层新建一个抽象类Condition.class
package com.hel.all.utils.persistence;
public abstract class Condition<T extends JpaDO> {
/**
* 返回一个空条件对象
*
* @param <T>
* 实体类型
* @return return
*/
public static <T extends JpaDO> Condition<T> empty() {
return new EmptyCondition();
}
/**
* 对象的条件转 {@link Specification} 类型
*
* @return return
*/
public abstract Specification<T> transfer();
/**
* 空条件对象, 推荐使用 {@link Condition#empty()}
*
* @param <T>
* 实体类型
*/
@Deprecated
public static class EmptyCondition<T extends JpaDO> extends Condition<T> {
@Override
public Specification<T> transfer() {
return Specification.where(null);
}
}
}
- 新建底层SortVO
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
public interface SortVO {
String getField();
default Sort transfer(@Nullable Boolean direction) {
String field = this.getField();
Sort.Direction direction2 = (null == direction || direction) ? Sort.Direction.ASC : Sort.Direction.DESC;
return StringUtils.isBlank(field) ? Sort.unsorted() : Sort.by(direction2, field);
}
}
- 新建Specification生成器
package com.hel.all.utils.jpa.generator;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.*;
import javax.persistence.metamodel.SingularAttribute;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.query.criteria.internal.OrderImpl;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
public final class SpecAdapter {
/**
* <pre>
* cb.like(root.get(field), "%" + value + "%")
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> contains(String field, String value) {
return StringUtils.isBlank(value) ? null : (root, query, cb) -> cb.like(root.get(field), "%" + value + "%");
}
/**
* <pre>
* cb.like(root.get(join).get(field), "%" + value + "%")
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> contains(String join, String field, String value) {
return StringUtils.isBlank(value) ? null
: (root, query, cb) -> cb.like(root.get(join).get(field), "%" + value + "%");
}
/**
* <pre>
* cb.notLike(root.get(field), "%" + value + "%")
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notContains(String field, String value) {
return StringUtils.isBlank(value) ? null : (root, query, cb) -> cb.notLike(root.get(field), "%" + value + "%");
}
/**
* <pre>
* cb.notLike(root.get(join).get(field), "%" + value + "%")
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notContains(String join, String field, String value) {
return StringUtils.isBlank(value) ? null
: (root, query, cb) -> cb.notLike(root.get(join).get(field), "%" + value + "%");
}
/**
* <pre>
* root.get(field).in(values)
* </pre>
*
* @param field
* 字段
* @param values
* 值
* @return Specification
*/
public static <T> Specification<T> in(String field, @NonNull Collection<?> values) {
return values.isEmpty() ? null : (root, query, cb) -> root.get(field).in(values);
}
/**
* <pre>
* cb.equal(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.get(field), value);
}
/**
* <pre>
* cb.equal(root.get(join).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String join, String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.get(join).get(field), value);
}
/**
* <pre>
* cb.equal(root.get(join1).get(join2).get(field), value)
* </pre>
*
* @param join1
* 从表字段1
* @param join2
* 从表字段2
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String join1, String join2, String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.get(join1).get(join2).get(field), value);
}
/**
* <pre>
* cb.notEqual(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notEqual(String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.notEqual(root.get(field), value);
}
@Deprecated
public static <T> Specification<T> contains(SingularAttribute<? super T, String> attribute, String value) {
return StringUtils.isBlank(value) ? null : (root, query, cb) -> cb.like(root.get(attribute), "%" + value + "%");
}
@Deprecated
public static <T, E> Specification<T> equal(SingularAttribute<? super T, E> attribute, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.get(attribute), value);
}
@Deprecated
public static <T, E> Specification<T> notEqual(SingularAttribute<? super T, E> attribute, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.notEqual(root.get(attribute), value);
}
/**
* <pre>
* cb.greaterThanOrEqualTo(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(String field, Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(field), value);
}
/**
* <pre>
* cb.greaterThanOrEqualTo(root.get(join).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(String join, String field, Y value) {
return nullOrBlank(value) ? null
: (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(join).get(field), value);
}
/**
* <pre>
* cb.lessThanOrEqualTo(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(String field, Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.lessThanOrEqualTo(root.get(field), value);
}
/**
* <pre>
* cb.lessThanOrEqualTo(root.get(join).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(String join, String field, Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.lessThanOrEqualTo(root.get(join).get(field), value);
}
@Deprecated
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(SingularAttribute<? super T, Y> attribute,
Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(attribute), value);
}
@Deprecated
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(SingularAttribute<? super T, Y> attribute,
Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.lessThanOrEqualTo(root.get(attribute), value);
}
/**
* <pre>
* cb.isNull(root.get(field))
* </pre>
*
* @param field
* 字段
* @return Specification
*/
public static <T> Specification<T> isNull(String field) {
return (root, query, cb) -> cb.isNull(root.get(field));
}
/**
* <pre>
* cb.isNotNull(root.get(field))
* </pre>
*
* @param field
* 字段
* @return Specification
*/
public static <T> Specification<T> isNotNull(String field) {
return (root, query, cb) -> cb.isNotNull(root.get(field));
}
/**
* 从表
* @date 2019/08/30
*/
public static class Joins {
public static <T> Specification<T> contains(String name, String attribute, String value) {
return StringUtils.isBlank(value) ? null
: (root, query, cb) -> cb.like(getJoin(root, name).get(attribute), "%" + value + "%");
}
public static <T> Specification<T> equal(String name, String attribute, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(getJoin(root, name).get(attribute), value);
}
public static <T> Specification<T> equal(String name, String attribute, String name2, String attribute2) {
return (root, query, cb) -> cb.equal(getJoin(root, name).get(attribute),
getJoin(root, name2).get(attribute2));
}
public static <T, E> Specification<T> isMember(String name, String attribute, E value) {
return nullOrBlank(value) ? null
: (root, query, cb) -> cb.isMember(value, getJoin(root, name).get(attribute));
}
}
public static class Sort {
public static <T> Specification<T> orderBy(String name, boolean asc) {
return (root, query, cb) -> {
List<Order> os = new LinkedList<>(query.getOrderList());
os.add(new OrderImpl(root.get(name), asc));
query.orderBy(os);
return query.getRestriction();
};
}
public static <T> Specification<T> selectCase(String name, @NonNull Map<Integer, Object> values) {
return values.isEmpty() ? null : (root, query, cb) -> {
CriteriaBuilder.Case<Object> c = cb.selectCase();
values.entrySet().forEach(v -> c.when(cb.equal(root.get(name), v.getValue()), cb.literal(v.getKey())));
c.otherwise(cb.literal(Integer.MAX_VALUE));
List<Order> os = new LinkedList<>(query.getOrderList());
os.add(cb.asc(c));
query.orderBy(os);
return query.getRestriction();
};
}
}
/* PRIVATE */
private static boolean nullOrBlank(Object value) {
return null == value || StringUtils.isBlank(value.toString());
}
private static <T> Join<T, ?> getJoin(Root<T> root, String name) {
return root.getJoins().stream().filter(j -> j.getAttribute().getName().equals(name)).findAny()
.orElse(root.join(name, JoinType.LEFT));
}
}
- 可以看到
org.springframework.data.jpa.repository.support.SimpleJpaRepository
里的
public List<T> findAll(@Nullable Specification<T> spec) {
return this.getQuery(spec, Sort.unsorted()).getResultList();
}
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = this.getQuery(spec, pageable);
return (Page)(isUnpaged(pageable) ? new PageImpl(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec));
}
这里的查询参数是Specification,这个写起来还是挺麻烦的,所以可以在上面的JpaRepository
里加一个查询方法
import com.hel.all.utils.persistence.Condition;
public interface JpaRepository<T extends JpaDO, ID> extends JpaRepositoryImplementation<T, ID> {
T create(T entity);
Optional<T> findOne(Condition<T> condition);
List<T> findAll(Condition<T> condition, Sort sort);
Page<T> findAll(Condition<T> condition, Pageable pageable);
}
- 然后在业务层接口类添加类中类Condition
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface UserService {
Optional<UserDO> findOne(com.hel.all.utils.persistence.Condition<UserDO> condition);
List<UserDO> findAll(com.hel.all.utils.persistence.Condition<UserDO> condition, Sort sort);
Page<UserDO> findAll(com.hel.all.utils.persistence.Condition<UserDO> condition, Pageable pageable);
Optional<UserDO> create(UserDO userDO);
@Builder
class Condition extends com.hel.all.utils.persistence.Condition<UserDO> {
private String id;
private String name;
private EntityEnum.Sex sex;
private String account;
private Date createDateL;
private Date createDateU;
}
@Override
public Specification<UserDO> transfer() {
return Specification.<UserDO>where(SpecAdapter.equal(UserDO_.ID, this.id))
.and(SpecAdapter.contains(UserDO_.NAME, this.name))
.and(SpecAdapter.equal(UserDO_.ACCOUNT, this.account))
.and(SpecAdapter.gtOrEt(UserDO_.INS_DATE, this.createDateL))
.and(SpecAdapter.ltOrEt(UserDO_.INS_DATE, this.createDateU));
}
}
- 添加VO层
public interface UserVO {
@Getter
enum SortVO implements com.hel.all.utils.controller.param.SortVO {
/**
* SEX
*/
SEX(UserDO_.SEX),
/**
* CELLPHONE
*/
CELLPHONE(UserDO_.CELLPHONE),
/**
* INS_DATE
*/
INS_DATE(StatusDO_.INS_DATE);
private String field;
SortVO(String field) {
this.field = field;
}
}
}
- 最后在控制层查询接口,可以传零个或多个参数,jpa会自动生成查询语句,ps:mvnUtils可以用PageRequest.of()原生方法代替。
@GetMapping("/users")
public WrapVO.PageVO<UserVO.UserView> findPage(//
@RequestParam(required = false, defaultValue = "0") Integer page, //
@RequestParam(required = false, defaultValue = "20") Integer size, //
@RequestParam(required = false) String id, //
@RequestParam(required = false) String name, //
@RequestParam(required = false) UserVO.SortVO sort, //
@RequestParam(required = false) Boolean direction) {
Page<UserDO> users =userService.findAll(UserService.Condition.builder().id(id)
.name(name).account(account).build(),PageRequest.of(page, size,
MvcUtils.toSort(sort, direction)));
return WrapVO.PageVO.of(users, UserVO.UserView.of(users.getContent()));
}
- 已上的SpecAdapter生成器一般只用在单表查询,如果有需要两表查询的话,可以使用新的生成器。
如果需要使用其他JoinType,可以使用setJoinType(JoinType j)
方法。
import java.util.Collection;
import javax.persistence.criteria.JoinType;
import javax.persistence.metamodel.SingularAttribute;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
/**
* 用于 JPA(QBC) 生成 Specification2
*
* 需要使用其它JoinType的可使用这个(SpecAdapter的JoinType一致为INNER)
*
* 使用方式:跟SpecAdapter一样,但需要先执行setJoinType(joinType)
*
* @date 2019/05/08
*/
public final class SpecAdapter2 {
private static JoinType joinType = JoinType.INNER;// 请不要把它当做默认值
/**
* <pre>
* cb.like(root.get(field), "%" + value + "%")
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> contains(String field, String value) {
return StringUtils.isBlank(value) ? null : (root, query, cb) -> cb.like(root.get(field), "%" + value + "%");
}
/**
* <pre>
* cb.like(root.join(join, joinType).get(field), "%" + value + "%")
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> contains(String join, String field, String value) {
return StringUtils.isBlank(value) ? null
: (root, query, cb) -> cb.like(root.join(join, joinType).get(field), "%" + value + "%");
}
/**
* <pre>
* cb.notLike(root.get(field), "%" + value + "%")
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notContains(String field, String value) {
return StringUtils.isBlank(value) ? null : (root, query, cb) -> cb.notLike(root.get(field), "%" + value + "%");
}
/**
* <pre>
* cb.notLike(root.join(join, joinType).get(field), "%" + value + "%")
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notContains(String join, String field, String value) {
return StringUtils.isBlank(value) ? null
: (root, query, cb) -> cb.notLike(root.join(join, joinType).get(field), "%" + value + "%");
}
/**
* <pre>
* root.get(field).in(values)
* </pre>
*
* @param field
* 字段
* @param values
* 值
* @return Specification
*/
public static <T> Specification<T> in(String field, @NonNull Collection<?> values) {
return values.isEmpty() ? null : (root, query, cb) -> root.get(field).in(values);
}
/**
* <pre>
* cb.equal(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.get(field), value);
}
/**
* <pre>
* cb.equal(root.join(join, joinType).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String join, String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.equal(root.join(join, joinType).get(field), value);
}
/**
* <pre>
* cb.equal(root.join(join1, joinType).join(join2, joinType).get(field)
* </pre>
*
* @param join1
* 从表字段1
* @param join2
* 从表字段2
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> equal(String join1, String join2, String field, Object value) {
return nullOrBlank(value) ? null
: (root, query, cb) -> cb.equal(root.join(join1, joinType).join(join2, joinType).get(field), value);
}
/**
* <pre>
* cb.notEqual(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T> Specification<T> notEqual(String field, Object value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.notEqual(root.get(field), value);
}
/**
* <pre>
* cb.greaterThanOrEqualTo(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(String field, Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(field), value);
}
/**
* <pre>
* cb.greaterThanOrEqualTo(root.join(join, joinType).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(String join, String field, Y value) {
return nullOrBlank(value) ? null
: (root, query, cb) -> cb.greaterThanOrEqualTo(root.join(join, joinType).get(field), value);
}
/**
* <pre>
* cb.lessThanOrEqualTo(root.get(field), value)
* </pre>
*
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(String field, Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.lessThanOrEqualTo(root.get(field), value);
}
/**
* <pre>
* cb.lessThanOrEqualTo(root.join(join, joinType).get(field), value)
* </pre>
*
* @param join
* 从表字段
* @param field
* 字段
* @param value
* 值
* @return Specification
*/
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(String join, String field, Y value) {
return nullOrBlank(value) ? null
: (root, query, cb) -> cb.lessThanOrEqualTo(root.join(join, joinType).get(field), value);
}
@Deprecated
public static <T, Y extends Comparable<Y>> Specification<T> gtOrEt(SingularAttribute<? super T, Y> attribute,
Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(attribute), value);
}
@Deprecated
public static <T, Y extends Comparable<Y>> Specification<T> ltOrEt(SingularAttribute<? super T, Y> attribute,
Y value) {
return nullOrBlank(value) ? null : (root, query, cb) -> cb.lessThanOrEqualTo(root.get(attribute), value);
}
/**
* 设置连接参数(需要每次都设置)
*
* 跟平常一样,Specification.where(SpecAdapter.setJoinType(JoinType.INNER)) 还有
* .and(SpecAdapter.setJoinType(JoinType.INNER))
*
* 由于本人在做的时候出现需要另外设置右连接的情况,就不写死用什么连接了吧
*
* @param j
* JoinType
* @return Specification
*/
public static <T> Specification<T> setJoinType(JoinType j) {
joinType = j;
return Specification.where(null);
}
/* PRIVATE */
private static boolean nullOrBlank(Object value) {
return null == value || StringUtils.isBlank(value.toString());
}
}