目录
3.可以在任何位置使用validate校验 rpc或内部service
1. @Valid和@Validated区别
2. 校验方式
- 自定义校验
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EncryptIdValidator.class})
public @interface EncryptId {
// 默认错误消息
String message() default "加密id格式错误";
// 分组
Class<?>[] groups() default {};
// 负载
Class<? extends Payload>[] payload() default {};
}
- 实现ConstraintValidator接口编写约束校验器
public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> {
private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 不为null才进行校验
if (value != null) {
Matcher matcher = PATTERN.matcher(value);
return matcher.find();
}
return true;
}
}
- 编程式校验
@Autowired
private javax.validation.Validator globalValidator;
// 编程式校验
@PostMapping("/saveWithCodingValidate")
public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) {
Set<ConstraintViolation<UserDTO>> validate = globalValidator.validate(userDTO, UserDTO.Save.class);
// 如果校验通过,validate为空;否则,validate包含未校验通过项
if (validate.isEmpty()) {
// 校验通过,才会执行业务逻辑处理
} else {
for (ConstraintViolation<UserDTO> userDTOConstraintViolation : validate) {
// 校验失败,做其它逻辑
System.out.println(userDTOConstraintViolation);
}
}
return Result.ok();
}
3.可以在任何位置使用validate校验 rpc或内部service
实现方式参考上面的编程式校验
定义注解
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
Class<?>[] value() default {};
}
注解切面实现
import cn.hutool.core.util.ArrayUtil;
import com.bjsdzk.backend.rpc.entity.response.ResultCode;
import com.bjsdzk.backend.rpc.entity.response.ResultHandler;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.*;
@Aspect
@Component
public class ValidatedAspect {
@Autowired
private Validator globalValidator;
@Pointcut("@annotation(com.bjsdzk.collector.config.Validated)")
private void pointcut() {
}
@Around(value = "pointcut()&&@annotation(validated)")
private Object aroundMethod(ProceedingJoinPoint point, Validated validated) throws Throwable {
Class<?>[] classArray = validated.value();
Object[] args = point.getArgs();
Set<ConstraintViolation<Object>> validateAll = new HashSet<>();
for (int j = 0; j < args.length; j++) {
Object parms = args[j];
Set<ConstraintViolation<Object>> validate;
if (ArrayUtil.isEmpty(classArray)) {
validateAll.addAll(globalValidator.validate(parms));
} else {
for (int i = 0; i < classArray.length; i++) {
validateAll.addAll(globalValidator.validate(parms));
validateAll.addAll(globalValidator.validate(parms, classArray[i]));
}
}
}
if (validateAll.isEmpty()) {
return point.proceed();
} else {
return ResultHandler.error(ResultCode.VALIDATION, validateAll.stream().map(ConstraintViolation::getMessage).reduce("", StringUtils::join));
}
}
}
参数实体类
@Data
public class DeviceInfo extends BaseDeviceInfo implements Serializable {
@NotNull(message = "companyId不能为空",groups = {AddGroup.class, UpdateGroup.class})
private String companyId;
@NotNull(message = "rangeCode不能为空",groups = {AddGroup.class, UpdateGroup.class})
private String rangeCode;
private String targetDeviceId;
}
使用方法
@Validated(AddGroup.class)
public Result add(DeviceInfo deviceInfo) {
log.info(deviceInfo.toString());
return localDeviceServiceMap.get(deviceInfo.getDtuType().toString()).add(deviceInfo);
}