【问题标题】:Hibernate pagination with AOP pointcuts使用 AOP 切入点进行休眠分页
【发布时间】:2014-10-20 08:52:27
【问题描述】:

是否有任何已知的方法可以使用面向方面的注释(或其他任何可以完成工作的方法)进行休眠分页,并使用切入点来识别任何给定方法中的Criteria 并将setFirstResultssetMaxResults API 应用于它方法?

例如,我想在我的 hibernate GenericDao 实现中应用如下分页:

@Paginate
public List<T> filter(Set<Criterion> filter, Map<String, String> alias){
    Criteria criteria = session.createCriteria(type.class);
    fillCriteria(criteria, filter, alias);
    return criteria.list();
}

@Paginate 注释将在 criteria.list() 调用上应用 setFirstResultssetMaxResults。这可能吗?

注意:@Paginate 是我想使用的示例。

【问题讨论】:

  • 请通过添加说明您的问题的可执行示例代码来更新您的问题,然后描述所需的结果。这里的人们喜欢讨论具体的编程问题。这样你更有可能得到一个好的答案。
  • 感谢您的建议;我修改了我的问题。

标签: hibernate pagination aop pointcut


【解决方案1】:

是的,您可以通过 AspectJ 执行此操作。

这是一个自洽的独立代码示例。您可以复制并粘贴类和方面并运行它。我没有使用原始的 Hibernate 类,而是使用一些虚拟替代品,因为我不是 Hibernate 用户,而且我也想将此作为通用答案:

虚拟的、类似休眠的接口和类:

package de.scrum_master.app;

public interface Criterion {}
package de.scrum_master.app;

public class MyCriterion implements Criterion {
    private String criterion;

    public MyCriterion(String criterion) {
        this.criterion = criterion;
    }

    @Override
    public String toString() {
        return "MyCriterion [criterion=" + criterion + "]";
    }
}
package de.scrum_master.app;

import java.util.List;

public interface Criteria {
    Criteria add(Criterion criterion);
    List list();
    Criteria setFirstResult(int firstResult);
    Criteria setMaxResults(int maxResults);
}
package de.scrum_master.app;

import java.util.LinkedList;
import java.util.List;

public class MyCriteria implements Criteria {
    private List<Criterion> criteria = new LinkedList<>();

    @Override
    public Criteria add(Criterion criterion) {
        criteria.add(criterion);
        return this;
    }

    @Override
    public List list() {
        return new LinkedList();
    }

    @Override
    public Criteria setFirstResult(int firstResult) {
        add(new MyCriterion("first result " + firstResult));
        return this;
    }

    @Override
    public Criteria setMaxResults(int maxResults) {
        add(new MyCriterion("max results " + maxResults));
        return this;
    }

    @Override
    public String toString() {
        return "MyCriteria [criteria=" + criteria + "]";
    }
}

如您所见,方法setFirstResult(..)setMaxResults(..) 通过add(..) 将特殊条件添加到内部列表中。我这样做只是为了稍后说明方面的效果。

分页注释:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Paginate {}

驱动程序应用:

package de.scrum_master.app;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Application {
    @Paginate
    public List filter(Set<Criterion> filter, Map<String, String> alias) {
        Criteria criteria = new MyCriteria();
        for (Criterion criterion : filter)
            criteria.add(criterion);
        return criteria.list();
    }

    public static void main(String[] args) {
        Set<Criterion> filterCriteria = new HashSet<>();
        filterCriteria.add(new MyCriterion("where"));
        filterCriteria.add(new MyCriterion("group by"));
        new Application().filter(filterCriteria, null);
    }
}

该应用程序包含一个由@Paginate 注释的方法,与您的示例代码执行类似的操作。它虽然不调用任何分页方法。这将通过以下方面来完成。

分页方面:

package de.scrum_master.aspect;

import java.util.List;
import de.scrum_master.app.Paginate;
import de.scrum_master.app.Criteria;

public aspect PaginationAspect {
    Object around(Criteria criteria) : 
        call(public List Criteria+.list())  &&
        cflow(execution(@Paginate * *(..))) &&
        target(criteria)
    {
        System.out.println(thisJoinPoint);
        System.out.println("Original criteria: " + criteria);
        criteria.setFirstResult(5);
        criteria.setMaxResults(10);
        System.out.println("Modified criteria: " + criteria);
        return proceed(criteria);
    }
}

切入点拦截对Criteria+.list() 的调用(+ 包括子类),但仅在由@Paginate 注释的任何执行方法的控制流 (cflow()) 中发出时。调用目标绑定到参数Criteria criteria,以便在绑定到该切入点的通知方法中使用它。我们需要一个对调用目标的引用,因为我们想在它上面调用分页方法。这就是建议的作用,控制台输出清楚地说明了这一点。

控制台输出:

call(List de.scrum_master.app.Criteria.list())
Original criteria: MyCriteria [criteria=[MyCriterion [criterion=group by], MyCriterion [criterion=where]]]
Modified criteria: MyCriteria [criteria=[MyCriterion [criterion=group by], MyCriterion [criterion=where], MyCriterion [criterion=first result 5], MyCriterion [criterion=max results 10]]]

享受吧!

【讨论】:

  • 这绝对有帮助!谢谢。
  • 请注意,我已将注释的保留策略更新为运行时,旧值是一个错字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 2011-03-14
  • 1970-01-01
  • 2010-11-26
  • 1970-01-01
  • 2013-03-08
相关资源
最近更新 更多