如何创建类似@PathVariable的自定义参数注解?Aspect不生效排查
问题分析与解决方案
1. 切面不触发的核心原因
你的切面切点表达式@annotation(com.org.app.service.security.annotation.PermittedMarkets)用于匹配标注了该注解的方法,但@PermittedMarkets是标注在方法参数上的,这个切点永远匹配不到目标方法,因此切面不会触发。
2. 正确实现参数注入的方式(替代切面)
要实现类似@PathVariable的参数注解功能,Spring官方标准方式是实现HandlerMethodArgumentResolver接口,这是Spring处理方法参数注解的原生机制,以下是完整步骤:
步骤1:保留自定义注解
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface PermittedMarkets { }
步骤2:实现参数解析器
@Component public class PermittedMarketsArgumentResolver implements HandlerMethodArgumentResolver { @Value("#{${config.market.permitted.marketmapping:{:}}}") private Map<String, String> roleToMarketCodeMap; // 判断是否支持处理带@PermittedMarkets注解的参数 @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(PermittedMarkets.class); } // 解析并生成参数值,注入到方法参数中 @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || authentication.getAuthorities().isEmpty()) { throw new AccessDeniedException("No authorities found"); } return authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .filter(entitlement -> entitlement.contains("app_user")) .map(roleToMarketCodeMap::get) .filter(Objects::nonNull) // 过滤掉映射表中无对应值的角色 .toArray(String[]::new); } }
步骤3:注册参数解析器
将解析器注册到Spring MVC配置中,确保Spring能识别并使用它:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { private final PermittedMarketsArgumentResolver permittedMarketsArgumentResolver; // 构造注入解析器实例 public WebMvcConfig(PermittedMarketsArgumentResolver permittedMarketsArgumentResolver) { this.permittedMarketsArgumentResolver = permittedMarketsArgumentResolver; } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(permittedMarketsArgumentResolver); } }
3. 仅解决切面触发问题(不推荐用于参数注入)
如果只是想让切面触发(比如做日志、权限校验),可修改切点表达式匹配包含该参数注解的方法,但这种方式无法实现参数注入:
@Aspect @Component public class MarketsAspect { @Value("#{${config.market.permitted.marketmapping:{:}}}") private Map<String,String> roleToMarketCodeMap; // 切点表达式:匹配任意方法,只要参数中有@PermittedMarkets注解 @Before("execution(* *(.., @com.org.app.service.security.annotation.PermittedMarkets (*), ..))") public void before(JoinPoint joinPoint) { final var grantedAuthorities = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()) .map(Authentication::getAuthorities) .orElseThrow(() -> new AccessDeniedException("No authorities found")); String[] marketCodes = grantedAuthorities.stream() .map(GrantedAuthority::getAuthority) .filter(entitlement -> entitlement.contains("app_user")) .map(roleToMarketCodeMap::get) .toArray(String[]::new); // 此处仅能做日志、校验等操作,无法将值注入到方法参数中 System.out.println("Permitted markets: " + Arrays.toString(marketCodes)); } }
内容的提问来源于stack exchange,提问作者chunkynuggy
相关产品推荐
相关产品推荐

