spring boot通过Constraint和ConstraintValidator自定义参数校验注解 文件上传前置校验注解 validMessage

本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041806

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S