首页 > 解决方案 > Spring MVC 验证和 Thymeleaf - 验证整数字段

问题描述

我正在将 .net 项目移至 Spring Boot。所以问题是如何在 Spring 中正确验证 Integer 字段。我有一个带有整数字段的实体:

@Entity
@Table(name = "tb_employee")
public class EmployeeDev {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "empl_id")
    private int emplId;
        
    @Range(min = 10, max = 50, message="Numbers only between 10 and 50")
    @Column(name = "default_vacation_days", nullable = true)
    private Integer defaultVacationDays;

...和一个捕获错误的控制器:

// update employee
    @PostMapping("/edit")
    public String showFormForUpdate(@Valid @ModelAttribute("employee") EmployeeDev employee, Errors errors,
            RedirectAttributes redirectAttributes,
            Model theModel) {

        if (null != errors && errors.getErrorCount() > 0) {
            
            List<ObjectError> errs = errors.getAllErrors();
            String errMsg = "";
            
            for (ObjectError e :errs)
                errMsg += e.getDefaultMessage();
            
            
            theModel.addAttribute("message", "Employee Edit failed. " + errMsg  );
            theModel.addAttribute("alertClass", "alert-danger");
            return "employeesdev/employee-form-edit";
        }

现在的问题是,当我在默认假期字段中输入超出范围的任何数字时,它会显示正确的验证消息:数字仅在 10 到 50 之间。

但是,如果我尝试插入类似 1A 的内容(可能是用户拼写错误),我会收到以下消息: Failed to convert property value of type java.lang.String to required type java.lang.Integer for property defaultVacationDays; 嵌套异常是 java.lang.NumberFormatException:对于输入字符串:“1A”

我知道这是正确的消息,但我讨厌向用户显示这样的消息。我宁愿只显示“仅在 10 到 50 之间的数字”而不是数据类型转换问题。为什么要用 Java 数据类型打扰用户?

我将不胜感激任何建议。

标签: javaspringvalidationthymeleaf

解决方案


If you want get custom behaviour from the annotation you need to define your own constriant annotation and validator for this annotation.

Here is basic example of custom constraint annotation:

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCalculationTypeValidator.class)
@Documented
public @interface CheckCalculationType {

   String message() default "calculation_type shall be not NULL if status = active";

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

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

and validator:

    public class CheckCalculationTypeValidator implements ConstraintValidator<CheckCalculationType, RequestDto> {

    @Override
    public boolean isValid(RequestDto dto, ConstraintValidatorContext constraintValidatorContext) {
        if (dto == null) {
            return true;
        }
        return !(Status.ACTIVE.equals(dto.getStatus()) && dto.getCalculationType() == null);
    }

    @Override
    public void initialize(CheckCalculationType constraintAnnotation) {
        // NOP
    }
}

Required dependency for Hibernate Validator:

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.2.Final</version>
</dependency>

推荐阅读