当前位置: 首页 > 知识库问答 >
问题:

请求反序列化期间的自定义声明性spring pojo验证

计泉
2023-03-14

我正在寻找注释来注释pojo类,我需要在请求反序列化期间对其进行验证。我正在搜索要作为参数类传递的注释,该类将验证我的pojo。

实现可以如下所示:

@ValidateAnnotation(class = ExampleClassValidator.class)
public class ExampleClass {
    private String name;
}

有人知道这种方法的Spring注释或提供声明性验证的依赖项吗?我问是因为我在留档中找不到任何类似的解决方案。

共有3个答案

邰英毅
2023-03-14

也许编写自定义注释和使用Spring AOP会对您有所帮助。Spring AOP非常简单。

萧阳波
2023-03-14

对于正常的验证,您可以使用javax中的注释对类进行注释。验证。约束包,如javax。验证。约束条件。注意空。对于自定义验证,您可以创建自己的注释来调用您编写的自定义验证程序。

例如,如果您想创建一个验证器来确保一个字段的长度为9个字符,您可以执行以下操作:

首先,创建自定义验证注释。

@Documented
@Constraint(validatedBy = NineCharactersValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NineCharactersOnly {
    String message() default "This field must contain exactly nine characters";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

接下来,创建自定义验证器:

public class NineCharactersValidator implements ConstraintValidator<NineCharactersOnly, String> {

    @Override
    public void initialize(NineCharactersOnly contactNumber) {
    }

    @Override
    public boolean isValid(String contactField, ConstraintValidatorContext cxt) {
        return contactField != null && contactField.length() == 9;
    }
}

接下来,对需要约束在pojo上的字段使用注释。

public class ExampleClass {
    @NineCharactersOnly
    private String fieldThatMustBeNineCharacters;
}

接下来,将控制器中的方法参数标记为@Valid,以便Spring验证它们:

@RestController
public class CustomValidationController {

    @PostMapping("/customValidationPost")
    public ResponseEntity<String> customValidation(@Valid ExampleClass exampleClass, BindingResult result, Model m) {
        // we know the data is valid if we get this far because Spring automatically validates the input and 
        // throws a MethodArgumentNotValidException if it's invalid and returns an HTTP response of 400 (Bad Request).
        return ResponseEntity.ok("Data is valid");
    }   
}

最后,如果您想要自定义逻辑来处理验证错误而不仅仅是发送400,您可以创建自定义验证处理程序方法。

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationException(MethodArgumentNotValidException e) {
    Map<String, String> errors = new HashMap<>();
    d.getBindingResult().getAllErrors().forEach((error) -> {
        String fieldName = ((FieldError) error).getField();
        String errorMessage = error.getDefaultMessage();
        errors.put(fieldName, errorMessage);
    });

    return errors;
}
谷森
2023-03-14

您可以使用@InitBinder根据方法的目标配置验证器。下面是一个简单的例子:

注释类:

package test.xyz;


import org.springframework.validation.Validator;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateAnnotation {
    Class<? extends Validator> value();
}

要验证的示例类:

package test.xyz;

@ValidateAnnotation(ExampleClassValidator.class)
public class ExampleClass {
}

验证程序类:

package test.xyz;

import org.springframework.validation.Errors;

public class ExampleClassValidator implements org.springframework.validation.Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return ExampleClass.class.isAssignableFrom(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {

    }
}

最后是具有@InitBinder定义的控制器类:

import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import test.xyz.ExampleClass;
import test.xyz.ValidateAnnotation;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;

@Controller
public class ExampleController {
    @RequestMapping(value="test-endpoint", method= RequestMethod.GET)
    public @ResponseBody
    Object testMethod(@Valid ExampleClass exampleClass, Errors errors) {
        return Collections.singletonMap("success", true);
    }


    @InitBinder
    public void initBinder(WebDataBinder binder, HttpServletRequest request) throws IllegalAccessException, InstantiationException {
        Class<?> targetClass = binder.getTarget().getClass();
        if(targetClass.isAnnotationPresent(ValidateAnnotation.class)) {
            ValidateAnnotation annotation = targetClass.getAnnotation(ValidateAnnotation.class);
            Class<? extends Validator> value = annotation.value();
            Validator validator = value.newInstance();
            binder.setValidator(validator);
        }
    }
}

说明:

您可以使用WebDataBinder的getTarget方法访问要验证的目标。从那里可以直接检查类上的注释,获取validator类,并将其设置在活页夹上。我相信您还可以使用@ControllerAdvice注释来配置全局InitBinder。作为免责声明,我不知道是否建议访问InitBinder中的binder目标,但我已经这样做了几次,没有遇到任何问题。

 类似资料:
  • 我有以下POJO: 以及以下控制器: 问题在于,它不是生成错误DataFormatException,而是生成: 虽然如上所述,问题是正确的,但信息是错误的。那么,为了产生想要的错误而不是杰克逊产生的错误,我们能做些什么呢?

  • 问题内容: 我有一个对象,即时通讯读取和写入,并从和。我不断收到Java期望的错误,但发现了另一个。 在我的课堂上,我已经实现并拥有一个我认为足够的领域。 我是Java序列化的新手。我在这里想念什么? 编辑 如果有关系,我实际上是在尝试读写 这是完整的痕迹: 问题答案: 您正在读取文件吗?在这种情况下,是否立即添加serialVersionUID无关紧要,它不同于文件中存储的那个,并且会创建异常。

  • I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器

  • 我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif

  • 问题内容: 我有一堂课 我想将下面的JSON数据反序列化到上面的类/对象中 我的想法是在JSON中是一个对象,但我只想获取(在JSON中)在反序列化期间将像在类中那样传递。 如何使用Json.NET实现该目标? 我相信我可以使用CustomJsonConverter完成它。但是我很困惑。docs中的示例仅用于,但不适用。 问题答案: 我只是使用上面在问题中提到的方法解决了我的问题。在我完整的代码下

  • 问题内容: 确定,所以我编辑了问题,因为它不够清楚。 编辑2 :更新了JSON文件。 我在Android应用程序中使用GSON,我需要解析来自服务器的JSON文件,这些文件有点太复杂了。我不想让我的对象结构太沉重,所以我想简化内容: 所以我的对象的结构将不是JSON文件的结构。 例如,如果在JSON中,我有以下内容: 我不想保留我当前的对象结构,即一个对象,其中包含一个和一个“总计”。但是我只想将