Spring MVC 文件上傳的示例代碼
一如既往記錄下常用而又容易忘記的東西,本篇博文主要針對Spring MVC是如何上傳文件的。以下記錄兩種上傳方法并針對案例進(jìn)行記錄。(有關(guān)spring mvc其他配置省略)
1、使用Spring MVC 上傳文件必須配置文件解析器,如下:
<!-- 上傳文件攔截,設(shè)置最大上傳文件大小 10M=10*1024*1024(B)=10485760 bytes --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760" /> <property name="maxInMemorySize" value="10240000" /> <property name="defaultEncoding" value="UTF-8" /> </bean>
2、建立上傳文件表單代碼,其中要注意form表單中的enctype 屬性,必須存在且必須為multipart/form-data。還有當(dāng)form中存在button標(biāo)簽時,用ajax異步提交表單后,也面會被刷新。原因:button 存在時會再次提交一下表單,所以頁面被刷新了。
<!--
enctype 屬性值:
1、application/x-www-form-urlencoded 在發(fā)送前編碼所有字符(默認(rèn))
2、multipart/form-data 不對字符編碼。 在使用包含文件上傳控件的表單時,必須使用該值。
3、text/plain 空格轉(zhuǎn)換為 "+" 加號,但不對特殊字符編碼。
-->
<div class="row">
<form method="post" enctype="multipart/form-data" id="form1">
<div><label>1、采用流的方式</label></div>
<div class="col-sm-7" style="padding-left:0px">
<div class="input-group">
<input type="text" class="form-control" id="showFileInput1">
<input type="file" style="display:none" name="txtFile" id="uploadFileInput1" accept="text/plain">
<span class="input-group-addon" id="uploadFileButton1">
<span class="glyphicon glyphicon-folder-open"></span>
<label>瀏覽</label>
</span>
</div>
</div>
<div class="col-sm-5">
<!--
當(dāng)form中存在button標(biāo)簽時,用ajax異步提交表單后,也面會被刷新。(感覺很詭異)
原因:button 存在時會再次提交一下表單,所以頁面被刷新了。(之前認(rèn)為button type='submit' 時)button才有提交表單的功能。
-->
<a class="btn btn-default" id="submit1">上傳</a>
</div>
</form>
</div>
3.1、使用CommonsMultipartFile接收上傳文件,其中要注意的是:方法中CommonsMultipartFile對應(yīng)的變量名如果不是對應(yīng)表單中文件輸入框<input type="file" style="display:none" name="txtFile" id="uploadFileInput1" accept="text/plain">的名稱就必須加上@RequestParam("txtFile") 強(qiáng)制注入。
/**
* @Description: 通過文件流的形式上傳
* @param file @RequestParam("txtFile") 將name=txtFile控件得到的文件封裝成CommonsMultipartFile對象,
* 如果不這樣做會報CommonsMultipartFile沒有初始化的錯誤
* java.lang.NoSuchMethodException: org.springframework.web.multipart.commons.CommonsMultipartFile.<init>()
* @return
* @author yuanfy
* @date 2017年9月15日 下午4:36:11
* @version 6.5
*/
@RequestMapping(value="test/upload1")
@ResponseBody
public String testUpload1(@RequestParam("txtFile")CommonsMultipartFile file){
Long times = System.currentTimeMillis();
if (file == null) {
return null;
}
StringBuilder fileContent = new StringBuilder();
//1、獲取文件信息
FileUtils.getFileInfo(file, fileContent);
//2、上傳文件并獲取文件內(nèi)容
try {
file.transferTo(new File("F:\\text.log"));//另存文件
fileContent.append(FileUtils.getFileContentByLine(file.getInputStream()));
}
catch (IOException e) {
return "獲取文件內(nèi)容失敗";
}
//3、返回文件信息和內(nèi)容
String content = fileContent.toString();
content = content.replace("times", (System.currentTimeMillis()-times) + "ms");
return content;
}
界面效果圖如下:

3.2、使用CommonsMultipartResolver獲取存放文件對象,拿到文件對象后遍歷每個文件上傳及獲取相關(guān)的內(nèi)容。
@RequestMapping(value="test/upload2")
@ResponseBody
public String testUpload2(HttpServletRequest request){
Long times = System.currentTimeMillis();
StringBuilder fileContent = new StringBuilder();
//1.根據(jù)servletContext獲取多文件上傳解析組件
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
if (!multipartResolver.isMultipart(request)) {
return "不是上傳文件表單,請檢查表單屬性";
}
//2.將請求對象轉(zhuǎn)換為多文件請求對象。
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
//3、根據(jù)多文件請求對象獲取文件存放Map
Map<String, MultipartFile> fileMap = multipartHttpServletRequest.getFileMap();
Iterator<Entry<String, MultipartFile>> iterator = fileMap.entrySet().iterator();
//4、迭代文件Map,獲取具體的MultipartFile
while (iterator.hasNext()) {
Entry<String, MultipartFile> entry = iterator.next();
MultipartFile multipartFile = entry.getValue();
//獲取文件頭信息
FileUtils.getFileInfo(multipartFile, fileContent);
try {
//上傳文件
multipartFile.transferTo(new File("F:\\text.log"));
//獲取文件內(nèi)容
fileContent.append(FileUtils.getFileContentByLine(multipartFile.getInputStream()));
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//5、返回文件信息和內(nèi)容
String content = fileContent.toString();
content = content.replace("times", (System.currentTimeMillis()-times) + "ms");
return content;
}
其中第一步獲取文件解析器對象應(yīng)該都清楚只要在容器中配置了對應(yīng)的對象我們就可以獲取到它,而它有根據(jù)上下文獲取的構(gòu)造函數(shù)就方便多了。
/**
* Constructor for standalone usage. Determines the servlet container's
* temporary directory via the given ServletContext.
* @param servletContext the ServletContext to use
*/
public CommonsMultipartResolver(ServletContext servletContext) {
this();
setServletContext(servletContext);
}
然后根據(jù)request判斷是否還有上傳文件的表單,如果不是肯定直接返回,我們看看源碼中是怎么判斷的。
//CommonsMultipartResolver.class 主要判斷request是否為空
@Override
public boolean isMultipart(HttpServletRequest request) {
return (request != null && ServletFileUpload.isMultipartContent(request));
}
//ServletFileUpload 主要判斷是否是post方法,因?yàn)樯蟼魑募仨毷莗ost提交,其實(shí)我們可以在我們自定義controller中的方法指定訪問
public static final boolean isMultipartContent(HttpServletRequest request) {
if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {
return false;
}
return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
}
//FileUploadBase.class 如果請求是MULTIPART 則返回true
public static final boolean isMultipartContent(RequestContext ctx) {
String contentType = ctx.getContentType();//類似:multipart/form-data; boundary=----WebKitFormBoundaryLF3eM94lDB0ocQxT
if (contentType == null) {
return false;
}
if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
return true;
}
return false;
}
所以如果request是上傳文件的請求對象,則進(jìn)行第二步。將request轉(zhuǎn)換成多文件請求對象,然后獲取存放文件的map。
可想而知這種方法效率是比第一種要低的,因?yàn)樗闅v文件map,但是在Spring MVC常用的卻是這種方法。
效果圖如下:

其中FileUtils.java代碼如下:
package com.yuanfy.monitorsite.common.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.web.multipart.MultipartFile;
/**
* @Description: 文件工具類方法
* @author yuanfy
* @date 2017年9月15日 下午2:45:40
* @version 1.0
*/
public class FileUtils {
/**
* @Description: 獲取文件信息
* @param file CommonsMultipartFile類型的文件
* @param fileContent StringBuilder,封裝文件信息
* @author yuanfy
* @date 2017年9月15日 下午2:51:34
* @version 1.0
*/
public static void getFileInfo(MultipartFile file, StringBuilder fileContent) {
fileContent.append("文件名稱:\t\t").append(file.getName()).append("\n")
.append("文件原始名稱:\t").append(file.getOriginalFilename()).append("\n")
.append("文件大?。篭t\t").append(file.getSize()).append("\n")
.append("文件類型:\t\t").append(file.getContentType()).append("\n")
.append("讀取文件時長:\t times").append("\n");
}
/**
* @Description: 根據(jù)文件對象獲取文件內(nèi)容
* @param file
* @author yuanfy
* @date 2017年9月15日 下午5:01:57
* @version 1.0
* @throws IOException
* @throws FileNotFoundException
*/
public static String getFileContentByLine(File file) throws FileNotFoundException, IOException {
return getFileContentByLine(new FileInputStream(file));
}
/**
* @Description: 根據(jù)文件輸入流對象獲取文件內(nèi)容
* @param in 文件輸入流對象
* @author yuanfy
* @date 2017年9月15日 下午5:01:57
* @version 1.0
* @throws IOException
*/
public static String getFileContentByLine(InputStream in) throws IOException {
StringBuilder fileContent = new StringBuilder();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = in.read(bytes)) != -1) {
String content = new String(bytes, 0, len, "UTF-8");
fileContent.append(content);
}
StreamUtils.close(in);
return fileContent.toString();
}
}
當(dāng)然要想查看整個代碼,可以訪問我項(xiàng)目的整個代碼:https://github.com/YuanFY/blog_demo。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot自動初始化數(shù)據(jù)庫的方法分享
我們在項(xiàng)目中應(yīng)該經(jīng)常遇到過初始化數(shù)據(jù)的場景,特別是項(xiàng)目部署或者交付的時候,那么有什么方式可以在項(xiàng)目啟動的時候自動初始化數(shù)據(jù)庫呢,下面小編就來和大家分享幾個方法吧2023-08-08
maven pom中內(nèi)置變量及引用的實(shí)現(xiàn)
maven其實(shí)有很多內(nèi)置變量供開發(fā)著在開發(fā)中使用,本文主要介紹了maven pom中內(nèi)置變量及引用的實(shí)現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-01-01
JAVA Spring Boot 自動配置實(shí)現(xiàn)原理詳解
這篇文章主要介紹了詳解SpringBoot自動配置原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2021-09-09
Java?Thread.currentThread().getName()?和?this.getName()區(qū)別詳
本文主要介紹了Thread.currentThread().getName()?和?this.getName()區(qū)別詳解,TestThread?testThread?=?new?TestThread();2022-02-02
淺談springboot項(xiàng)目中定時任務(wù)如何優(yōu)雅退出
這篇文章主要介紹了淺談springboot項(xiàng)目中定時任務(wù)如何優(yōu)雅退出?具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Springboot整合分頁插件PageHelper步驟解析
這篇文章主要介紹了Springboot整合分頁插件PageHelper步驟解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06

