本文主要是介绍spring boot通过Constraint和ConstraintValidator自定义参数校验注解 文件上传前置校验注解 validMessage,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Constraint注解
在spring boot进行开发的时候,有时需要对请求的参数进行校验, 而@Constraint可以实现自定义的校验注解。
Spring boot自定义参数校验注解
1. 如果Spring boot是2.3.0之后的版本,需要引入新的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
2. 自定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MultipartFileValidator.class)
public @interface MultipartFileUploadPreCheck {String DEFAULT_MAXSIZE = "-1";/*** AliasFor("endsWith")*/
// FileUtils.Type[] value() default {};/*** 支持的文件后缀类型,默认全部,AliasFor("value")*/FileUtils.Type[] allowFileType() default {};/*** 文件后缀是否区分大小写*/boolean ignoreCase() default true;/*** 上传的文件是否允许为空*/boolean allowEmpty() default false;/*** Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or* kilobytes respectively.<br/>* 默认不限制但必须小于等于SpringMVC中文件上传配置*/String maxSize() default DEFAULT_MAXSIZE;/*** Min file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or* kilobytes respectively. default byte*/String minSize() default "0MB";String message() default "The uploaded file is not verified.";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}
3. FileUtils.Type文件
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)public static enum Type {/*** json*/JSON("json"),/*** JEPG.*/JPEG("FFD8FF"),JPG("FFD8FF"),/*** PNG.*/PNG("89504E47"),/*** GIF.*/GIF("47494638"),/*** TIFF.*/TIFF("49492A00"),/*** Windows Bitmap.*/BMP("424D"),/*** CAD.*/DWG("41433130"),/*** Adobe Photoshop.*/PSD("38425053"),/*** Rich Text Format.*/RTF("7B5C727466"),/*** XML.*/XML("3C3F786D6C"),/*** HTML.*/HTML("68746D6C3E"),/*** CSS.*/CSS("48544D4C207B0D0A0942"),/*** JS.*/JS("696B2E71623D696B2E71"),/*** Email [thorough only].*/EML("44656C69766572792D646174653A"),/*** Outlook Express.*/DBX("CFAD12FEC5FD746F"),/*** Outlook (pst).*/PST("2142444E"),/*** MS Word/Excel.* XLS_DOC:ppt,doc,xls* XLSX_DOCX:xlsx*/XLS("D0CF11E0"), XLSX("504B0304"),DOC("D0CF11E0"), DOCX("504B0304"),/*** Visio*/VSD("d0cf11e0a1b11ae10000"),/*** MS Access.*/MDB("5374616E64617264204A"),/*** WPS文字wps、表格et、演示dps都是一样的*/WPS("d0cf11e0a1b11ae10000"),/*** torrent*/TORRENT("6431303A637265617465"),/*** WordPerfect.*/WPD("FF575043"),/*** Postscript.*/EPS("252150532D41646F6265"),/*** Adobe Acrobat.*/PDF("255044462D312E"),/*** Quicken.*/QDF("AC9EBD8F"),/*** Windows Password.*/PWL("E3828596"),/*** ZIP Archive.*/
// ZIP("504b0304140000000800"),/*** RAR Archive.*/RAR("52617221"),/*** JSP Archive.*/JSP("3C2540207061676520"),/*** JAVA Archive.*/JAVA("7061636B61676520"),/*** CLASS Archive.*/CLASS("CAFEBABE0000002E00"),
// /**
// * JAR Archive.
// */
// JAR("504b03040a0000000000"),/*** MF Archive.*/MF("4D616E69666573742D56"),/*** EXE Archive.*/EXE("4D5A9000030000000400"),/*** CHM Archive.*/CHM("49545346030000006000"),/*** Wave.*/WAV("57415645"),/*** AVI.*/AVI("41564920"),/*** Real Audio.*/RAM("2E7261FD"),/*** Real Media.*/RM("2E524D46"),/*** MPEG (mpg).*/MPG("000001BA"),/*** Quicktime.*/MOV("6D6F6F76"),/*** Windows Media.*/ASF("3026B2758E66CF11"),/*** MIDI.*/MID("4D546864"),/*** MP4.*/MP4("00000020667479706d70"),/*** MP3.*/MP3("49443303000000002176"),/*** FLV.*/FLV("464C5601050000000900"),/*** TXT:txt,docx*/TXT("0000000000000000000000000000");@Getterprivate final String value;private static HashMap<String, Type> codeValueMap = new HashMap<>(47);static {for (FileUtils.Type currentOne : FileUtils.Type.values()) {codeValueMap.put(currentOne.getValue(), currentOne);}}public static FileUtils.Type getInstance(int code) {return codeValueMap.get(code);}public static boolean exists(int code) {return codeValueMap.containsKey(code);}}
3. 编写自定义注解处理文件
public class MultipartFileValidator implements ConstraintValidator<MultipartFileUploadPreCheck, MultipartFile> {@Autowiredprivate MultipartProperties multipartProperties;private long maxSize = -1;private long minSize = 0;private MultipartFileUploadPreCheck multipartFileUploadPreCheck;private final ArrayList<FileUtils.Type> extension = new ArrayList<>();@Overridepublic void initialize(MultipartFileUploadPreCheck constraintAnnotation) {this.multipartFileUploadPreCheck = constraintAnnotation;//支持的文件扩展名集合
// Collections.addAll(extension, multipartFileUploadPreCheck.value());Collections.addAll(extension, multipartFileUploadPreCheck.allowFileType());//文件上传的最大值if (constraintAnnotation.maxSize().equals(MultipartFileUploadPreCheck.DEFAULT_MAXSIZE)) {//默认最大值采用Spring中配置的单文件大小DataSize maxFileSize = multipartProperties.getMaxFileSize();this.maxSize = parseSize(maxFileSize.toString());} else {this.maxSize = parseSize(constraintAnnotation.maxSize());}//文件上传的最小值this.minSize = parseSize(constraintAnnotation.minSize());}private long parseSize(String size) {Assert.hasLength(size, "Size must not be empty");size = size.toUpperCase();long length = Long.parseLong(size.substring(0, size.length() - 2));if (size.endsWith("KB")) {return length * 1024;}if (size.endsWith("MB")) {return length * 1024 * 1024;}return Long.parseLong(size);}/*** 多个文件也可以 效验* @param multipartFiles* @param cvc* @return*/@SneakyThrowspublic boolean isValids(MultipartFile[] multipartFiles, ConstraintValidatorContext cvc) {//上传的文件是空的情况if (Objects.isNull(multipartFiles)) {if (multipartFileUploadPreCheck.allowEmpty()) {return true;}validMessage("上传文件不能为空", cvc);return false;}for (MultipartFile multipartFile : multipartFiles) {boolean valid = isValid(multipartFile, cvc);if (!valid) {return false;}}return true;}@SneakyThrows@Overridepublic boolean isValid(MultipartFile multipartFile, ConstraintValidatorContext cvc) {String fieldName = multipartFile.getName();//上传的文件是空的情况if (multipartFile.isEmpty()) {if (multipartFileUploadPreCheck.allowEmpty()) {return true;}validMessage("上传文件不能为空" + ",参数名:" + fieldName, cvc);return false;}//上传的文件不是空的情况,验证其他条件是否成立//获取文件名,如果上传文件后缀名不区分大小写则统一转成小写String originalFilename = multipartFile.getOriginalFilename();if (multipartFileUploadPreCheck.ignoreCase()) {originalFilename = originalFilename.toLowerCase();}if (StringUtils.isBlank(originalFilename)){validMessage("上传文件名不能为空", cvc);return false;}// 先通过后缀名过滤一部分明显错误的, 因为读取文件流获取文件头信息 比较消耗资源
// String fileSuffixName = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
// List<String> allowedFileSuffixNames = extension.stream().map(e -> e.name().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
// if (StringUtils.isNotBlank(fileSuffixName) && allowedFileSuffixNames.stream().noneMatch(e -> e.equals(fileSuffixName))) {
// validMessage("上传文件类型不符合要求" + ",参数名:" + fieldName, cvc);
// return false;
// }FileUtils.Type type = FileUtils.getType(multipartFile.getInputStream());if (extension.size() > 0 && extension.stream().noneMatch(e -> e.equals(type))) {validMessage("上传文件类型不符合要求" + ",参数名:" + fieldName, cvc);return false;}//上传文件字节数long size = multipartFile.getSize();if (size < this.minSize) {validMessage("上传文件不能小于指定最小值" + ",参数名:" + fieldName, cvc);return false;}if (size > this.maxSize) {validMessage("上传文件不能大于指定最大值" + ",参数名:" + fieldName, cvc);return false;}return true;}private void validMessage(String message, ConstraintValidatorContext cvc) {cvc.disableDefaultConstraintViolation();cvc.buildConstraintViolationWithTemplate(message).addConstraintViolation();}}
这篇关于spring boot通过Constraint和ConstraintValidator自定义参数校验注解 文件上传前置校验注解 validMessage的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!