SpringBoot 如何優(yōu)雅的實(shí)現(xiàn)跨服務(wù)器上傳文件的示例
項(xiàng)目完整代碼鏈接:代碼鏈接
跨服務(wù)上傳文件示意圖
一、創(chuàng)建項(xiàng)目
- springboot:2.2.6
- JDK:1.8
由于資源有限,就用不同端口表示不同服務(wù)器了。
1.1 上傳文件的項(xiàng)目
首先idea快速搭建工具創(chuàng)建一個(gè)springboot項(xiàng)目,名字為fileupload
,作為上傳文件的服務(wù)端。
選擇spring web模塊即可
配置相關(guān)參數(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/
添加坐標(biāo)依賴
跨服器上傳所需要的jar包坐標(biāo)
<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 保存文件服務(wù)器
創(chuàng)建一個(gè)jeex項(xiàng)目,項(xiàng)目名字為fileuploadserver
,什么都不需要配置。然后再webapp目錄下創(chuàng)建一個(gè)uploads
文件夾,與上面項(xiàng)目設(shè)置的文件保存地址一直,然后配置好tomcat環(huán)境啟動(dòng)即可。記得把web.xml文件里面的配置信息刪掉
如下圖所示
記得改下Http和JMX的端口,免得和其他項(xiàng)目沖突了。
二、編寫服務(wù)器接收文件上傳代碼
編寫一個(gè)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("跨服務(wù)器上傳文件上傳"); String filename = upload.getOriginalFilename(); // 把文件的名稱設(shè)置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; // 創(chuàng)建客戶端的對象 Client client = Client.create(); // 和圖片服務(wù)器進(jìn)行連接 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 問題分析
正如上面寫的,只要我們關(guān)聯(lián)了服務(wù)器地址之后就可以直接通過put
方法把文件上傳上去,這無疑是非常危險(xiǎn)的行為。因?yàn)樵谏蟼鬟^程中并沒有進(jìn)行用戶校驗(yàn),那么如果被人知道了服務(wù)器保存圖片的路徑,甚至不需要知道準(zhǔn)確路徑,只要知道服務(wù)器ip地址就夠了,那么他就可以通過put方法無限量的進(jìn)行服務(wù)器上傳。
根據(jù)apache官方在2017公布的一個(gè)漏洞,如果開啟了put方法,那么就可以任意寫寫入文件到服務(wù)器。但是如果禁用了put
方法,那么又有導(dǎo)致一些需要put
方法的業(yè)務(wù)無法使用。
一個(gè)解決辦法就是修改tomcat的配置。修改在tomcat的/conf目錄下的web.xml
。找到下面這段
把readonly
設(shè)置成true。這樣就無法通過put
往服務(wù)器中寫入文件了。
<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ìn)行跨服務(wù)器上傳了,因?yàn)槲募?wù)器已經(jīng)禁止了通過put
方法寫入文件。那么這種情況應(yīng)該怎么辦呢?
有一種思路就是把服務(wù)器接收到的文件上傳請求,通過HttpPost再把上傳的文件信息發(fā)送到文件服務(wù)器。由文件服務(wù)器自己處理是否接收保存文件。
3.2 修改項(xiàng)目fileupload的配置
添加HttpPost的相關(guān)坐標(biāo)依賴
<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 項(xiàng)目
創(chuàng)建一個(gè)springboot項(xiàng)目,選擇如**fileload
**項(xiàng)目一樣。
創(chuàng)建好之后在/resources/
目錄下創(chuàng)建一個(gè)uploads
文件夾,用作保存上傳文件的位置。(也可以根據(jù)自己實(shí)際需要,更改文件保存的位置)
配置相關(guān)參數(shù)
# 文件上傳位置 這里是路徑是相對于項(xiàng)目而言,可以根據(jù)實(shí)際情況更改 file.upload.save-path=/uploads/ #文件訪問路徑 file.upload.url=/uploads/** server.port=8888 #文件大小設(shè)置 spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=30MB spring.servlet.multipart.max-request-size=100MB
3.4 編寫服務(wù)器接收文件上傳代碼
用數(shù)組的形式接收MultipartFile
參數(shù),實(shí)現(xiàn)多文件上傳。
把上傳的文件用MultipartEntityBuilder
打包好之后,再用HttpPost發(fā)送到文件服務(wù)器。這里最好需要了解一些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("跨服務(wù)器上傳文件上傳"); 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 編寫文件服務(wù)器接收代碼
接收的Controller
ResourceUtils.getURL("classpath:")
獲取當(dāng)前項(xiàng)目所在的路徑,最好別存在中文,可能會出錯(cuò)
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 效果展示
到此這篇關(guān)于SpringBoot 如何優(yōu)雅的實(shí)現(xiàn)跨服務(wù)器上傳文件的示例的文章就介紹到這了,更多相關(guān)SpringBoot 跨服務(wù)器上傳文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12淺談System.getenv()和System.getProperty()的區(qū)別
這篇文章主要介紹了System.getenv()和System.getProperty()的區(qū)別,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06解決SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題的幾種方法
本篇文章主要介紹了解決SpringMvc后臺接收json數(shù)據(jù)中文亂碼問題的幾種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Java網(wǎng)絡(luò)編程教程之設(shè)置請求超時(shí)的方法
這篇文章主要給大家介紹了關(guān)于Java網(wǎng)絡(luò)編程教程之設(shè)置請求超時(shí)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12spring boot aop 記錄方法執(zhí)行時(shí)間代碼示例
這篇文章主要介紹了spring boot aop 記錄方法執(zhí)行時(shí)間代碼示例,分享了相關(guān)代碼,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02