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í)行流程
- 使用aop獲取controller方法中分頁的相關請求數(shù)據(jù)PageBean
- 將PageBean保存在線程變量中
- 使用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字段名需和實體類保持一致
異步調(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();
}