本來隻是研究一下Total的值,後面越陷越深!
資料查詢到html發現沒有總數!!!一開始想着Total應該是查的資料總數,但是測試幾遍發現,傳回的是目前分頁的總條數,這顯然不是我想要的,然後發現了PageInfo的繼承類PageSerializable下的初始化方法:

很顯然,如果我們傳執行個體不是屬于Page,那麼就會把list.size()複制給total;
Page page = PageHelper.startPage(page,pageSize);
//資料查詢語句。。。 傳回的List
//資料包裝類等等....
PageInfo pageInfo = new PageInfo<>(你自己的list);
//需要指派下
pageInfo.setTotal(sqlpage.getTotal());
這個分頁插件前後執行的都是一樣的代碼,很顯然這個分頁方法應該提取出來。然後我寫了一個A方法,查詢出List,調用A方法。呃呃,居然沒有分頁,而是查詢了所有資料。一開始對分頁了解不夠,查詢語句必須要再中間執行。
既然前後代碼一樣的就可用動态代理來寫。
主要代碼
JDK 代理方式:
public class PageProxy implements InvocationHandler {
private Object object;
public PageProxy(Object object) {
this.object = object;
}
public Object getinfoimpl() {
//初始值
ClassLoader classLoader = this.object.getClass().getClassLoader();
Class<?>[] cs = this.object.getClass().getInterfaces();
return Proxy.newProxyInstance(this.object.getClass().getClassLoader(), cs, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用來擷取總數,如果說資料不進行傳輸類轉換 可以直接傳回 page
Page sqlpage = PageHelper.startPage((int)args[0],(int)args[1]);
//執行方法傳回的list
List objlist= (List) method.invoke(object, args);
PageInfo pageInfo = new PageInfo<>(objlist);
//設定總頁
pageInfo.setTotal(sqlpage.getTotal());
return pageInfo;
}
}
AOP 注解方式:
@Component
@Aspect
public class PagingAop {
@Pointcut("execution(* com.lemon.sell.service.impl.*.select*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint pj) {
//擷取參數 page sieze 分頁
Object[] args = pj.getArgs();
Page sqlpage = PageHelper.startPage((int) args[0], (int) args[1]);
Object ret = null;
try {
//這裡應該傳回 傳輸類的list集合
ret = pj.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//強轉為List 實際傳回值為PageInfo的執行個體對象
PageInfo pageInfo = new PageInfo<>((List)ret);
//設定總頁
pageInfo.setTotal(sqlpage.getTotal());
return pageInfo;
}
}
其他動态代理方式,自行研究。
最終我選擇AOP注解方式的動态代理(代碼少)。發現被代理的方法傳回值必須是Object(需要修改傳回值,傳回List給代理類處理,傳回Pageinfo給Controller層)。
那麼我Controller層傳回是Object類型,需要強轉,每次在Controller層強轉一個Object類型很難看啊。
我想着直接在Service層進行強轉,例如:
//這是被代理的方法
public Object B(int page,int size){
//查詢資料庫傳回 list資料
List list = .....;
return list;
}
//這是Controller層調用的方法
public PageInfo C(int page,int size){
//調用被代理的方法
PageInfo pageInfo = (PageInfo)B(page,size);
return pageInfo;
}
我興緻勃勃的去測試,丫的!AOP根本沒有攔截。然後以為自己的execution路徑配置有問題(建議攔截某個接口方法)。檢查了幾遍,發現類的内部調用自個方法,根本不會被攔截。詳細檢視:AOP 不攔截内部方法原因 (另外幾種方法,自行了解)
直接通過上下文擷取bean來調用方法,而不直接從方法内部調用。
//啟動類
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(App.class, args);
SpringContextUtil.setApplicationContext(applicationContext);
}
}
public class SpringContextUtil {
private static ApplicationContext applicationContext;
//擷取上下文
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//設定上下文
public static void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
//通過名字擷取上下文中的bean
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
//通過類型擷取上下文中的bean
public static Object getBean(Class<?> requiredType) {
return applicationContext.getBean(requiredType);
}
}
修改後這樣就可以正常攔截了
//因為内部調用 其他方法 是不會被Aop攔截的 是以内部要通過擷取bean來調用
private XXXServiceImpl getService() {
return (XXXServiceImpl) SpringContextUtil.getBean(this.getClass());
}
//這是被代理的方法
public Object B(int page,int size){
//查詢資料庫傳回 list資料
List list = .....;
return list;
}
//這是Controller層調用的方法
public PageInfo C(int page,int size){
//調用被代理的方法
PageInfo pageInfo = (PageInfo)getService.B(page,size);
return pageInfo;
}
血案到此結束!