数据校验JSR303入门实践
1 基础校验
1.引入pom
javax.validation
validation-api
2.0.1.Final
2.在Controller入口处增加@Valid
3.在实体属性上增加校验规则注解 如@NotBlank和 @URL(是hibernate提供的注解,实现了JSR303规范)
3.1使用@URL 需要引入hibernate pom
org.hibernate.validator
hibernate-validator
6.2.0.Final
2 分组校验
1.在Controller入口处替换@Valid为@Validated 并指定分组接口,如@Validated(value = UpdateValidateGroup.class)
2.在实体属性校验规则注解中设置groups参数,指定为分组接口类,如
@NotNull(groups = {UpdateValidateGroup.class}) 更新操作不能为null
@Null(groups = {AddValidateGroup.class}) 新增操作必须为null
3.测试生效
3 自定义校验
1.创建校验组件接口ListValue
2.创建自定义校验器 ListValueValidatorForInteger
3.在组件接口中指定自定义校验器,如@Constraint(validatedBy = {ListValueValidatorForInteger.class})
4.注解到实体属性上 如 @ListValue(value = {0, 1}, message = “仅支持0和1”, groups = AddValidateGroup.class)
5.测试生效
4 上code
4.1 导入POM
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
4.2 定义实体类
import com.iosc.bcmls.bcmlsps1.validate.ListValue;
import com.iosc.bcmls.bcmlsps1.validate.group.AddValidateGroup;
import com.iosc.bcmls.bcmlsps1.validate.group.UpdateValidateGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
@Data
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull(groups = {UpdateValidateGroup.class})
@Null(groups = {AddValidateGroup.class})
private Long brandId;
/**
* 约束name不能为null,且至少有一个非空字符
*/
@NotBlank(message = "品牌名必须提交", groups = {AddValidateGroup.class})
private String name;
/**
* URL是hibernate提供的注解,实现了JSR303规范。约束如果logo不为null的话,必须符合url格式
*/
@NotBlank(message = "logo不能为空")
@URL(message = "logo格式不符")
private String logo;
private String desc;
/**
* 自定义校验组件 ListValue
*
* @Pattern(regexp = "[0-1]")
* pattern不支持Integer
*/
@ListValue(value = {0, 1}, message = "仅支持0和1", groups = AddValidateGroup.class)
private Integer showStatus;
/**
* 使用正则表达式约束字段
*/
@Pattern(regexp = "^[a-zA-Z]$", message = "首字母必须是一个字母")
private String firstLetter;
@Min(value = 0, message = "排序字段必须大于等于0")
private Integer sort;
}
4.3 controller入口类
import com.alibaba.cola.dto.SingleResponse;
import com.iosc.bcmls.bcmlsps1.domain.BrandEntity;
import com.iosc.bcmls.bcmlsps1.validate.group.AddValidateGroup;
import com.iosc.bcmls.bcmlsps1.validate.group.UpdateValidateGroup;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
@RequestMapping("/validate")
public class Jsr303Controller {
/**
* 【基础校验】
* 1.引入pom
* <dependency>
* <groupId>javax.validation</groupId>
* <artifactId>validation-api</artifactId>
* <version>2.0.1.Final</version>
* </dependency>
* 2.在Controller入口处增加@Valid
* 3.在实体属性上增加校验规则注解 如@NotBlank和 @URL(是hibernate提供的注解,实现了JSR303规范)
* 3.1使用@URL 需要引入hibernate pom
* <dependency>
* <groupId>org.hibernate.validator</groupId>
* <artifactId>hibernate-validator</artifactId>
* <version>6.2.0.Final</version>
* </dependency>
*
* 【分组校验】
* 1.在Controller入口处替换@Valid为@Validated 并指定分组接口,如@Validated(value = UpdateValidateGroup.class)
* 2.在实体属性校验规则注解中设置groups参数,指定为分组接口类,如
* @NotNull(groups = {UpdateValidateGroup.class}) 更新操作不能为null
* @Null(groups = {AddValidateGroup.class}) 新增操作必须为null
* 3.测试生效
*
* 【自定义校验组件】
* 1.创建校验组件接口ListValue
* 2.创建自定义校验器 ListValueValidatorForInteger
* 3.在组件接口中指定自定义校验器,如@Constraint(validatedBy = {ListValueValidatorForInteger.class})
* 4.注解到实体属性上 如 @ListValue(value = {0, 1}, message = "仅支持0和1", groups = AddValidateGroup.class)
* 5.测试生效
*
*
* @param brandEntity
* @return
*/
@PostMapping("base")
public SingleResponse base(@RequestBody @Valid BrandEntity brandEntity) {
return SingleResponse.of("base validate ok!");
}
@PostMapping("update")
public SingleResponse update(@RequestBody @Validated(value = UpdateValidateGroup.class) BrandEntity brandEntity) {
return SingleResponse.of("update validate ok!");
}
@PostMapping("add")
public SingleResponse add(@RequestBody @Validated(value = AddValidateGroup.class) BrandEntity brandEntity) {
return SingleResponse.of("add validate ok!");
}
}
4.4 全局异常处理
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.util.NestedServletException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* description: 全局异常处理
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 参数校验异常
*
* @param exception
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Response handleArgumentException(MethodArgumentNotValidException exception) {
BindingResult bindingResult = exception.getBindingResult();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
Map<String, String> map = new HashMap<>();
for (FieldError fieldError : fieldErrors) {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
SingleResponse response = new SingleResponse();
response.setData(map);
response.setCode("10001");
response.setMsg("请求参数不合法");
return response;
}
/**
* 未知异常
*
* @param exception
* @param webRequest
* @return
*/
@ExceptionHandler({Exception.class, NestedServletException.class, IllegalStateException.class})
public Response handleOtherException(Exception exception, WebRequest webRequest) {
log.error("global exception handleOtherException", exception);
return SingleResponse.buildFailure("10000", exception.getMessage());
}
}
4.5 分组校验
public interface AddValidateGroup {
}
public interface UpdateValidateGroup {
}
4.6 自定义校验组件
定义注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ListValueValidatorForInteger.class})
public @interface ListValue {
String message() default "{com.validate.group.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] value() default {};
}
定义校验器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
public class ListValueValidatorForInteger implements ConstraintValidator<ListValue, Integer> {
private HashSet<Integer> set = new HashSet<>();
@Override
public void initialize(ListValue listValue) {
int[] value = listValue.value();
for (int i : value) {
set.add(i);
}
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}