基于jsr303 通过自定义注解实现,实现思路:
存在一些瑕疵,后续补充完善。
部分版本已不默认自动引入该依赖,选择手动引入
创建自定义注解以及实现类org.springframework.boot spring-boot-starter-validation
目录结构:
- FileNotEmpty 自定义注解
- FileNotEmptyValidator 单文件校验
- FilesNotEmptyValidator 多文件校验
@documented
@Constraint(
validatedBy = {FileNotEmptyValidator.class, FilesNotEmptyValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FileNotEmpty {
String message() default "文件格式不正确";
Class>[] groups() default {};
Class extends Payload>[] payload() default {};
String[] format() default {};
boolean required() default true;
public class FileNotEmptyValidator implements ConstraintValidator{ private Set formatSet = new HashSet<>(); private boolean required; @Override public void initialize(FileNotEmpty constraintAnnotation) { String[] format = constraintAnnotation.format(); this.formatSet = new HashSet<>(Arrays.asList(format)); this.required = constraintAnnotation.required(); } @Override public boolean isValid(MultipartFile multipartFile, ConstraintValidatorContext constraintValidatorContext) { if (multipartFile == null || multipartFile.isEmpty()) { return !required; } String originalFilename = multipartFile.getOriginalFilename(); assert originalFilename != null; String type = originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase(); if (!formatSet.isEmpty()) { return formatSet.contains(type); } return true; } }
public class FilesNotEmptyValidator implements ConstraintValidator全局异常处理{ private Set formatSet = new HashSet<>(); private boolean required; @Override public void initialize(FileNotEmpty constraintAnnotation) { String[] format = constraintAnnotation.format(); this.formatSet = new HashSet<>(Arrays.asList(format)); this.required = constraintAnnotation.required(); } @Override public boolean isValid(MultipartFile[] multipartFiles, ConstraintValidatorContext constraintValidatorContext) { if (multipartFiles == null || multipartFiles.length == 0) { return !required; } for (MultipartFile file : multipartFiles) { String originalFilename = file.getOriginalFilename(); assert originalFilename != null; String type = originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase(); if (formatSet.isEmpty() || !formatSet.contains(type)) { return false; } } return true; } }
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
logger.error(e.getMessage());
StringBuilder stringBuilder = new StringBuilder();
//jsr303异常
if (e instanceof ConstraintViolationException) {
ConstraintViolationException ex = (ConstraintViolationException)e;
Set> constraintViolations = ex.getConstraintViolations();
for (ConstraintViolation> constraintViolation : constraintViolations) {
stringBuilder.append(constraintViolation.getMessageTemplate());
}
} else if (e instanceof BindException) {
BindException bindException = (BindException)e;
stringBuilder.append(bindException.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(",")));
} else {
stringBuilder.append("未知错误:").append("请联系后台运维人员检查处理!");
}
return ResultUtil.fail(stringBuilder.toString());
}
}
使用示例
@RestController
@Validated
@RequestMapping("/annex")
public class AnnexController {
@Resource
private IAnnexService annexService;
@PostMapping(value = "/upload1")
public Result upload(@Valid AnnexUploadDTO uploadDTO) {
return Boolean.TRUE.equals(annexService.upload(uploadDTO)) ? ResultUtil.success() : ResultUtil.fail();
}
@PostMapping(value = "/upload2")
public Result upload(@NotBlank(@FileNotEmpty(format = {"png", "jpg"}, message = "图片为png/jpg格式", required = false)
MultipartFile pictureFile, @FileNotEmpty(format = {"doc", "docx", "xls", "xlsx"}, message = "附件为doc/docx/xls/xlsx格式", required = false)
MultipartFile annexFile) {
return Boolean.TRUE.equals(annexService.upload( pictureFile, annexFile)) ? ResultUtil.success() : ResultUtil.fail();
}
@Data
static class AnnexUploadDTO{
@FileNotEmpty(format = {"pdf","doc","zip"}, message = "文件为pdf/doc/zip格式")
private MultipartFile[] file;
}
}
结果展示



