超級通道 :Spring MVC代碼執行個體系列-緒論
本章主要記錄Spring MVC實作簡單的檔案上傳和下載下傳。涉及到的知識點有:
-
CommonsMultipartResolver
:通用多部件解析器,用來實作多檔案上傳
-
MultipartFile
:多部件檔案,用來傳輸多種類型的檔案
- 兩種檔案儲存方式:1.通過
BufferedOutputStream
寫入伺服器。2.通過MultipartFile封裝的方法寫入。
- 兩種檔案下載下傳方式:通過設定
Content-Disposition
為
inline
和
attachment
試下浏覽器顯示和檔案下載下傳。
1.檔案上傳
1.1.spring-mvc-servlet.xml
添加
CommonsMultipartResolver
,用于解析POST請求中的
MultiPartFile
.
<!--檔案上傳-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--一次上傳限制10Mb(一次可以上傳多種多個檔案)-->
<property name="maxUploadSize" value="10485760"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
1.2.FileUtils.java
兩種上傳方式
1. saveFileByStream通過原生的BufferedOutputStream将将檔案儲存在伺服器
2. saveFileByMultiPartFile通過MultiPartFile.transferTo()将檔案儲存
package pers.hanchao.hespringmvc.file;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
/**
* <p>簡單的檔案上傳和下載下傳執行個體,
* 檔案上傳實作了兩種方式的上傳:流和MultiPartFile;
* 檔案下載下傳實作了兩種方式的下載下傳:inline和attachment</p>
* @author hanchao 2018/1/24 22:35
**/
@Component
@RequestMapping("file")
public class FileUtils {
private static final Logger LOGGER = Logger.getLogger(FileUtils.class);
/**
* <p>上傳檔案的兩種方式:流上傳和Multipart上傳</p>
* @author hanchao 2018/1/22 22:22
**/
@PostMapping("/upload")
public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile[] files,Model model){
boolean isSuccess = true;
//擷取上傳根目錄
String uploadRootPath = request.getServletContext().getRealPath("upload");
LOGGER.debug("uploadRoot:" + uploadRootPath);
File uploadRootDir = new File(uploadRootPath);
//判斷上傳根目錄是否存在,如果不存在,則建立層級目錄
if (!uploadRootDir.exists()){
uploadRootDir.mkdirs();
}
//上傳檔案
List<File> savedFileList = new ArrayList<File>();
for (int i = ; i < files.length; i++) {
MultipartFile file = files[i];
//如果檔案大于200kb,則不能上傳
if (file.getSize() > ){
isSuccess = false;
break;
}
/*
兩種上傳方式
1.saveFileByStream通過原生的BufferedOutputStream将将檔案儲存在伺服器
2.saveFileByMultiPartFile通過MultiPartFile.transferTo()将檔案儲存
*/
File savedFile = saveFileByStream(file, uploadRootDir);
// File savedFile = saveFileByMultiPartFile(file, uploadRootDir);
savedFileList.add(savedFile);
}
if (!isSuccess){
model.addAttribute("returnMessage","檔案太大,禁止上傳!");
LOGGER.error("檔案太大,禁止上傳!");
}else {
model.addAttribute("savedFileList",savedFileList);
}
return "/file/file";
}
/**
* <p>通過流操作儲存檔案</p>
* @param srcFile 需要儲存的檔案
* @param uploadRootDir 上傳檔案根目錄
* @return 上傳完的檔案
* @author hanchao 2018/1/22 22:09
**/
private File saveFileByStream(MultipartFile srcFile, File uploadRootDir) {
//擷取用戶端名稱
String srcFileName = srcFile.getOriginalFilename();
LOGGER.debug("用戶端檔案名稱:" + srcFileName);
File serverFile = null;
if (srcFileName != null && srcFileName.length() > ){
try{
byte[] bytes = srcFile.getBytes();
//建立伺服器檔案
serverFile = new File(uploadRootDir.getAbsolutePath() + File.separator + srcFileName);
//寫入伺服器檔案
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(serverFile));
bos.write(bytes);
bos.close();
//列印上傳了哪些檔案
LOGGER.info("寫入了檔案:" + serverFile);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("删除檔案失敗!");
}
}
return serverFile;
}
/**
* <p>通過MultipartFile的封裝方法儲存檔案</p>
* @param srcFile 需要儲存的檔案
* @param uploadRootDir 上傳檔案根目錄
* @return 上傳完的檔案
* @author hanchao 2018/1/23 22:09
**/
public File saveFileByMultiPartFile(MultipartFile srcFile, File uploadRootDir){
File serverFile = null;
//如果檔案不為空,則可以上傳
if (!srcFile.isEmpty()){
try{
serverFile = new File(uploadRootDir.getAbsolutePath() + File.separator + srcFile.getOriginalFilename());
srcFile.transferTo(serverFile);
//列印上傳了哪些檔案
LOGGER.info("寫入了檔案:" + serverFile);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("删除檔案失敗!");
}
}
return serverFile;
}
}
1.3.file.jsp
注意:
1. 一定要注意設定
enctype="multipart/form-data"
2. 一定要注意
name="file"
要與背景傳參對應,如
@RequestParam("file") MultipartFile[] files
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: hanchao
Date: //
Time: :
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
<title>檔案上傳下載下傳</title>
<style type="text/css">
div {margin: px px;text-align:center; border:px solid #96c2f1; background:#eff7ff;}
</style>
</head>
<body>
<div style="width: 600px;">
<h3>檔案上傳和下載下傳執行個體</h3>
</div>
<div style="width: 290px;height: 180px;float: left;">
<%--一定要注意設定enctype="multipart/form-data"--%>
<form method="post" action="/file/upload" enctype="multipart/form-data">
<label>單個檔案上傳</label><hr/>
<input type="file" name="file"/><hr/>
<input type="submit" value="上傳"/>
</form>
</div>
<div style="width: 290px;height: 180px;float: left">
<%--一定要注意設定enctype="multipart/form-data"--%>
<form method="post" action="/file/upload" enctype="multipart/form-data">
<label>多個檔案上傳</label><hr/>
<%--一定要注意name="file"要與背景傳參對應--%>
<input type="file" name="file"/><br/>
<input type="file" name="file"/><br/>
<input type="file" name="file"/><br/>
<input type="file" name="file"/><br/><hr/>
<input type="submit" value="上傳"/>
</form>
</div>
</body>
</html>
1.4.result
上傳結果:
2.檔案下載下傳
2.1.spring-mvc-servlet.xml
檔案下載下傳并沒有依賴
CommonsMultipartResolver
,無需配置。
2.2.FileUtils.java
設定檔案下載下傳方式:
1. inline:浏覽器内打開此檔案(如txt、xml等),不能打開的再下載下傳(如rar等)
2. attachment:下載下傳檔案到本地
/**
* <p>下載下傳</p>
* @param fileName 檔案名
* @param suffix 檔案字尾
* @param type 下載下傳方式:inline[浏覽器内顯示]、attachment[下載下傳]
* @author hanchao 2018/1/24 22:08
**/
@GetMapping("/download/{name}/{suffix}/{type}")
public void download(HttpServletRequest request,HttpServletResponse response,
@PathVariable("name") String fileName,@PathVariable("suffix") String suffix,
@PathVariable("type") String type, Model model){
//擷取根目錄路徑
File uploadRootDir = new File(request.getServletContext().getRealPath("upload"));
//擷取目标檔案
File file = new File(uploadRootDir.getAbsolutePath() + File.separator + fileName + "." + suffix);
if (!file.exists()){
model.addAttribute("returnMessage","檔案不存在!");
}else{
//擷取檔案類型
String mimeType = URLConnection.guessContentTypeFromName(file.getName());
//如果檔案類型為空,則使用預設檔案類型
if (null == mimeType){
mimeType = "application/octet-stream";
}
LOGGER.debug("mimeType:" + mimeType);
//設定contentType
response.setContentType(mimeType);
/*
設定檔案下載下傳方式:
1.inline:浏覽器内打開此檔案(如txt、xml等),不能打開的再下載下傳(如rar等)
2.attachment:下載下傳檔案到本地
*/
response.setHeader("Content-Disposition",type + ";filename=\"" + file.getName() + "\"");
//設定長度
response.setContentLength((int) file.length());
//下載下傳檔案
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
FileCopyUtils.copy(inputStream,response.getOutputStream());
inputStream.close();
response.getOutputStream().close();
} catch (FileNotFoundException e) {
e.printStackTrace();
LOGGER.error("下載下傳檔案失敗");
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("下載下傳檔案失敗");
} finally {
try {
inputStream.close();
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("下載下傳檔案失敗");
}
}
}
}
2.3.file.jsp
<div style="width: 600px;">
<a href="/file/download/5/jpg/inline">顯示5.jpg</a><hr/>
<a href="/file/download/11/xml/inline">顯示11.xml</a><hr/>
<a href="/file/download/1/txt/inline">顯示1.txt</a><hr/>
<a href="/file/download/5/jpg/attachment">下載下傳5.jpg</a><hr/>
<a href="/file/download/11/xml/attachment">下載下傳11.xml</a><hr/>
<a href="/file/download/1/txt/attachment">下載下傳1.txt</a>
</div>