<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
/** * 防止文件大於10M時Tomcat鏈接重置 * * @return */ @Bean public TomcatServletWebServerFactory tomcatEmbedded() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> { if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) { ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1); } }); return tomcat; }
# 禁用 thymeleaf 緩存 spring.thymeleaf.cache=false # 是否支持批量上傳 (默認值 true) spring.servlet.multipart.enabled=true # 上傳文件的臨時目錄 (通常狀況下不用特地修改) spring.servlet.multipart.location= # 上傳文件最大爲 1M (默認值 1M 根據自身業務自行控制便可) spring.servlet.multipart.max-file-size=10MB # 上傳請求最大爲 10M(默認值10M 根據自身業務自行控制便可) spring.servlet.multipart.max-request-size=10MB # 文件大小閾值,當大於這個閾值時將寫入到磁盤,不然存在內存中,(默認值0 通常狀況下不用特地修改) spring.servlet.multipart.file-size-threshold=0 # 判斷是否要延遲解析文件(至關於懶加載,通常狀況下不用特地修改) spring.servlet.multipart.resolve-lazily=false file.upload.path: /file/upload
@PostMapping("/upload") public Map<String, String> upload(@RequestParam MultipartFile file) throws IOException { //建立本地文件 File localFile = new File(path, file.getOriginalFilename()); //把傳上來的文件寫到本地文件 file.transferTo(localFile); //返回localFile文件路徑 Map<String, String> path = new HashMap<>(); path.put("path", localFile.getAbsolutePath()); return path; }
這時候系統將會出現FileNotFoundException
,日誌相似下面這樣:java
java.io.FileNotFoundException:C:\Users\cheng\AppData\Local\Temp\tomcat.7543349588424487992.9000\work\Tomcat\localhost\ROOT\file\upload\tmp\file\upload\1558332190813.jpg (系統找不到指定的路徑。)
這是什麼緣由呢?能夠進入transferTo
方法git
@Override public void transferTo(File dest) throws IOException, IllegalStateException { this.part.write(dest.getPath()); if (dest.isAbsolute() && !dest.exists()) { // Servlet 3.0 Part.write is not guaranteed to support absolute file paths: // may translate the given path to a relative location within a temp dir // (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths). // At least we offloaded the file from memory storage; it'll get deleted // from the temp dir eventually in any case. And for our user's purposes, // we can manually copy it to the requested location as a fallback. FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest.toPath())); } }
然後咱們再進入write
方法github
@Override public void write(String fileName) throws IOException { File file = new File(fileName); if (!file.isAbsolute()) { file = new File(location, fileName); } try { fileItem.write(file); } catch (Exception e) { throw new IOException(e); } }
這時候咱們看到若是file.isAbsolute()
成立,也就是咱們沒有使用絕對路徑,那麼file = new File(location,fileName);
會在原來的基礎上加上location路徑.這就是緣由所在,能夠經過修改絕對路徑解決web
在代碼中控制spring
@PostMapping("/upload") public Map<String, String> upload(@RequestParam MultipartFile file) throws IOException { //建立本地文件 String classpath = ResourceUtils.getURL("classpath:").getPath(); File localFile = new File(classpath + path, file.getOriginalFilename()); //把傳上來的文件寫到本地文件 file.transferTo(localFile); //返回localFile文件路徑 Map<String, String> path = new HashMap<>(); path.put("path", localFile.getAbsolutePath()); return path; }
經過ResourceUtils.getURL("classpath:").getPath()
得到項目路徑,而後加上設置的相對路徑。json
網絡上還有一種修改location
值的方式,能夠看 這篇博客可是我我的使用是一直不能夠。緩存
或者能夠不使用transferTo,代碼以下tomcat
@PostMapping("/singleFileUpload") public String singleFileUpload(@RequestParam("file") MultipartFile file) throws IOException { byte[] bytes = file.getBytes(); Path filePath = Paths.get(path + file.getOriginalFilename()); Files.write(filePath, bytes); return file.getOriginalFilename(); }
Paths.get
所使用的也是絕對路徑,若是您在Windows機器上使用了這種路徑(從/開始的路徑),那麼路徑將被解釋爲相對於當前驅動器,例如springboot
/file/upload/1.txt
而您的項目位於D盤。那麼這條路徑就會對應這條完整的路徑:網絡
D:\file\upload\1.txt
爲了簡便,如下代碼均是使用絕對路徑。
@PostMapping("/uploads") public Map<String, String> uploads(@RequestParam MultipartFile[] files) throws IOException { StringBuilder sb = new StringBuilder(); Map<String, String> paths = new HashMap<>(); for (MultipartFile file : files) { //建立本地文件 File localFile = new File(path, file.getOriginalFilename()); //把傳上來的文件寫到本地文件 file.transferTo(localFile); sb.append(localFile.getAbsolutePath()).append(","); paths.put(file.getOriginalFilename(), localFile.getAbsolutePath()); } //返回localFile文件路徑 return paths; }
@PostMapping("/uploadsWithForm") public Map<String, String> uploadsWithForm(@RequestParam String tmpString, @RequestParam MultipartFile[] files) throws IOException { StringBuilder sb = new StringBuilder(); Map<String, String> paths = new HashMap<>(); paths.put("tmpString", tmpString); for (MultipartFile file : files) { //建立本地文件 File localFile = new File(path, file.getOriginalFilename()); //把傳上來的文件寫到本地文件 file.transferTo(localFile); sb.append(localFile.getAbsolutePath()).append(","); paths.put(file.getOriginalFilename(), localFile.getAbsolutePath()); } //返回localFile文件路徑 return paths; }
@PostMapping(value = "/uploadsWithJson") public Map<String, String> uploadsWithJson(@RequestPart("files") MultipartFile[] files, @RequestPart("jsonMap") Map<String, Object> jsonMap) throws IOException { StringBuilder sb = new StringBuilder(); Map<String, String> paths = new HashMap<>(); System.out.println(jsonMap); for (MultipartFile file : files) { //建立本地文件 File localFile = new File(path, file.getOriginalFilename()); //把傳上來的文件寫到本地文件 file.transferTo(localFile); sb.append(localFile.getAbsolutePath()).append(","); paths.put(file.getOriginalFilename(), localFile.getAbsolutePath()); } paths.put("jsonMap", JsonUtils.obj2json(jsonMap)); //返回localFile文件路徑 return paths; }
呵呵,很差用對不對。項目拋出了個異常,HttpMediaTypeNotSupportedException
。
WARN o.s.w.s.m.support.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported]
因此咱們須要添加個轉換器類
@Component public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter { /** * Converter for support http request with header Content-Type: multipart/form-data */ public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) { super(objectMapper, MediaType.APPLICATION_OCTET_STREAM); } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return false; } @Override public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) { return false; } @Override protected boolean canWrite(MediaType mediaType) { return false; } }
這樣就可以識別了
感受把springboot文件上傳所能遇到的坑全踩了個變,心累。
若是須要項目代碼,能夠去個人github中下載;具體代碼能夠查看file.upload目錄