technology-integration(六)---AOP實現(xiàn)PageHelper零入侵分頁

AOP實現(xiàn)分頁有什么好處

利用AOP實現(xiàn)分頁功能可以達到零代碼入侵的目的嘉栓,只需要在請求方法上傳入對應的分頁請求數(shù)據(jù)即可侵佃,SQL的編寫以及后臺業(yè)務與分頁代碼無關奠支。

PageHelper

PageHelper是Mybatis的一款分頁插件,利用ThreadLocal實現(xiàn)分頁功能胚宦。PageHelper先是根據(jù)你即將發(fā)出的SQL命令獲取count值(也就是數(shù)據(jù)總量),然后獲取當前線程上的線程變量進行分頁操作井联。如果你還沒有使用過PageHelper您旁,推薦先去敲個代碼體驗一下

執(zhí)行流程

  1. 使用aop獲取controller方法中分頁的相關請求數(shù)據(jù)PageBean
  2. 將PageBean保存在線程變量中
  3. 使用aop攔截dao方法,調(diào)用PageHelper的分頁方法(使用兩次aop是因為PageHelper只會對即將執(zhí)行的SQL語句進行分頁鹤盒,假設你要分頁的數(shù)據(jù)是第二順序執(zhí)行,這時候則會導致第一順序執(zhí)行的SQL語句被分頁驼鞭,而第二順序執(zhí)行的SQL語句相反)

業(yè)務內(nèi)容

獲取所有商品信息尺碰,并分頁

編寫ProductMapper.xml

//編寫獲取全部商品的SQL語句
<select id="selectAllProduct" resultMap="BaseResultMap">
    select product_id, product_name, product_price, product_stock, product_type, product_status,product_version
    from t_product
  </select>

編寫ProductMapper.java

public interface ProductMapper {
    List<Product> selectAllProduct();
}

編寫ProductDao

//PageInfo是PageHelper封裝的一個分頁信息類译隘,里面存放著詳細的分頁字段
public interface ProductDao {
    PageInfo<Product> selectAllProductWithPage();
}

@Repository
public class ProductDaoImpl extends BaseDao implements ProductDao {
    @Autowired
    private ProductMapper productMapper;
  
    @Override
    public PageInfo<Product> selectAllProductWithPage() {
        return new PageInfo<>(productMapper.selectAllProduct());
    }

}

編寫ProductService

public interface ProductService {
    PageInfo getAllProductWithPage();
}

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductDao productDao;

    @Override
    public PageInfo getAllProductWithPage() {
        return productDao.selectAllProductWithPage();
    }

}

PageBean(分頁實體類)

public class PageBean<T> {
    // 當前頁
    private Integer currentPage = 1;
    // 每頁顯示的總條數(shù)
    private Integer pageSize = 10;
    // 總條數(shù)
    private Integer totalNum;
    // 是否有下一頁
    private Integer isMore;
    // 總頁數(shù)
    private Integer totalPage;
    // 開始索引
    private Integer startIndex;
    // 分頁結果
    private List<T> items;

    public PageBean() {
        super();
    }

    public PageBean(Integer currentPage, Integer pageSize, Integer totalNum) {
        super();
        //
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.totalNum = totalNum;
        this.totalPage = (this.totalNum+this.pageSize-1)/this.pageSize;
        this.startIndex = (this.currentPage-1)*this.pageSize;
        this.isMore = this.currentPage >= this.totalPage?0:1;
    }

    public PageBean(Integer currentPage, Integer pageSize) {
        this.currentPage = currentPage;
        this.pageSize = pageSize;
    }

    public Integer getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(Integer currentPage) {
        this.currentPage = currentPage;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getTotalNum() {
        return totalNum;
    }

    public void setTotalNum(Integer totalNum) {
        this.totalNum = totalNum;
    }

    public Integer getIsMore() {
        return isMore;
    }

    public void setIsMore(Integer isMore) {
        this.isMore = isMore;
    }

    public Integer getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(Integer totalPage) {
        this.totalPage = totalPage;
    }

    public Integer getStartIndex() {
        return startIndex;
    }

    public void setStartIndex(Integer startIndex) {
        this.startIndex = startIndex;
    }

    public List<T> getItems() {
        return items;
    }

    public void setItems(List<T> items) {
        this.items = items;
    }
}

編寫Controller

Controller方法中使用了PageBean接收分頁參數(shù)或者使用restful風格接收參數(shù),這里并沒有限制你必須這么接收厅目,不過你怎么接收分頁參數(shù)的就需要在aop中怎么攔截并獲取

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    @PostMapping("/all")
    public Result getAllProductWithPage(@RequestBody PageBean pageBean) {
        PageInfo pageInfo = productService.getAllProductWithPage();
        return Result.success(pageInfo);
    }

    @GetMapping("/all/{currentPage}/{pageSize}")
    public Result getAllProduct2WithPage(@PathVariable int currentPage,@PathVariable int pageSize) {
        PageInfo pageInfo = productService.getAllProductWithPage();
        return Result.success(pageInfo);
    }
}

編寫PageHelperAOP類


@Component
@Aspect
public class PageHelperAop {

    private static final Logger log = LoggerFactory.getLogger(PageHelperAop.class);

    private static final ThreadLocal<PageBean> pageBeanContext = new ThreadLocal<>();

    //以WithPage結尾的Controller方法都是需要分頁的方法
    @Before(value = "execution(* com.viu.technology.controller..*.*WithPage(..))")
    public void controllerAop(JoinPoint joinPoint) throws Exception {
        log.info("正在執(zhí)行PageHelperAop");
        PageBean pageBean =null;

        Object[] args = joinPoint.getArgs();

        //獲取類名
        String clazzName = joinPoint.getTarget().getClass().getName();
        //獲取方法名稱
        String methodName = joinPoint.getSignature().getName();
        //該方法通過反射獲取參數(shù)列表
        Map<String,Object > nameAndArgs = this.getFieldsName(this.getClass(), clazzName, methodName,args);

        pageBean=(PageBean) nameAndArgs.get("pageBean");

        if (null == pageBean) {
            pageBean = new PageBean();
            pageBean.setCurrentPage((Integer) nameAndArgs.get("currentPage"));
            pageBean.setPageSize((Integer) nameAndArgs.get("pageSize"));
        }

        //將分頁參數(shù)放置線程變量中
        pageBeanContext.set(pageBean);

    }

    @Before(value = "execution(* com.viu.technology.dao..*.*WithPage(..))")
    public void daoAop(JoinPoint joinPoint) throws Exception {
        PageBean pageBean = pageBeanContext.get();
        PageHelper.startPage(pageBean.getCurrentPage(), pageBean.getPageSize());
    }

    private Map<String,Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args) throws Exception {
        Map<String,Object > map=new HashMap<String,Object>();

        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            // exception
        }
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < cm.getParameterTypes().length; i++){
            map.put( attr.variableName(i + pos),args[i]);
        }
        return map;
    }

}

PostMan測試

請?zhí)崆皩胂嚓P數(shù)據(jù)

使用JSON請求會自動將json轉換為PageBean實體類,請注意json字段名需和實體類保持一致


image.png

image.png

異步調(diào)用dao導致分頁失敗方法

由于異步調(diào)用導致子線程無法訪問主線程的線程變量嗤锉,導致PageHelper分頁失敗
所以你就老老實實的傳參,然后調(diào)用PageHelper.startPage方法吧瘟忱,哈哈哈苫幢,88

public PageInfo asyncGetAllProductWithPage(int currentPage,int pageSize) {
        PageHelper.startPage(currentPage, pageSize);
        return productDao.selectAllProductWithPage();
    }


更多文章請關注該 technology-integration全面解析專題

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末韩肝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哀峻,更是在濱河造成了極大的恐慌,老刑警劉巖剩蟀,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件育特,死亡現(xiàn)場離奇詭異,居然都是意外死亡缰冤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門怀薛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迷郑,“玉大人迂苛,你說我怎么就攤上這事鼓择【脱” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵摆出,是天一觀的道長。 經(jīng)常有香客問我偎漫,道長有缆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任杯矩,我火速辦了婚禮袖外,結果婚禮上,老公的妹妹穿的比我還像新娘曼验。我一直安慰自己,他們只是感情好鬓照,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布颖杏。 她就那樣靜靜地躺著,像睡著了一般留储。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上获讳,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天丐膝,我揣著相機與錄音钾菊,去河邊找鬼偎肃。 笑死,一個胖子當著我的面吹牛累颂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播紊馏,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼朱监,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赫编?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤赡若,失蹤者是張志新(化名)和其女友劉穎团甲,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躺苦,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年嘀趟,在試婚紗的時候發(fā)現(xiàn)自己被綠了她按。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡酌泰,死狀恐怖匕累,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欢嘿,我是刑警寧澤也糊,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布羡宙,位于F島的核電站,受9級特大地震影響辛辨,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一慷妙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虑啤,春花似錦、人聲如沸狞山。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屏鳍。三九已至,卻和暖如春钓瞭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背山涡。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工鸭丛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人系吩。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像月弛,于是被迫代替她去往敵國和親肴盏。 傳聞我的和親對象是個殘疾皇子菜皂,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容