spring限制上传文件的类型(含代码)

devtools/2024/9/23 0:11:19/

为了安全,有时我们需要限制前端上传文件的类型,这个功能可以结合Spring的拦截器和Hutool的文件类型判断来完成。

我们实现如下功能:

  1. 整个项目默认仅允许一些常见文件类型的上传,比如xlsx等
  2. 如果某个接口有具体要求,还可以在接口级指定该接口额外允许上传的文件类型

首先,我们需要加载hutool包:

            <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><!-- 版本号去官网找最新的就行 --><version>5.8.27</version></dependency>

下面是代码,实现了上面的功能:

java">
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AdditionAllowUploadFileTypes {String[] value() default "";
}
java">
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;/*** 默认支持上传:* 1. 文档类: "xlsx", "xls", "docx", "doc", "pdf", "txt"* 2. 图片/视频类: "jpg", "jpeg", "png", "bmp", "mp4"* 3. 压缩包:zip** @author */
@ConfigurationProperties(prefix = "myservice.filetype")
@Data
public class FileTypeProperties {private static final Logger LOGGER = LoggerFactory.getLogger(FileTypeProperties.class);/*** 默认允许的文件类型** @see cn.hutool.core.io.FileTypeUtil*/private List<String> defaultAllowTypes = Lists.newArrayList("xlsx", "xls", "docx", "doc", "pdf", "txt","jpg", "jpeg", "png", "bmp", "mp4","zip");/*** 自定义支持的扩展类型** @see cn.hutool.core.io.FileTypeUtil*/private List<String> additionalAllowTypes;private Set<String> allowedTypes;@PostConstructpublic void preSetAllowedTypes() {allowedTypes = new HashSet<>();if (CollectionUtil.isNotEmpty(defaultAllowTypes)) {for (String type : defaultAllowTypes) {if (StrUtil.isNotBlank(type)) {allowedTypes.add(type.toLowerCase(Locale.ROOT));}}}if (CollectionUtil.isNotEmpty(additionalAllowTypes)) {for (String type : additionalAllowTypes) {if (StrUtil.isNotBlank(type)) {allowedTypes.add(type.toLowerCase(Locale.ROOT));}}}LOGGER.info("File Allowed Types 初始化完成!");}
}
java">
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpStatus;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;/*** 限制上传文件类型** @author */
public class FileTypeFilter implements HandlerInterceptor {private final FileTypeProperties fileTypeProperties;public FileTypeFilter(FileTypeProperties fileTypeProperties) {this.fileTypeProperties = fileTypeProperties;}@Overridepublic boolean preHandle(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler) throws Exception {if (!(request instanceof MultipartHttpServletRequest)) {return true;}Map<String, MultipartFile> allFiles = ((MultipartHttpServletRequest) request).getFileMap();List<String> notAllowedFiles = getNotAllowedFiles(handler, allFiles);if (CollUtil.isNotEmpty(notAllowedFiles)) {String message = CharSequenceUtil.format("不被允许的文件类型!不被允许的文件列表如下:{}", notAllowedFiles);ServletUtil.write(response, message, MediaType.TEXT_PLAIN_VALUE));return false;}return true;}private List<String> getNotAllowedFiles(Object handler, Map<String, MultipartFile> allFiles) throws IOException {List<String> notAllowedFilenames = null;for (MultipartFile file : allFiles.values()) {if (!isAllowedFile(file, handler)) {if (notAllowedFilenames == null) {notAllowedFilenames = new ArrayList<>();}notAllowedFilenames.add(file.getOriginalFilename());}}return notAllowedFilenames;}boolean isAllowedFile(MultipartFile file, Object handler) throws IOException {String fileName = file.getOriginalFilename();try (InputStream in = file.getInputStream()) {String type = FileTypeUtil.getType(in, fileName);if (StringUtils.isBlank(type)) {// 无法通过文件头或者扩展名识别文件类型。return false;}String extType = FileUtil.extName(fileName);if (StringUtils.isBlank(extType)) {// 后缀读不到类型,直接拒绝return false;}// 文件头类型和后缀类型都要满足白名单if (CollectionUtils.containsAll(fileTypeProperties.getAllowedTypes(),Lists.newArrayList(type.toLowerCase(Locale.ROOT), extType.toLowerCase(Locale.ROOT)))) {return true;}String[] additionAllowUploadFileTypes = getAdditionAllowUploadFileTypes(handler);return Arrays.stream(additionAllowUploadFileTypes).anyMatch(type::equalsIgnoreCase) &&Arrays.stream(additionAllowUploadFileTypes).anyMatch(extType::equalsIgnoreCase);}}private String[] getAdditionAllowUploadFileTypes(Object handle) {String[] res = new String[0];if (!(handle instanceof HandlerMethod)) {return res;}HandlerMethod handlerMethod = (HandlerMethod) handle;if (handlerMethod.hasMethodAnnotation(AdditionAllowUploadFileTypes.class)) {AdditionAllowUploadFileTypes types = handlerMethod.getMethodAnnotation(AdditionAllowUploadFileTypes.class);if (types != null) {String[] allowedTypes = types.value();if (allowedTypes != null) {res = allowedTypes;}}}return res;}
}

使用方法:
项目中可以在application.yaml中指定项目级别额外允许的文件类型,默认允许的类型:"xlsx", "xls", "docx", "doc", "pdf", "txt", "jpg", "jpeg", "png", "bmp", "mp4","zip",可以通过myservice.filetype.default-allow-types变量来覆盖

myservice:filetype: additional-allow-types: - xxx

接口级的可以在接口上使用注解@AdditionAllowUploadFileTypes("xxx")来额外允许指定类型的文件上传。


http://www.ppmy.cn/devtools/39695.html

相关文章

漫谈AI时代的手机

以chatGPT 为代表的大语言的横空出世使人们感受到AI 时代的到来&#xff0c;大语言模型技术的最大特点是机器开始”懂人话“&#xff0c;”说人话“了。如同任何一个革命性工具的出现一样&#xff0c;它必将改变人类生活和工作。 在这里。我谈谈AI时代的手机。 语音通信的历史…

全球化战略中的技术支柱:出海企业的网络技术解决方案

随着全球市场的一体化&#xff0c;中国的电商与游戏行业越来越倾向于扩展国际市场&#xff0c;这一过程被称为“出海”。成功的出海战略不仅需要强大的市场洞察和文化适应能力&#xff0c;还需依赖高效的网络技术&#xff0c;包括SOCKS5代理、代理IP、以及全面的网络安全策略。…

conan2 基础入门(01)-介绍

conan2 基础入门(01)-介绍 文章目录 conan2 基础入门(01)-介绍⭐什么是conan官网Why use Conan? ⭐使用现状版本情况个人知名开源企业 ⭐ConanCenter包中心github ⭐说明文档END ⭐什么是conan 官网 官网&#xff1a;Conan 2.0: C and C Open Source Package Manager 一句话来…

如何在没有备份的情况下恢复 Mac 上丢失的数据

如果您因意外删除、错误格式化硬盘或文件损坏而丢失了重要的、感伤的文件、照片或音乐&#xff0c;那么这可能会令人非常痛苦。幸运的是&#xff0c;您有几个选择。 您的 Mac 位于数字宇宙的中心。您可能会在上面留下照片和视频形式的记忆&#xff0c;以及来自您不再见面的朋友…

如何在Java中使用异常处理机制

如何在Java中使用异常处理机制在Java中&#xff0c;异常处理是一种在程序运行时识别和响应错误情况的机制。它允许程序在出现异常时继续执行&#xff0c;而不是崩溃。Java异常处理机制的核心概念包括try、catch、finally、throw和throws关键字。下面详细介绍这些概念&#xff0…

华为eNSP中型企业局域网网络规划设计(上)

敲半天一个闪退全™给我干没了呜呜呜&#xff0c;eNSP&#xff0c;wcnm&#xff01;wcnm&#xff01;wcnm&#xff01; →b站传送门&#xff0c;感谢大佬← →华为eNSP中型企业局域网网络规划设计&#xff08;下&#xff09;← →拓扑图传送门&#xff0c;可以自己配置着玩←…

重学计算机网络

一、应用层 1. http1.0 与 http2.0 的区别 有两点 1是持久化&#xff0c; 这个持久化并不是磁盘的持久化&#xff0c;而是tcp连接建立的持久化。 HTTP/1.0默认情况下使用短连接&#xff0c;即每个请求/响应都会关闭连接。这意味着每次请求都需要重新建立连接&#xff0c;增…

设计模式——外观模式(Facade)

外观模式&#xff08;Facade Pattern&#xff09; 是一种结构型设计模式&#xff0c;它为一个子系统中的一组接口提供一个统一的高层接口&#xff0c;使得子系统更加容易使用。这种类型的设计模式属于结构型模式&#xff0c;它向客户端提供了一个接口&#xff0c;隐藏了子系统的…