为了账号安全,请及时绑定邮箱和手机立即绑定

在没有控制器的情况下使用杰克逊创建对象时@Valid

在没有控制器的情况下使用杰克逊创建对象时@Valid

慕后森 2022-09-14 15:38:25
我有一个模型,当从前端发送请求时,我在我的控制器中用@Valid验证了该模型:@NotNull@Size(min=1, message="Name should be at least 1 character.")private String name;@NotNull@Pattern(regexp = "^https://github.com/.+/.+$", message = "Link to github should match https://github.com/USER/REPOSITORY")private String github;但现在我也在用杰克逊的对象映射器创建一个没有控制器的对象。有没有办法在对象映射器中注册此验证,或者我是否应该只检查设置器中的变量?
查看完整描述

2 回答

?
智慧大石

TA贡献1946条经验 获得超3个赞

您可以在反序列化后扩展和验证对象。要注册此豆,请使用 。BeanDeserializerSimpleModule


简单的豆子去蛭蛭验证器:


class BeanValidationDeserializer extends BeanDeserializer {


    private final static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

    private final Validator validator = factory.getValidator();


    public BeanValidationDeserializer(BeanDeserializerBase src) {

        super(src);

    }


    @Override

    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

        Object instance = super.deserialize(p, ctxt);

        validate(instance);


        return instance;

    }


    private void validate(Object instance) {

        Set<ConstraintViolation<Object>> violations = validator.validate(instance);

        if (violations.size() > 0) {

            StringBuilder msg = new StringBuilder();

            msg.append("JSON object is not valid. Reasons (").append(violations.size()).append("): ");

            for (ConstraintViolation<Object> violation : violations) {

                msg.append(violation.getMessage()).append(", ");

            }

            throw new ConstraintViolationException(msg.toString(), violations);

        }

    }

}

我们可以按如下方式使用它:


import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.databind.BeanDescription;

import com.fasterxml.jackson.databind.DeserializationConfig;

import com.fasterxml.jackson.databind.DeserializationContext;

import com.fasterxml.jackson.databind.JsonDeserializer;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.fasterxml.jackson.databind.deser.BeanDeserializer;

import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;

import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;

import com.fasterxml.jackson.databind.module.SimpleModule;


import javax.validation.ConstraintViolation;

import javax.validation.ConstraintViolationException;

import javax.validation.Validation;

import javax.validation.Validator;

import javax.validation.ValidatorFactory;

import javax.validation.constraints.NotNull;

import javax.validation.constraints.Pattern;

import javax.validation.constraints.Size;

import java.io.File;

import java.io.IOException;

import java.util.Set;


public class JsonApp {


    public static void main(String[] args) throws Exception {

        File jsonFile = new File("./resource/test.json").getAbsoluteFile();


        SimpleModule validationModule = new SimpleModule();

        validationModule.setDeserializerModifier(new BeanDeserializerModifier() {

            @Override

            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {

                if (deserializer instanceof BeanDeserializer) {

                    return new BeanValidationDeserializer((BeanDeserializer) deserializer);

                }


                return deserializer;

            }

        });


        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(validationModule);


        System.out.println(mapper.readValue(jsonFile, Pojo.class));

    }

}


class Pojo {


    @NotNull

    @Size(min = 1, message = "Name should be at least 1 character.")

    private String name;


    @NotNull

    @Pattern(regexp = "^https://github.com/.+/.+$", message = "Link to github should match https://github.com/USER/REPOSITORY")

    private String github;


    // getters, setters, toString()

}

对于有效有效负载:JSON


{

  "name": "Jackson",

  "github": "https://github.com/FasterXML/jackson-databind"

}

指纹:


Pojo{name='Jackson', github='https://github.com/FasterXML/jackson-databind'}

对于无效的有效负载:JSON


{

  "name": "",

  "github": "https://git-hub.com/FasterXML/jackson-databind"

}

指纹:


Exception in thread "main" javax.validation.ConstraintViolationException: JSON object is not valid. Reasons (2): Name should be at least 1 character., Link to github should match https://github.com/USER/REPOSITORY, 

    at BeanValidationDeserializer.validate(JsonApp.java:110)

    at BeanValidationDeserializer.deserialize(JsonApp.java:97)


查看完整回答
反对 回复 2022-09-14
?
喵喔喔

TA贡献1735条经验 获得超5个赞

我还将发布我如何设法做到这一点。创建实现验证程序的类:


public class UserValidator implements Validator {


    private static final int MINIMUM_NAME_LENGTH = 6;


    @Override

    public boolean supports(Class<?> clazz) {

        return User.class.isAssignableFrom(clazz);

    }


    public void validate(Object target, Errors errors) {

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "Name must be at least 7 characters long.");

        User foo = (User) target;


        if(foo.getGithub().length() > 0 && !extensionSpec.getGithub().matches("^(www|http:|https:)+//github.com/.+/.+$")){

            errors.rejectValue("github", "Github must match http://github.com/:user/:repo");

        }


        if (errors.getFieldErrorCount("name") == 0 && foo.getName().trim().length() < MINIMUM_NAME_LENGTH) {

            errors.rejectValue("name", "Name must be at least 7 characters");

        }

    }

}

然后使用反序列化对象创建数据明细器,获取绑定结果,然后验证该对象:


ObjectMapper mapper = new ObjectMapper();

User foo = mapper.readValue(FooJson, User.class);


Validator validator = new ObjectValidator();

BindingResult bindingResult = new DataBinder(foo).getBindingResult();

validator.validate(foo, bindingResult);


if(bindingResult.hasErrors()){

    throw new BindException(bindingResult);

}

另外,如果要在响应的正文中获取错误代码:


@ExceptionHandler

ResponseEntity handleBindException(BindException e){

    return ResponseEntity

            .status(HttpStatus.BAD_REQUEST)

            .body(e.getBindingResult().getAllErrors()

                    .stream()

                    .map(DefaultMessageSourceResolvable::getCode)

                    .toArray());


}


查看完整回答
反对 回复 2022-09-14
  • 2 回答
  • 0 关注
  • 81 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信