SpringMVC 中透過 MultipartFile 實現上傳圖片以及瀏覽圖片

前言

配置資源

由於 Spring 的 CommonsMultipartResolver 依賴Apache Commons FileUpload 函式庫,Apache Commons FileUpload 依賴於Apache Commons IO,所以在開始實作前我們必須先將這兩個函式庫匯入專案中。

檢查 web>lib 是否有以下兩個資源:

1
2
commons-fileupload-1.2.2.jar
commons-io-2.1.jar

接著,由於SpringMVC 使用 MultipartFile 來進行檔案上傳,所以我們要在 spring-servlet.xml 配置 MultipartResolve:

1
2
3
4
5
6
7
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 單位bytes-->
<property name="maxUploadSize" value="20971520" /> <!-- 20MB --><!-- 全部檔案最大上上傳大小, -1代表不限制 -->
<property name="maxUploadSizePerFile" value="5242880"/> <!-- 5MB --><!-- 每個檔案最大上傳大小, -1代表不限制 -->
<property name="maxInMemorySize" value="1048576" /> <!-- 1MB --><!-- 檔案上傳最大的暫存記憶體大小,預設為10240 bytes(1KB) -->
<property name="defaultEncoding" value="UTF-8" />
</bean>

若沒有配置會出現以下錯誤:
java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided

程式碼實作 - 上傳圖片

建立資料表

在 SQL Server 中建立存放圖片的資料表(其他資料庫的語法可能不太一樣要注意一下)

1
2
3
4
CREATE TABLE Image(
[id] [nchar](32) NOT NULL PRIMARY KEY,
[data] [varbinary](max) NOT NULL
)

上傳圖片:前端

前端畫面的 form 表單記得需要加上 multipart/form-data,它是屬於 Content-Type 的其中之一,可以避免對字元編碼(Encoding),直接傳送二進位資料到後端。

1
2
3
4
5
6
<form id="form" enctype="multipart/form-data">
<input name="file" type="file" id="image-input" accept="image/jpeg, image/png, image/jpg">
<button type="button" id="form-btn">
上傳圖片
</button>
</form>

這裡我們使用 jQuery AJAX 去向後端發送我們上傳的圖片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$("#form-btn").click(function(){
let formData = new FormData($("#form")[0]);
formData.append("file",$("#form")[0])
$.ajax({
type : 'POST',
url : 'uploadImage',
processData:false,
contentType : false,
data :formData,
success:function(rs){
console.log(rs)
},
error : function(e) {
console.log(e)
}
});
})

上傳圖片:後端

後端使用 MultipartFile 來接收檔案,它包含二進位資料和檔案名稱,接收到檔案後再透過 getInputStream() 轉換成 inputStream。

這裡我們使用 BufferedInputStream 創建了一個輸入流。這是因為 InputStream 是一個抽像類,我們不能直接創建InputStream的物件。

1
2
3
4
5
6
7
@RequestMapping(value="/uploadImage",method=RequestMethod.POST)
@ResponseBody
public String multipartResolver(@RequestParam(value="file") MultipartFile file) {
InputStream stream = new BufferedInputStream(file.getInputStream());
String result = util.uploadImage(stream);
return result;
}

在 Dao 中將剛剛取得到的 inputStream 輸入我們的資料表中。這裡我使用 UUID 建立 id,如果有別的需求也可以自行修改。成功新增後,後端會回傳新增的圖片id,而我們可以在前面的 AJAX success 中接收到它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package dao;

import java.io.InputStream;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

public class UtilDao {
@Autowired
JdbcTemplate jdbcTemplate;

public String uploadImage(InputStream stream) {
try {
String sql = "insert into Image(id,data) OUTPUT INSERTED.ID values(?,?)";
String id = getUUID();
return jdbcTemplate.queryForObject(sql, new Object[] { id, stream }, String.class);
} catch (Exception e) {
System.out.println(e);
return "0";
}
}

public String getUUID() {
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
return uuid;
}
}

程式碼實作 - 瀏覽圖片

瀏覽圖片:前端

前面我們已經成功將圖片存進資料庫,接著就要來嘗試顯示出我們加入的圖片。在前端我們可以透過 GET 加上 URL 中的 id 參數來顯示對應的圖片:http://localhost:8080/專案名稱/getImage?id=???

1
<img src="/getImage?id=baa2d08bd84340faa1b2">

瀏覽圖片:後端

1
2
3
4
5
6
7
8
9
10
11
12
13
@RequestMapping(value="/getImage",method=RequestMethod.GET)
public void getDBImage(@RequestParam(value="id") String id,HttpServletRequest request,HttpServletResponse response) throws IOException {
try {
byte[] data = util.getImage(id);
response.setContentType("image/png"); // 設定為回傳一個 png 檔案
ByteArrayInputStream bis = new ByteArrayInputStream(data);
BufferedImage bImage = ImageIO.read(bis); // //讀取影象到影象緩衝區
ServletOutputStream out = response.getOutputStream(); // 取得 ServletOutputStream 實例
ImageIO.write(bImage, "png", out);
out.close();
}catch(Exception e){
// 錯誤處理
}
1
2
3
4
5
public byte[] getImage(String id) {
String sql = "select data from Image where id =?";
byte[] data = jdbcTemplate.queryForObject(sql, new Object[] { id }, byte[].class);
return data;
}

參考資料

Spring MVC 上傳檔案 java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
https://matthung0807.blogspot.com/2018/03/spring-mvc-javalangillegalstateexceptio.html

HTML:Form表單標籤的Enctype屬性的作用及應用示例介紹
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/544448/

Upload and Download Files with JDBC to SQL Servers
https://www.codeproject.com/Articles/872109/Upload-and-Download-Files-with-JDBC-to-SQL-Servers

使用CommonsMultipartFile获取ajax上传的文件
https://blog.csdn.net/qq_34377830/article/details/88045561

使用ajax,Jquery,Spring Boot,MultipartFile實現檔案上傳功能
https://www.796t.com/content/1547351102.html

JavaWeb(實現文件上傳)(一)
https://www.796t.com/content/1513886170.html


SpringMVC 中透過 MultipartFile 實現上傳圖片以及瀏覽圖片
https://shinyu0430.github.io/2022/05/06/springUploadImage/
作者
Mavis Tsai
發布於
2022年5月6日
許可協議