靈活使用AOP面向切面Aspect校驗Controller層單個型別的引數是否為空
阿新 • • 發佈:2018-12-12
我們經常註解使用對controller傳過來的引數進行判空校驗,但使用註解校驗的話常常會遇到controller層方法接收的必須是一個物件(實體類),而我們要校驗並使用的值只有一個或幾個,這樣就會導致判空會出現校驗不靈活的問題,只適合表單提交校驗比較合適,但對一個引數或幾個引數欄位校驗就不行了。那麼我們可以使用AOP機制完美解決cotroller層中引數進行校驗問題。
1.在springmvc.xml配置檔案中掃描aop存放aspect的相關類
<context:component-scan base-package="com.awaymeet.fly.platform.aspect"/> <!--啟動AspectJ支援--> <aop:aspectj-autoproxy proxy-target-class="true" />
2.建立aspect包和VerificationAspect.java類(用於攔截引數校驗)
package com.awaymeet.fly.platform.aspect; import com.awaymeet.fly.platform.exception.bean.Nullable; import com.awaymeet.fly.platform.exception.bean.ParameterException; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.CodeSignature; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.HashMap; import java.util.Map; /** * 處理資料校驗,配合 自定義註解 * 預設所有引數為空,若可以為空則在 引數前 加註解,其他校驗未寫 */ @Aspect @Component public class VerificationAspect { /** * 宣告切面 應用在,所有 Controller下的, 以Controller結尾的類中的,所有 public 方法 */ @Pointcut("execution(public * com.awaymeet.fly.platform.controller.*.*(..))") public void joinPointInAllController() { } /** * 切入點執行前方法 * * @param point 切入點 */ @Before("joinPointInAllController()") public void checkParameter( JoinPoint point) throws Exception { String[] paramNames = ((CodeSignature) point.getSignature()).getParameterNames(); //key Object[] args = point.getArgs();//value // 獲得切入的方法 Method method = ((MethodSignature) point.getSignature()).getMethod(); // 獲得所有引數 Parameter[] parameters = method.getParameters(); // 儲存需要校驗的args Map<Object,Object> map = new HashMap<Object,Object>(); // 對沒有Nullable註解的引數進行非空校驗 for (int i = 0; i < parameters.length; i++) { Parameter parameter = parameters[i]; String name = parameter.getName(); Annotation[] annotations = parameter.getDeclaredAnnotationsByType(Nullable.class); if (annotations.length < 1) { if(StringUtils.isEmpty(args[i])){ map.put(paramNames[i],""); }else{ map.put(paramNames[i],args[i]); } } } for (Object o : map.keySet()) { if (StringUtils.isEmpty(map.get(o))) { String name = "" ; if(o instanceof String){ name = (String)o ; }else{ name = o.getClass().getName(); } //欄位名+引數為空! throw new ParameterException(name +"引數為空!"); } } } }
自定義異常類ParameterException。如果遍歷的引數為空則丟擲自定義異常,丟擲的異常統一在@ControllerAdvice註解類進行異常捕捉。
3.自定義引數可以為空的註解Nullable.java(在controller層的引數前新增該註解表示:該引數可為空)
package com.awaymeet.fly.platform.exception.bean; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.PARAMETER; /** * 資料校驗 | 可空 * 加在 Controller 的函式 的 引數 前面,本註解代表可空, 其他未寫 */ @Retention(RetentionPolicy.RUNTIME) @Target({PARAMETER}) public @interface Nullable { }
自定義異常類ParameterException.java
package com.awaymeet.fly.platform.exception.bean;
public class ParameterException extends Exception {
public ParameterException(Exception e) {
super(e);
}
public ParameterException(String message) {
super(message);
}
}
4.使用@ControllerAdvice註解建立統一異常處理類GlobalExceptionHandler.java
package com.awaymeet.fly.platform.exception;
import com.awaymeet.fly.common.pojo.APPFinalConfig;
import com.awaymeet.fly.common.pojo.JResult;
import com.awaymeet.fly.common.utils.JsonUtils;
import com.awaymeet.fly.platform.exception.bean.InternalAPIServiceException;
import com.awaymeet.fly.platform.exception.bean.UserException;
import org.apache.log4j.Logger;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.UndeclaredThrowableException;
/**
* @Title: exceptionHandle
* @Description: 預設異常處理
* @author lc
* @param ex
* @return JResult 返回型別
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public JResult exceptionHandle( Exception ex)
throws IOException {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
result.setDescription("系統出現異常");
return result ;
}
/**
* @Description: 物件引數異常處理
* @author lc
* @param ex
* @throws
* @return JResult 返回型別
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public JResult bindException(BindException ex) {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
StringBuilder msg = new StringBuilder() ;
BindException exception = (BindException)ex ;
for (FieldError error : exception.getBindingResult().getFieldErrors()) {
/*msg.append("引數");
msg.append(error.getField());
msg.append("=");
msg.append(error.getRejectedValue());
msg.append(",說明:");*/
msg.append(error.getDefaultMessage());
}
result.setDescription(msg.toString());
return result ;
}
/**
* @Title: exceptionHandle
* @Description: 單個或幾個引數異常處理
* @author lc
* @param ex
* @throws IOException
* @return JResult 返回型別
*/
@ExceptionHandler(UndeclaredThrowableException.class)
@ResponseBody
public JResult parameterException(UndeclaredThrowableException ex)
throws IOException {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
result.setDescription(ex.getCause().getMessage());
return result ;
}
}
5.controller層請求的相應方法體
@RequestMapping("/select")
@ResponseBody
public JResult select(long id ,String inspectionName ){
return auditAndRagistService.select(id);
}
最後執行專案,傳送請求!