1、需求
调用微信接口之前:统一权限校验及异常处理。
2、思路
- 提供自定义注解,可配置需要的参数
- aop拦截自定义注解,方法执行前校验权限,拦截并过滤方法抛出的异常
3、核心代码
3.1、自定义注解@WxFuncAuth
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WxFuncAuth {
String[] funcs() default {};
boolean isVerify() default true;
String appId() default ""; }
|
3.2、微信方法权限注解拦截WxFuncAuthAspect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| @Aspect @Component @Slf4j public class WxFuncAuthAspect {
private final SpelExpressionParser parser = new SpelExpressionParser();
private final ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
@AfterThrowing(throwing = "ex", value = "@annotation(wxFuncAuth)") public void wxFuncAuth(JoinPoint joinPoint, Throwable ex, WxFuncAuth wxFuncAuth) { String appId = generateKeyBySpringEL(wxFuncAuth.appId(), joinPoint); log.info("After throwing appId:{},message:{}", appId, ex.getMessage()); if (ex instanceof WxServiceException) { if (((WxServiceException) ex).getErrorCode() == WxMaErrorMsgEnum.CODE_48001.getCode()) { } } }
@Before(value = "@annotation(wxFuncAuth)") public void wxFuncAuth(JoinPoint joinPoint, WxFuncAuth wxFuncAuth) { String appId = generateKeyBySpringEL(wxFuncAuth.appId(), joinPoint); log.info("annotation WxFuncAuth Before appId:{}", appId); if (StringUtils.isBlank(appId)) { throw new WxServiceException("appId不存在"); } log.info("annotation WxFuncAuth Before funcs:{}", JSON.toJSONString(wxFuncAuth.funcs()));
if (wxFuncAuth.funcs().length > 0) { }
}
private String generateKeyBySpringEL(String elString, JoinPoint joinPoint) { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method targetMethod = AopUtils.getMostSpecificMethod(methodSignature.getMethod(), AopUtils.getTargetClass(joinPoint.getTarget())); Expression expression = parser.parseExpression(elString); EvaluationContext context = new MethodBasedEvaluationContext(new Object(), targetMethod, joinPoint.getArgs(), nameDiscoverer); return Objects.requireNonNull(expression.getValue(context)).toString(); } }
|
3.3、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component public class WxFuncAuthAnnotationCaller {
@WxFuncAuth(appId = "#appId", funcs = {"1", "2"}) public String callNormal(String appId) { return appId + ": I'm very good"; }
@WxFuncAuth(appId = "#appId", funcs = {"1", "2"}) public void callError(String appId) { throw new WxServiceException(appId+"权限不足",48001); } }
|
4、总结
通过@Cacheable中Spring EL表达式的借鉴完成了这个需求,重点关注WxFuncAuthAspect类中的generateKeyBySpringEL方法:
- 通过org.springframework.aop.support.AopUtils#getMostSpecificMethod获取方法对象,这块曾经有个坑。
- TemplateAwareExpressionParser#parseExpression解析SpEL表达式
- 再通过MethodBasedEvaluationContext和DefaultParameterNameDiscoverer配合,从方法中获取参数