如何实现通用分页
我不是在寻找 Hibernate/JPA/JDBC 实现,而是在寻找通用设计模式。
谷歌搜索“分页”给了我大量的信息,很多有趣的文章解释了如何在 UI 上实现分页以及或多或少做同样事情的各种实现。
由于我使用的是 Spring 3.0.5,并且我偶然发现了这篇很好的参考文章 如何在 Spring MVC 3 中实现分页。
简单的 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);
}
以及 hibernate 实现
@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());
}
现在,我在想如果我必须在所有接口中包含类似的参数,那么这里确实有问题。要么我可以将请求包装在请求 bean 对象中,然后将此 bean 传递给方法,如下所示
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());
}
这似乎也有点脆弱,出于某种原因,我一直认为桥接模式可能会有所帮助,但仍然远远不合适。
知道你会如何处理这个问题吗?
I am not looking for a Hibernate/JPA/JDBC implementation, but for a general design pattern.
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.
Since I am using Spring 3.0.5, and I stumbled this good reference article How to implement pagination in Spring MVC 3.
Simple bean:
public class Person{
private String personName;
private int age;
// ...
}
A simple DAO interface:
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
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
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果我是你,我不会返回结果 (
Set
) 本身,而是返回封装结果检索的内容。某种 ResultBuilder。看:然后更改 DAO 方法签名:
这样您就可以从 find-family 方法中提取出与业务无关的参数。
如果您不想让客户端指定此参数,那么就不要让他指定。
需要明确的是:
If I were you I would return not the result (
Set
) itself but something that encapsulates retrieval of the result. Some sort of ResultBuilder. Look:and then change DAO method signature:
This way you can factor out business-irrelevant arguments from find-family methods.
If you don't want to make client specify this params then don't make him.
Just to be clear:
我会考虑在这里应用策略模式。
基本上,不要将开始和限制作为参数提供或将它们包装在可变参数中,而是创建一个真实的对象,将它们放在那里,并将根据条件设置分页的责任转移到该对象。
粗略地说(我没有编译......):
然后当然将其传递给您的查找器并在明显的地方调用它。
这样做的优点之一是您可以创建一个不执行任何操作的
NullPagingSpecification
实现,这样当您实际上不需要分页时就可以使用相同的代码。另一个是,您可以将可能需要的
next()
和previous()
方法(以允许实际分页)移至PagingSpecification< /code> 类,并共享更多代码。
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.
Roughly speaking (I'm not compiling...):
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.Another is that you can move things like the
next()
andprevious()
methods you're likely to need (to allow actual paging) into thePagingSpecification
classes as well, and share yet more code.