java - Dropwizard 支持非资源类中的验证 (JSR-303)

标签 java spring dropwizard bean-validation spring-validator

根据this link :

If you need to validate entities outside of resource endpoints, the validator can be accessed in the Environment when the application is first ran.

这意味着下面的@Valid将不起作用,我必须以编程方式使用profile对象上的 validator 并对返回的错误进行处理:

public class ProfilesManager {  
    ...
    public void createProfile(@Valid Profile profile) {
        Set<ConstraintViolation<Profile>> errors = validator.validate(profile);
        ...
    }
}

在 Spring Boot 中,我所要做的就是用 @Validated 注释它,然后会自动抛出 ConstraintViolationException:

@Validated
@Component
public class ProfilesManager { 
    public void createProfile(@Valid Profile profile) {
        // if invalid, exception thrown before getting here
    }
}

Dropwizard、官方或第 3 方是否有等效的解决方案?

最佳答案

使用 HK2's interception service 自己实现这一点很容易。您需要做的就是提供一个 MethodInteceptor 来检查 @Valid 注释的方法参数,并使用 Validator 验证这些参数

public class ValidationMethodInterceptor implements MethodInterceptor {

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        for (int i = 0; i < args.length; i++) {
            Parameter parameter = invocation.getMethod().getParameters()[i];
            if (parameter.getAnnotation(Valid.class) != null) {
                handleValidation(args[i]);
            }
        }
        return invocation.proceed();
    }

    private void handleValidation(Object arg) {
        Set<ConstraintViolation<Object>> constraintViolations
                = validator.validate(arg);

        if (!constraintViolations.isEmpty()) {
            throw new IllegalArgumentException(
                    "constraint violations in bean argument");
        }
    }
}

在您的 InterceptionService 实现中,您可以决定应使用自定义 Filter 来验证哪些服务,该过滤器会在以下位置查找自定义 @Validated 注释:服务等级

public class ValidatedFilter implements Filter {

    @Override
    public boolean matches(Descriptor descriptor) {
        try {
            return Class.forName(descriptor.getImplementation())
                    .isAnnotationPresent(Validated.class);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

public class ValidationInterceptionService implements InterceptionService {

    private final static MethodInterceptor METHOD_INTERCEPTOR = new ValidationMethodInterceptor();
    private final static List<MethodInterceptor> METHOD_LIST = Collections.singletonList(METHOD_INTERCEPTOR);

    @Override
    public Filter getDescriptorFilter() {
        return new ValidatedFilter();
    }

    @Override
    public List<MethodInterceptor> getMethodInterceptors(Method method) {
        for (Parameter parameter: method.getParameters()) {
            if (parameter.isAnnotationPresent(Valid.class)) {
                return METHOD_LIST;
            }
        }
        return null;
    }

    @Override
    public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> c) {
        return null;
    }
}

请参阅 this GitHub repository 中包含测试用例的完整示例.

关于java - Dropwizard 支持非资源类中的验证 (JSR-303),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50290398/

相关文章:

java - 在 Java 中解析大型 XML 响应

java - 允许特定用户访问 Spring Security

logback - 在 SLF4J 中使用 JSON 日志记录时如何包含多个 JSON 字段?

java - Dropwizard REST API服务器已退出,代码为1

Java:在不消耗内存的情况下始终需要一长串变量的最佳方法?

java - 如何将多个元素相互对齐?

java - 日志记录在 Android 设备上的实际作用是什么?

java - Spring Framework 与 JVM 相互连接

java - Gradle、Spring Boot、Maven 发布 - 发布仅包含依赖项和/或约束而没有版本

freemarker - 无法在 freemarker 模板中加载图像