文件上傳功能在網頁中見的太多了,比如上傳照片作為頭像、上傳Excel文檔導入數據等
先寫個上傳文件的html
<!DOCTYPE html>
<html>
<head>
<title>Spring MVC文件上傳與下載</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form action="upload" method="POST" enctype="multipart/form-data"> <!-- 上傳文件注意enctype -->
文件描述:<input type="text" name="desc" /> <br><br>
選擇文件:<input type="file" name="file" /> <br><br>
<input type="submit" value="上傳" />
</form>
</body>
</html>
寫個controller接收上傳的文件
package net.sonng.mvcdemo.controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadController {
@RequestMapping("/upload")
public String upload(HttpServletRequest request,@RequestParam("desc") String desc,@RequestParam("file") MultipartFile file) throws Exception{
//接收到的文件綁定到MultipartFile對象中
System.out.println(desc);
if (!file.isEmpty()){ //如果文件不為空,那么將它存起來
String path=request.getServletContext().getRealPath("/images"); //接收的文件放在/images目錄下,並獲得文件系統目錄
String filename=file.getOriginalFilename();//獲取文件名
File filepath=new File(path,filename); //根據文件所在目錄和文件名創建File對象
if(!filepath.getParentFile().exists()){ //如果所在目錄不存在,那么創建
filepath.getParentFile().mkdirs();
}
file.transferTo(new File(path+File.separator+filename)); //調用transferTo()方法將文件存儲到目標位置
//file.transferTo(filepath) //也可以用這條語句
return "result";
}else{
return "error";
}
}
}
關於multipartFile
常用方法有:
- String getContentType(): 獲取文件的MIME類型
- String getOriginalFilename(): 獲取文件名
- long getSize(): 獲取文件大小,單位KB
- boolean isEmpty(): 文件是否為空
- void transferTo(File dest): 將文件存儲到dest
- String getName(): 獲取表單的參數名
- byte[] getBytes(): 獲取文件數據
- InputStream getInputStream(): 獲取文件流
Spring MVC的文件上傳組件需要MultipartResolver接口,依賴於Apache Commons FileUpload技術實現了一個實現類CommonsMultipartResolver,因此還需要兩方面的工作:1. 引入Apache Commons FileUpload包;2. 配置xml
引入Apache Commons FileUpload及其依賴的Commons IO
配置xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize"> <!-- 還可以限制上傳文件的大小 -->
<value>10485760</value>
</property>
<property name="defaultEncoding" > <!-- 注意這個編碼格式,要跟上傳的頁面的編碼一致 -->
<value>UTF-8</value>
</property>
</bean>
部署訪問,檢查Tomcat的該app目錄下的/images目錄下是否有上傳的文件。
將上傳的文件以對象屬性的形式保存
比如頭像,總是屬於某個用戶,因此在用戶類中可以定義一個MultipartFile屬性存儲用戶頭像
上傳用戶頭像的html
<!DOCTYPE html>
<html>
<head>
<title>Spring MVC文件上傳與下載</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form action="upload" method="POST" enctype="multipart/form-data">
用戶名:<input type="text" name="username" /> <br><br>
選擇圖片:<input type="file" name="avatar" /> <br><br>
<input type="submit" value="上傳" />
</form>
</body>
</html>
實體類user:
package net.sonng.mvcdemo.entity;
import org.springframework.web.multipart.MultipartFile;
public class User {
private String username;
private MultipartFile avatar; //上傳的頭像作為User的一個屬性
//。。。。。
}
寫controller:
package net.sonng.mvcdemo.controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import net.sonng.mvcdemo.entity.User;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UploadController {
@RequestMapping("/upload")
public String upload(HttpServletRequest request,@ModelAttribute User user,Model model) throws Exception{
if (!user.getAvatar().isEmpty()){
String path=request.getServletContext().getRealPath("/avatars/");
String filename=user.getAvatar().getOriginalFilename();
File filepath=new File(path,filename);
if(!filepath.getParentFile().exists()){
filepath.getParentFile().mkdirs();
}
user.getAvatar().transferTo(new File(path+File.separator+filename));
model.addAttribute("user", user);
return "result";
}else{
return "error";
}
}
@RequestMapping("/download") //上傳了之后再下載
public ResponseEntity<byte[]> download(HttpServletRequest request,@RequestParam("filename") String filename,Model model)throws Exception{
String path=request.getServletContext().getRealPath("/avatars/"); //獲取文件所在路徑
filename=new String(filename.getBytes("ISO-8859-1"),"UTF-8"); //不知何故,result.jsp的請求參數是ISO-8859-1編碼的,但明明設置了charset=utf-8
File file=new File(path+File.separator+filename);
HttpHeaders headers=new HttpHeaders();
String downloadFileName=new String(filename.getBytes("UTF-8"),"ISO-8859-1"); //少了這句,可能導致下載中文文件名的文檔,只有后綴名的情況
headers.setContentDispositionFormData("attachment", downloadFileName);//告知瀏覽器以下載方式打開
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);//設置MIME類型
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);//
//用FileUpload組件的FileUtils讀取文件,並構建成ResponseEntity<byte[]>返回給瀏覽器
//HttpStatus.CREATED是HTTP的狀態碼201
}
}
上傳成功后,返回頁面result.jsp,
<%@page pageEncoding="utf-8"
contentType="text/html;charset=utf-8" %>
<html>
<head>
<title>文件的上傳與下載</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p>下載剛才上傳的文件</p>
<a href="download?filename=${user.avatar.originalFilename }">下載文件</a>
</body>
</html>
部署測試,分別測試中文/英文文件名
總結
上傳文件:上傳的文件綁定到MultipartFile中;獲取文件名;要存儲的文件系統路徑;創建目錄;用MultipartFile的transferTo()存儲
下載文件:獲取要下載的文件名,注意編碼;在HttpHeaders中設置以下載方式打開,設置MIME類型;用FileUtils.readFileToByteArray()讀取文件數據;用ResponseEntity<byte[]>構建返回對象