天天看點

動态代理使用分頁插件PageHelper

本來隻是研究一下Total的值,後面越陷越深!

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

動态代理使用分頁插件PageHelper

很顯然,如果我們傳執行個體不是屬于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;
}
           

血案到此結束!

繼續閱讀