Введение
JSR-303 — это подспецификация JAVA EE 6, называемая проверкой компонентов.
Всякий раз, когда вы имеете дело с бизнес-логикой приложения, проверка данных — это то, что вы должны учитывать и сталкиваться с этим. Приложение должно иметь средства для обеспечения семантической корректности входящих данных. В обычном случае приложение является многоуровневым, и разные слои создаются разными разработчиками. Много раз одна и та же логика проверки данных будет появляться на разных уровнях, что приведет к избыточности кода и некоторым проблемам управления, таким как семантическая согласованность. Чтобы избежать этой ситуации, лучше всего привязать логику проверки к соответствующей модели предметной области.
Bean Validation определяет соответствующую модель метаданных и API для проверки JavaBean. Метаданные по умолчанию — это аннотации Java, а исходная информация метаданных может быть перезаписана и расширена с помощью XML. В приложении вы можете убедиться в правильности модели данных (JavaBean) с помощью Bean Validation или собственных определенных ограничений, таких как @NotNull, @Max, @ZipCode. Ограничение может быть прикреплено к полю, методу получения, классу или интерфейсу. Для некоторых конкретных требований пользователи могут легко разработать собственные ограничения. Bean Validation — это среда проверки данных во время выполнения, и сообщения об ошибках проверки возвращаются сразу после проверки.
Аннотации ограничений, встроенные в спецификацию Bean Validation
пример
Базовое приложение
импортировать зависимости
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Добавьте аннотации проверки к объектам параметров
@Data
public class User {
private Integer id;
@NotBlank(message = "用户名不能为空")
private String username;
@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
private String password;
@Email
private String email;
private Integer gender;
}
Добавьте @Valid перед параметром Bean, который необходимо проверить в контроллере, чтобы активировать функцию проверки, и добавьте BindingResult сразу после проверяемого Bean.BindingResult инкапсулирует результат проверки предыдущего Bean.
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("")
public Result save (@Valid User user , BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
Map<String , String> map = new HashMap<>();
bindingResult.getFieldErrors().forEach( (item) -> {
String message = item.getDefaultMessage();
String field = item.getField();
map.put( field , message );
} );
return Result.build( 400 , "非法参数 !" , map);
}
return Result.ok();
}
}
Тест выглядит следующим образом:
Унифицированная обработка исключений
В случае сбоя проверки параметра будет создано исключение BingBindException, которое может быть обработано единообразно в унифицированной обработке исключений, поэтому вам не нужно использовать BindingResult для получения результата проверки в каждом месте, где требуется проверка параметра.
@Slf4j
@RestControllerAdvice(basePackages = "com.itwolfed.controller")
public class GlobalExceptionControllerAdvice {
@ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class})
public Result handleVaildException(Exception e){
BindingResult bindingResult = null;
if (e instanceof MethodArgumentNotValidException) {
bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
} else if (e instanceof BindException) {
bindingResult = ((BindException)e).getBindingResult();
}
Map<String,String> errorMap = new HashMap<>(16);
bindingResult.getFieldErrors().forEach((fieldError)->
errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
);
return Result.build(400 , "非法参数 !" , errorMap);
}
}
проверка разрешения группы
Правила проверки для новых сущностей и модификаций разные, например, когда id автоинкрементируется, id должен быть пустым при добавлении и изменении Entity, тогда нужно использовать групповую проверку.
Аннотации проверки имеют атрибут groups, который может группировать аннотации проверки Давайте посмотрим на исходный код @NotNull:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
NotNull[] value();
}
}
Из исходного кода видно, что groups — это массив типа Class>, тогда можно создать файл Groups.
public class Groups {
public interface Add{}
public interface Update{}
}
Добавить группировку в аннотацию проверки объекта параметра
@Data
public class User {
@Null(message = "新增不需要指定id" , groups = Groups.Add.class)
@NotNull(message = "修改需要指定id" , groups = Groups.Update.class)
private Integer id;
@NotBlank(message = "用户名不能为空")
@NotNull
private String username;
@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
private String password;
@Email
private String email;
private Integer gender;
}
Исходный @Valid в контроллере не может указывать группу и должен быть заменен на @Validated.
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("")
public Result save (@Validated(Groups.Add.class) User user) {
return Result.ok();
}
}
Тест выглядит следующим образом:
Пользовательские аннотации проверки
Хотя JSR303 и springboot-validator предоставили множество аннотаций проверки, столкнувшись со сложной проверкой параметров, они все еще не могут удовлетворить наши требования.В настоящее время нам нужно настроить аннотации проверки.
Например, для пола у пользователя используйте 1, чтобы представлять мужчину и 2 для представления женщин. Мы определяем аннотацию проверки @ListValue, а указанные значения могут быть только 1 и 2.
Создание правил ограничения
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
Аннотация определяется с помощью ключевого слова @interface Свойства в этой аннотации объявляются как методы, такие как Стиль, как того требует спецификация Bean Validation API:
- Атрибут сообщения, этот атрибут используется для определения шаблона сообщения по умолчанию, когда ограничение не может быть проверено через Используйте это свойство для вывода сообщений об ошибках.
- Атрибут groups используется для указания, к какой группе (группам) проверки принадлежит это ограничение. Значением по умолчанию для этого должен быть массив типа Class>.
- Свойство полезной нагрузки, которое пользователи Bean Validation API могут использовать для указания уровней серьезности ограничений. Это свойство не используется самим API.
В дополнение к этим трем обязательным свойствам (сообщение, группы и полезная нагрузка) мы добавляем Добавлен атрибут для указания требуемого значения.Имя vals этого атрибута более конкретно в определении аннотации В частности, если назначено только это свойство, то это имя свойства можно игнорировать при использовании этой аннотации.
Кроме того, мы также аннотировали эту аннотацию некоторыми метааннотациями (мета аннотации):
- @Target ({Method, Field, Annotation_Type}): указывает, что эту аннотацию можно использовать в методах, полях или Аннотация заявляет.
- @Retention(RUNTIME): указывает, что информация аннотации считывается посредством отражения во время выполнения.
- @Constraint(validatedBy = ListValueConstraintValidator.class): указывает, какой валидатор (класс) использовать для проверки элементов с помощью этой аннотации.
- @Documented: указывает, что эта аннотация будет добавлена к операции javadoc класса, который использует аннотацию. в джавадоке.
Создайте валидатор ограничений
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
/**
* 初始化方法
*/
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
/**
* 判断是否校验成功
*
* @param value 需要校验的值
* @param context
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
ListValueConstraintValidator определяет два общих параметра: первый — это тип аннотации, которую обслуживает этот валидатор (ListValue в нашем случае), а второй — тип проверяемого элемента (т. е. ListValue в нашем случае — Integer).
Если обозначенное ограничение поддерживает несколько типов проверяемых элементов, то необходимо определить тип каждого из поддерживаемых для ConstraintValidator и зарегистрировать вызов ограничения.
Реализация этого валидатора очень распространена.Метод initialize() передает экземпляр типа аннотации для проверки. В примере мы используем этот экземпляр, чтобы получить значение его свойства vals и сохранить его как коллекцию Set для следующего шага. использовать.
isValid() - это место, где реализуется реальная логика проверки, исходя из того, что данный int является условием ограничения @ListValue. Это законно.
Используйте аннотацию @ListValue для объекта параметра.
@Data
public class User {
@Null(message = "新增不需要指定id" , groups = Groups.Add.class)
@NotNull(message = "修改需要指定id" , groups = Groups.Update.class)
private Integer id;
@NotBlank(message = "用户名不能为空")
@NotNull
private String username;
@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
private String password;
@Email
private String email;
@ListValue( message = "性别应指定相应的值" , vals = {1,2} , groups = {Groups.Add.class , Groups.Update.class})
private Integer gender;
}
Тест выглядит следующим образом:
Адрес источника
GitHub.com/Kung Fu-Change сенсорный экран…
Ссылаться на
Woohoo. IBM.com/developer Я… docs.JBoss.org/hibernate/V…