簡介:
大家應該對Spring並不陌生,而且對Spring AOP也一樣不陌生。本章講解使用註解AOP方式去校驗參數。首先,介紹一下Spring AOP的原理,Spring AOP採用動態代理實現, 在Spring 容器中的bean被代理對象所代替,代理對象加入了增強邏輯,當調用代理調用對象的方法時,目標對象的方法就會被攔截。該AOP在Controller使用,必須是SpringMVC容器中去管理,也因此存在Spring和SpringMVC父子容器的關係。Spring父容器一般是管理Dao和Service層,而Spring的子容器一般配置的是Controller層,父子容器的訪問關係是,子容器可以訪問父容器中的對象,但是父容器無法訪問子容器中的對象。比如controller可以把Dao和Service注入進來,但是Dao和Service無法把Controller注進來。
實踐:
註解類:
@Retention(RetentionPolicy.RUNTIME)//@Retention定義了該Annotation被保留的時間長短,用於描述註解的生命週期
@Target(ElementType.METHOD)//@Target說明了Annotation所修飾的對象範圍
public @interface CheckParam {
/**
* 請求當前接口所需要的參數,多個以小寫的逗號隔開
* @return
*/
String fieldNames() default "";
/**
*傳遞參數的對象類型
*/
Class<?> parameter() default Object.class;
/**
* 默認不校驗參數;
* @return
*/
boolean require() default false;
}
aop類:
@Aspect
@Component
public class RequiredParam {
private static final Logger logger = Logger.getLogger(RequiredParam.class);
public RequiredParam() {
logger.info("初始化AOP切面校驗類");
}
@Pointcut("@annotation(com.jeeplus.modules.capital.controller.CheckParam)")
public void controllerRequired() {
}
@Around("controllerRequired()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
try {
//獲取被註解的方法
MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) pjp;
MethodSignature signature = (MethodSignature) mjp.getSignature();
Method method = signature.getMethod();
//獲取方法上的註解
CheckParam checkParam = method.getAnnotation(CheckParam.class);
if (!checkParam.require()) {//放行
pjp.proceed();
}
String result = requestParameter();
Gson gson = new Gson();
List<Map> param = gson.fromJson(result, ArrayList.class);
logger.info(String.format("Request Param;{%s}", param));
Preconditions.checkNotNull(param, "request param is null");
//獲取方法上的校驗字段;以防萬一,將中文的逗號替換成英文的逗號;
String fieldNames = checkParam.fieldNames().replace(",", ",");
for (String fieldName : fieldNames.split(",")) {
Preconditions.checkNotNull(param.get(0).get(fieldName),fieldName + " not found");
}
} catch (Exception e) {
e.printStackTrace();
return Result.fail(SysMessageEnums.MISS_REQUEST_PARAM.getVal(),SysMessageEnums.MISS_REQUEST_PARAM.getContext());
}
//如果沒有報錯,放行
return pjp.proceed();
}
/**
* 獲取請求中的數據,通過字符輸入流中讀取JSON數據
*
* @return
* @throws Exception
*/
public static String requestParameter() throws Exception {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sra.getRequest();
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
String jsonStr = null;
StringBuilder result = new StringBuilder();
while ((jsonStr = reader.readLine()) != null) {
result.append(jsonStr);
}
if (StringUtils.isEmpty(result)) {
return ERROR_MESSAGE;
}
return result.toString();
}
private static final String ERROR_MESSAGE = "缺少必要參數";
controller類:
@RequestMapping("/txUser")
@Controller("txUserController")
public class TxUserController {
@RequestMapping(value = "/insert")
@CheckParam(fieldNames="name,age",require=true)
public String insert(User user){
System.out.println("參數:" + user);
return "success";
}
}
test類:
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-mvc.xml");
TxUserController ps = ac.getBean("txUserController",TxUserController.class);
String str = ps.insert(new User("test",25));
sout(str);
}
xml配置,這裏主要提到一個AOP用到的配置,其它配置不貼了,這個配置一點就是一定要配置在component-scan以註冊bean後:
<aop:aspectj-autoproxy proxy-target-class="true"/>