如何从自定义验证注释

时间:2018-03-16 11:08:46

标签: java spring spring-mvc spring-boot spring-security

我有一个请求data transfer object(DTO),用于接受API的POST主体。该DTO具有X实体的ENUM密钥。我创建了一个自定义验证注释,并通过其实体存储库验证ENUM是否存在于我的系统中,该存储库返回实体或基于存在的null。

我想将X经过验证的实体传递给我的控制器。我不想在我的业务逻辑中再次通过ENUM获取X实体,因为我已经在验证中完成了这项工作。

我将该实体保存在注释验证器类的静态变量中,稍后当我想要在业务逻辑中访问它时,如果API同时被命中,我的静态变量会被第二个请求覆盖,当我的第一个业务逻辑被覆盖时请求获取X实体,由于覆盖问题,它获取第二个请求的实体。

我希望X实体对象在其自己的请求周期内作用域,并在请求完成后销毁或GC,就像其他对象一样。我怎样才能做到这一点?

我的自定义验证器:

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidateXimpl.class)
@Documented
public @interface ValidateX {
    String message()  default "Message";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default{};
}

自定义验证器实现:

public class ValidateXimpl implements ConstraintValidator<ValidateX, String> {

    @Autowired
    DBRepo dbRepo;

    @Override
    public void initialize(ValidateX annotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext ctx) {
        try {
            XEntity X = dbRepo.findByEnum(value); // I want this entity in my controller
            return (!value.isEmpty() && X != null);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

我在DTO中进行验证:

public class DTO{
    ....
    @ValidateX
    String xEntityEnum
    ....
}

我的控制器:

@RequestMapping(value = '/x', method = RequestMethod.POST)
public @ResponseBody
Map<String, Object> createX(@Validated @RequestBody DTO dto, BindingResult errors) {
    // I want that entity here which I get from db repo in my validator
}

1 个答案:

答案 0 :(得分:1)

我刚从RequestContextHolder

解决了这个问题

解决方案代码:

验证码实施

public class ValidateXimpl implements ConstraintValidator<ValidateX, String> {

@Autowired
DBRepo dbRepo;

@Override
public void initialize(ValidateX annotation) {
}

@Override
public boolean isValid(String value, ConstraintValidatorContext ctx) {
    try {
        XEntity X = dbRepo.findByEnum(value); // I want this entity in my controller
        RequestContextHolder.getRequestAttributes().setAttribute(
                "XEntity", X, RequestAttributes.SCOPE_REQUEST
        ); // I saved it in RequestContextHolder
        return (!value.isEmpty() && X != null);
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
}

我的控制器

@RequestMapping(value = '/x', method = RequestMethod.POST)
public @ResponseBody
Map<String, Object> createX(@Validated @RequestBody DTO dto, BindingResult errors) {
     // I want that entity here which I get from db repo in my validator
    System.out.println(
            RequestContextHolder.getRequestAttributes().getAttribute(
                    "XEntity",
                    RequestAttributes.SCOPE_REQUEST
            )
    ); // I get that from RequestContextHolder
}

这就是我真正需要的。由于RequestContextHolder函数中的请求范围设置,setAttribute在请求完成时变得清晰,并且仅在其自己的请求线程中可用。