业务概要: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); }