考虑一个UrlValidator
方法注释,在调用方法之前测试给定的 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)
or
@UrlValidator("#p1.url")
public void doSomething(Request request)
是否可以通过这种方式使注释动态化?
Related
这是我找到的最接近的 https://stackoverflow.com/questions/20350961/spring-expression-language-in-custom-annotation?rq=1,但线程已经过时,并且接受的答案非常麻烦/难以遵循。是否有一个最小的工作示例/更新的方法来做到这一点?
我不完全确定这是否是您的想法,但我可以建议使用 Spring AOP,因为它可以为您提供很大的灵活性。
既然您在评论之一中提到您已经在使用 Spring AOP,我将假设您已经添加了spring-boot-starter-aop
作为依赖项,并且您已通过使用注释您的配置类之一来启用对处理标有 @Aspect 的组件的支持@EnableAspectJAutoProxy
例如,定义注释如下:
@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;
}
}
我希望它有所帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)