業務概要:java
一、表單驗證。spring
二、短信驗證碼驗證,若是是認證用戶須要校驗接收驗證碼的手機號和認證的手機號是否一致。apache
這種通用代碼抽取,你們天然想起來用AOP解決。我先去處理的 業務2 這就形成了一個問題。表單驗證在這個業務處理以後進行。很尷尬。就想着在這個AOP類中把表單驗證的邏輯添加進去。可是代碼越寫越繁瑣。邏輯混雜。看着就不爽。想了想用兩個AOP去解決這個問題。果真很爽。這樣代碼減小了一大半。app
具體的思路 :.net
一、自定義註解在方法上使用。code
二、spring 掃描這個註解切面。orm
三、執行業務1 @Before。對象
四、執行業務2 @Around(這裏其實使用@Before也沒啥問題)。blog
http://blog.csdn.net/rainbow702/article/details/52185827 感謝此文的指導!接口
碰見問題:
代碼莫名其妙不知道去了哪裏不繼續流轉了。這裏就該
注意@Order ( Lower values have higher priority.更低的值具備更高的優先級。)執行順序了!
網上有個兩個圈圈的圖(應該百度就能看見),更能很好的解釋AOP的執行順序,對理解AOP頗有用!
如下代碼僅供參考 無複製價值
/** * 描述 驗證碼手機認證信息驗證 標記註解 * @author lienbo */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WorkOrderVerify { }
如下代碼僅供參考 無複製價值
package com.lienbo.interceptor; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.validation.BindingResult; import com.lienbo.exceptions.FormValidException; @Aspect @Component @Order(1) public class ValidFormInterceptor { private final static Logger LOGGER = LoggerFactory .getLogger(ValidFormInterceptor.class); @Pointcut("@annotation(com.lienbo.handler.WorkOrderVerify)") public void pointcut() { } @Before("pointcut()") public void verifyForm(JoinPoint joinPoint) { LOGGER.info("【工單表單參數校驗----------------開始】"); Object[] args = joinPoint.getArgs(); if (args == null || args.length < 1) { LOGGER.info("【獲取方法參數失敗】"); return; } List<Object> argsList = Arrays.asList(args); // 對參數進行過濾 List<Object> list = argsList.stream() .filter(x -> x instanceof BindingResult) .collect(Collectors.toList()); if (list.size() != 1) { LOGGER.info("【獲取表單vo失敗】"); return; } BindingResult result = (BindingResult) list.get(0); // 表單驗證 if (result.hasErrors()) { String errorMsg = result.getAllErrors().get(0).getDefaultMessage(); LOGGER.info("【工單表單參數校驗----------------{}】", errorMsg); throw new FormValidException(errorMsg); } LOGGER.info("【工單表單參數校驗----------------完畢】"); } }
如下代碼僅供參考 無複製價值
package com.lienbo.interceptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 通用邏輯驗證 驗證手機認證 驗證手機驗證 * * @author lienbo */ @Aspect @Component @Order(2) public class WoVerifyInterceptor { private final static Logger LOGGER = LoggerFactory .getLogger(HttpRequestInterceptor.class); /** 獲取vo中的 phone 屬性的值 */ private final static String PHONE = "phone"; /** 獲取vo中的 askAccount 屬性的值 */ private final static String ASK_ACCOUNT = "askAccount"; /** 獲取vo中的 verifyCode 屬性的值 */ private final static String VERIFY_CODE = "verifyCode"; /** 獲取vo中的 isNeedAuthPhone 方法的返回值 */ private final static String IS_NEED_AUTH_PHONE = "isNeedAuthPhone"; @Autowired AgentService agentService; /** * <p> * 方法說明 : 切點 * </p> */ @Pointcut("@annotation(com.lienbo.interceptor.WorkOrderVerify)") public void pointcut() { } /** * * <p> * 方法說明 : 環繞切面 * </p> * * @param joinPoint * void */ @Around("pointcut()") public void verifyByAgent(JoinPoint joinPoint) { LOGGER.info("【WorkOrderVerify 工單認證和短信驗證碼驗證 ------------ 驗證開始】"); // 獲取參數 PHONE ASK_ACCOUNT VERIFY_CODE IS_NEED_AUTH_PHONE Map<String, String> voValueMap = getVoValueMap(joinPoint); String string = voValueMap.get(IS_NEED_AUTH_PHONE); LOGGER.info("【WorkOrderVerify IS_NEED_AUTH_PHONE={}】", string); WoWorkOrder wo = new WoWorkOrder(); if (StringUtils.isNotBlank(string) && "true".equals(string)) { // 方法說明 : 獲取手機認證信息並設置到wo_work_order LOGGER.info("【獲取手機認證信息並設置到wo_work_order】"); wo = verifyAuth(voValueMap); // 方法說明 : 驗證 認證手機帳戶 的短信驗證碼;業務要求 接收驗證碼的手機號碼必須是認證手機號碼 agentService.verifrAuthPhoneMessageCaptcha( voValueMap.get(ASK_ACCOUNT), voValueMap.get(VERIFY_CODE), voValueMap.get(PHONE)); } else { LOGGER.info("【WorkOrderVerify 不須要驗證認證手機號碼和接收驗證碼手機號碼是否一致】"); if (StringUtils.isNotBlank(voValueMap.get(VERIFY_CODE)) && StringUtils.isNotBlank(voValueMap.get(PHONE))) { boolean result = agentService.verifyMessageCaptcha( voValueMap.get(VERIFY_CODE), voValueMap.get(PHONE)); if (!result) { throw new BizException("驗證碼驗證失敗"); } } } // 方法說明 : 從VO表單獲取數據保存到wo_work_order中 LOGGER.info("【從VO表單獲取數據保存到wo_work_order中】"); setWoWithVo(joinPoint, wo); LOGGER.info("【WorkOrderVerify 工單認證和短信驗證碼驗證------------ 驗證完成】"); } /** * * <p> * 方法說明 : 從VO表單獲取數據保存到wo_work_order中 * </p> * * @param joinPoint * @param wo * @return WoWorkOrder */ private WoWorkOrder setWoWithVo(JoinPoint joinPoint, WoWorkOrder wo) { Object[] args = joinPoint.getArgs(); if (args == null || args.length < 1) { LOGGER.info("【獲取方法參數失敗】"); return wo; } List<Object> argsList = Arrays.asList(args); // 表單VO均實現了 CreateWorkOrderVo 接口,對參數進行過濾 List<Object> list = argsList.stream() .filter(x -> x instanceof CreateWorkOrderVo) .collect(Collectors.toList()); // 一個工單隻用一個 VO 對象提交 if (list.size() != 1) { LOGGER.info("【獲取表單vo失敗:無實現CreateWorkOrderVo的VO對象】"); return wo; } Object obj = list.get(0); Class<?> clz = obj.getClass(); Field[] fields = clz.getDeclaredFields(); for (Field field : fields) { // 獲取屬性的名字 String name = field.getName(); if (WO.equals(name)) { // 將屬性的首字符大寫, 構造get,set方法 String suffix = name.substring(0, 1).toUpperCase() + name.substring(1); // 獲取屬性的類型 String type = field.getGenericType().toString(); // 若是type是wo_work_order類型,則前面包含"class ",後面跟類名 String 類型 if (type.equals( "class com.lienbo.beans.wo.WoWorkOrder")) { try { Method m = clz.getMethod("set" + suffix, WoWorkOrder.class); LOGGER.info("【爲wo賦值{}】", wo); return (WoWorkOrder) m.invoke(obj, wo); } catch (Exception e) { e.printStackTrace(); } } break; } } return wo; } /** * * <p> * 方法說明 : 獲取手機認證信息並設置到wo_work_order * </p> * * @param voValueMap * @return WoWorkOrder */ private WoWorkOrder verifyAuth(Map<String, String> voValueMap) { // 獲取手機認證信息 認證時間 已認證時間 ResultBean<AuthPhoneBean> userPhone = agentService .verifyAuthPhone(voValueMap.get(ASK_ACCOUNT).toString()); WoWorkOrder wo = new WoWorkOrder(); LOGGER.info("【userPhone={} 】", userPhone); if (userPhone.isSuccess()) { if (PhoneAuthStatus.AUTHFINISH .equals(userPhone.getData().getStatus()) || PhoneAuthStatus.AUTHING .equals(userPhone.getData().getStatus())) { wo.setIsAuthPhone(true); wo.setPhoneAuthTime(userPhone.getData().getValidateTime()); wo.setPhoneAuthDiffday( userPhone.getData().getPhoneAuthDiffday()); LOGGER.info( "【設置認證手機帳號setIsAuthPhone={},setPhoneAuthTime={},setPhoneAuthDiffday={}】", true, userPhone.getData().getValidateTime(), userPhone.getData().getPhoneAuthDiffday()); return wo; } } LOGGER.info("【設置未認證手機帳號默認值】"); wo.setIsAuthPhone(DefaultCode.DEFAULT_IS_AUTH_PHONE); wo.setPhoneAuthTime(DefaultCode.DEFAULT_PHONE_AUTH_TIME); wo.setPhoneAuthDiffday(DefaultCode.DEFAULT_PHONE_AUTH_DIFF_DAY); return wo; } /** * * <p> * 方法說明 : 從VO獲取 PHONE VERIFY_CODE ASK_ACCOUNT 的值 * </p> * * @param joinPoint * @return Map<String,String> */ private Map<String, String> getVoValueMap(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); if (args == null || args.length < 1) { LOGGER.info("【獲取方法參數失敗】"); return Collections.emptyMap(); } List<Object> argsList = Arrays.asList(args); // 表單VO均實現了 CreateWorkOrderVo 接口,對參數進行過濾 List<Object> list = argsList.stream() .filter(x -> x instanceof CreateWorkOrderVo) .collect(Collectors.toList()); // 一個工單隻用一個 VO 對象提交 if (list.size() != 1) { LOGGER.info("【獲取表單vo失敗:無實現CreateWorkOrderVo的VO對象】"); return Collections.emptyMap(); } Map<String, String> map = new HashMap<>(); Object obj = list.get(0); Class<?> clz = obj.getClass(); try { Method m = clz.getMethod(IS_NEED_AUTH_PHONE); map.put(IS_NEED_AUTH_PHONE, m.invoke(obj).toString()); } catch (Exception e) { e.printStackTrace(); } Field[] fields = clz.getDeclaredFields(); for (Field field : fields) { // 獲取屬性的名字 String name = field.getName(); if (PHONE.equals(name) || VERIFY_CODE.equals(name) || ASK_ACCOUNT.equals(name)) { // 將屬性的首字符大寫, 構造get,set方法 String suffix = name.substring(0, 1).toUpperCase() + name.substring(1); // 獲取屬性的類型 String type = field.getGenericType().toString(); // 若是type是字符串類型,則前面包含"class ",後面跟類名 String 類型 if (type.equals("class java.lang.String")) { try { Method m = clz.getMethod("get" + suffix); String value = m.invoke(obj).toString(); map.put(name, value); } catch (Exception e) { e.printStackTrace(); } } } else { continue; } } return map; } }
如下代碼僅供參考 無複製價值
@WorkOrderVerify @PostMapping("resume/info/createResume") public ResultBean<String> saveResume(@Valid CreateResumeVo vo, BindingResult result) { resumeService.saveWorkOrder(wo); return ResultBean.ok("SUCCESS", null); }