Введение
В работе по внутренней разработке Java некоторые проверки часто выполняются для параметров, переданных из внешнего интерфейса.В бизнесе возникает исключение или информация о проверке, когда исключение постоянно возвращается.Он полон кодов проверки, таких как как будто-иначе.Довольно многословно в коде. Например, когда пользователь регистрируется, он проверяет правильность формата мобильного телефона, длину имени пользователя и т. д. Хотя внешний интерфейс также может выполнять проверку параметров, чтобы обеспечить надежность нашего API-интерфейса и правильность конечного хранения данных, проверку параметров внутреннего интерфейса нельзя игнорировать.Hibernate Validator
Предоставляет унифицированный и удобный способ быстрой реализации проверки параметров.
Hibernate Validator
Используйте аннотации для реализации декларативной проверки. С точки зрения принципа реализации, он также основан на перехвате Spring AOP для реализации операций, связанных с проверкой.javax.validation.constraints
В пакете определен ряд аннотаций ограничений. Некоторые часто используемые аннотации будут размещены в конце статьи.
Если фреймворком проекта является SpringBoot, вspring-boot-starter-web
уже включены вHibernate-validator
зависимости (Версия ).
2.3
в будущих версияхspring-boot-starter-web
Эта зависимость была удалена и должна быть введена вручнуюHibernate-validator
полагаться. Эта статья была обновлена до2.3.3
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Полный код загружен на GitHub:GitHub.com/night777/val…
RequestBody
проверка параметров
1. Создайте класс сущностей
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
/**
* 用户ID
*/
@NotNull(message = "用户id不能为空")
private Long userId;
/**
* 用户名
*/
@NotBlank(message = "用户名不能为空")
@Length(max = 20, message = "用户名不能超过10个字符")
@Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户名限制:最多10字符,包含文字、字母和数字")
private String username;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
private String password;
/**
* 手机号
*/
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
private String mobile;
/**
* 性别
*/
@NotNull(message = "性别不能为空")
private Integer sex;
/**
* 年龄
*/
@NotNull(message = "年龄不能为空")
@Min(value = 1, message = "年龄最小为1岁")
@Max(value = 120, message = "年龄最大为120岁")
private Integer age;
/**
* 邮箱
*/
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式错误")
private String email;
}
2. Создайте контроллер
import com.yese.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class UserController {
/**
* controller方法的入参里面在实体类前面加上@Validated
*/
@PostMapping("/user")
public void add(@RequestBody @Validated User user) {
log.info("user====={}", user);
}
}
3. Создайте глобальный обработчик исключений
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* post方式提交json数据,参数校验失败后,会抛出一个MethodArgumentNotValidException
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
// 获取所有的错误
// List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
// 获取错误提示
// System.out.println(fieldErrors.get(0).getDefaultMessage());
// 获取错误字段
// System.out.println(fieldErrors.get(0).getField());
// 将所有的错误提示使用";"拼接起来并返回
StringJoiner sj = new StringJoiner(";");
e.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getDefaultMessage()));
// 此处通常定义一个全局相应对象返回
Map<String, Object> map = new HashMap<>();
// 此处状态码可以通过枚举或者常量定义
map.put("code", 1001);
map.put("msg", sj.toString());
return map;
}
/**
* get方式提交参数,参数校验失败后,会抛出一个ConstraintViolationException
*/
@ExceptionHandler(ConstraintViolationException.class)
public Map<String, Object> handleConstraintViolationException(ConstraintViolationException e) {
StringJoiner sj = new StringJoiner(";");
e.getConstraintViolations().forEach(x -> sj.add(x.getMessage()));
Map<String, Object> map = new HashMap<>();
map.put("code", 1001);
map.put("msg", sj.toString());
return map;
}
}
4. Тест
Эффект ожидаемый!
RequestParam/PathVariable
проверка параметров
/**
* 入参校验时,Controller上面要加:@Validated
* @RequestParam方式绑定参数
*/
@GetMapping("/get1")
public void get1(@RequestParam("id") @NotNull(message = "id不能为空") Integer id,
@RequestParam("name") @NotBlank(message = "name不能为空") @Length(max = 10, message = "用户名不能超过10个字符") String name) {
log.info("id:{},name:{}", id, name);
}
/**
* @PathVariable方式绑定参数
*/
@GetMapping("/get2/{id}")
public void get2(@PathVariable("id") @Min(value = 0, message = "id最小为0") Integer id) {
log.info("id:{}", id);
}
@Действительный и @Проверенный
В большинстве случаев мы можем использовать аннотацию @Validated.
В случае вложенной проверки мы используем аннотацию @Valid для добавления к свойству члена. Ссылаться на:
public class Dog {
@NotBlank(message = "狗的名字不能为空")
private String name;
}
public class User {
// 省略其他。。。
// 用于嵌套校验
@Valid
private Dog dog;
}
Централизованное определение оперативной информации
Создайте новый в каталоге ресурсовValidationMessages.properties
файл со следующим содержимым:
id.NotNull=id不能为空
username.NotBlank=用户名不能为空
username.length=用户名不能超过10个字符
username.invalid=用户名限制:最多10字符,包含文字、字母和数字
password.NotBlank=密码不能为空
phone.NotBlank=手机号不能为空
phone.invalid=手机号格式不合法
sex.NotNull=性别不能为空
age.NotNull=年龄不能为空
age.min=年龄最小为1岁
age.max=年龄最大为120岁
email.NotBlank=邮箱不能为空
email.invalid=邮箱格式不合法
dogName.NotBlank=狗的名字不能为空
Измените текст исходной аннотации проверки, используя заполнители.{key}
способ получитьValidationMessages.properties
Текстовое содержимое, определенное в . Чтобы определить другую информацию о приглашении в будущем, вам нужно только централизованно определить ее в свойствах, и ее можно будет использовать повторно. Ссылка выглядит следующим образом:
Проверка пакетов
Когда один и тот же объект должен использоваться повторно, например, пользователю необходимо проверить идентификатор пользователя при обновлении, но не нужно проверять идентификатор пользователя при добавлении, а другие параметры необходимо проверять в обоих случаях, поэтому используйтеgroups
функция.
Определите два интерфейса:
import javax.validation.groups.Default;
/**
* 用于新增时的分组校验
*/
public interface Insert extends Default {
}
import javax.validation.groups.Default;
/**
* 用于更新时的分组校验
*/
public interface Update extends Default {
}
Измените сущность, если остальные параметры нужно проверить, группы также можно не добавлять.
public class User {
/**
* 用户ID
*/
@NotNull(message = "{id.NotNull}", groups = {Update.class})
private Long userId;
/**
* 用户名
*/
@NotBlank(message = "{username.NotBlank}", groups = {Insert.class, Update.class})
@Length(max = 10, message = "{username.length}")
@Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "{username.invalid}")
private String username;
}
Массив groups представляет эффективный диапазон. Изменить метод контроллера
@PostMapping("/user")
public void add(@RequestBody @Validated(Insert.class) User user) {
log.info("user====={}", user);
}
@Validated(Insert.class)
Указывает, что проверка проверяет только то, что группы содержат параметры Insert.class. То есть в текущем случае userId не проверяется. Оба случая проверяются, если другие параметры объекта не имеют явно определенных групп.
При добавлении id не проверяется, а эффект следующий:
Если изменить на@Validated(Update.class)
При обновлении проверяется id, и эффект следующий:
Пользовательские аннотации проверки
1. Аннотации пользовательских ограничений
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UsernameValidator.class)
public @interface Username {
// 默认错误消息
String message() default "用户名不合法";
// 分组
Class<?>[] groups() default {};
// 负载
Class<? extends Payload>[] payload() default {};
}
2. ОсознайтеConstraintValidator
Валидатор ограничения записи интерфейса
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 自定义用户名验证规则
* 用户名需要以abc开头
*/
public class UsernameValidator implements ConstraintValidator<Username, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 不为null才进行校验
if (value != null) {
return value.startsWith("abc");
}
return true;
}
}
3. Используйте
@NotBlank(message = "name不能为空")
@Username(message = "name需要以abc开头")
private String name;
С общими нотами
javax.validation.constraints
под пакетом
аннотация | Проверенный тип данных | иллюстрировать |
---|---|---|
@Null | любой тип | Значение элемента аннотации проверки должно быть нулевым. |
@NotNull | любой тип | Убедитесь, что значение элемента аннотации не равно нулю |
@NotBlank | нить | Убедитесь, что значение элемента аннотации не равно нулю (не равно нулю, длина больше 0 после удаления первого пробела) |
@NotEmpty | Подтип CharSequence, Коллекция, Карта, Массив | Убедитесь, что значение элемента аннотации не равно нулю и не пусто (длина строки не равна 0, размер коллекции не равен 0). |
@Мин(значение=значение) | Числовой тип | Убедитесь, что значение элемента аннотации больше или равно значению, заданному параметром @Min. |
@Макс (значение = значение) | То же, что спросил @Min | Убедитесь, что значение элемента аннотации меньше или равно значению, указанному @Max. |
@DecimalMin (значение = значение) | То же, что спросил @Min | Убедитесь, что значение элемента аннотации больше или равно значению, указанному @DecimalMin |
@DecimalMax (значение = значение) | То же, что спросил @Min | Убедитесь, что значение элемента аннотации меньше или равно значению, указанному @DecimalMax. |
@Digits(целое=целые цифры, дробь=десятичные цифры) | То же, что спросил @Min | Подтвердите максимальное количество целых и десятичных знаков для значения элемента аннотации. |
@Size(мин=нижний предел, максимум=верхний предел) | Строка, коллекция, карта, массив и т. д. | Убедитесь, что значение элемента аннотации находится в пределах указанного интервала минимума и максимума (включительно), например длина символа, заданный размер |
@Positive | Оценка положительных чисел | |
@PositiveOrZero | Определение положительных чисел или 0 . | |
@Negative | Оцените отрицательные числа. | |
@NegativeOrZero | Определение отрицательных чисел или 0 . | |
@Past | тип даты | Убедитесь, что значение элемента аннотации (тип даты) предшествует текущему времени. |
@Future | То же, что и @Past запрос | Убедитесь, что значение элемента аннотации (тип даты) позже текущего времени. |
@AssertFalse | Boolean | Подтвердите, что значение элемента аннотации является ложным |
@AssertTrue | Boolean | Убедитесь, что значение элемента аннотации истинно. |
@Range(мин=минимум, максимум=максимум) | Атомарные типы и типы-оболочки, такие как BigDecimal, BigInteger, CharSequence, byte, short, int, long | Убедитесь, что значение элемента аннотации находится между минимальным и максимальным значениями. |
нить | Убедитесь, что значением элемента аннотации является электронная почта, или вы можете указать собственный формат электронной почты с помощью регулярного выражения и флага. | |
@Pattern(regexp=регулярное выражение, flag=шаблон флага) | нить | Убедитесь, что значение элемента аннотации соответствует указанному регулярному выражению. |
@Valid | любой неатомарный тип | Укажите объект, связанный с рекурсивной проверкой. Например, в объекте пользователя есть свойство объекта адреса. Если вы хотите вместе проверять объект адреса при проверке объекта пользователя, добавьте аннотацию @Valid к объекту адреса для каскадной проверки. |
org.hibernate.validator.constraints
В пакете определен ряд аннотаций ограничений. следующим образом:
@Range(min=, max=)
: Аннотированный элемент должен находиться в соответствующей области.
@Length(min=, max=)
: Размер аннотированной строки должен быть в пределах указанного диапазона.
@URL(protocol=,host=,port=,regexp=,flags=)
: Аннотированная строка должна быть допустимым URL-адресом.
@SafeHtml
: определяет, является ли отправленный HTML безопасным. Например, он не может содержать javascript-скрипты и т. д.