为了说明原理,以下提供一个可以上传多个文件的例子,html页面代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>http upload file</title>
</head>
<body><form action="/TestWeb/upload" method="post" enctype="multipart/form-data"><input type="text" name="uploadName1" id="uploadName1"><p /><input type="file" name="fileName1" id="file1"><p /><input type="text" name="uploadName2" id="uploadName2"><p /><input type="file" name="fileName2" id="file2"><p /><input type="submit" value="上传"></form>
</body>
</html>
显示效果如下:
通过点“浏览”选择要上传的文件,并分别输入保存时文件名:
我们使用spring来处理上传的文件,代码如下:
import java.io.IOException;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;@Controller
public class FileUploadController {@PostMapping("/upload")public String handleFormUpload(//@RequestParam("uploadName1") String uploadName1, //@RequestPart("fileName1") MultipartFile file1, //@RequestParam("uploadName2") String uploadName2, //@RequestPart("fileName2") MultipartFile file2) throws IOException {print(file1, uploadName1);System.out.println("+++++++++++++++");print(file2, uploadName2);return "redirect:upload";}private void print(MultipartFile file, String uploadName) throws IOException {String contentType = file.getContentType();String name = file.getName();String originalFilename = file.getOriginalFilename();long size = file.getSize();byte[] bytes = file.getBytes();System.out.println(uploadName);System.out.println(contentType);System.out.println(name);System.out.println(originalFilename);System.out.println(size);System.out.println(bytes.length);}
}
为了能使以上代码正常运行,还要做一些配置。比如,如果使用servlet3.0作为底层处理组件,还需要使用如下代码做配置:
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected void customizeRegistration(ServletRegistration.Dynamic registration) {// Optionally also set maxFileSize, maxRequestSize, fileSizeThresholdregistration.setMultipartConfig(new MultipartConfigElement("/tmp"));}@Overrideprotected Class<?>[] getRootConfigClasses() {return null;}@Overrideprotected Class<?>[] getServletConfigClasses() {return null;}@Overrideprotected String[] getServletMappings() {return null;}
}
点击“上传”,打印日志如下:
report.txt
text/plain
fileName1
report.txt
31
31+++++++++++++++
temp.txt
text/plain
fileName2
temp.txt
284
284
如果使用拦截工具,可以获取到如下上传报文:
POST /TestWeb/upload HTTP/1.1
Host: 127.0.0.1:9090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------38678334721585548371903973726
Content-Length: 951
Origin: http://127.0.0.1:9090
Connection: keep-alive
Referer: http://127.0.0.1:9090/TestWeb/index.html-----------------------------38678334721585548371903973726
Content-Disposition: form-data; name="uploadName1"report.txt
-----------------------------38678334721585548371903973726
Content-Disposition: form-data; name="fileName1"; filename="report.txt"
Content-Type: text/plain工作计划和工作总结
-----------------------------38678334721585548371903973726
Content-Disposition: form-data; name="uploadName2"temp.txt
-----------------------------38678334721585548371903973726
Content-Disposition: form-data; name="fileName2"; filename="temp.txt"
Content-Type: text/plainjava.lang.IncompatibleClassChangeError:Expected non-static field org.springframework.web.reactive.result.method.InvocableHandlerMethod.logger
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.logArgumentErrorIfNecessary(InvocableHandlerMethod.java:207)
-----------------------------38678334721585548371903973726--
通过打印的日志和拦截的报文,结合代码,就可以知道整个上传的处理过程。
以上是通过html页面上传文件,其实也可以不用页面也可以实现html上传,比如使用postman或curl。下面使用cur可以实现与html页面相同的功能:
curl -v http://127.0.0.1:9090/TestWeb/upload
-F "fileName1=@/D/Temp/temp.txt"
-F "uploadName1=temp.txt"
-F "fileName2=@/D/Temp/report.txt"
-F "uploadName2=report.txt"