Java 如何实现通用分页

Java 如何实现通用分页,java,hibernate,spring,design-patterns,pagination,Java,Hibernate,Spring,Design Patterns,Pagination,我不是在寻找Hibernate/JPA/JDBC实现,而是寻找一种通用的设计模式 谷歌搜索“分页”给了我大量的信息,许多有趣的文章解释了如何在UI上实现分页,以及各种或多或少都是这样做的实现 因为我使用的是Spring3.0.5,所以我偶然发现了这篇很好的参考文章 简单bean: public class Person{ private String personName; private int age; // ... } 一个简单的DAO接口: public

我不是在寻找Hibernate/JPA/JDBC实现,而是寻找一种通用的设计模式

谷歌搜索“分页”给了我大量的信息,许多有趣的文章解释了如何在UI上实现分页,以及各种或多或少都是这样做的实现

因为我使用的是Spring3.0.5,所以我偶然发现了这篇很好的参考文章

简单bean:

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

public interface PersonDAO{
   Set<Person> getAllPersons(PersonRequest request);
   Set<Person> findPersonsByName(PersonRequest request);
}
PersonDAO公共接口{
设置getAllPersons(PersonRequest请求);
设置FindPersonByName(PersonRequest请求);
}
但出于某种原因,这似乎也不自然。然后我想到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());
         }
PersonDAO公共接口{
设置getAllPersons(对象…参数);
设置findPersonsByName(字符串名称、对象…参数);
}
@存储库
公共类persondaimpl实现PersonDAO{
@自动连线(必需=真)
私人会话工厂会话工厂;
公共集getAllPersons(对象…参数){
Criteria crit=sessionFactory.getCurrentSession().createCriteria(Person.class);
crit.setFirstResult((整数)参数[0]);
标准setMaxResults((整数)参数[1]);
标准添加顺序(Order.asc(“人名”);
返回新的LinkedHashSet(crit.list());
}
公共集findPersonsByName(字符串名称、对象…参数){
Criteria crit=sessionFactory.getCurrentSession().createCriteria(Person.class);
标准添加(限制条件(“名称”,名称));
crit.setFirstResult((整数)参数[0]);
标准setMaxResults((整数)参数[1]);
crit.addOrder(Order.asc((String)参数[2]);
返回新的LinkedHashSet(crit.list());
}
这似乎也有点脆弱,出于某种原因,我一直认为桥梁模式可能会有所帮助,但仍然是远远不合适的


你知道怎么处理这个问题吗?

如果我是你,我不会返回结果(
Set
)本身,而是返回封装结果检索的内容。某种类型的ResultBuilder。看:

public interface ResultBuilder<T> {

    ResultBuilder<T> withOffset(int offset);

    ResultBuilder<T> withLimit(int limit);

    ResultBuilder<T> orderedBy(String property);

    List<T> result();
}
公共接口结果生成器{
带偏移量的结果生成器(整数偏移量);
结果生成器withLimit(int limit);
ResultBuilderOrderedBy(字符串属性);
列出结果();
}
然后更改DAO方法签名:

ResultBuilder<Person> findPersonsByName(String name);
ResultBuilder findPersonsByName(字符串名);
通过这种方式,您可以从find family方法中排除与业务无关的参数。 如果您不想让客户机指定此参数,则不要让他指定

我想说清楚:

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());
    }
}
公共最终类HibernateGenericResultBuilder实现ResultBuilder{
私人最终标准;
公共HibernateGenericResultBuilder(标准){
本标准=标准;
}
@用偏移量(int offset)覆盖公共结果生成器{
标准。setFirstResult(偏移量);
归还这个;
}
@用限制覆盖公共结果生成器(整数限制){
标准。setMaxResults(限制);
归还这个;
}
@重写公共结果生成器orderedBy(字符串属性){
标准.addOrder(Order.asc(property));
归还这个;
}
@覆盖公共列表结果(){
返回新的LinkedHashSet(criteria.list());
}
}

> p>我会考虑在这里应用策略模式。

基本上,与其提供start和limit作为参数,或者将它们包装在varargs中,不如创建一个真实的对象,将它们放在那里,并将设置条件分页的责任转移到这个对象上

粗略地说(我不是在编译…):

然后,当然要把它传递给你的发现者,并在明显的地方调用它

这样做的一个优点是,您可以创建一个不执行任何操作的
NullPagingSpecification
实现,以便在您实际上不需要分页时可以使用相同的代码


另一个是,您可以将您可能需要的
next()
previous()
方法(允许实际分页)也移动到
PagingSpecification
类中,并共享更多的代码。

但这会用
标准将他锁定(休眠)。此外,现在客户端依赖于
标准。
。这正是人们试图避免引入DAO的原因。@pavelrappo-是的,这可以通过另一个间接层次来解决。然后上一层是无用的:)当我们看到某个抽象的内部与抽象本身处于同一层次时,这是不对的。谢谢,这个解决方案on非常类似于向每个DAO方法发送请求对象以传递公共参数,但看起来要好得多(没有hibernate特定的依赖项).1:但是实现中的result方法仍然需要调用hibernate,正如我的策略建议一样。在编译期间,我们只有
ResultBuilder
通用接口。所以我们不关心它下面是什么。实现的实际来源是
PersonDAO
。在本例中,
PersonDAO
排序关于
ResultBuilder
s的工厂。有趣的是,您是否建议我们检索所有数据,然后将任务委托给java端而不是DB端的筛选/限制数据?@sachnik--不。我的解决方案没有强制执行此操作(但如果您愿意,可以这样做)。请参阅update.looks Professional..谢谢。最后一个问题,由于DAO接口没有参数列表(限制、orderby、偏移量),此信息是如何传递的?到目前为止,我看到我们已将orderby/limit等参数列表抽象为一个单独的接口(ResultBuilder).就我理解这一点的方式而言,我仍然需要了解如何沟通/传递请求类对象,以便为每个find family方法识别限制/订单限制。我是否遗漏了什么?
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());
    }
}
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);         
    }
}