1、实现思路
之前做的分页只是session级别的,在同一个session中才可以取分页信息。
基于AOP技术实现的分页功能是application级别,所有访问web项目的请求,只要满足条件,就可以从session中取出分页信息。
完整的思路如下:
定义两个HashMap。
- 第一个的key是uuid,value是查询的所有数据。
- 第二个的key是一个全限定名+方法原型+参数拼接的字符串,value是对应的uuid。
发出请求后:
- 判断PageInfo中的uuid是否为空。若不为null,则直接从第一个HashMap中取数据。
- 若uuid=null,则继续判断:该请求的methodNameAndParams是否在第二个HashMap中,若存在,则根据key取出uuid,然后从第一个HashMap中取数据。
- 若不存在,则访问数据库,此时该方法被代理。
- 在切片类中,先调用原方法得到所有数据,然后随机生成uuid,将这两部分放入第一个HashMap中。除此之外,还会通过
proceedingJoinPoint
对象得到methodNameAndParams,把它和uuid放到第二个HashMap中。
切片类会返回出uuid。在controller中通过得到的uuid取数据。
2、代码实现
业务层的代码不加赘述。值得一提的是查询数据的方法返回类型应为Object。
首先需要在配置文件中添加<aop:aspectj-autoproxy/>
切片类:
@Component
@Aspect
public class QueryAspectInfo
{
@Pointcut("execution(* com.studentinfo.service.impl.*.query*(..))")
// 使用一个返回值为void、方法体为空的方法来命名切入点
private void myPointCut(){}
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
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)
{
//System.out.println(object.getClass().getName());
// System.out.println(object.toString());
stf.append(object.getClass().getSimpleName()); stf.append("=");
stf.append(object.toString()).append("&");
}
//把查询记录放入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;
}
}
查询池:
public class QueryPools
{
/*
* 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)
{
queryMaps.put(uuid, rows);
}
public static void add(String methodName,String uuid)
{
queryMethodMaps.put(methodName, uuid);
}
public static String getQueryUUID(String methodNameAndParams)
{
return queryMethodMaps.get(methodNameAndParams);
}
/*
* 1:请求中是否有UUID,
* 2:有则去UUID去找拿数据
* 3: 从pageInfo 去当前页面页面数据;
* 比如: total=12, count=5 page=4
*/
public static PageInfo getPageInfo(PageInfo pageInfo)
{
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())
{
if(data.size()%pageInfo.getCount()==0)
page=data.size()/pageInfo.getCount();
else
page=data.size()/pageInfo.getCount()+1;
}
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++)
{
if(i>=data.size()) break;
rows.add(data.get(i));
}
pageInfo.setRows(rows);
return pageInfo;
}
}
控制处理层:
@RequestMapping("viewAllStudentInfo.do")
@ResponseBody
public PageInfo getAllStudentInfo(PageInfo pageInfo)
{
if(pageInfo.getUuid() == null)
{
String methodNameAndParams = "com.studentinfo.service.impl-queryAllStudentInfo?";
if(QueryPools.getQueryUUID(methodNameAndParams) == null)
{
Object object = teacherService.queryAllStudentInfo();
pageInfo.setUuid(object.toString());
}
else
pageInfo.setUuid(QueryPools.getQueryUUID(methodNameAndParams));
}
return QueryPools.getPageInfo(pageInfo);
}
3、总结
谈谈自己怎么在项目中使用AOP实现分页功能的。
我的整体思路是当一个查询请求发到后端后,先看有没有uuid,如果有的话就直接根据uuid取数据。没有uuid的话还需要看看这个请求对应的业务层查询方法之前有没有调用过,如果之前调用过,就可以通过这个方法原型得到uuid,然后取数据。如果这个方法还没有被调用过,那就只能去调用这个查询方法了。使用AOP技术对这个方法进行切片操作。在切片类中,除了调用原方法外,还需要将原方法返回的数据和一个随机的uuid放到一个HashMap中,除此之外还要通过切片方法的参数得到原方法的全限定名,原型,参数信息,把这些信息拼接后放到第二个HashMap中,value就放之前的uuid。这就是第一次查询。