Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java spring注释可以访问方法参数吗?_Java_Spring_Annotations - Fatal编程技术网

Java spring注释可以访问方法参数吗?

Java spring注释可以访问方法参数吗?,java,spring,annotations,Java,Spring,Annotations,考虑一个urlvalidater方法注释,该注释在调用方法之前测试给定的url是否有效 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface UrlValdator{ String value(); } 当路由是静态的并且提前知道时,这种方法可以很好地工作。例如: @UrlValidator("http://some.known.url") public void doSome

考虑一个
urlvalidater
方法注释,该注释在调用方法之前测试给定的url是否有效

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UrlValdator{
    String value();
}
当路由是静态的并且提前知道时,这种方法可以很好地工作。例如:

@UrlValidator("http://some.known.url")
public void doSomething();
但这不是很灵活。例如,如果路由隐含在
doSomething()
方法签名中,该怎么办?我可以通过Spring表达式语言或其他方式访问它吗?例如,这不起作用,但这正是我拍摄的目的

@UrlValidator("#p1")
public void doSomething(String url)

这样可以使注释动态化吗

相关的 ,但思路陈旧,公认的答案非常繁琐/难以理解。是否有一个最简单的工作示例/更新的方法可以做到这一点?

简短回答:是

长答覆: 指定批注的目标,可以是以下对象:
批注类型、构造函数、字段、局部变量、方法、包、模块、参数、类型和类型参数
。我们对这里的
参数
感兴趣。由于我们希望从编译器运行代码,
RetentionPolicy.RUNTIME
适合保留类型。 接下来,我们必须添加
@Constraint
注释,根据文档:

将注释标记为Bean验证约束

这意味着,Spring将获取您的参数并在运行时验证它。我们必须做的最后一件事是实现验证本身,这意味着创建一个实现接口的类

总而言之:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UrlValidatorImplementation.class)
public @interface UrlValidator{
    String message() default "Invalid url";
}
urlvalidateImplementation
类的实现:

public class UrlValidatorImplementation implements ConstraintValidator<UrlValidator, String> {
    @Override
    public void initialize(UrlValidator annotation) {
        // initialization, probably not needed
    }

    @Override
    public boolean isValid(String url, ConstraintValidatorContext context) {
        // implementation of the url validation
    }
}

我不完全确定这是否是您的想法,但我可以建议使用SpringAOP,因为它可以给您很大的灵活性

由于您在其中一条评论中提到您已经在使用Spring AOP,我将假设您已经添加了
Spring boot starter AOP
作为依赖项,并且您已经通过使用
@enableSpectAOP

例如,定义了这样的注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EnsureUrlValid {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface UrlToVerify {
}
我可以在示例弹簧组件中使用它们,如下所示:

@Component
public class SampleComponent {

    private static final Logger logger = LogManager.getLogger(SampleComponent.class);

    @EnsureUrlValid
    public void fetchData(String url) {
        logger.info("Fetching data from " + url);
    }

    @EnsureUrlValid
    public long fetchData(Long id, @UrlToVerify String url) {
        logger.info("Fetching data for user#" + id + " from " + url);
        // just to show that a method annotated like this can return values too
        return 10L;
    }

    @EnsureUrlValid
    public void fetchDataFailedAttempt() {
        logger.info("This should not be logged");
    }
}
下面是
EnsureUrlValid
注释的“处理器”示例。它查找带注释的方法,尝试提取传入的url,并根据url是否有效,继续调用该方法或引发异常。这很简单,但它表明您可以完全控制已注释的方法

@Aspect
@Component
public class UrlValidator {

    @Around(value = "@annotation(EnsureUrlValid)")
    public Object checkUrl(ProceedingJoinPoint joinPoint) throws Throwable {
        final Optional<String> urlOpt = extractUrl(joinPoint);
        if (urlOpt.isPresent()) {
            final String url = urlOpt.get();
            if (isUrlValid(url)) {
                return joinPoint.proceed();
            }
        }
        throw new RuntimeException("The passed-in url either could not be resolved or is not valid");
    }

    private Optional<String> extractUrl(JoinPoint joinPoint) {
        Object[] methodArgs = joinPoint.getArgs();

        Object rawUrl = null;
        if (methodArgs.length == 1) {
            rawUrl = methodArgs[0];
        }
        else if (methodArgs.length > 1) {
            // check which parameter has been marked for validation
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            Parameter[] parameters = method.getParameters();
            boolean foundMarked = false;
            int i = 0;
            while (i < parameters.length && !foundMarked) {
                final Parameter param = parameters[i];
                if (param.getAnnotation(UrlToVerify.class) != null) {
                    rawUrl = methodArgs[i];
                    foundMarked = true;
                }
                i++;
            }
        }

        if (rawUrl instanceof String) { // if rawUrl is null, instanceof returns false
            return Optional.of((String) rawUrl);
        }
        // there could be some kind of logic for handling other types

        return Optional.empty();
    }

    private boolean isUrlValid(String url) {
        // the actual validation logic
        return true;
    }
}
@方面
@组成部分
公共类UrlValidator{
@周围(value=“@annotation(EnsureUrlValid)”)
公共对象检查URL(ProceedingJoinPoint joinPoint)抛出可丢弃的{
最终可选urlOpt=提取URL(连接点);
if(urlOpt.isPresent()){
最后一个字符串url=urlOpt.get();
if(isUrlValid(url)){
返回joinPoint.procedure();
}
}
抛出新的RuntimeException(“传入的url无法解析或无效”);
}
私有可选提取URL(连接点连接点){
Object[]methodArgs=joinPoint.getArgs();
对象rawUrl=null;
if(methodArgs.length==1){
rawUrl=methodArgs[0];
}
否则如果(methodArgs.length>1){
//检查已标记要验证的参数
方法Method=((MethodSignature)joinPoint.getSignature()).getMethod();
Parameter[]parameters=method.getParameters();
布尔值=false;
int i=0;
而(i

我希望它能有所帮助。

您可以尝试spring AOP,围绕@UrlValidator注释的控制器方法创建切入点。我已经在使用spring AOP,但不明白切入点如何帮助我实现这一点。你能举个例子吗?谢谢。让我尽快试用,然后回来标记接受/投票。是的,我正在使用APO。这看起来确实像我的想法。并不是说这是非常必要的,而是当场位于一个对象上时会发生什么情况呢。例如
@urlvalidater(obj.url)
。这可能不可行,对吧?我询问的唯一原因是,我想要验证的一些URL是在传递到方法中的对象上。也许重构是按顺序进行的:0
ConstraintValidator
——而不是您传入任何所需的
对象的
String
。此外,验证方法将具有以下签名:
public boolean isValid(对象对象、约束验证或上下文上下文)
@Component
public class SampleComponent {

    private static final Logger logger = LogManager.getLogger(SampleComponent.class);

    @EnsureUrlValid
    public void fetchData(String url) {
        logger.info("Fetching data from " + url);
    }

    @EnsureUrlValid
    public long fetchData(Long id, @UrlToVerify String url) {
        logger.info("Fetching data for user#" + id + " from " + url);
        // just to show that a method annotated like this can return values too
        return 10L;
    }

    @EnsureUrlValid
    public void fetchDataFailedAttempt() {
        logger.info("This should not be logged");
    }
}
@Aspect
@Component
public class UrlValidator {

    @Around(value = "@annotation(EnsureUrlValid)")
    public Object checkUrl(ProceedingJoinPoint joinPoint) throws Throwable {
        final Optional<String> urlOpt = extractUrl(joinPoint);
        if (urlOpt.isPresent()) {
            final String url = urlOpt.get();
            if (isUrlValid(url)) {
                return joinPoint.proceed();
            }
        }
        throw new RuntimeException("The passed-in url either could not be resolved or is not valid");
    }

    private Optional<String> extractUrl(JoinPoint joinPoint) {
        Object[] methodArgs = joinPoint.getArgs();

        Object rawUrl = null;
        if (methodArgs.length == 1) {
            rawUrl = methodArgs[0];
        }
        else if (methodArgs.length > 1) {
            // check which parameter has been marked for validation
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            Parameter[] parameters = method.getParameters();
            boolean foundMarked = false;
            int i = 0;
            while (i < parameters.length && !foundMarked) {
                final Parameter param = parameters[i];
                if (param.getAnnotation(UrlToVerify.class) != null) {
                    rawUrl = methodArgs[i];
                    foundMarked = true;
                }
                i++;
            }
        }

        if (rawUrl instanceof String) { // if rawUrl is null, instanceof returns false
            return Optional.of((String) rawUrl);
        }
        // there could be some kind of logic for handling other types

        return Optional.empty();
    }

    private boolean isUrlValid(String url) {
        // the actual validation logic
        return true;
    }
}