为方便演示, 全部处理逻辑所有放在Controller完成, 再也不写Service等各层接口及实现. 如需在Service层处理, 思路及方法也是彻底同样的.html
先说前台. 运行之后就是这样子的. 一个很是简单的表单页面, 两个文件上传按钮, 一个提交java
其中单个文件上传, 即只能选择一个文件, 没法同时选择多个web
相对的, 多个文件就是能够同时选择多个文件了spring
文件选择之后就是这个样子apache
代码以下: 一个form, 文件上传就是一个<input>输入, 属性type="file". 此时只能选择单个文件. 然后面加一个multiple, 便可同时选择多个文件app
action属性中的路径后缀为.htm, 是由于个人环境中配置了映射, 因此要在Controller中指定的路径后添加一个.htm后缀, 不然系统会报404. 若是没有配置该项则无需添加后缀
ide
[html] view plain copy post
<body> 测试
<form action="${pageContext.request.contextPath}/test/upload.htm" enctype="multipart/form-data" method="post"> 编码
单个文件: <input type="file" name="fileTest"><br/>
多个文件: <input type="file" name="fileList" multiple/></br/>
<input type="submit" value="提交" />
</form>
</body>
另外一点须要注意的是, 要实现文件上传, form中必须指定属性enctype="multipart/form-data". method属性为"post"
前台就这些东西了, 没什么特殊的. 而后再看后台
首先Spring配置文件中加这么一个bean
[html] view plain copy
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
也能够在代码中直接建立对象
[java] view plain copy
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
可是我的认为配置之后使用比较方便, 各位根据实际须要来吧
其中maxUploadSize属性用来设计上传文件的最大值, 单位是字节. 注意这里是总的上传限制, 好比设置为10M, 上传了4个3M的文件. 虽然单个文件都在10M之内, 可是总大小已经超过10M限制, 会抛出MaxUploadSizeExceededException异常
[java] view plain copy
package com.test.controller;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
/**
* 文件上传测试类
*/
@Controller
@RequestMapping("/test")
public class FileUploadController {
@ResponseBody
@RequestMapping(value="upload")
public void testUpload(MultipartHttpServletRequest request) throws IOException {
/*
* MultipartHttpServletRequest: 继承于HttpServletRequest以及MultipartRequest.
* 其中MultipartRequest中定义了相关的访问操做. MultipartHttpServletRequest重写
* 了HttpServletRequest中的方法, 并进行了扩展. 若是以HttpServletRequest来接收参
* 数, 则须要先将其转为MultipartHttpServletRequest类型
* MultipartHttpServletRequest request = (MultipartHttpServletRequest) HttpServletRequest;
*/
/*
* 再说回刚才的form, 假设咱们在单个文件选框中上传了文件1, 多个文件选框中上传了文件2, 3, 4.
* 那么对于后台接收到的, 能够这么理解, 就是一个Map的形式(实际上它后台真的是以Map来存储的).
* 这个Map的Key是什么呢? 就是上面<input>标签中的name=""属性. Value则是咱们刚才上传的
* 文件, 经过下面的示例能够看出每个Value就是一个包含对应文件集合的List
*
* 传到后台接收到的Map就是这样:
* fileTest: 文件1
* fileList: 文件2, 文件3, 文件4
*
* 虽然从方法名的表面意义来看是获得文件名, 但实际上这个文件名跟上传的文件自己并无什么关系.
* 刚才说了这个Map的Key就是<input>标签中的name=""属性, 因此获得的也就是这个属性的值
*/
Iterator<String> fileNames = request.getFileNames();
while (fileNames.hasNext()) {
//把fileNames集合中的值打出来
String fileName=fileNames.next();
System.out.println("fileName: "+fileName);
/*
* request.getFiles(fileName)方法即经过fileName这个Key, 获得对应的文件
* 集合列表. 只是在这个Map中, 文件被包装成MultipartFile类型
*/
List<MultipartFile> fileList=request.getFiles(fileName);
if (fileList.size()>0) {
//遍历文件列表
Iterator<MultipartFile> fileIte=fileList.iterator();
while (fileIte.hasNext()) {
//得到每个文件
MultipartFile multipartFile=fileIte.next();
//得到原文件名
String originalFilename = multipartFile.getOriginalFilename();
System.out.println("originalFilename: "+originalFilename);
//设置保存路径.
String path ="G:/testUpload/";
//检查该路径对应的目录是否存在. 若是不存在则建立目录
File dir=new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
String filePath = path + originalFilename;
System.out.println("filePath: "+filePath);
//保存文件
File dest = new File(filePath);
if (!(dest.exists())) {
/*
* MultipartFile提供了void transferTo(File dest)方法,
* 将获取到的文件以File形式传输至指定路径.
*/
multipartFile.transferTo(dest);
/*
* 若是需对文件进行其余操做, MultipartFile也提供了
* InputStream getInputStream()方法获取文件的输入流
*
* 例以下面的语句即为经过
* org.apache.commons.io.FileUtils提供的
* void copyInputStreamToFile(InputStream source, File destination)
* 方法, 获取输入流后将其保存至指定路径
*/
//FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), dest);
}
//MultipartFile也提供了其余一些方法, 用来获取文件的部分属性
//获取文件contentType
String contentType=multipartFile.getContentType();
System.out.println("contentType: "+contentType);
/*
* 获取name
* 其实这个name跟上面提到的getFileName值是同样的,
* 就是Map中Key的值. 即前台页面<input>中name=""
* 属性. 可是上面的getFileName只是获得这个Map的Key,
* 而Spring在处理上传文件的时候会把这个值以name属性
* 记录到对应的每个文件. 若是须要从文件层面获取这个
* 值, 则可使用该方法
*/
String name=multipartFile.getName();
System.out.println("name: "+name);
//获取文件大小, 单位为字节
long size=multipartFile.getSize();
System.out.println("size: "+size);
System.out.println("---------------------------------------------------");
}
}
}
}
}