You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建类似@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:28:31