SpringMVC文件上传功能实例解析
说明:
文件上传的途径
文件上传主要有两种方式:
1.使用apache commons fileupload元件。
2.利用servlet3.0及其更高版本的内置支持。
客户端编程
1.为了上传文件,必须将html表格的enctype属性值设为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之前,如果要想上传多个文件,必须使用多个文件input元素。但是,在html5中,通过在input元素中引入多个multiple属性,使得多个文件的上传变得更加简单,下面均可使一个上传框支持多个文件上传。
<input type="file" name="fieldname" multiple/> <input type="file" name="fieldname" multiple="multiple"/> <input type="file" name="fieldname" multiple=""/>
multipartfile接口
在springmvc中处理已经上传的文件十分简单,上传到springmvc应用程序中的文件会被包在一个multipartfile对象中,你唯一要做的事情就是用类型为multipartfile的属性编写一个domain类。就像下面这样:
package domain; import org.springframework.web.multipart.multipartfile; import java.io.serializable; import java.util.list; public class product implements serializable { //实现了这个接口,可以安全的将数据保存到httpsession中 private long id; private string name; private string description; private string price; //在domain类中加入multipartfile类型的属性,用来保存上传的文件 private list<multipartfile> images; public list<multipartfile> getimages() { return images; } public void setimages(list<multipartfile> images) { this.images = images; } ......多个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. |
实例:用commonsfileupload上传文件
导入jar包及配置环境变量
编写视图
代码:
<%@ 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>
说明:
首先为了上传文件,必须将html表格的enctype属性值设为multipart/form-data
其次,在html5之前,如果要想上传多个文件,必须要用到多个文件input元素。
但是在html5,通过在input元素中引入过个multiple属性,使得多个文件上传变得更加简单。
<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("文件数量是"+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);//用于将文件写到服务器本地 } 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"; } }
配置文件
你可以看到我们在springmvc的配置文件中配置了一个名为multipartresolver的bean。
基于servlet的multipartresolver实现apache commons fileupload 1.2或以上。
提供“maxuploadsize”、“maxinmemorysize”和“defaultencoding”设置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>元素注册用于支持基于注解的控制器的请求处理方法的bean对象。 详解: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那些静态资源需要单独处理--> <mvc:resources mapping="/image/**" location="/image/"/> <bean id="multipartresolver" class="org.springframework.web.multipart.commons.commonsmultipartresolver"> <property name="maxuploadsize" value="2000000"/> </bean> </beans>
说明:
resources 元素指示springmvc那些静态资源需要单独处理,此处我们要单独处理的是image,如果不单独处理而是经过dispatcher的话,就会发生404错误.
实例:用servlet3及其更高版本上传文件
说明:
有了servlet3,就不需要commons fileupload 和commons io元件了.因为在servlet3中内置了上传文件的特性.
幸运的是domain类和controller类基本不变,我们仅仅需要修改一下配置文件。
配置文件:
修改web.xml
我们可以看到实在dispatcher的基础上添加了配置项: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> <!--上传内文件的最大容量--> <max-request-size>418018841</max-request-size> <!--表示多部分http请求允许的最大容量--> <file-size-threshold>1048576</file-size-threshold> <!--超过这个容量将会被写到磁盘中--> <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接口的标准实现,基于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>
实例:为多文件上传添加一个进度条
说明:
我们关注的是html5 input元素的change事件,当input元素的值发生改变时,他就会被触发。其次,我们还关注xmlhttprequest对象中添加progress事件。xmlhttprequest自然是ajax的骨架。当异步使用xmlhttprequest对象上传文件的时候就会持续地触发progress事件,直到上传进度完成或者取消。通过轻松监听progress事件,可以轻松地检测文件上传操作的进度。
编写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("已经写人本地文件:"+file1.getname()); } catch (exception e) { e.printstacktrace(); } } }
编写html5页面
<%-- 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) { //输出调试信息 var debug = document.getelementbyid('debug'); if(debug) { debug.innerhtml =debug.innerhtml+'</br>'+s; } } function onuploadcomplete(e) { //当一个文件上传完成,紧接着开始调用下次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) {//当进度发生改变时,改变进度条 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对象的progress事件添加到onloadprogress并将load事件和error事件分别绑定到对应方法。 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) { //当选择的文件发生改变时,重新获取并打印现在所选的文件信息 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() { //当用户点击提交以后开始执行 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>
说明:
progressbar div用于展示上传进度,debug div用于显示调试信息。
执行脚本时,第一件事就是为4个变量分配空间:totalfilelength,totaluploaded,filecount,filesuploaded;
- totalfilelength:主要用于保存上传文件的总长度。
- totaluploaded:指示目前已经上传的字节数。
- filecount:包含了要上传的文件数量。
- fileuploaded:指示了已经上传的文件数量。
以上所述是小编给大家介绍的springmvc文件上传功能实例解析,希望对大家有所帮助