SpringMVC文件上傳功能實(shí)例解析
說(shuō)明:
文件上傳的途徑
文件上傳主要有兩種方式:
1.使用Apache Commons FileUpload元件。
2.利用Servlet3.0及其更高版本的內(nèi)置支持。
客戶端編程
1.為了上傳文件,必須將HTML表格的enctype屬性值設(shè)為multipart/form-data,像下面這樣:
<form action="action" enctype="multipart/form-data" method="post"> Select a file<input type="file" name="fieldName"/> <input type="submit" value="Upload"/> </form>
2.在HTML5之前,如果要想上傳多個(gè)文件,必須使用多個(gè)文件input元素。但是,在HTML5中,通過(guò)在input元素中引入多個(gè)multiple屬性,使得多個(gè)文件的上傳變得更加簡(jiǎn)單,下面均可使一個(gè)上傳框支持多個(gè)文件上傳。
<input type="file" name="fieldName" multiple/> <input type="file" name="fieldName" multiple="multiple"/> <input type="file" name="fieldName" multiple=""/>
MultipartFile接口
在SpringMVC中處理已經(jīng)上傳的文件十分簡(jiǎn)單,上傳到SpringMVC應(yīng)用程序中的文件會(huì)被包在一個(gè)MultipartFile對(duì)象中,你唯一要做的事情就是用類型為MultipartFile的屬性編寫一個(gè)Domain類。就像下面這樣:
package domain;
import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable;
import java.util.List;
public class Product implements Serializable {
//實(shí)現(xiàn)了這個(gè)接口,可以安全的將數(shù)據(jù)保存到HttpSession中
private long id;
private String name;
private String description;
private String price;
//在Domain類中加入MultipartFile類型的屬性,用來(lái)保存上傳的文件
private List<MultipartFile> images;
public List<MultipartFile> getImages() {
return images;
}
public void setImages(List<MultipartFile> images) {
this.images = images;
}
......多個(gè)get和set方法。
MultipartFile接口提供了以下方法:
| Modifier and Type | Method and Description |
|---|---|
| byte[] | getBytes()Return the contents of the file as an array of bytes. |
| String | getContentType()Return the content type of the file. |
| InputStream | getInputStream()Return an InputStream to read the contents of the file from. |
| String | getName()Return the name of the parameter in the multipart form. |
| String | getOriginalFilename()Return the original filename in the client's filesystem. |
| long | getSize()Return the size of the file in bytes. |
| boolean | isEmpty()Return whether the uploaded file is empty, that is, either no file hasbeen chosen in the multipart form or the chosen file has no content. |
| void | transferTo(File dest)Transfer the received file to the given destination file. |
實(shí)例:用CommonsFileUpLoad上傳文件
導(dǎo)入Jar包及配置環(huán)境變量

編寫視圖
代碼:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Add Product Form</title>
</head>
<body>
<form:form action="product_save" method="post" commandName="product" enctype="multipart/form-data">
<fieldset>
<legend>Add a Product</legend>
<p>
<label for="name">ProductName</label>
<form:input type="text" id="name" name="name" tabindex="1" path="name"/>
</p>
<p>
<label for="description">ProductDescription</label>
<form:input type="text" id="description" name="description" tabindex="2" path="description"/>
</p>
<p>
<label for="price">ProductPrice</label>
<form:input type="text" id="price" name="price" tabindex="3" path="price"/>
</p>
<p>
<label for="image">ProductImage</label>
<input type="file" name="images[0]">
</p>
<p>
<input type="reset">
<input type="submit">
</p>
</fieldset>
</form:form>
</body>
</html>
說(shuō)明:
首先為了上傳文件,必須將HTML表格的enctype屬性值設(shè)為multipart/form-data
其次,在HTML5之前,如果要想上傳多個(gè)文件,必須要用到多個(gè)文件input元素。
但是在HTML5,通過(guò)在Input元素中引入過(guò)個(gè)multiple屬性,使得多個(gè)文件上傳變得更加簡(jiǎn)單。
<input type="file" name="fieldName" multiple/> <input type="file" name="fieldName" multiple="multiple"/> <input type="file" name="fieldName" multiple=""/>
圖示:
編寫控制器
package controller;
import domain.Product;
import Service.ProductService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;
@Controller
public class ProductController {
private static final Log logger=LogFactory.getLog(ProductController.class);
@Autowired
private ProductService productService;
@RequestMapping(value = "/product_input")
public String inputProduct(Model model)
{
logger.info("inputProduct called");
model.addAttribute("product",new Product());
return "ProductForm";
}
@RequestMapping(value = "/product_save",method = RequestMethod.POST)
public String saveProduct(HttpServletRequest servletRequest, @ModelAttribute Product product,
BindingResult bindingResult,Model model)
{
List<MultipartFile> files= product.getImages();
System.out.println("文件數(shù)量是"+files.size());
if(null!=files&&files.size()>0)
{
for (MultipartFile file:files)
{
String fileName=file.getOriginalFilename(); //獲得文件名稱
File imagFile = new File(servletRequest.getServletContext().getRealPath("/image"),fileName);try {
file.transferTo(imagFile);//用于將文件寫到服務(wù)器本地
} catch (IOException e) {
e.printStackTrace();
}
}
}
model.addAttribute("product",product);
return "ProductDetails";
}
@RequestMapping(value = "/product_view/{id}")
public String viewProduct(@PathVariable Long id,Model model)
{
Product product =productService.get(id);
model.addAttribute("product",product);
return "ProductDetails";
}
}
配置文件
你可以看到我們?cè)赟pringMVC的配置文件中配置了一個(gè)名為multipartResolver的Bean。
基于servlet的multipartresolver實(shí)現(xiàn)Apache Commons FileUpload 1.2或以上。
提供“maxuploadsize”、“maxinmemorysize”和“defaultencoding”設(shè)置bean的屬性(繼承commonsfileuploadsupport)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="controller"/>
<context:component-scan base-package="Service"/>
<!--
<mvc:annotation-driven>元素注冊(cè)用于支持基于注解的控制器的請(qǐng)求處理方法的Bean對(duì)象。
詳解:https://my.oschina.net/HeliosFly/blog/205343
-->
<mvc:annotation-driven></mvc:annotation-driven>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--resources 元素指示SpringMVC那些靜態(tài)資源需要單獨(dú)處理-->
<mvc:resources mapping="/image/**" location="/image/"/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2000000"/>
</bean>
</beans>
說(shuō)明:
resources 元素指示SpringMVC那些靜態(tài)資源需要單獨(dú)處理,此處我們要單獨(dú)處理的是image,如果不單獨(dú)處理而是經(jīng)過(guò)dispatcher的話,就會(huì)發(fā)生404錯(cuò)誤.
實(shí)例:用Servlet3及其更高版本上傳文件
說(shuō)明:
有了Servlet3,就不需要Commons FileUpload 和Commons IO元件了.因?yàn)樵赟ervlet3中內(nèi)置了上傳文件的特性.
幸運(yùn)的是Domain類和Controller類基本不變,我們僅僅需要修改一下配置文件。
配置文件:
修改Web.xml
我們可以看到實(shí)在dispatcher的基礎(chǔ)上添加了配置項(xiàng):multipart-config
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<multipart-config>
<max-file-size>20848820</max-file-size>
<!--上傳內(nèi)文件的最大容量-->
<max-request-size>418018841</max-request-size>
<!--表示多部分HTTP請(qǐng)求允許的最大容量-->
<file-size-threshold>1048576</file-size-threshold>
<!--超過(guò)這個(gè)容量將會(huì)被寫到磁盤中-->
<location>/image/</location>
<!--要將已上傳的文件保存到磁盤中的位置-->
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--Spring中文亂碼攔截器-->
<filter>
<filter-name>setcharacter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>setcharacter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
SpringMVC配置文件添加多部分解析器
MultipartResolver接口的標(biāo)準(zhǔn)實(shí)現(xiàn),基于Servlet 3.0部分API. To be added as "multipartResolver" bean to a Spring DispatcherServlet context, without any extra configuration at the bean level. <bean id="MultipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"></bean>
實(shí)例:為多文件上傳添加一個(gè)進(jìn)度條
說(shuō)明:
我們關(guān)注的是HTML5 input元素的change事件,當(dāng)input元素的值發(fā)生改變時(shí),他就會(huì)被觸發(fā)。其次,我們還關(guān)注XMLHttpRequest對(duì)象中添加progress事件。XMLHttpRequest自然是AJAX的骨架。當(dāng)異步使用XMLHttpRequest對(duì)象上傳文件的時(shí)候就會(huì)持續(xù)地觸發(fā)progress事件,直到上傳進(jìn)度完成或者取消。通過(guò)輕松監(jiān)聽(tīng)progress事件,可以輕松地檢測(cè)文件上傳操作的進(jìn)度。
編寫Domain和Controller
1.Domain:UploadFile
package domain;
import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable;
public class UploadFile implements Serializable {
private MultipartFile multipartFile;
public MultipartFile getMultipartFile() {
return multipartFile;
}
public void setMultipartFile(MultipartFile multipartFile) {
this.multipartFile = multipartFile;
}
}
2.Controller:Html5FileUploadController類
package controller;
import domain.UploadFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
@Controller
public class Html5FileUploadController {
private static final Log logger = LogFactory.getLog(Html5FileUploadController.class);
@RequestMapping("/html5")
public String inputProduct()
{
return "html5";
}
@RequestMapping("/file_upload")
public void saveFile(HttpServletRequest servletRequest, @ModelAttribute UploadFile file, BindingResult result)
{
MultipartFile multipartFile =file.getMultipartFile();
String filename =multipartFile.getOriginalFilename();
try {
File file1 = new File(servletRequest.getServletContext().getRealPath("/image"),filename);
multipartFile.transferTo(file1);
System.out.println("已經(jīng)寫人本地文件:"+file1.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
編寫HTML5頁(yè)面
<%--
Created by IntelliJ IDEA.
User: zy
Date: 17-3-8
Time: 下午10:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<script>
var totalFileLength,totalUploaded,fileCount,filesUploaded;
function debug(s) { //輸出調(diào)試信息
var debug = document.getElementById('debug');
if(debug)
{
debug.innerHTML =debug.innerHTML+'</br>'+s;
}
}
function onUploadComplete(e) { //當(dāng)一個(gè)文件上傳完成,緊接著開(kāi)始調(diào)用下次upLoadNext();
totalUploaded+=document.getElementById('files').files[filesUploaded].size;
filesUploaded++;
debug('Complete'+filesUploaded+" of "+fileCount);
debug('totalUploaded:'+totalUploaded);
if(filesUploaded<fileCount)
{
upLoadNext();
}
}
function onUploadFailed() {
alert("Error uploading file");
}
function onUploadProgress(e) {//當(dāng)進(jìn)度發(fā)生改變時(shí),改變進(jìn)度條
if(e.lengthComputable)
{
var percentComplete =parseInt((e.loaded+totalUploaded)*100/totalFileLength);
var bar = document.getElementById("bar");
bar.style.width=percentComplete+"%";
bar.innerHTML =percentComplete+"% complete";
}
else
{
debug('unable to compute');
}
}
function upLoadNext() { //將XMLHttpRequest對(duì)象的progress事件添加到onLoadProgress并將load事件和error事件分別綁定到對(duì)應(yīng)方法。
var xhr = new XMLHttpRequest();
var fd =new FormData();
var file =document.getElementById('files').files[filesUploaded];
fd.append("multipartFile",file);
xhr.upload.addEventListener("progress",onUploadProgress,false);
xhr.addEventListener("load",onUploadComplete,false);
xhr.addEventListener("error",onUploadFailed,false);
xhr.open("POST","file_upload");
debug('uploading'+file.name);
xhr.send(fd);
}
function onFileSelect(e) { //當(dāng)選擇的文件發(fā)生改變時(shí),重新獲取并打印現(xiàn)在所選的文件信息
var files =e.target.files;
var output=[];
fileCount =files.length;
totalFileLength =0;
for(var i=0;i<fileCount;i++)
{
var file =files[i];
output.push(file.name,'(',file.size,'bytes',')',file.lastModifiedDate.toLocaleDateString());
output.push("<br/>");
debug('add'+file.size);
totalFileLength+=file.size;
}
document.getElementById('selectedFiles').innerHTML = output.join('');
debug('totalFileLength:'+totalFileLength);
}
function startUpload() { //當(dāng)用戶點(diǎn)擊提交以后開(kāi)始執(zhí)行
totalUploaded=filesUploaded=0;
upLoadNext();
}
window.onload=function () {
document.getElementById('files').addEventListener('change',onFileSelect,false);
document.getElementById('upLoadButton').addEventListener('click',startUpload,false);
}
</script>
</body>
<h1>Multipart File Uploads with Progress Bar</h1>
<div id="bar" style="height:100px;background: #33dd33;width: 0%">
</div>
<form>
<input type="file" id="files" multiple>
<br>
<output id="selectedFiles"></output>
<input id="upLoadButton" type="button" value="Upload">
</form>
<div id="debug" style="height: 100%;border: 2px solid green;overflow: auto">
</div>
</html>
說(shuō)明:
progressBar div用于展示上傳進(jìn)度,debug div用于顯示調(diào)試信息。
執(zhí)行腳本時(shí),第一件事就是為4個(gè)變量分配空間:totalFileLength,totalUploaded,fileCount,filesUploaded;
- totalFileLength:主要用于保存上傳文件的總長(zhǎng)度。
- totalUploaded:指示目前已經(jīng)上傳的字節(jié)數(shù)。
- fileCount:包含了要上傳的文件數(shù)量。
- fileUploaded:指示了已經(jīng)上傳的文件數(shù)量。

以上所述是小編給大家介紹的SpringMVC文件上傳功能實(shí)例解析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之隊(duì)列
這篇文章主要介紹了Java隊(duì)列數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),隊(duì)列是一種特殊的線性表,只允許在表的隊(duì)頭進(jìn)行刪除操作,在表的后端進(jìn)行插入操作,隊(duì)列是一個(gè)有序表先進(jìn)先出,想了解更多相關(guān)資料的小伙伴可以參考下面文章的詳細(xì)內(nèi)容2022-02-02
Spring Boot+Mybatis+Druid+PageHelper實(shí)現(xiàn)多數(shù)據(jù)源并分頁(yè)的方法
這篇文章主要給大家介紹了關(guān)于Spring Boot+Mybatis+Druid+PageHelper實(shí)現(xiàn)多數(shù)據(jù)源并分頁(yè)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們來(lái)一起看看吧2018-05-05
阿里SpringBoot應(yīng)用自動(dòng)化部署實(shí)現(xiàn)IDEA版Jenkins
這篇文章主要為大家介紹了阿里SpringBoot應(yīng)用自動(dòng)化部署實(shí)現(xiàn)IDEA版Jenkins過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
設(shè)計(jì)模式之構(gòu)建(Builder)模式 建造房子實(shí)例分析
構(gòu)建模式主要用來(lái)針對(duì)復(fù)雜產(chǎn)品生產(chǎn),分離部件構(gòu)建細(xì)節(jié),以達(dá)到良好的伸縮性,考慮到設(shè)計(jì)模式來(lái)源于建筑學(xué),因此舉一個(gè)建造房子的例子,需要的朋友可以參考下2012-12-12
SpringBoot讀寫xml上傳到AWS存儲(chǔ)服務(wù)S3的示例
這篇文章主要介紹了SpringBoot讀寫xml上傳到S3的示例,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-10-10
Maven發(fā)布項(xiàng)目到Nexus私有服務(wù)器
本文主要介紹了Maven發(fā)布項(xiàng)目到Nexus私有服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Java實(shí)現(xiàn)帶GUI的氣泡詩(shī)詞效果
這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)帶GUI的氣泡詩(shī)詞效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,感興趣的可以了解一下2022-12-12

