Spring文件上传,包括一次选中多个文件
为方便演示, 所有处理逻辑全部放在Controller完成, 不再写Service等各层接口及实现. 如需在Service层处理, 思路及方法也是完全一样的.
先说前台. 运行以后就是这样子的. 一个非常简单的表单页面, 两个文件上传按钮, 一个提交
其中单个文件上传, 即只能选择一个文件, 无法同时选择多个
相对的, 多个文件就是可以同时选择多个文件了
文件选择以后就是这个样子
代码如下: 一个form, 文件上传就是一个<input>输入, 属性type="file". 此时只能选择单个文件. 而后面加一个multiple, 即可同时选择多个文件
action属性中的路径后缀为.htm, 是因为我的环境中配置了映射, 所以要在Controller中指定的路径后添加一个.htm后缀, 否则系统会报404. 如果没有配置该项则无需添加后缀
- <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
- <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>
也可以在代码中直接创建对象
- CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
但是个人认为配置以后使用比较方便, 各位根据实际需要来吧
其中maxUploadSize属性用来设计上传文件的最大值, 单位是字节. 注意这里是总的上传限制, 比如设置为10M, 上传了4个3M的文件. 虽然单个文件都在10M以内, 但是总大小已经超过10M限制, 会抛出MaxUploadSizeExceededException异常
- 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("---------------------------------------------------");
- }
- }
- }
- }
- }
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<html>
<head>
<title>用户管理</title>
<meta name="decorator" content="default" />
<script type="text/javascript">
$(document).ready(function(){
$("#btnImport").click(function(){
$.jBox($("#importBox").html(),
{
title:"导入数据",
buttons:
{
"关闭":true
},
bottomText:"导入文件不能超过5M,仅允许导入“xls”或“xlsx”格式文件!"
});
});
});
</script>
</head>
<body>
<div id="importBox">
<form id="importForm" action="${ctx}/sys/hrSendMail/import" method="post" enctype="multipart/form-data" class="form-search" style="padding-left: 20px; text-align: center;" onsubmit="loading('正在导入,请稍等...');">
<br />
<input id="uploadFile" name="files" type="file" style="width: 330px" multiple/>
<br /> <br />
<input id="btnImportSubmit" class="btn btn-primary" type="submit" value=" 发 送 " />
</form>
</div>
<sys:message content="${message}" />
</body>
</html>
/* 发送工资条数据
*
* @param file
* @param redirectAttributes
* @return
*/
@RequestMapping(value = "import", method = RequestMethod.POST)
public String importFile(@RequestParam("files") MultipartFile[] files,
RedirectAttributes redirectAttributes) {
if (files != null && files.length > 0) {
try {
int successNum = 0;
int failureNum = 0;
StringBuilder failureMsg = new StringBuilder();
ImportExcel ei = null;
List<Payroll> list = null;
List<String> messageList = null;
for (MultipartFile file : files) {
ei = new ImportExcel(file, 0, 0);
list = ei.getHrDataList(Payroll.class);
for (Payroll Payroll : list) {
try {
if (emailFormat(Payroll.getMail())) {
BeanValidators.validateWithException(validator,
Payroll);
SendMailUtil.sendInlineMail(Payroll);
successNum++;
} else {
failureMsg.append("<br/>邮箱 "
+ Payroll.getMail() + " 不符合邮箱规范 ");
failureNum++;
}
} catch (ConstraintViolationException ex) {
failureMsg.append("<br/>工资条" + Payroll.getMail()
+ " 发送失败:");
messageList = BeanValidators
.extractPropertyAndMessageAsList(ex, ": ");
for (String message : messageList) {
failureMsg.append(message + "; ");
failureNum++;
}
} catch (Exception ex) {
failureMsg.append("<br/>工资条 " + Payroll.getMail()
+ " 发送失败:" + ex.getMessage());
}
}
}
if (failureNum > 0) {
failureMsg.insert(0, ",失败 " + failureNum + " 条工资条,发送信息如下:");
}
addMessage(redirectAttributes, "已成功发送 " + successNum + " 条工资条"
+ failureMsg);
} catch (Exception e) {
addMessage(redirectAttributes, "发送工资条失败!失败信息:" + e.getMessage());
}
}
return "redirect:" + adminPath + "/sys/hrSendMail/index?repage";
}
/**
* 验证输入的邮箱格式是否符合
*
* @param email
* @return 是否合法
*/
public boolean emailFormat(String email) {
boolean tag = true;
if (!email.matches("[\\w\\.\\-][email protected]([\\w\\-]+\\.)+[\\w\\-]+")) {
tag = false;
}
return tag;
}