【问题标题】:Validation Exception - the right way to handle验证异常——正确的处理方式
【发布时间】:2020-12-30 14:40:29
【问题描述】:

我正在尝试验证我的邮政编码,但我想的方法行不通,我不明白为什么。

我创建了一个验证器,如果它无效,它必须抛出一个ValidationException

@Service
public class ZipCodeValidator{

    public void validate(String zipCode){
        validateNotEmpty(zipCode);
        validateHasNoSpaces(zipCode);
    }

    private void validateNotEmpty(String zipCode){
       if (zipCode.length() != 0){
           throw new ValidationException("Postal Code can't be empty");
       }
    }

    private void validateHasNoSpaces(String zipCode) {
        if (zipCode.contains(" ")){
            throw new ValidationException("Postal Code can't contain spaces");
        }
    }

}

在我的服务中,我收到邮政编码我想抛出我的自定义异常(我将错误消息传递给它),如下所示:

    try{
        validator.validate(zipCode);
    }catch (ValidationException ex){
        throw new ZipCodeValidationException(ex.getMessage());
    }

但它似乎不起作用,该异常没有被捕获,因此程序运行得更远。

我做错了什么?

整个方法错了吗?你会推荐什么?

这是我的自定义异常

public class ZipCodeValidationException extends Exception{
    public ZipCodeValidationException(String message) {
        super(message);
    }
}

【问题讨论】:

  • 你应该到处使用 Exception 而不是 ValidationException。
  • 您要在哪里验证 Controller 中的 ZipCode ?如果您在控制器内部进行操作,则有特定的位置
  • @silentsudo 它目前正在我从控制器调用的服务中发生。但我是一名初级学生,所以我不知道是否可以这样做。
  • 你能显示zipCode的代码值吗?看起来你的代码中有错误@Diana
  • @Deadpool zipCode 的值是 "" ,在我将 ValidationException 更改为 Exception 之后,我的代码开始做它应该做的事情。

标签: java spring-boot exception validationexception


【解决方案1】:

我推荐以下:

  • 将通用位置的所有异常处理为ExceptionHandler 类,更多详细信息请参见:https://www.baeldung.com/exception-handling-for-rest-with-spring
  • 您可以从 RuntimeException 扩展 ValidationException,这种方法将允许从 try-catch 结构中卸载代码
  • @Service 注解不太适合转换器或验证器,因为规则@Service 类包含业务逻辑,对于帮助程序类将更好地使用@Component,这两个注解之间完全没有区别,只了解该组件的哪一层应用程序有

请分享代码以获得更多建议和帮助。

【讨论】:

    【解决方案2】:

    您好,请分两步找到我的答案,首先是正确的,然后是建议的实施方式。

    更正:

    请使用ObjectUtils.isEmpty(arg) 来检查字符串是0 长度还是空值。这是您的代码的修改版本

    public interface ZipcodeService {
            void validate(@Zipcode String zipCode) throws ZipCodeValidationException;
        }
    
        @Service
        public static class ZipcodeServiceImpl implements ZipcodeService {
            private final ZipCodeRegexMatcher zipCodeRegexMatcher;
    
            public ZipcodeServiceImpl() {
                zipCodeRegexMatcher = new ZipCodeRegexMatcher();
            }
    
            @Override
            public void validate(String zipCode) throws ZipCodeValidationException {
                // uncomment for Regex Validation
                // boolean valid = zipCodeRegexMatcher.isValid(zipCode);
                // uncomment for Simple text validation
                final boolean valid = !ObjectUtils.isEmpty(zipCode);
    
                if (!valid) {
                    throw new ZipCodeValidationException("Invalid zipcode");
                }
            }
        }
    

    这是Controller调用者的样子

    @GetMapping(path = "dummy")
        public String getDummy(@RequestParam("zipcode") String zipCode) {
            try {
                zipcodeService.validate(zipCode);
                return zipCode;
            } catch (ZipCodeValidationException e) {
                return e.getMessage();
            }
        }
    

    建议方式:

    将以下条目添加到pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    

    如下所示创建注释和验证器

    @Constraint(validatedBy = {ZipcodeValidator.class})
        @Target({ElementType.FIELD, ElementType.PARAMETER})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Zipcode {
            String message() default "Invalid Zipcode value";
    
            Class<?>[] groups() default {};
    
            Class<? extends Payload>[] payload() default {};
        }
    
        public static class ZipcodeValidator implements ConstraintValidator<Zipcode, String> {
            private final ZipCodeRegexMatcher zipCodeRegexMatcher;
    
            public ZipcodeValidator() {
                zipCodeRegexMatcher = new ZipCodeRegexMatcher();
            }
    
            @Override
            public boolean isValid(String zipCode, ConstraintValidatorContext constraintValidatorContext) {
                return zipCodeRegexMatcher.isValid(zipCode);
            }
        }
    

    完成此设置后,转到 Controller 类和带注释的类 @Validated 和您希望使用自定义注释进行验证的字段,即我们刚刚创建的 Zipcode。在这种情况下,我们通过扩展 ConstraintValidator 创建一个自定义验证器 ZipcodeValidator。

    调用者是这样的:

        @GetMapping
        public String get(@Zipcode @RequestParam("zipcode") String zipCode) {
            return zipCode;
        }
    

    在验证失败时,它会抛出javax.validation.ConstraintViolationException: get.zipCode: Invalid Zipcode value,您可以根据需要使用ControllerAdvice 进行自定义。

    您也可以在服务级别使用@Zipcode 注释,它的工作方式相同。关于ZipCodeRegexMatcher,您可以创建一个bean并注入该依赖项,而不是在构造函数中创建它。这是一个简单的类,具有zipcode 的正则表达式并执行验证。

    public static class ZipCodeRegexMatcher {
            public static final String ZIP_REGEX = "^[0-9]{5}(?:-[0-9]{4})?$";
            private final Pattern pattern;
    
            public ZipCodeRegexMatcher() {
                pattern = Pattern.compile(ZIP_REGEX);
            }
    
            public boolean isValid(String zipCode) {
                return pattern.matcher(zipCode).matches();
            }
        }
    

    整个代码位于here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多