简体   繁体   English

如何实现一般分页

[英]How to implement general pagination

I am not looking for a Hibernate/JPA/JDBC implementation, but for a general design pattern.我不是在寻找 Hibernate/JPA/JDBC 实现,而是在寻找通用设计模式。

Googling "pagination" gives me loads of information, lot of interesting articles that explain how to implement pagination on the UI and various implementations which more or less do the same.谷歌搜索“分页”为我提供了大量信息,很多有趣的文章解释了如何在 UI 上实现分页以及或多或少做相同的各种实现。

Since I am using Spring 3.0.5, and I stumbled this good reference article How to implement pagination in Spring MVC 3 .由于我使用的是 Spring 3.0.5,并且偶然发现了这篇很好的参考文章How to implement pagination in Spring MVC 3

Simple bean:简单豆:

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

A simple DAO interface:一个简单的 DAO 接口:

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

And the hibernate implementation和休眠实现

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

Now, I am thinking if I have to include similar parameters across all the interface then there is something really wrong here.现在,我在想,如果我必须在所有界面中都包含类似的参数,那么这里确实有问题。 Either I can wrap the request in a request bean object and pass this bean to the methods, something like this我可以将请求包装在请求 bean 对象中并将这个 bean 传递给方法,就像这样

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

And subsequently随后

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

But this too seems unnatural, for some reason.但这也似乎不自然,出于某种原因。 Then I am thinking of varargs in Java然后我想到了 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());
         }

This too seems bit flimsy, for some reason I keep thinking bridge pattern could be helpful but still is distant unfit.这似乎也有点脆弱,出于某种原因,我一直认为桥牌模式可能会有所帮助,但仍然不适合。

Any idea how you would deal with this?知道你会如何处理这个问题吗?

If I were you I would return not the result ( Set ) itself but something that encapsulates retrieval of the result.如果我是你,我不会返回结果 ( Set ) 本身,而是返回一些封装了结果的检索。 Some sort of ResultBuilder.某种 ResultBuilder。 Look:看:

public interface ResultBuilder<T> {

    ResultBuilder<T> withOffset(int offset);

    ResultBuilder<T> withLimit(int limit);

    ResultBuilder<T> orderedBy(String property);

    List<T> result();
}

and then change DAO method signature:然后更改 DAO 方法签名:

ResultBuilder<Person> findPersonsByName(String name);

This way you can factor out business-irrelevant arguments from find-family methods.通过这种方式,您可以从 find-family 方法中提取出与业务无关的参数。 If you don't want to make client specify this params then don't make him.如果您不想让客户指定此参数,则不要让他指定。

Just to be clear:只是要清楚:

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

I would consider applying the Strategy Pattern here.我会考虑在这里应用策略模式。

Basically, instead of supplying the start and limit as parameters or wrapping them in a varargs, make a real object, put them there, and move the responsibility of setting the paging on the criteria to this object.基本上,不是提供 start 和 limit 作为参数或将它们包装在 varargs 中,而是创建一个真实的对象,将它们放在那里,然后将在标准上设置分页的责任转移到这个对象。

Roughly speaking (I'm not compiling...):粗略地说(我不是在编译...):

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);         
    }
}

And then of course pass this into your finders and call it in the obvious places.然后当然把它传递给你的发现者并在明显的地方调用它。

One advantage of this is that you can make a NullPagingSpecification implementation which does nothing, so that you can use the same code when you don't actually want paging.这样做的一个优点是,您可以创建一个什么都不做的NullPagingSpecification实现,以便在您实际上不需要分页时可以使用相同的代码。

Another is that you can move things like the next() and previous() methods you're likely to need (to allow actual paging) into the PagingSpecification classes as well, and share yet more code.另一个是您可以将可能需要(以允许实际分页)的next()previous()方法之类的内容也移动到PagingSpecification类中,并共享更多代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM