基于AOP实现分页


1、实现思路

​ 之前做的分页只是session级别的,在同一个session中才可以取分页信息。

​ 基于AOP技术实现的分页功能是application级别,所有访问web项目的请求,只要满足条件,就可以从session中取出分页信息。

​ 完整的思路如下:

  1. 定义两个HashMap。

    • 第一个的key是uuid,value是查询的所有数据。
    • 第二个的key是一个全限定名+方法原型+参数拼接的字符串,value是对应的uuid。
  2. 发出请求后:

    • 判断PageInfo中的uuid是否为空。若不为null,则直接从第一个HashMap中取数据。
    • 若uuid=null,则继续判断:该请求的methodNameAndParams是否在第二个HashMap中,若存在,则根据key取出uuid,然后从第一个HashMap中取数据。
    • 若不存在,则访问数据库,此时该方法被代理。
    • 在切片类中,先调用原方法得到所有数据,然后随机生成uuid,将这两部分放入第一个HashMap中。除此之外,还会通过proceedingJoinPoint对象得到methodNameAndParams,把它和uuid放到第二个HashMap中。
  3. 切片类会返回出uuid。在controller中通过得到的uuid取数据。

2、代码实现

​ 业务层的代码不加赘述。值得一提的是查询数据的方法返回类型应为Object。

​ 首先需要在配置文件中添加<aop:aspectj-autoproxy/>

​ 切片类:

@Component
@Aspect
public class QueryAspectInfo 
&#123;
    @Pointcut("execution(* com.studentinfo.service.impl.*.query*(..))")
    // 使用一个返回值为void、方法体为空的方法来命名切入点
    private void myPointCut()&#123;&#125;


    @Around("myPointCut()")
  public Object myAround(ProceedingJoinPoint proceedingJoinPoint) 
            throws Throwable &#123;
        // 开始
    System.out.print("分页查询...");
        // 执行当前目标方法
        Object resultData = proceedingJoinPoint.proceed();
        // 结束

      //拼接字符串
          String method=proceedingJoinPoint.getTarget().getClass().getName()+"-"+
          proceedingJoinPoint.getSignature().getName(); 
          StringBuffer stf=new StringBuffer(1000); 
          stf.append(method+"?"); 
          Object[] args=proceedingJoinPoint.getArgs(); //joinPoint. 
          for (Object object : args) 
          &#123;
          //System.out.println(object.getClass().getName()); 
          //  System.out.println(object.toString());
              stf.append(object.getClass().getSimpleName()); stf.append("=");
              stf.append(object.toString()).append("&"); 
          &#125; 
    //把查询记录放入mappers         
     String uuid=UUID.randomUUID().toString();   
     QueryPools.queryMaps.put(uuid,(ArrayList<Object>)resultData);
     QueryPools.queryMethodMaps.put(stf.toString(), uuid);
     //System.out.println(stf.toString());
            return uuid;
    &#125;
&#125;

​ 查询池:

public class QueryPools 
&#123;
    /*
     * key:uuid,每次查询都会给一个唯一值
     * value: 查询的全部结果
     */
    public static HashMap<String,ArrayList<Object>> queryMaps=
            new HashMap<String,ArrayList<Object>>();

    /*
     * key:由全限定名,方法原型,参数  拼接成的字符串
     * value: uuid
     */
    public static HashMap<String,String> queryMethodMaps=
            new HashMap<String,String>();

    public static void add(String uuid,ArrayList<Object> rows)
    &#123;
        queryMaps.put(uuid, rows);
    &#125;

    public static void add(String methodName,String uuid)
    &#123;
        queryMethodMaps.put(methodName, uuid);
    &#125;
    public static String getQueryUUID(String methodNameAndParams)
    &#123;
        return queryMethodMaps.get(methodNameAndParams);
    &#125;
    /*
     *  1:请求中是否有UUID,
     *  2:有则去UUID去找拿数据
     *  3: 从pageInfo 去当前页面页面数据;
     *  比如: total=12, count=5  page=4  
     */


    public static PageInfo getPageInfo(PageInfo pageInfo)
    &#123;
        if(pageInfo.getUuid()==null) return null;
        if(pageInfo.getPage()==null) pageInfo.setPage(1);
        if(pageInfo.getCount()==null) pageInfo.setCount(4);
        ArrayList<Object> data=queryMaps.get(pageInfo.getUuid());
        //if(data==null) return null;
        int start=0;
        int page=pageInfo.getPage();
        if(page<=1) page=1;
        else if(page>=data.size()/pageInfo.getCount())
        &#123;
            if(data.size()%pageInfo.getCount()==0) 
                page=data.size()/pageInfo.getCount();
            else  
                page=data.size()/pageInfo.getCount()+1;

        &#125;
        pageInfo.setPage(page);
        pageInfo.setTotal(data.size());
        start=(pageInfo.getPage()-1)*pageInfo.getCount();

         System.out.println("start= "+start);
         ArrayList<Object> rows=new ArrayList<Object>();

         for(int i=start;i<start+pageInfo.getCount();i++)
         &#123;
             if(i>=data.size()) break;
             rows.add(data.get(i));
         &#125;
         pageInfo.setRows(rows);
         return pageInfo;
    &#125;
&#125;

控制处理层:

@RequestMapping("viewAllStudentInfo.do")
@ResponseBody
    public PageInfo getAllStudentInfo(PageInfo pageInfo)
    &#123;
        if(pageInfo.getUuid() == null)
        &#123;
            String methodNameAndParams = "com.studentinfo.service.impl-queryAllStudentInfo?";
            if(QueryPools.getQueryUUID(methodNameAndParams) == null)
            &#123;
                Object object = teacherService.queryAllStudentInfo();
                pageInfo.setUuid(object.toString());
            &#125;
            else
                pageInfo.setUuid(QueryPools.getQueryUUID(methodNameAndParams));
        &#125;
        return QueryPools.getPageInfo(pageInfo);
    &#125;

3、总结

​ 谈谈自己怎么在项目中使用AOP实现分页功能的。

​ 我的整体思路是当一个查询请求发到后端后,先看有没有uuid,如果有的话就直接根据uuid取数据。没有uuid的话还需要看看这个请求对应的业务层查询方法之前有没有调用过,如果之前调用过,就可以通过这个方法原型得到uuid,然后取数据。如果这个方法还没有被调用过,那就只能去调用这个查询方法了。使用AOP技术对这个方法进行切片操作。在切片类中,除了调用原方法外,还需要将原方法返回的数据和一个随机的uuid放到一个HashMap中,除此之外还要通过切片方法的参数得到原方法的全限定名,原型,参数信息,把这些信息拼接后放到第二个HashMap中,value就放之前的uuid。这就是第一次查询。


文章作者: kilig
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kilig !
 上一篇
RPC技术 RPC技术
1、RPC技术介绍​ RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程
下一篇 
AOP技术(3) AOP技术(3)
1、通过xml配置文件实现AOP​ 流程: 将所有的切片操作放到一个类中。 在xml配置文件中,通过扫描器、手动配置两种方式,得到被代理类对象和切片类对象。 通过<aop:config>标签,配置切面,切入点以及增强哪些
2020-08-02
  目录