spring data jpaはJpaSpecification Exectorを利用して複雑な検索をします.

10308 ワード

spring data jpaは作成方法によって名来で検索するしかないです.簡単な検索しかできません.もし複雑な検索をするなら、多条件のページはどうすればいいですか?ここで、spring data jpaはJpaSpecification Exectorインターフェースを提供してくれました.
1.まず私達のインターフェースをJpaSpecification Exectorに引き継ぎます.
public interface TaskDao extends JpaSpecificationExecutor<Task>{

}
2.JpaSpecification Exectorは以下のインターフェースを提供しています.
public interface JpaSpecificationExecutor<T> {

    T findOne(Specification<T> spec);

    List<T> findAll(Specification<T> spec);

    Page<T> findAll(Specification<T> spec, Pageable pageable);

    List<T> findAll(Specification<T> spec, Sort sort);

    long count(Specification<T> spec);
}
その中でもSpecificationは私たちが送るパラメータが必要です.インターフェースです.

public interface Specification<T> {

    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}
唯一の方法ToPredicateを提供します.JPA 2.0 criteria apiによって検索条件を記入すればいいです.JPA 2.0 criteria apiの紹介と使用については、ご参考ください.http://blog.csdn.net/dracotianlong/article/details/28445725 http://developer.51cto.com/art/200911/162722.htm
2.これから私たちはservice beanにいます.
@Service
public class TaskService {

    @Autowired TaskDao taskDao ;


    /** *        * @param page * @param size * @return */
    public Page<Task> findBySepc(int page, int size){

        PageRequest pageReq = this.buildPageRequest(page, size);
        Page<Task> tasks = this.taskDao.findAll(new MySpec(), pageReq);

        return tasks;

    }

     /** *          * @param page * @param size * @return */
     private PageRequest buildPageRequest(int page, int size) {
           Sort sort = new Sort(Direction.DESC,"createTime");
           return new PageRequest(page,size, sort);
     }

    /** *        * @author liuxg * @date 2016 3 30    2:04:39 */
    private class MySpec implements Specification<Task>{

        @Override
        public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

     //1.      
          /*Path<String> exp1 = root.get("taskName"); Path<Date> exp2 = root.get("createTime"); Path<String> exp3 = root.get("taskDetail"); Predicate predicate = cb.and(cb.like(exp1, "%taskName%"),cb.lessThan(exp2, new Date())); return cb.or(predicate,cb.equal(exp3, "kkk"));    sql   : Hibernate: select count(task0_.id) as col_0_0_ from tb_task task0_ where ( task0_.task_name like ? ) and task0_.create_time<? or task0_.task_detail=? */

    //2.    
        /*Join<Task,Project> join = root.join("project", JoinType.INNER); Path<String> exp4 = join.get("projectName"); return cb.like(exp4, "%projectName%"); Hibernate: select count(task0_.id) as col_0_0_ from tb_task task0_ inner join tb_project project1_ on task0_.project_id=project1_.id where project1_.project_name like ?*/ 
           return null ;  
        }
    }
}
3.実体類taskコードは以下の通りである.
@Entity
@Table(name = "tb_task")
public class Task {

    private Long id ;
    private String taskName ;
    private Date createTime ;
    private Project project;
    private String taskDetail ;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "task_name")
    public String getTaskName() {
        return taskName;
    }
    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    @Column(name = "create_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }


    @Column(name = "task_detail")
    public String getTaskDetail() {
        return taskDetail;
    }
    public void setTaskDetail(String taskDetail) {
        this.taskDetail = taskDetail;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "project_id")
    public Project getProject() {
        return project;
    }
    public void setProject(Project project) {
        this.project = project;
    }

}
toPredicate方法を書き換えることによって、一つのクエリPredicateに戻ります.spring data jpaは私達に問い合わせをしてくれます.
毎回一つのカテゴリーを書いてSpecificationを実現するのは面倒くさいと思うかもしれません.そう書いてもいいです.
public class TaskSpec {

    public static Specification<Task> method1(){

        return new Specification<Task>(){
            @Override
            public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return null;
            }

        };
    }

    public static Specification<Task> method2(){

        return new Specification<Task>(){
            @Override
            public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return null;
            }

        };
    }

}
じゃ、使う時はこのように使います.
Page<Task> tasks = this.taskDao.findAll(TaskSpec.method1(), pageReq);
JpaSpecification Exectorの紹介はここまでにします.今度はhqlやsql文を書く方法で調べてみます.