如何在@InitBinder校验前修改文件名并执行对应代码?
在@InitBinder校验前修改文件名的实现方案
我刚好遇到过类似的场景,要解决这个问题,核心是让文件名格式化逻辑在数据绑定的校验步骤之前执行——毕竟@InitBinder的校验是在参数绑定完成后触发的。这里有两种实用的方案可以参考:
方案一:通过自定义PropertyEditor在绑定阶段处理文件名
我们可以给MultipartFile类型注册一个自定义属性编辑器,让WebDataBinder在绑定请求参数时先修改文件名,再执行校验。
步骤1:编写自定义MultipartFile编辑器
这个编辑器会包装原始的MultipartFile对象,替换成格式化后的文件名:
public class CustomMultipartFileEditor extends PropertyEditorSupport { @Override public void setValue(Object value) { if (value instanceof MultipartFile) { MultipartFile originalFile = (MultipartFile) value; // 这里替换成你的文件名格式化逻辑,比如替换特殊字符 String formattedFileName = originalFile.getOriginalFilename() .replaceAll("[^a-zA-Z0-9._-]", "_"); // 包装MultipartFile,覆盖getOriginalFilename返回格式化后的名称 MultipartFile formattedFile = new MultipartFile() { @Override public String getName() { return originalFile.getName(); } @Override public String getOriginalFilename() { return formattedFileName; } @Override public String getContentType() { return originalFile.getContentType(); } @Override public boolean isEmpty() { return originalFile.isEmpty(); } @Override public long getSize() { return originalFile.getSize(); } @Override public byte[] getBytes() throws IOException { return originalFile.getBytes(); } @Override public InputStream getInputStream() throws IOException { return originalFile.getInputStream(); } @Override public void transferTo(File dest) throws IOException { originalFile.transferTo(dest); } }; super.setValue(formattedFile); } else { super.setValue(value); } } }
步骤2:在@InitBinder中先注册编辑器再设置校验器
修改你的initBinderUploadForm方法,确保编辑器的注册在校验器设置之前:
@InitBinder("uploadFileForm") protected void initBinderUploadForm(WebDataBinder binder) { // 先执行文件名格式化的编辑器 binder.registerCustomEditor(MultipartFile.class, new CustomMultipartFileEditor()); // 再设置校验器,此时校验的是格式化后的文件名 binder.setValidator(fileNameFormatValidator); }
方案二:在表单对象的Setter中处理文件名
如果你的uploadFileForm是自定义的表单DTO,也可以把格式化逻辑放到属性的Setter方法里,这样在数据绑定赋值时就会自动处理文件名:
public class UploadFileForm { private MultipartFile file; public void setFile(MultipartFile file) { if (file != null && !file.isEmpty()) { String formattedFileName = file.getOriginalFilename() .replaceAll("[^a-zA-Z0-9._-]", "_"); // 同样包装MultipartFile返回格式化后的文件名 this.file = new MultipartFile() { @Override public String getName() { return file.getName(); } @Override public String getOriginalFilename() { return formattedFileName; } @Override public String getContentType() { return file.getContentType(); } @Override public boolean isEmpty() { return file.isEmpty(); } @Override public long getSize() { return file.getSize(); } @Override public byte[] getBytes() throws IOException { return file.getBytes(); } @Override public InputStream getInputStream() throws IOException { return file.getInputStream(); } @Override public void transferTo(File dest) throws IOException { file.transferTo(dest); } }; } else { this.file = file; } } public MultipartFile getFile() { return file; } }
这种方式不需要修改@InitBinder的代码,逻辑更内聚在表单对象中,适合简单的格式化场景。
关键注意点
因为标准的MultipartFile实现(比如StandardMultipartFile)都是只读的,无法直接修改原文件名,所以我们必须通过包装类的方式覆盖getOriginalFilename()方法,这样校验器调用该方法时拿到的就是格式化后的文件名了。
内容的提问来源于stack exchange,提问作者Chris Garsonn
相关产品推荐
相关产品推荐

