SpringAOP的自定義註解實踐
springaop屬於spring的重要屬性,在java中有相當廣泛的用途,大家一般都接觸過aop實現事務的管理,在xml裏配好聲明式事務,然後直接在service上直接加上相應註解即可,
今天我們來實現下SpringAOP的自定義註解,用來在前置通知中做下權限校驗,有利於我們代碼的解藕,提高復用性,增加代碼B格;
話不多說,上代碼,首先定義一個自定義註解
這裏的參數我們並沒有在使用,先隨意定義個type,以後想使用時可以再賦值
再來看切面
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.jiubao.common.core.cache.redis.JedisUtil;
import com.jiubao.common.core.exception.MyException;
import com.jiubao.livenet.cache.JiuBaoCache;
import com.jiubao.livenet.constant.ServiceConstants;
import com.jiubao.livenet.enums.Limitsenum;
import com.jiubao.livenet.service.CustomerService;
/**
* 註解切面
* @author Administrator
*
*/
@Aspect
@Component
public class AuthorityAspect {
private static final Logger logger = LoggerFactory.getLogger(AuthorityAspect.class);
@Resource
private CustomerService customerService;
//Controller層切點
@Pointcut("execution (* com.jiubao.livenet.controller.*.*(..))")
public void controllerAspect() {}
/**
* 前置通知
* 只攔截帶有Authority註解的controller方法
* @param joinPoint 切點
* @return
*/
//@org.springframework.stereotype.Controller *) 表示攔截controller方法 @annotation(Authority) 表示只攔截帶此註解的方法
@Before("within(@org.springframework.stereotype.Controller *) && @annotation(Authority)")
public void doBefore(JoinPoint joinPoint) throws MyException {
logger.info("==========執行商戶權限controller前置通知===============");
Object[] args = joinPoint.getArgs();
HttpServletRequest request=null;
for (int i = 0; i < args.length; i++) {
Object object = args[i];
if(object instanceof HttpServletRequest) {
request=(HttpServletRequest) args[i];
break;
}
}
Map<String, Object> paramMap = new HashMap<String, Object>();
if(request ==null) {
return;
}
String url = request.getRequestURI().toString(); //請求的url
/**
* 權限控制
*/
JedisUtil jedis = JiuBaoCache.getJedisUtil();
String userId = jedis.getUserId(request);
paramMap.put("uid", userId); //登錄人UID
boolean isAccess=false;
List<Map<String, String>> userAuthlist= customerService.getUserAuth(paramMap); //查詢登錄人的商戶角色列表
for (int i = 0; i < userAuthlist.size(); i++) {
if(userAuthlist.get(i).get("role")!=null) {
String[] limitsArray = Limitsenum.limitsArray(Integer.valueOf(userAuthlist.get(i).get("role"))); //使用枚舉得到此角色對應的URL數組
for (int a = 0; a < limitsArray.length; a++) {
if(url.contains(limitsArray[a])) { //判斷是否有,如果有則跳出
isAccess=true;
break;
}
}
if(isAccess) {
break;
}
}
}
if (!isAccess){
throw new MyException(-1,ServiceConstants.NO_ACCESS); //無權限訪問,如果沒有權限直接扔出個自定義異常,在那裏會用response返回給前端提示
}
}
//全部攔截,這樣的before就是全局攔截,會攔截所有方法
@Before("controllerAspect()")
public void doBefore2(JoinPoint joinPoint) {
System.out.println("==========執行全部攔截controller前置通知===============");
}
}
再看看調用過程
直接加在controller裏想要限制的方法上即可
上面就是全部邏輯了,還有after和Around註解在此省略,這裏要開始測試了,我幾次都測不通,發現根本無效,而且
我配置文件裏也有 <aop:aspectj-autoproxy proxy-target-class="true" />,不知道怎麽回事,後來才發現
如果你的配置文件是這樣的:
你除了在spring-mybaits.xml裏要有這個外,還需要在spring-mvc.xml裏有,好吧,都要加上才有效,而且別忘了頭部的聲明哦
順便鄙視一下springmvc,配置文件就是麻煩
在此就完成了所有代碼了,親測是有效的
需提醒是的,當一個切面裏有多個同樣的註解時,會按鏈式分先後執行,比如上面第1個before,所有配了@Authority的方法會執行,接著執行第2個before,
而沒有配@Authority的方法會直接執行第2個before,第1個由於不滿足條件不會執行,這樣方便我們在一個切面裏寫多種靈活的邏輯.
springaop由於配置靈活,復用性強,無性能損耗,在封裝代碼上很好用,比攔截器更方法,推薦使用
再推薦幾個這方面比較好的文章:
1.https://www.cnblogs.com/jianjianyang/p/4910851.html
2.https://www.cnblogs.com/sjlian/p/7325602.html
3.https://www.cnblogs.com/mouseIT/p/5033746.html
SpringAOP的自定義註解實踐