spring boot custom repository

The default spring boot provided repository for most of the scene, for some special scene, a special method, in addition to using @NAMEQUERY @QUERY custom sql statement, but also can customize the basic repository

Here are some caveats record of stepped pit or encounter

 

1, custom query, use custom query specification

Where noted root acquire property, criteriaBuilder custom criteria

package com.duoke.demo.bean;
import static com.google.common.collect.Iterables.toArray;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

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;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class CustomerSpecs {

    /**
     * 自定义查询
     * @param manager
     * @param example
     * @param <T>
     * @return
     */
    public static <T>Specification<T> byAuto(final EntityManager manager,final T example){

        // 获取泛型类别
        final Class<T> type = (Class<T>) example.getClass();

        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                // 获取实体类的entitytype
                EntityType<T> entity = manager.getMetamodel().entity(type);

                // 对实体类的所有属性循环
                for (Attribute<T,?> attr:entity.getDeclaredAttributes()) {
                    Object attrValue = getValue(example,attr);
                    if(attrValue !=null){
                        if(attr.getJavaType() == String.class){
                            if(!StringUtils.isEmpty(attrValue)){
                                predicates.add(criteriaBuilder.like(root.get(attribute(entity,attr.getName(),String.class)),pattern((String) attrValue)));
                            }
                        }else{
                            predicates.add(criteriaBuilder.equal(root.get(attribute(entity,attr.getName(),attrValue.getClass())),attrValue));
                        }
                    }
                }
                return predicates.isEmpty() ? criteriaBuilder.conjunction() : criteriaBuilder.and(toArray(predicates,Predicate.class));
            }


            /**
             * 获取field属性
             * @param example
             * @param attr
             * @param <T>
             * @return
             */
            private  <T>Object getValue(T example,Attribute<T,?> attr){
                return ReflectionUtils.getField((Field) attr.getJavaMember(),example);
            }

            /**
             * 获取实体类的当前属性
             * @param entity
             * @param fieldName
             * @param fieldClass
             * @param <T>
             * @param <E>
             * @return
             */
            private <T,E> SingularAttribute<T,E> attribute(EntityType<T>entity,String fieldName,Class<E> fieldClass){
                return entity.getDeclaredSingularAttribute(fieldName,fieldClass);
            }
        };

    }

    static private  String pattern(String str){
        return "%"+str+"%";
    }

}

2, custom collar repository after (1-5 steps to get that done, it is easy to forget the most important step is the step in the sixth step, attention, otherwise the project will start being given, can not find such entity type, not suitable constructors such as the lack of and other errors)

1), define an interface class repository, add custom interfaces

Package com.duoke.demo.service; 

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 the java.io.Serializable; 

// specified in the current art interface is not a class model (-Service) 
@NoRepositoryBean
 // inherited methods with a base such as JPARES findAll
 / / succession with the use of a custom basis spec condition 
public  interface CustomRepo <T, ID the extends the Serializable> the extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
    Page<T> findByAuto(T example, Pageable pageable);
}

2) define the implementation class

package com.duoke.demo.service;

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.duoke.demo.bean.CustomerSpecs.*;

public class CustomRepoImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements CustomRepo<T,ID>{
    private EntityManager entityManager;

    public CustomRepoImpl(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);
    }
}

3) the definition repository bean plants

package com.duoke.demo.service;

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.JpaRepositoryImplementation;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

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

/**
 * 自定义jpa 工厂bean
 * @param <T>
 * @param <S>
 * @param <ID>
 */
public class CustomRepoFactoryBean<T extends JpaRepository<S, ID>,S,ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {
    /**
     * Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
     *
     * @param repositoryInterface must not be {@literal null}.
     */
    public CustomRepoFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }

    // 工厂生产repo 方法
    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new CustomRepoFactory(entityManager);
    }

    private class CustomRepoFactory extends JpaRepositoryFactory{

        private final EntityManager entityManager;
        /**
         * Creates a new {@link JpaRepositoryFactory}.
         *
         * @param entityManager must not be {@literal null}
         */
        public CustomRepoFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }

        @Override
        // 重写获取实现类
        protected JpaRepositoryImplementation<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
            return  new CustomRepoImpl<T,ID>((Class<T>) information.getDomainType(),entityManager);
        }

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

 

res inheritance before 4) change

package com.duoke.demo.service;

import com.duoke.demo.bean.Person;
import com.sun.xml.internal.bind.v2.model.core.ID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
 * JPA 数据访问接口
 */
public interface IPersonRepository  extends CustomRepo<Person,String> {
    // 定义访问接口
//    List<Person> findByName(String name);

//    List<Person> findByAge(Integer age);

//
//    List<Person> findByNameLike(String name);
//
//    List<Person> findByNameAndAddress(String name,String address);
//
//    @Query("select p from Person p where p.address = :address and p.name = :name")
//    List<Person> withNameAndAddress(@Param("address") String address,@Param("name") String name);
//
//    @Modifying
//    @Transactional
//    @Query("update person set name = ?1")
//    int setName(String name);

}

 

5) controller can be used directly after the injection repository

@RequestMapping("custom")
    public List<Person> findByCustom(String name){
        Person person = new Person();
        person.setName(name);
        Page<Person> peoples = iPersonRepository.findByAuto(person,buildPage(1,2));
        return peoples.getContent();
    }

 

6) * Start class specified bean factory classloading

@SpringBootApplication(scanBasePackages = "com.duoke")
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepoFactoryBean.class)
public class DemoApplication {
//    项目启动main方法
    public static void main(String[] args) {
//        关闭banner
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run();
//        SpringApplication.run(DemoApplication.class, args);
    }
}

 

Guess you like

Origin www.cnblogs.com/jony-it/p/11427051.html