SpringBoot 如何優(yōu)雅的實現(xiàn)跨服務器上傳文件的示例
項目完整代碼鏈接:代碼鏈接
跨服務上傳文件示意圖
一、創(chuàng)建項目
- springboot:2.2.6
- JDK:1.8
由于資源有限,就用不同端口表示不同服務器了。
1.1 上傳文件的項目
首先idea快速搭建工具創(chuàng)建一個springboot項目,名字為fileupload
,作為上傳文件的服務端。
選擇spring web模塊即可
配置相關參數(shù)
spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=30MB spring.servlet.multipart.max-request-size=30MB #文件保存的url,末尾的 / 別漏了 file.upload.path=http://localhost:8888/fileuploadserver/uploads/
添加坐標依賴
跨服器上傳所需要的jar包坐標
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.18.1</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency>
1.2 創(chuàng)建fileuploadserver 保存文件服務器
創(chuàng)建一個jeex項目,項目名字為fileuploadserver
,什么都不需要配置。然后再webapp目錄下創(chuàng)建一個uploads
文件夾,與上面項目設置的文件保存地址一直,然后配置好tomcat環(huán)境啟動即可。記得把web.xml文件里面的配置信息刪掉
如下圖所示
記得改下Http和JMX的端口,免得和其他項目沖突了。
二、編寫服務器接收文件上傳代碼
編寫一個controller類,用與處理文件上傳
MultipartFile類用來保存上傳的文件數(shù)據(jù)
package cn.jxj4869.fileupload.controller; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.UUID; @Controller public class FileController { @Value("${file.upload.path}") private String path; @RequestMapping("/fileupload/method1") @ResponseBody private String method1(@RequestParam("upload") MultipartFile upload) throws IOException { System.out.println("跨服務器上傳文件上傳"); String filename = upload.getOriginalFilename(); // 把文件的名稱設置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; // 創(chuàng)建客戶端的對象 Client client = Client.create(); // 和圖片服務器進行連接 WebResource webResource = client.resource(path + filename); webResource.put(upload.getBytes()); return "success"; } }
前端代碼
放在/resources/static/
目錄下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>fileupload</title> </head> <body> <h3>method1</h3> <form method="post" enctype="multipart/form-data" action="fileupload/method1"> <input type="file" name="upload"> <br> <input type="submit"> </form> </body> </html>
上傳效果如下
三、分析存在問題以及解決辦法
3.1 問題分析
正如上面寫的,只要我們關聯(lián)了服務器地址之后就可以直接通過put
方法把文件上傳上去,這無疑是非常危險的行為。因為在上傳過程中并沒有進行用戶校驗,那么如果被人知道了服務器保存圖片的路徑,甚至不需要知道準確路徑,只要知道服務器ip地址就夠了,那么他就可以通過put方法無限量的進行服務器上傳。
根據(jù)apache官方在2017公布的一個漏洞,如果開啟了put方法,那么就可以任意寫寫入文件到服務器。但是如果禁用了put
方法,那么又有導致一些需要put
方法的業(yè)務無法使用。
一個解決辦法就是修改tomcat的配置。修改在tomcat的/conf目錄下的web.xml
。找到下面這段
把readonly
設置成true。這樣就無法通過put
往服務器中寫入文件了。
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>readonly</param-name> <param-value>true</param-value> </init-param> </servlet>
但是這樣一來,我們就無法通過上述方法來進行跨服務器上傳了,因為文件服務器已經(jīng)禁止了通過put
方法寫入文件。那么這種情況應該怎么辦呢?
有一種思路就是把服務器接收到的文件上傳請求,通過HttpPost再把上傳的文件信息發(fā)送到文件服務器。由文件服務器自己處理是否接收保存文件。
3.2 修改項目fileupload的配置
添加HttpPost的相關坐標依賴
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.6</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.1</version> </dependency>
添加配置:
application.properties
file.upload.path1=http://localhost:8888/fileupload/
3.3 創(chuàng)建fileuploadserver1 項目
創(chuàng)建一個springboot項目,選擇如**fileload
**項目一樣。
創(chuàng)建好之后在/resources/
目錄下創(chuàng)建一個uploads
文件夾,用作保存上傳文件的位置。(也可以根據(jù)自己實際需要,更改文件保存的位置)
配置相關參數(shù)
# 文件上傳位置 這里是路徑是相對于項目而言,可以根據(jù)實際情況更改 file.upload.save-path=/uploads/ #文件訪問路徑 file.upload.url=/uploads/** server.port=8888 #文件大小設置 spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=30MB spring.servlet.multipart.max-request-size=100MB
3.4 編寫服務器接收文件上傳代碼
用數(shù)組的形式接收MultipartFile
參數(shù),實現(xiàn)多文件上傳。
把上傳的文件用MultipartEntityBuilder
打包好之后,再用HttpPost發(fā)送到文件服務器。這里最好需要了解一些HttpPost
用法。
package cn.jxj4869.fileupload.controller; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.WebResource; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.UUID; @Controller public class FileController { @Value("${file.upload.path1}") private String path1; @RequestMapping("/fileupload/method2") @ResponseBody private String method2(@RequestParam("upload") MultipartFile[] uploads) throws IOException { System.out.println("跨服務器上傳文件上傳"); CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(path1); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); for (MultipartFile upload : uploads) { String filename = upload.getOriginalFilename(); builder.addBinaryBody("upload", upload.getBytes(), ContentType.MULTIPART_FORM_DATA, filename); } try { HttpEntity entity = builder.build(); httpPost.setEntity(entity); CloseableHttpResponse response = httpClient.execute(httpPost); System.out.println(response.getStatusLine().getStatusCode()); String s = response.getEntity().toString(); System.out.println(s); } catch (Exception e) { } finally { httpClient.close(); } return "success"; } }
前端部分的代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>fileupload</title> </head> <body> <h3>method2</h3> <form method="post" enctype="multipart/form-data" action="fileupload/method2"> <input type="file" name="upload"><br><br> <input type="file" name="upload"><br><br> <input type="file" name="upload"> <br><br> <input type="submit"> </form> </body> </html>
3.5 編寫文件服務器接收代碼
接收的Controller
ResourceUtils.getURL("classpath:")
獲取當前項目所在的路徑,最好別存在中文,可能會出錯
package cn.jxj4869.fileuploadserver1.controller; import com.sun.javafx.scene.shape.PathUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.system.ApplicationHome; import org.springframework.stereotype.Controller; import org.springframework.util.ResourceUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.UUID; @Controller public class FileController { @Value("${file.upload.save-path}") private String savePath; @PostMapping("/fileupload") @ResponseBody private String fileupload(HttpServletRequest request, @RequestParam("upload")MultipartFile[] uploads) throws IOException { System.out.println("文件上傳"); String path= ResourceUtils.getURL("classpath:").getPath()+savePath; File file = new File(path); if (!file.exists()) { file.mkdir(); } for (MultipartFile upload : uploads) { String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replace("-", ""); filename=uuid+"_"+filename; upload.transferTo(new File(path,filename)); } return "success"; } }
編寫配置類
package cn.jxj4869.fileuploadserver1.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.cglib.core.WeakCacheKey; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MySpringMvcConfig implements WebMvcConfigurer { @Value("${file.upload.save-path}") private String savePath; @Value("${file.upload.url}") private String url; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(url).addResourceLocations("classpath:"+savePath); } }
3.6 效果展示
到此這篇關于SpringBoot 如何優(yōu)雅的實現(xiàn)跨服務器上傳文件的示例的文章就介紹到這了,更多相關SpringBoot 跨服務器上傳文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼
這篇文章主要介紹了Mybatis如何傳入多個參數(shù)的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12淺談System.getenv()和System.getProperty()的區(qū)別
這篇文章主要介紹了System.getenv()和System.getProperty()的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06解決SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題的幾種方法
本篇文章主要介紹了解決SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題的幾種方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01spring boot aop 記錄方法執(zhí)行時間代碼示例
這篇文章主要介紹了spring boot aop 記錄方法執(zhí)行時間代碼示例,分享了相關代碼,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02