springMVC的上傳和下載
1. 文件上傳
上傳文件必須將表單的
method
設(shè)置為post
,并且將enctype
設(shè)置為multipart/form-data
。在
springmvc
中實(shí)現(xiàn)文件上傳有兩種方式:1恳不、使用
Apache Commons FileUpload
元件。2疲酌、利用
servlet3.0
及其更高版本的內(nèi)置支持预厌。
-
MultipartFile
常用方法:
返回參數(shù) | 方法 |
---|---|
byte[] getBytes() |
返回文件的內(nèi)容作為一個(gè)字節(jié)數(shù)組。 |
String getContentType() |
返回文件的內(nèi)容類型毡代。 |
InputStream getInputStream() |
返回InputStream讀取文件的內(nèi)容劫拗。 |
String getName() |
返回表單中文件組件的名字间校。 |
String getOriginalFilename() |
返回上傳文件的原名 |
long getSize() |
返回文件的大小,以字節(jié)byte為單位。 |
boolean isEmpty() |
返回是否上傳文件是空的,也就是說,沒有文件 選擇多部分形式或所選的文件中沒有的內(nèi)容页慷。 |
void transferTo(File dest) |
接收到的文件轉(zhuǎn)移到給定的目標(biāo)文件憔足。 |
1.1 配置tomcat虛擬路徑
編輯
server
文件(%tomcathome%\conf\server.xml)
我們打算建立一個(gè)images的虛擬目錄,只要在%tomcathome%\conf\server.xml
文件,在<host>
標(biāo)簽中加入文件中加入如下代碼即可:
<Context debug="0" docBase="D:\APPFile\images" path="/images" reloadable="true"/>
注意酒繁,此時(shí)path一定要寫,因?yàn)槲覀兇藭r(shí)沒有新建xml文件了,所以一定要指明web滓彰。
配置文件屬性的含義:
docBase
為希望將文件存儲(chǔ)到的物理目錄的絕對(duì)路徑。path
為訪問文件時(shí)的虛擬目錄州袒。reloadable
屬性的設(shè)置有些用處揭绑,當(dāng)reloadable=true
時(shí),相關(guān)文件改變,Tomcat先停止webapp
并釋放內(nèi)存,然后重新加載webapp
郎哭。這樣以來可以省去手工部署web app
工程的時(shí)間他匪。和開發(fā)工具一起使用可以稍微提高點(diǎn)工作效菇存。
2.使用 Apache Commons FileUpload
元件上傳
2.1 添加jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2.2 springmvc配置
spring MVC
上下文中沒有裝配multipartResolver
,不能處理文件上傳
bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上傳文件大小上限,單位為字節(jié)(10MB) -->
<property name="maxUploadSize">
<value>10485760</value>
</property>
<!-- 請(qǐng)求的編碼格式邦蜜,必須和jSP的pageEncoding屬性一致依鸥,以便正確讀取表單的內(nèi)容,默認(rèn)為ISO-8859-1 -->
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>
2.3 Controller
@Controller
@RequestMapping(value = "/file")
public class FileUploadController {
@RequestMapping(value = "/{formName}")
public String loginForm(@PathVariable String formName) {
// 動(dòng)態(tài)跳轉(zhuǎn)頁面
return "file/" + formName;
}
// 上傳文件會(huì)自動(dòng)綁定到MultipartFile中
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(HttpServletRequest request, @RequestParam("description") String description,
@RequestParam("file") MultipartFile file) throws Exception {
System.out.println(description);
// 如果文件不為空畦徘,寫入上傳路徑
if (!file.isEmpty()) {
// 上傳文件路徑
// String path = request.getServletContext().getRealPath("/images/");
//圖片服務(wù)器路徑
String path = "D:\\QYAPP\\images\\";
// 上傳文件名 原始文件名
String filename = file.getOriginalFilename();
//創(chuàng)建新文件毕籽,路徑為:圖片服務(wù)器路徑+新文件名
File filepath = new File(path, filename);
// 判斷路徑是否存在抬闯,如果不存在就創(chuàng)建一個(gè)
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
// 將上傳文件保存到一個(gè)目標(biāo)文件當(dāng)中
file.transferTo(new File(path + File.separator + filename));
return "file/" + "success";
} else {
return "file/" + "error";
}
}
}
2.4 jsp
uploadForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上傳</title>
</head>
<body>
<h2>文件上傳</h2>
<form action="upload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="description"></td>
</tr>
<tr>
<td>請(qǐng)選擇文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td><input type="submit" value="上傳"></td>
</tr>
</table>
</form>
</body>
</html>
3. 使用對(duì)象接收上傳文件
3.1 實(shí)體類
public class User implements Serializable{
private String username;
private MultipartFile image;
private String path;
//省略get/set方法
}
3.2 Controller層
@RequestMapping(value="/register")
public String register(HttpServletRequest request,
@ModelAttribute User user,
Model model)throws Exception{
System.out.println(user.getUsername());
// 如果文件不為空井辆,寫入上傳路徑
if(!user.getImage().isEmpty()){
// 上傳文件路徑
//String path = request.getServletContext().getRealPath("/images/");
//圖片服務(wù)器路徑
String path = "D:\\QYAPP\\images\\";
// 上傳文件名
String filename = user.getImage().getOriginalFilename();
File filepath = new File(path,filename);
// 判斷路徑是否存在,如果不存在就創(chuàng)建一個(gè)
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
// 將上傳文件保存到一個(gè)目標(biāo)文件當(dāng)中
user.getImage().transferTo(new File(path+File.separator+ filename));
//虛擬圖片路徑
String imagePath = request.getRequestURL().toString();
imagePath = imagePath.substring(0, getIndexAtStr(imagePath, "/", 3))+"images"+File.separator+ filename;
System.out.println(imagePath);
user.setPath(imagePath);
// 將用戶添加到model
model.addAttribute("user", user);
return "file/" + "userInfo";
}else{
return "file/" + "error";
}
}
/**
* 返回字符出現(xiàn)第num次的位置索引
* @param str 字符串
* @param key 指定字符串
* @param num 在字符串中出現(xiàn)的次數(shù)
* @return
*/
public static int getIndexAtStr(String str,String key,int num){
int count = 0;
int index = 0;
while((index=str.indexOf(key,index))!=-1){
//System.out.println("index="+index);
index = index+key.length();//根據(jù)在字符串中出現(xiàn)的位置溶握,計(jì)數(shù)一次杯缺,下次從該位置后重新查找出現(xiàn)新的位置
count++;
if(count==num) break;//第幾次跳槽循環(huán)
}
//return count;
return index;
}
3.3 jsp
3.3.1 registerForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用戶注冊(cè)</title>
</head>
<body>
<h2>用戶注冊(cè)</h2>
<form action="register" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>用戶名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>請(qǐng)上傳頭像:</td>
<td><input type="file" name="image"></td>
</tr>
<tr>
<td><input type="submit" value="注冊(cè)"></td>
</tr>
</table>
</form>
</body>
</html>
3.3.2 userInfo.jsp
<a href="download?filename=${requestScope.user.image.originalFilename}">
${requestScope.user.image.originalFilename }
</a>
<img alt="${requestScope.user.image.originalFilename }" src="${requestScope.user.path }">
4. Spring MVC 文件下載
頁面給出 超鏈接,
href
的屬性等于下載文件的路徑睡榆,即可下載
springMVC
提供了一個(gè)ResponseEntity
類型萍肆,可以定義返回的HttpHeaders
和HttpStatus
。
4.1 Controller層
@RequestMapping(value="/download")
public ResponseEntity<byte[]> download(HttpServletRequest request,
@RequestParam("filename") String filename,
Model model)throws Exception{
// 下載文件路徑
//String path = request.getServletContext().getRealPath("/images/");
//圖片服務(wù)器路徑
String path = "D:\\QYAPP\\images\\";
File file = new File(path+File.separator+ filename);
HttpHeaders headers = new HttpHeaders();
// 下載顯示的文件名胀屿,解決中文名稱亂碼問題
String downloadFielName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
// 通知瀏覽器以attachment(下載方式)打開圖片
headers.setContentDispositionFormData("attachment", downloadFielName);
// application/octet-stream : 二進(jìn)制流數(shù)據(jù)(最常見的文件下載)塘揣。
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 201 HttpStatus.CREATED
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.CREATED);
}
5. 利用servlet3.0及其更高版本的內(nèi)置支持上傳文件
有了
Servlet3
,就不再需要Commons FileUpload
和Commons IO
元件了宿崭。在servlet3
及以上版本的容器進(jìn)行上傳文件亲铡,處理已上傳文件的Servlets
必須以@MultipartConfig
進(jìn)行標(biāo)注。下列是可能在MultipartConfig
標(biāo)注類型中出現(xiàn)的屬性葡兑,它們都是可選的:
maxFileSize
:上傳問件的最大容量奖蔓,默認(rèn)值為-1,表示沒有限制讹堤。大于指定值的文件將遭到拒絕吆鹤。maxRequestSize
:表示多部分HTTP請(qǐng)求允許的最大容量,默認(rèn)值為-1洲守。location
:表示在part調(diào)用write方法時(shí)疑务,要將已上傳文件保存的磁盤中的位置。fileSizeThreshold
:上傳文件超出這個(gè)容量界限時(shí)梗醇,會(huì)被寫入磁盤暑始。
5.1 配置web.xml
(1)web.xml
Spring MVC
的DispatcherServlet
處理大部分或所有請(qǐng)求,如果要以@MultipartConfig
進(jìn)行標(biāo)注婴削,需要修改源代碼廊镜。這是不可取的,不過唉俗,Servlet3
中有一個(gè)比較容易的方法嗤朴,能使一個(gè)servlet
變成一個(gè)MultipartConfig Servlet
配椭,即給部署描述符(web.xml
)中的servlet
聲明賦值。以下代碼與用@MultipartConfig
給DispatcherServlet
進(jìn)行標(biāo)注的效果一樣雹姊。
<!-- springMVC配置 前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- 用servlet3及其更高版本上傳文件股缸,給DispatcherServlet添加MultipartConfig標(biāo)注 -->
<multipart-config>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
</multipart-config>
</servlet>
5.2 springmvc配置
<!-- 用servlet3及其更高版本上傳文件,使用一個(gè)不同的多部分解析器multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
5.3 Controller層(多圖上傳)
@RequestMapping(value="/multiUpload")
public String multiUpload(HttpServletRequest request, @ModelAttribute User user,//@RequestParam("username") String username,
@RequestParam("files") MultipartFile[] files,
Model model)throws Exception{
/*User user = new User();
user.setUsername(username);*/
List<String> listImagePath=new ArrayList<String>();
/*List<MultipartFile> files = null;
//得到多部分解析器
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
//判斷request是否有文件上傳,即多部分
if(multipartResolver.isMultipart(request)){
//轉(zhuǎn)換為多部分request
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//取得multipartRequest中的所有文件
files = multipartRequest.getFiles("files");
}*/
//虛擬圖片路徑
String imagePath = request.getRequestURL().toString();
imagePath = imagePath.substring(0, getIndexAtStr(imagePath, "/", 3))+"images/";
/** 圖片按類別存儲(chǔ) */
/** 支持多圖片上傳 */
//if(files != null && files.size() > 0){
if(files != null && files.length>0) {
int i = 0;
//圖片服務(wù)器路徑
String file_path = "D:\\QYAPP\\images\\";
String filename = "jpg";
//根據(jù)類別名創(chuàng)建文件夾
File dir = new File(file_path + filename);
if(!dir.exists() || !dir.isDirectory()){
dir.mkdir();
}
for(MultipartFile file : files){
if(file != null && file.getOriginalFilename() != null && file.getOriginalFilename().length()>0){
//原始文件名
String originalFileName = file.getOriginalFilename();
//新文件名吱雏,添加原始文件名后綴
String newFileName = UUID.randomUUID() + originalFileName.substring(originalFileName.lastIndexOf("."));
//創(chuàng)建新文件敦姻,路徑為:圖片服務(wù)器路徑+文件夾名+新文件名
File newFile = new File(file_path + filename + "\\" + newFileName);
//將內(nèi)存中的數(shù)據(jù)寫入磁盤
file.transferTo(newFile);
i++;
listImagePath.add(imagePath+ filename + "\\" + newFileName);
user.setImage(file);
}
}
// 將用戶添加到model
model.addAttribute("listImagePath", listImagePath);
user.setPath(listImagePath.get(0));
model.addAttribute("user", user);
return "file/" + "userInfo";
}else{
return "file/" + "error";
}
}
5.4 jsp
5.4.1 multiUploadForm.jsp
<form action="multiUpload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>請(qǐng)選擇文件:</td>
<td><input type="file" name="files"></td>
<td><input type="file" name="files"></td>
<td><input type="file" name="files"></td>
</tr>
<tr>
<td><input type="submit" value="上傳"></td>
</tr>
</table>
</form>
5.4.2 userInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件下載</title>
</head>
<body>
<h3>文件下載</h3>
<a href="download?filename=${requestScope.user.image.originalFilename}">
${requestScope.user.image.originalFilename }
</a>
<img alt="${requestScope.user.image.originalFilename }" src="${requestScope.user.path }">
<c:forEach items="${listImagePath}" var="image">
<img src="${image}"><br/>
</c:forEach>
</body>
</html>
6.總結(jié):
以上兩種方式,在pojo類和
controller
類以及jsp
中的代碼并無不同歧杏,只是第二種方式需要在web.xml
中對(duì)DispatcherServlet
添加multipart-config
標(biāo)注镰惦,并且兩種方法在springmvc
中配置的多部分解析器的bean不同。其余代碼無需改變犬绒。
- 多圖上傳見 5.3