前文说到springMVC映射普通表单的开发方法,接下来讨论如何使用springmvc上传单个文件。
springmvc对form表单的支持已经很成熟,仅仅两步:
- 配置支持文件上传的bean:org.springframework.web.multipart.commons.CommonsMultipartResolver
同时设置文件编码、单次提交表单上传文件最大字节数、以及写文件时使用的缓冲区大小 - 开发处理:handler[org.hy.ssm.web.controller.FormController.uploadOne(MultipartFile)]
/** * @Title: uploadOne * @Description: 单文件上传 * @param file * @return ModelMap */ @RequestMapping("/uploadOne") @ResponseBody public ModelMap uploadOne(MultipartFile file) { final String UPLOAD_DIR = "/upload/"; final String KEY_OF_ORIGINAL_FILE_NAME = "origFileName"; final String KEY_OF_FILE_URL = "fileUrl"; final String KEY_OF_FILE_SUFFIX = "fileSuffix"; boolean flag = false; String message = null; Map<String, String> data = Maps.newHashMap(); // 原文件名(通常用于下载展示) String originalFilename = file.getOriginalFilename(); data.put(KEY_OF_ORIGINAL_FILE_NAME, originalFilename); // 文件类型(后缀) String suffix = FileUtil.getSuffix(originalFilename); data.put(KEY_OF_FILE_SUFFIX, suffix); // 目标文件名(通常情况需要重命名, 防止同名文件覆盖) String fileName = String.valueOf(System.currentTimeMillis()) + suffix; String fileUrl = (UPLOAD_DIR + fileName); data.put(KEY_OF_FILE_URL, fileUrl); try { File dest = WebUtil.getFile(fileUrl); file.transferTo(dest); flag = true; } catch (Exception e) { flag = false; message = ""; LOGGER.warn(message + " : " + e.getMessage(), e); } return WebUtil.getModelMap(flag, data, message); }
接下来验证结果是否正确:
- 正常验证
- 非法验证,文件大小超出。当前测试数据70+MB
org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size of 32505856 bytes exceeded; nested exception is org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (79882924) exceeds the configured maximum (32505856) at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:160) at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139) at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1020) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:883) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:722) Caused by: org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (79882924) exceeds the configured maximum (32505856) at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:937) at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331) at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351) at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126) at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156) ... 28 more
由错误也可定位出,#multipartResolver.maxUploadSize 是用来定位单次表单提交时,文件的限定大小
到此,单文件上传已经搞定。是不是很简单呢?当然了还有稍微原始的方法,通过 org.apache.commons.fileupload.servlet.ServletFileUpload 也能实现文件上传的功能,在此不做详解。大致步骤如下:
- 获取工厂 DiskFileItemFactory
- 通过工厂获取上传组件 ServletFileUpload
- 解析请求获取表单项
- 判断表单项类型
- 解析表单项
/** * @Title: uploadByFileUpload * @Description: 使用Commons.FileUpload上传文件 */ @RequestMapping("/uploadByFileUpload") public void uploadByFileUpload() { final String UPLOAD_DIR = "upload/"; final String basePath = WebUtil.getBaseFilPath(); HttpServletRequest request = WebUtil.getRequest(); try { // 防止中文名乱码 request.setCharacterEncoding("utf-8"); // 1. 获取工厂 DiskFileItemFactory DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(); // 缓存区目录 fileItemFactory.setRepository(new File(basePath + "tmp/")); // 缓存区大小 fileItemFactory.setSizeThreshold(1024 * 6); // 2. 通过工厂获取上传组件 ServletFileUpload ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory); // 设置文件的大小为2M servletFileUpload.setSizeMax(1024 * 1024 * 2); // 防止中文乱码(文件名) servletFileUpload.setHeaderEncoding("UTF-8"); // 3. 解析请求获取表单项 @SuppressWarnings("unchecked") List<FileItem> items = servletFileUpload.parseRequest(request); // 4. 判断表单项类型 for (FileItem item : items) { // 5. 解析表单项 // 表单项名称 String fieldName = item.getFieldName(); if (item.isFormField()) { // 普通表单项处理 String name = fieldName; String value = item.getString("UTF-8"); System.out.println(name + ":" + value); } else { // 文件表单项 // 获取文件名 String originalFileName = item.getName(); String suffix = FileUtil.getSuffix(originalFileName); String newFileName = String.valueOf(System.currentTimeMillis()); // 写入文件 String fileName = File.separator + newFileName + suffix; File newFile = FileUtil.createQuietly(basePath + UPLOAD_DIR + fileName); item.write(newFile); item.delete(); } } } catch (Exception e) { LOGGER.warn(e.getMessage(), e); } }
注意:如果使用上面的方式获取上传文件,需要停止 springmvc 的文件解析机制,否则将不能获取数据 !!
源码下载:ssmFU.zip