Java 如何实现通用分页
我不是在寻找Hibernate/JPA/JDBC实现,而是寻找一种通用的设计模式 谷歌搜索“分页”给了我大量的信息,许多有趣的文章解释了如何在UI上实现分页,以及各种或多或少都是这样做的实现 因为我使用的是Spring3.0.5,所以我偶然发现了这篇很好的参考文章 简单bean: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
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);
}
}