動態代理使用分頁外掛PageHelper
阿新 • • 發佈:2018-11-19
本來只是研究一下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;
}
血案到此結束!