【笔记】Spring MVC学习指南(十一)上传文件
2015-10-06 22:49
597 查看
只有实现了Servlet3.0及其更高版本规范的Servlet容器,才支持文件上传。对于低版本的容器,则需要Apache Commons FileUpload元件及Apache commons IO,下载地址:http://commons.apache.org/proper/commons-fileupload/
http://commons.apache.org/proper/commons-io/
为了使用Commons FileUpload,首先要在springmvc-config.xml中定义multipartResolver bean:
在HTML5中定义文件上传按钮的代码:
在SpringMVC中,上传的文件会被包在一个MultipartFile对象中,我们要做的,是新建一个带有该类型属性的类。MultipartFile本身是一个接口,包含一些获取及处理上传文件的api,其中最重要的是void transferTo(File destination),该方法将上传的文件保存到目标目录下。
首先需要编写包含MultipartFile属性的类:
先来看ProductController.java:
对应的ProductForm.jsp:
ProductDetails.jsp:
如果容器为Servlet3或者更高版本,则可以直接使用内置特性
其余部分一样,不重复了。
11.10小节,可以说是本书到目前为止个人觉得最有难度的部分了,一来对javascript的这些内容不熟悉,二来还用到了XMLHttpRequest对象。
最重要的jsp页面(该有的注释都写了,如何实现上传进度的显示):
运行过程也还是不错的,下半部分的信息显示,感觉可以把样式改的更友好一些^_^
这篇的博客最早是上个月最后一天写的,保存了草稿之后今天才完成,嗯,就是因为那天不在状态,看js代码老走神 o(︶︿︶)o 唉
http://commons.apache.org/proper/commons-io/
为了使用Commons FileUpload,首先要在springmvc-config.xml中定义multipartResolver bean:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--使用Commons FileUpload--> <property name="maxUploadSize" value="2000000"/> </bean>
在HTML5中定义文件上传按钮的代码:
<!-- 文件多选框 --> <input type="file" name="fieldName" multiple=""/> <input type="file" name="fieldName" multiple="multiple"/> <input type="file" name="fieldName" multiple/> <!-- 文件单选框 --> <input type="file" name="fieldName"/>
在SpringMVC中,上传的文件会被包在一个MultipartFile对象中,我们要做的,是新建一个带有该类型属性的类。MultipartFile本身是一个接口,包含一些获取及处理上传文件的api,其中最重要的是void transferTo(File destination),该方法将上传的文件保存到目标目录下。
首先需要编写包含MultipartFile属性的类:
package app11a.domain; import org.springframework.web.multipart.MultipartFile; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.List; public class Product implements Serializable { private static final long serialVersionUID = 74458L; @NotNull @Size(min = 1, max = 10) private String name; private String description; private Float price; private List<MultipartFile> images; // 上传的文件保存在此 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Float getPrice() { return price; } public void setPrice(Float price) { this.price = price; } public List<MultipartFile> getImages() { return images; } public void setImages(List<MultipartFile> images) { this.images = images; } }
先来看ProductController.java:
package app11a.controller; import app11a.domain.Product; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.RequestMapping; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; @Controller public class ProductController { private static final Log logger = LogFactory.getLog(ProductController.class); @RequestMapping(value = "/product_input") public String inputProduct(Model model) { model.addAttribute("product", new Product()); return "ProductForm"; } @RequestMapping(value = "/product_save") public String saveProduct(HttpServletRequest servletRequest, @ModelAttribute Product product, BindingResult bindingResult, Model model) { List<MultipartFile> files = product.getImages(); List<String> fileNames = new ArrayList<String>(); if (null != files && files.size() > 0) { for (MultipartFile multipartFile : files) { String fileName = null; try { fileName = new String(multipartFile.getOriginalFilename().getBytes("ISO8859-1"), "UTF-8"); // 这样才不会中文乱码,但是product.images[0].name依然无法正常显示,会是html编码 } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(fileName); fileNames.add(fileName); File imageFile = new File(servletRequest.getServletContext().getRealPath("/image"), fileName); // 从这里可以知道,上传的文件会被保存到这个image文件夹下 try { multipartFile.transferTo(imageFile); // 关键性代码,保存上传的文件 } catch (IOException e) { e.printStackTrace(); } } } // save product here model.addAttribute("product", product); return "ProductDetails"; } }
对应的ProductForm.jsp:
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page pageEncoding="UTF-8" %> <!DOCTYPE HTML> <html> <head> <title>Add Product Form</title> <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style> </head> <body> <div id="global"> <form:form commandName="product" action="product_save" method="post" enctype="multipart/form-data"><%--enctype设置为multipart/form-data!!!--%> <fieldset> <legend>Add a product</legend> <p> <label for="name">Product Name: </label> <form:input id="name" path="name" cssErrorClass="error"/> <form:errors path="name" cssClass="error"/> </p> <p> <label for="description">Description: </label> <form:input id="description" path="description"/> </p> <p> <label for="price">Price: </label> <form:input id="price" path="price" cssErrorClass="error"/> </p> <p> <label for="image">Product Image: </label> <%-- input的type="file" --%> <%-- input的name值,与product.images对应,如果多个input的name重复,以第一个为准。这里有个问题,如果图片名称为中文,会乱码 --%> <input id="image" type="file" name="images[0]"/> </p> <p> <label for="image2">Product Image2: </label> <%--这里一定是images[1],如果为[0],会被之前的屏蔽,如果为[2]或者更大的数,会报空指针错误 --%> <input id="image2" type="file" name="images[1]"/> </p> <p id="buttons"> <input id="reset" type="reset" tabindex="4"> <input id="submit" type="submit" tabindex="5" value="Add Product"> </p> </fieldset> </form:form> </div> </body> </html>
ProductDetails.jsp:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page pageEncoding="UTF-8" %> <!DOCTYPE HTML> <html> <head> <title>Save Product JSP</title> <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style> </head> <body> <div id="global"> <h4>The product has been saved.</h4> <p> <h5>Details:</h5> Product Name: ${product.name}<br/> Description: ${product.description}<br/> Price: $${product.price} <p>Following files are uploaded successfully.</p> <ol> <c:forEach items="${product.images}" var="image"> <%--<c:set var="kx" value="${new String(image.getOriginalFilename().getBytes(\"ISO8859-1\"), \"UTF-8\")"} />--%> <li>${image.originalFilename} <img width="100" src="<c:url value="/image/"/>${image.originalFilename}"/> </li> </c:forEach> </ol> </p> </div> </body> </html>
如果容器为Servlet3或者更高版本,则可以直接使用内置特性
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"> <!--使用Servlet3及以上版本自带的上传功能--> </bean>
其余部分一样,不重复了。
11.10小节,可以说是本书到目前为止个人觉得最有难度的部分了,一来对javascript的这些内容不熟悉,二来还用到了XMLHttpRequest对象。
最重要的jsp页面(该有的注释都写了,如何实现上传进度的显示):
<!DOCTYPE HTML> <html> <head> <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) { totalUploaded += document.getElementById('files').files[filesUploaded].size; /*files数组依旧是从零开始*/ filesUploaded++; debug('complete ' + filesUploaded + " of " + fileCount); debug('totalUploaded: ' + totalUploaded); if (filesUploaded < fileCount) { uploadNext(); } else { var bar = document.getElementById('bar'); bar.style.width = '100%'; bar.innerHTML = '100% complete'; alert('Finished uploading file(s)'); } } function onFileSelect(e) { // 对于e.target.files这段代码,表示第一次见,js还真是简单粗暴。。。 var files = e.target.files; // FileList object 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(), ')'); // push()向数组的末尾添加元素,并返回新的数组长度 output.push('<br/>'); debug('add ' + file.size); totalFileLength += file.size; } document.getElementById('selectedFiles').innerHTML = output.join(''); // join()将数组中的所有元素合并为一个字符串,不同元素之间通过指定的分隔符进行分隔 debug('totalFileLength:' + totalFileLength); } 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 onUploadFailed(e) { alert("Error uploading file"); } function uploadNext() { 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); // 捕捉(true)or 冒泡(false),一般都为false。注意这里的progress事件,正是这个内置的事件类型才得以实现上传进度的获取,完全不需要自己去编写代码实现,之前一直觉得监控上传进度很厉害是以为这部分是需要自己编写代码来实现的!!! xhr.addEventListener("load", onUploadComplete, false); xhr.addEventListener("error", onUploadFailed, false); xhr.open("POST", "file_upload"); // 请求方式, url debug('uploading ' + file.name); xhr.send(fd); // 提交,参数可以为null } function startUpload() { totalUploaded = filesUploaded = 0; uploadNext(); } window.onload = function () { document.getElementById('files').addEventListener('change', onFileSelect, false); document.getElementById('uploadButton').addEventListener('click', startUpload, false); } </script> </head> <body> <h1>Multiple file uploads with progress bar</h1> <div id='progressBar' style='height:20px;border:2px solid green'> <div id='bar' style='height:100%;background:#33dd33;width:0%'> </div> </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:100px;border:2px solid green;overflow:auto'> </div> </body> </html>
运行过程也还是不错的,下半部分的信息显示,感觉可以把样式改的更友好一些^_^
这篇的博客最早是上个月最后一天写的,保存了草稿之后今天才完成,嗯,就是因为那天不在状态,看js代码老走神 o(︶︿︶)o 唉
相关文章推荐
- 大龄屌丝自学笔记--Java零基础到菜鸟--026
- 深入理解Java的接口和抽象类
- 常见的几种RuntimeException
- 第6周-π的近似值
- Java基础知识学习
- java实现杨辉三角,输出对齐
- java复习:线程间通信
- 第6周-打印金字塔形的数字
- JavaBean的编译和部署说明
- Eclipse各种优化,美化——doc源码导入
- Java基础知识强化之集合框架笔记47:Set集合之TreeSet保证元素唯一性和比较器排序的原理及代码实现(比较器排序)
- Java高级3
- Java基础重点指南
- Java语言程序设计(基础篇)原书第十版 课后习题 第三章
- java的JDK环境配置详细说明
- Struts2中参数传递与OGNL
- CXF框架集成到Spring
- javaWEB项目心得之模块开发步骤
- Struts2 MySQL数据库访问
- spring整合struts2、mybatis的配置