日照網(wǎng)站建設哪家好看廣告賺錢的平臺
前言
文件上傳和下載是 Web 開發(fā)中的重要環(huán)節(jié),但它們往往不那么容易實現(xiàn)。幸運的是,Spring MVC 提供了一套簡單而又強大的解決方案,讓我們可以專注于業(yè)務邏輯,而不必過多關注底層的文件處理細節(jié)。
在本篇博客中,我們將學習如何利用 Spring MVC 實現(xiàn)文件上傳和下載功能。首先,我們將了解文件上傳的過程以及必要的配置。隨后,我們將介紹如何在控制器中處理上傳的文件,并對其進行存儲或處理。最后,我們將學習如何實現(xiàn)文件下載的功能,使用戶能夠方便地獲取指定的文件。
?一、前期準備
1、新建項目,結構如下
2、導入依賴
<dependencies><!-- springmvc 依賴,會將spring的核心包一并添加進來 --><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version></dependency><!-- 上傳組件 --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency></dependencies>
?使用Apache Commons FileUpload庫的上傳組件,你可以輕松地處理HTTP請求中的文件上傳部分。它提供了一些方便的類和方法,使文件上傳變得簡單和可靠。
?3、配置 web.xml?
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
用于配置 Servlet 的映射和加載。在 Spring MVC 中,它用于配置 DispatcherServlet 的初始化和請求映射。
具體來說,這段配置的作用如下:
- 定義了一個名為 "dispatcher" 的 Servlet,并指定了 org.springframework.web.servlet.DispatcherServlet 作為其處理類。
- 設置了 load-on-startup 屬性為 1,表示在應用啟動時就加載該 Servlet。
- 使用 <servlet-mapping> 元素將 "dispatcher" Servlet 映射到所有的請求路徑上(即 <url-pattern>/</url-pattern>),意味著所有的請求都會經過該 Servlet 進行處理。
?這段配置的作用是將所有的請求交給 DispatcherServlet 處理,并讓它成為應用的核心控制器。DispatcherServlet 將根據(jù)請求的 URL 和其他配置信息,將請求分發(fā)給相應的處理器方法進行處理,然后返回響應結果。
4、編寫 ResultVO 類
@Data
public class ResultVO<T> {private Integer code = HttpStatus.OK.value();private String message;private T data;}
這段代碼定義了一個名為
ResultVO
的泛型類。它使用了Lombok注解@Data
,該注解用于自動生成類的常用方法,如構造函數(shù)、Getter和Setter等。這個
ResultVO
類有以下幾個字段:
code
:表示響應的狀態(tài)碼,默認值為HttpStatus.OK.value()
,即200。message
:表示響應的消息,可以是任意字符串。data
:表示響應的數(shù)據(jù),使用了泛型T
,可以是任意類型。通過使用
@Data
注解,Lombok將會自動生成以下方法:
- 無參構造函數(shù):用于創(chuàng)建
ResultVO
對象。- 全參構造函數(shù):用于根據(jù)提供的參數(shù)創(chuàng)建
ResultVO
對象。- Getter和Setter方法:用于獲取和設置
code
、message
和data
字段的值。equals
和hashCode
方法:用于比較兩個ResultVO
對象的相等性。toString
方法:用于返回ResultVO
對象的字符串表示。通過使用這個通用的
ResultVO
類,你可以在應用程序中統(tǒng)一封裝響應結果,包括狀態(tài)碼、消息和數(shù)據(jù)。它可以幫助你更方便地構建和處理API的響應,并且具有靈活性和可擴展性,適用于各種不同類型的響應數(shù)據(jù)。
5、編寫 ProductVO 類
/*** @Date 2023-10-24* @Author qiu* 商品 VO 對象,用于保存頁面提交的數(shù)據(jù)* 后續(xù)將這個 vo 拷貝到 entity 中*/
@Data
public class ProductVO {/*** 商品名稱*/private String productName;/*** 商品圖片*/private MultipartFile[] file;}
?這段代碼定義了一個名為
ProductVO
的類,用于保存頁面提交的商品數(shù)據(jù)。它使用了Lombok注解@Data
,該注解用于自動生成類的常用方法。
ProductVO
類有以下幾個字段:
productName
:表示商品名稱,使用了private
訪問修飾符,類型為字符串。file
:表示商品圖片,使用了private
訪問修飾符,類型為MultipartFile[]
,即文件數(shù)組。通過使用
@Data
注解,Lombok將會自動生成以下方法:
- 無參構造函數(shù):用于創(chuàng)建
ProductVO
對象。- 全參構造函數(shù):用于根據(jù)提供的參數(shù)創(chuàng)建
ProductVO
對象。- Getter和Setter方法:用于獲取和設置
productName
和file
字段的值。equals
和hashCode
方法:用于比較兩個ProductVO
對象的相等性。toString
方法:用于返回ProductVO
對象的字符串表示。
ProductVO
類主要用于接收前端頁面提交的商品數(shù)據(jù)。在后續(xù)的操作中,可以將這個ProductVO
對象的數(shù)據(jù)拷貝到實體類(entity)中進行進一步處理和持久化。其中,
MultipartFile
是Spring框架提供的一個接口,用于處理文件上傳。MultipartFile[]
表示多個文件的數(shù)組,可以用于接收前端上傳的多個商品圖片文件。通過使用這個
ProductVO
類,你可以方便地接收和保存頁面提交的商品數(shù)據(jù),其中包括商品名稱和商品圖片。這樣可以更好地組織和管理商品相關的信息,并將其傳遞給后續(xù)的業(yè)務邏輯處理。
二、 實現(xiàn)文件上傳
1、文件上傳
@RestController
@Slf4j
public class ProductContoroler {/*** 添加商品,同時帶有上傳的附件* @param productVO* @return*/@PostMapping("/add")public ResultVO add(ProductVO productVO) throws IOException {ResultVO resultVO = new ResultVO();// 獲取上傳的路徑(絕對路徑)String uploadPath = "d://file/";// 拼接完整的上傳路徑
// uploadPath += filename;log.info(uploadPath);// 根據(jù)路徑構建一個上傳的文件對象File uploadFile = new File(uploadPath);// 判斷路徑中的文件夾是否存在,不存在則創(chuàng)建if (!uploadFile.exists()) {// 將文件夾創(chuàng)建出來uploadFile.mkdirs();}// 獲取上傳的文件名MultipartFile[] file = productVO.getFile();for (MultipartFile multipartFile : file) {// 獲取文件名String filename = multipartFile.getOriginalFilename();// 執(zhí)行上傳Path path = FileSystems.getDefault().getPath(uploadFile.getAbsolutePath(),filename);multipartFile.transferTo(path);}return resultVO;}}
add
的方法,使用了@PostMapping("/add")
注解,表示當接收到POST請求時,會調用這個方法來處理。該方法的參數(shù)是一個
ProductVO
對象,用于接收前端提交的商品數(shù)據(jù)。方法內部首先創(chuàng)建了一個
ResultVO
對象,用于封裝響應結果。然后,指定了一個上傳文件的路徑
uploadPath
(這里設置為"d://file/")。接著,通過日志記錄工具
log
,將uploadPath
輸出到日志中,方便查看。在
uploadPath
路徑下創(chuàng)建一個文件夾uploadFile
,如果該文件夾不存在的話。接下來,從
productVO
對象中獲取上傳的商品圖片文件數(shù)組file
。然后,使用循環(huán)遍歷
file
數(shù)組,對每個文件進行處理。對于每個文件,首先獲取其原始文件名
filename
。然后,使用
FileSystems.getDefault().getPath()
方法構建一個文件路徑path
,指定了文件的保存位置。最后,調用
multipartFile.transferTo()
方法將文件保存到指定路徑path
。最后,返回
resultVO
對象作為響應結果。這個
add
方法實現(xiàn)了接收商品信息以及商品圖片的上傳功能。它將商品圖片保存到指定路徑,并返回一個結果對象作為響應。
2、編寫 xml 完成配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 掃描 --><context:component-scan base-package="edu.nf.ch08"/><!-- mvc注解驅動--><mvc:annotation-driven/><!-- 靜態(tài)資源處理器--><mvc:default-servlet-handler/><!-- 裝配上傳附件解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 限制文件上傳的總大小(單位:字節(jié)),不配置此屬性默認不限制 --><property name="maxUploadSize" value="104857600"/><!-- 設置文件上傳的默認編碼--><property name="defaultEncoding" value="utf-8"/></bean></beans>
?在該配置文件中,首先聲明了XML命名空間
xmlns
,以及XML命名空間的映射關系xsi:schemaLocation
。這些聲明用于引入和定義XML模式(XSD)。然后,使用
<context:component-scan>
指定要掃描的基礎包,以便自動注冊Spring的組件。接下來,通過
<mvc:annotation-driven/>
啟用Spring MVC的注解驅動,以支持處理器映射和處理器適配器。使用
<mvc:default-servlet-handler/>
配置靜態(tài)資源處理器,以便將靜態(tài)資源(如CSS、JavaScript等)映射到默認的Servlet上。通過
<bean>
配置上傳附件解析器,這里使用的是CommonsMultipartResolver
,用于處理文件上傳功能??梢酝ㄟ^設置maxUploadSize
屬性限制文件上傳的總大小,并設置defaultEncoding
屬性指定文件上傳的默認編碼。
3、編寫頁面實現(xiàn)上傳
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script>
</head>
<body><form id="f1" enctype="multipart/form-data">Name:<input type="text" name="productName"/><br>Image:<input type="file" name="file" multiple/><br><input type="button" value="提交"/><br></form><script>$(function () {$(':button').on('click',function () {// 構建 formData 對象let formData = new FormData($('#f1')[0]);$.ajax({url:'../add',type:'post',data:formData,processData:false, // 告訴 jquery 不要處理發(fā)送的數(shù)據(jù)類型contentType:false, // 告訴 jquery 不要設置請求頭的 contentTypesuccess:function ( result ) {if ( result.code === 200 ){alert("上傳成功");} else {alert("上傳失敗");}}})})})
</script></body>
</html>
?在頁面中,定義了一個帶有id為"f1"的form元素,使用了
enctype="multipart/form-data"
屬性來支持文件上傳。在表單中,有兩個輸入字段:
- Name:一個文本輸入框,用于輸入商品名稱,其name屬性為"productName"。
- Image:一個文件選擇框,用于選擇商品圖片,其name屬性為"file",并且設置了multiple屬性,表示可以選擇多個圖片文件。
接著,定義了一個JavaScript腳本,在頁面加載完成后執(zhí)行。
腳本中,通過選擇器$(':button')選中所有按鈕元素,并綁定了一個點擊事件處理函數(shù)。當按鈕被點擊時,會執(zhí)行該函數(shù)。
在函數(shù)內部,首先創(chuàng)建一個FormData對象formData,并將表單f1的數(shù)據(jù)添加到formData中。
然后,使用jQuery的ajax方法,發(fā)送一個POST請求到服務器的"../add"路徑。
請求的數(shù)據(jù)為formData,同時設置了processData為false,告訴jQuery不要處理發(fā)送的數(shù)據(jù)類型;contentType也設置為false,告訴jQuery不要設置請求頭的contentType。
在請求成功后的回調函數(shù)中,根據(jù)服務器返回的結果result,判斷上傳是否成功。如果返回的code為200,則彈出上傳成功的提示框;否則,彈出上傳失敗的提示框。
該HTML頁面實現(xiàn)了一個簡單的圖片上傳功能,通過選擇商品名稱和圖片文件,點擊提交按鈕后,將數(shù)據(jù)發(fā)送到服務器進行處理,并根據(jù)返回的結果給出相應的提示。
4、運行效果
1)單個文件
?2)多個文件
?三、實現(xiàn)文件下載
1、文件下載
/*** 文件下載* @param fileName* @return*/@GetMapping("/download/{fileName}")public ResponseEntity<InputStreamResource> download(@PathVariable("fileName") String fileName) throws Exception {// 文件下載目錄(也就是上傳路徑)String downloadPath = "d://file/" + fileName;// 構建一個文件輸入流讀取服務器上的文件FileInputStream fis = new FileInputStream(downloadPath);// 設置響應頭,告訴瀏覽器響應流程HttpHeaders headers = new HttpHeaders();// 對文件名進行編碼,防止響應頭中出現(xiàn)亂碼fileName = URLEncoder.encode(fileName,"UTF-8");// 設置頭信息,將響應內容處理的方式設置為附件下載headers.setContentDispositionFormData("attachment",fileName);// 設置響應類型為流類型headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);// 創(chuàng)建 InputStreamResource 對象封裝輸入流,用于讀取服務器文件InputStreamResource isr = new InputStreamResource(fis);// 創(chuàng)建 ResponseEntity 對象(封裝 InputStreamResource,響應頭,以及響應狀態(tài)碼)ResponseEntity<InputStreamResource> entity = new ResponseEntity<>(isr, headers,HttpStatus.CREATED);return entity;}
這段代碼實現(xiàn)了一個文件下載的功能。具體來說,當訪問URL為"/download/{fileName}"時,該方法會被執(zhí)行。
方法接收一個文件名參數(shù)fileName,并根據(jù)該文件名構建文件下載路徑downloadPath。
然后,通過FileInputStream讀取指定路徑上的文件。
接下來,創(chuàng)建一個HttpHeaders對象,用于設置響應頭信息。
在響應頭中,使用URLEncoder對文件名進行編碼,以防止出現(xiàn)亂碼。
然后,設置響應內容處理方式為附件下載,并將響應類型設置為流類型。
接著,使用InputStreamResource對象封裝文件輸入流,以便于讀取服務器上的文件。
最后,創(chuàng)建一個ResponseEntity對象,將封裝好的InputStreamResource、響應頭和響應狀態(tài)碼封裝到其中,并將其返回給客戶端進行下載。
2、運行效果?
?四、總結
本次案例只是簡單的文件上傳和下載,都是上傳在本地,那可不可以上傳到遠程的服務器上呢?也是可以的,后面會出一個案例講解怎么上傳文件到遠程服務器 minion 上。
五、gitee 案例
地址:ch08 · qiuqiu/SpringMVC - 碼云 - 開源中國 (gitee.com)