Spring Boot中如何全局配置MultipartFile文件名的默认解码
全局统一处理MultipartFile文件名解码的Spring Boot方案
当然有啦!Spring Boot完全支持全局统一处理MultipartFile文件名的URL解码,这样你就不用在每个控制器或服务里重复写URLDecoder.decode()代码了。下面给你推荐一种从源头解决问题的实现方案:
方案:自定义MultipartResolver实现全局解码
这个方案的核心是替换Spring Boot默认的Multipart解析器,在解析文件的时候自动对文件名进行解码,后续所有地方拿到的MultipartFile都直接返回解码后的文件名。
1. 编写MultipartFile包装类
创建一个包装类,重写getOriginalFilename()方法,自动完成URL解码:
import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.file.Path; public class DecodedFilenameMultipartFile implements MultipartFile { private final MultipartFile delegate; public DecodedFilenameMultipartFile(MultipartFile delegate) { this.delegate = delegate; } @Override public String getOriginalFilename() { String encodedName = delegate.getOriginalFilename(); if (encodedName == null) { return null; } // 自动解码文件名,使用UTF-8编码(可根据实际场景调整) return URLDecoder.decode(encodedName, StandardCharsets.UTF_8); } // 以下方法直接委托给原始MultipartFile对象,无需修改 @Override public String getName() { return delegate.getName(); } @Override public String getContentType() { return delegate.getContentType(); } @Override public boolean isEmpty() { return delegate.isEmpty(); } @Override public long getSize() { return delegate.getSize(); } @Override public byte[] getBytes() throws IOException { return delegate.getBytes(); } @Override public InputStream getInputStream() throws IOException { return delegate.getInputStream(); } @Override public void transferTo(File dest) throws IOException, IllegalStateException { delegate.transferTo(dest); } @Override public void transferTo(Path dest) throws IOException, IllegalStateException { delegate.transferTo(dest); } }
2. 自定义MultipartResolver解析器
继承Spring默认的StandardServletMultipartResolver,在解析请求时用上面的包装类包装所有MultipartFile:
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.StandardMultipartHttpServletRequest; import org.springframework.web.multipart.StandardServletMultipartResolver; import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class DecodedFilenameMultipartResolver extends StandardServletMultipartResolver { @Override protected StandardMultipartHttpServletRequest newMultipartHttpServletRequest(HttpServletRequest request) { return new DecodedFilenameMultipartHttpServletRequest(request); } private static class DecodedFilenameMultipartHttpServletRequest extends StandardMultipartHttpServletRequest { public DecodedFilenameMultipartHttpServletRequest(HttpServletRequest request) { super(request); } @Override protected void initializeMultipart() { super.initializeMultipart(); // 对所有解析出来的MultipartFile进行包装 Map<String, MultipartFile> decodedFileMap = new HashMap<>(); for (Map.Entry<String, MultipartFile> entry : getFileMap().entrySet()) { decodedFileMap.put(entry.getKey(), new DecodedFilenameMultipartFile(entry.getValue())); } // 更新文件映射为解码后的版本 setMultipartFiles(Collections.unmodifiableMap(decodedFileMap)); } } }
3. 注册自定义解析器为Spring Bean
在配置类中注册这个自定义的MultipartResolver,替换默认的解析器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.MultipartResolver; @Configuration public class MultipartConfig { @Bean(name = "multipartResolver") public MultipartResolver decodedFilenameMultipartResolver() { return new DecodedFilenameMultipartResolver(); } }
效果验证
做完以上配置后,你原来的控制器代码完全不需要修改:
@PostMapping(consumes = MULTIPART_FORM_DATA_VALUE) public void upload(@RequestParam(value = FILES_KEY, required = false) MultipartFile multipartFile) { // 这里直接拿到的就是解码后的文件名,比如"测试 文件.txt"而不是"测试%20文件.txt" System.out.println(multipartFile.getOriginalFilename()); }
注意事项
- 解码时使用的编码(这里是UTF-8)要和前端上传时的编码保持一致,避免出现乱码;
- 如果你的项目中已经有自定义的MultipartResolver,只需要把包装文件的逻辑整合进去即可。
内容的提问来源于stack exchange,提问作者Robert Strauch
相关产品推荐
相关产品推荐

