복붙노트

[SPRING] 일반적인 페이지 매김을 구현하는 방법

SPRING

일반적인 페이지 매김을 구현하는 방법

나는 Hibernate / JPA / JDBC 구현을 찾고 있지는 않지만 일반적인 디자인 패턴을 찾고있다.

"페이지 매김"을 검색하면 많은 정보와 UI에서 페이지 매김을 구현하는 방법 및 다소 차이가있는 다양한 구현을 설명하는 많은 흥미로운 기사를 얻을 수 있습니다.

Spring 3.0.5를 사용하고 있기 때문에 Spring MVC 3에서 페이지 매김을 구현하는 좋은 참고 자료를 발견했다.

간단한 콩 :

public class Person{
     private String personName;
     private int age;
     // ...
}

간단한 DAO 인터페이스 :

public interface PersonDAO{
   Set<Person> getAllPersons(int start, int limit,String orderBy);
   Set<Person> findPersonsByName(String name, int start, int limit,String orderBy);
}

그리고 최대 절전 모드 구현

   @Repository
   public class PersonDAOImpl implements PersonDAO {

        @Autowired(required = true)
    private SessionFactory sessionFactory;

        public Set<Person> getAllPersons(int start, int limit, String orderBy){
                Criteria crit = sessionFactory.getCurrentSession().createCriteria(Person.class);
                crit.setFirstResult(start);
                crit.setMaxResults(limit);
                crit.addOrder(Order.asc("personName"));
                return new LinkedHashSet<Person>(crit.list());
        }


        public Set<Person> findPersonsByName(String name, int start, int limit, String orderBy){
                Criteria crit = sessionFactory.getCurrentSession().createCriteria(Person.class);
                crit.add(Restrictions.eq("name", name));
                crit.setFirstResult(start);
                crit.setMaxResults(limit);
                crit.addOrder(Order.asc(orderBy));
                return new LinkedHashSet<Person>(crit.list());
         }

이제 모든 인터페이스에 비슷한 매개 변수를 포함해야한다면 정말 잘못된 것이 있습니다. 요청 빈 객체에 요청을 래핑하고이 빈을 메소드에 전달할 수 있습니다.

public class PersonRequest{
   private int start;
   private int limit;
   private String orderBy;
   private String name;
   // ...
}

그리고이어서

public interface PersonDAO{
   Set<Person> getAllPersons(PersonRequest request);
   Set<Person> findPersonsByName(PersonRequest request);
}

그러나 이것 역시 어떤 이유로 인해 부 자연스럽게 보입니다. 그런 다음 Java에서 varargs를 생각하고 있습니다.

public interface PersonDAO{
   Set<Person> getAllPersons(Object... params);
   Set<Person> findPersonsByName(String name,Object... params);
}


   @Repository
   public class PersonDAOImpl implements PersonDAO {

        @Autowired(required = true)
    private SessionFactory sessionFactory;



        public Set<Person> getAllPersons(Object... params){
                Criteria crit = sessionFactory.getCurrentSession().createCriteria(Person.class);
                crit.setFirstResult((Integer)params[0]);
                crit.setMaxResults((Integer)params[1]);
                crit.addOrder(Order.asc("personName"));
                return new LinkedHashSet<Person>(crit.list());
        }


        public Set<Person> findPersonsByName(String name, Object... params){
                Criteria crit = sessionFactory.getCurrentSession().createCriteria(Person.class);
                crit.add(Restrictions.eq("name", name));
                crit.setFirstResult((Integer)params[0]);
                crit.setMaxResults((Integer)params[1]);
                crit.addOrder(Order.asc((String)params[2]));
                return new LinkedHashSet<Person>(crit.list());
         }

이것 역시 너무 가벼운 것처럼 보이기 때문에, 나는 다리 패턴이 도움이 될 수 있다고 생각하고 있지만 여전히 부적절하다.

이 문제를 어떻게 처리 할 생각인가요?

해결법

  1. ==============================

    1.내가 너라면 나는 결과 (Set) 자체가 아니라 결과 검색을 캡슐화하는 것을 반환 할 것이다. ResultBuilder의 일종입니다. 보기:

    내가 너라면 나는 결과 (Set) 자체가 아니라 결과 검색을 캡슐화하는 것을 반환 할 것이다. ResultBuilder의 일종입니다. 보기:

    public interface ResultBuilder<T> {
    
        ResultBuilder<T> withOffset(int offset);
    
        ResultBuilder<T> withLimit(int limit);
    
        ResultBuilder<T> orderedBy(String property);
    
        List<T> result();
    }
    

    다음 DAO 메서드 서명을 변경하십시오.

    ResultBuilder<Person> findPersonsByName(String name);
    

    이렇게하면 가족 찾기 방법에서 비즈니스와 관련없는 주장을 분석 할 수 있습니다. 클라이언트가이 매개 변수를 지정하게하지 않으려면 매개 변수를 지정하지 마십시오.

    그냥 분명히 :

    public final class HibernateGenericResultBuilder<T> implements ResultBuilder<T> {
    
        private final Criteria criteria;
    
        public HibernateGenericResultBuilder(Criteria criteria) {
            this.criteria = criteria;
        }
    
        @Override public ResultBuilder<T> withOffset(int offset) {
            criteria.setFirstResult(offset);
            return this;
        }
    
        @Override public ResultBuilder<T> withLimit(int limit) {
            criteria.setMaxResults(limit);
            return this;
        }
    
        @Override public ResultBuilder<T> orderedBy(String property) {
            criteria.addOrder(Order.asc(property));
            return this;
        }
    
        @Override public List<T> result() {
            return new LinkedHashSet<T>(criteria.list());
        }
    }
    
  2. ==============================

    2.여기에 전략 패턴을 적용하는 것이 좋습니다.

    여기에 전략 패턴을 적용하는 것이 좋습니다.

    기본적으로 매개 변수로 시작 및 제한을 제공하거나 varargs에 래핑하는 대신 실제 개체를 만들어서 거기에 넣고 기준에 따라 페이징 설정의 책임을이 개체로 옮깁니다.

    대략 말하기 (나는 컴파일하지 않는다 ...) :

    public interface PagingSpecification {
        void apply(Criteria criteria);
    }
    
    public class ConcretePagingSpecification implements PagingSpecification {
        private int start;
        private int limit;
    
        public ConcretePagingSpecification(int start, int limit) {
           this.start = start;
           this.limit = limit;
        }
    
        public void apply(Criteria crit) {
           crit.setFirstResult(start);
           crit.setMaxResults(limit);         
        }
    }
    

    그리고 이것을 물론 당신의 파인더에 넘겨주고 명백한 장소에서 호출하십시오.

    이 기능의 한 가지 장점은 아무것도 수행하지 않는 NullPagingSpecification 구현을 만들 수 있으므로 페이징을 실제로 원하지 않을 때 동일한 코드를 사용할 수 있다는 것입니다.

    또 하나는 PagingSpecification 클래스에 (실제 페이징을 허용하기 위해) 필요할 가능성이있는 next () 및 previous () 메소드를 이동하고 더 많은 코드를 공유 할 수 있다는 것입니다.

  3. from https://stackoverflow.com/questions/5412059/how-to-implement-general-pagination by cc-by-sa and MIT license