jpa-基础到动态查询

本文介绍了JPA的基础知识,包括Repository接口的层级结构,如何搭建JPA底层,以及实战应用。重点讲解了动态查询的实现,通过创建Specification抽象类、SortVO和生成器,实现多条件查询。此外,还提到了在业务层接口和控制层如何使用这些工具进行灵活的查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.七个Repository接口:

  1. Repository (org.springframework.data.repository)
    这是一个标识接口
  2. 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();
  1. PagingAndSortingRepository (org.springframework.data.repository)
	Iterable<T> findAll(Sort var1);
    Page<T> findAll(Pageable var1);
  1. 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);
  1. 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);
  1. 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);
  1. 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));
    }
}

进阶:动态查询
当一个实体有多个查询条件时,每个条件写一个查询方法是不现实的,这里就用到动态查询。主要用到JpaSpecificationExecutorList<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());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值