【Spring Boot】整合JPA模糊分页查询

Spring Boot整合JPA

一、POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.squirrel</groupId>
    <artifactId>squirrel-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- Spring boot 父引用-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>
    <!-- Spring boot 核心web-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.1.0.BUILD-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
    </dependencies>
    
</project>

二、配置文件

#监听端口号
server.port=8888
#用户会话session过期时间,以秒为单位
server.session-timeout=7200
#数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#输出日志级别
logging.level.org.springframework.web=DEBUG

#JPA
#1表结构:update自动更新,none不采取措施
spring.jpa.hibernate.ddl-auto=update
#2显示sql
spring.jpa.show-sql=true
#3让控制器输出的json字符格式更美观
spring.jackson.serialization.indent-output=true

三、启动类

package com.squirrel;

import com.squirrel.support.CustomRepositoryFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@ComponentScan(basePackages={"com.squirrel"})
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class StartApplication {

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}

四、entity

package com.squirrel.entity;

import javax.persistence.*;

@Entity
public class User {


    private Long id;

    private String name;

    private Integer age;

    public User() {
        super();
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}


五、分页模糊查询方法封装

package com.squirrel.specs;

import static com.google.common.collect.Iterables.toArray;

import com.squirrel.entity.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;



public class CustomerSpecs {
    /**
     * 1.定义一个返回值为Specification的方法byAuto,这里使用的是泛型 T,所以这个Specification是可以用于任意的实体类的,
     * 它接受的参数是entityManager和当前的包含值作为查询条件的实体类对象
     */
    public  static <T> Specification<T> byAuto(final EntityManager entityManager,final  T example){
        /**
         * 2.获得当前实体类对象类的类型
         */
        final Class<T> type = (Class<T>) example.getClass();

        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                /**
                 * 3.新建Predicate列表存储构造的查询条件
                 */
                List<Predicate> predicates = new ArrayList<>();

                /**
                 * 4.获取实体类的EntityType,我们可以从EntityType获取实体类的属性
                 */
                EntityType<T> entity = entityManager.getMetamodel().entity(type);
                /**
                 * 5.对实体类的所有属性做循环
                 */
                for (Attribute<T,?> attr : entity.getDeclaredAttributes()) {
                    /**
                     * 6.获得实体类对象某一个属性的值
                     */
                    Object attrValue = getValue(example, attr);

                    if(attrValue != null){
                            /**
                             * 7.当前属性值为字符类型的时候
                             */
                            if(attr.getJavaType() == String.class) {
                                /**
                                 * 8.若当前字符不为空的情况下
                                 */
                                if(!StringUtils.isEmpty(attrValue)){
                                    /**
                                     * 构造当前属性like(前后%)属性值查询条件,并添加到条件列表中
                                     */
                                    predicates.add(cb.like(root.get(attribute(entity, attr.getName(),String.class)),panttern((String) attrValue)));
                                }
                            }else{
                                /**
                                 * 10.其余情况下,构造属性和属性值equal查询条件,并添加到条件列表中
                                 */
                                predicates.add(cb.equal(root.get(attribute(entity, attr.getName(),attrValue.getClass())),attrValue));
                            }
                    }
                }
                /**
                 * 11.将条件列表转换成Predicate
                 */
                return predicates.isEmpty() ? cb.conjunction() : cb.and(toArray(predicates, Predicate.class));
            }
            /**
             * 12.通过反射获得实体类对象对应属性的属性值
             */
            private <T> Object getValue(T example, Attribute<T, ?> attr){
                Field field = null;
                try {
                    field = example.getClass().getDeclaredField(attr.getName());
                    //设置对象的访问权限,保证对private的属性的访问
                    field.setAccessible(true);
                    return ReflectionUtils.getField(field,example);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                    return null;
                }
            }

            /**
             * 13.获得实体类的当前属性的SingularAttribute,SingularAttribute包含的是实体类的某个单独属性
             */
            private <E,T> SingularAttribute<T, E> attribute(EntityType<T> entity, String fileName, Class<E> fieldClass) {
                return entity.getDeclaredSingularAttribute(fileName,fieldClass);
            }
        };
    }



    /**
     * 14.构造like的查询模式,即前后加%
     */
    static  private String panttern(String str) {
        return "%" + str + "%";
    }
}

package com.squirrel.support;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;

@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> ,JpaSpecificationExecutor<T> {

    Page<T> findByAuto(T example, Pageable pageable);

}
package com.squirrel.support;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import java.io.Serializable;

import static com.squirrel.specs.CustomerSpecs.*;

public class CustomRepositoryImpl <T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID> implements
        CustomRepository<T,ID> {

    private  final EntityManager entityManager;

    public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public Page<T> findByAuto(T example, Pageable pageable) {
        return findAll(byAuto(entityManager, example),pageable);
    }
}
package com.squirrel.support;

import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

public class CustomRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable>
    extends JpaRepositoryFactoryBean<T, S, ID>{

    public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager){
        return new CustomRepositoryFactory(entityManager);
    }

    private static class CustomRepositoryFactory extends JpaRepositoryFactory{
        public CustomRepositoryFactory(EntityManager entityManager){
            super(entityManager);
        }

        @Override
        @SuppressWarnings({"unchecked"})
        protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager){
            return  new CustomRepositoryImpl<T, ID>((Class<T>) information.getDomainType(), entityManager);
        }

        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
            return CustomRepositoryImpl.class;
        }
    }
}



六、DAO

package com.squirrel.dao;


import com.squirrel.entity.User;
import com.squirrel.support.CustomRepository;

import java.util.List;

public  interface UserDao extends CustomRepository<User, Long> {

    List<User> findByName(String name);

}

七、controller

package com.squirrel.controller;

import com.squirrel.dao.UserDao;
import com.squirrel.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
@RequestMapping("user")
public class UserController {
    private final Logger log = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserDao userDao;

    @RequestMapping("/getName")
    public List<User> getName (){
        log.info("访问/user/getName接口成功");
        List<User> users = userDao.findByName("哈哈");
        return users;
    }

    @RequestMapping("/insert")
    public String insert (){
        log.info("访问/user/insert接口成功");
        User user = new User();
        user.setName("是我");
        user.setAge(18);
        userDao.save(user);
        return "插入成功";
    }

    @RequestMapping("/sort")
    public List<User> sort (){
        log.info("访问/user/sort接口成功");
        List<User> users = userDao.findAll(new Sort(Sort.Direction.DESC,"age"));
        return users;
    }

    @RequestMapping("/page")
    public  Page<User> page (){
        log.info("访问/user/sort接口成功");
        Page<User> userPage = userDao.findAll(new PageRequest(10, 2));
        return userPage;
    }

    @RequestMapping("/auto")
    public Page<User> auto(User user){
        log.info("访问/user/auto接口成功");
        Page<User> userPage = userDao.findByAuto(user, new PageRequest(0, 10));
        return userPage;
    }
}

猜你喜欢

转载自blog.csdn.net/qq654129588/article/details/80184070