为方便演示, 所有处理逻辑全部放在Controller完成, 不再写Service等各层接口及实现. 如需在Service层处理, 思路及方法也是完全一样的.


先说前台. 运行以后就是这样子的. 一个非常简单的表单页面, 两个文件上传按钮, 一个提交



其中单个文件上传, 即只能选择一个文件, 无法同时选择多个



相对的, 多个文件就是可以同时选择多个文件了



文件选择以后就是这个样子



代码如下: 一个form, 文件上传就是一个<input>输入, 属性type="file". 此时只能选择单个文件. 而后面加一个multiple, 即可同时选择多个文件


action属性中的路径后缀为.htm, 是因为我的环境中配置了映射, 所以要在Controller中指定的路径后添加一个.htm后缀, 否则系统会报404. 如果没有配置该项则无需添加后缀

[html] view plain copy

  1. <body>  

  2.     <form action="${pageContext.request.contextPath}/test/upload.htm" enctype="multipart/form-data" method="post">  

  3.         单个文件: <input type="file" name="fileTest"><br/>  

  4.         多个文件: <input type="file" name="fileList" multiple/></br/>  

  5.         <input type="submit" value="提交" />  

  6.     </form>  

  7. </body>  


另一点需要注意的是, 要实现文件上传, form中必须指定属性enctype="multipart/form-data". method属性为"post"


前台就这些东西了, 没什么特殊的. 然后再看后台


首先Spring配置文件中加这么一个bean

[html] view plain copy

  1. <bean id="multipartResolver"  

  2.     class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  

  3.     <!-- 默认编码 -->  

  4.     <property name="defaultEncoding" value="utf-8" />  

  5.     <!-- 文件大小最大值 -->  

  6.     <property name="maxUploadSize" value="10485760" />  

  7.     <!-- 内存中的最大值 -->  

  8.     <property name="maxInMemorySize" value="40960" />  

  9. </bean>  


也可以在代码中直接创建对象

[java] view plain copy

  1. CommonsMultipartResolver commonsMultipartResolver = new   CommonsMultipartResolver(request.getSession().getServletContext());  

但是个人认为配置以后使用比较方便, 各位根据实际需要来吧


其中maxUploadSize属性用来设计上传文件的最大值, 单位是字节. 注意这里是总的上传限制, 比如设置为10M, 上传了4个3M的文件. 虽然单个文件都在10M以内, 但是总大小已经超过10M限制, 会抛出MaxUploadSizeExceededException异常


[java] view plain copy

  1. package com.test.controller;  

  2.   

  3. import java.io.File;  

  4. import java.io.IOException;  

  5. import java.util.Iterator;  

  6. import java.util.List;  

  7.   

  8. import org.springframework.stereotype.Controller;  

  9. import org.springframework.web.bind.annotation.RequestMapping;  

  10. import org.springframework.web.bind.annotation.ResponseBody;  

  11. import org.springframework.web.multipart.MultipartFile;  

  12. import org.springframework.web.multipart.MultipartHttpServletRequest;  

  13.   

  14. /** 

  15.  * 文件上传测试类 

  16.  */  

  17. @Controller  

  18. @RequestMapping("/test")  

  19. public class FileUploadController {  

  20.   

  21.     @ResponseBody  

  22.     @RequestMapping(value="upload")  

  23.     public void testUpload(MultipartHttpServletRequest request) throws IOException {  

  24.         /* 

  25.          * MultipartHttpServletRequest: 继承于HttpServletRequest以及MultipartRequest. 

  26.          * 其中MultipartRequest中定义了相关的访问操作. MultipartHttpServletRequest重写 

  27.          * 了HttpServletRequest中的方法, 并进行了扩展. 如果以HttpServletRequest来接收参 

  28.          * 数, 则需要先将其转为MultipartHttpServletRequest类型 

  29.          * MultipartHttpServletRequest request = (MultipartHttpServletRequest) HttpServletRequest; 

  30.          */  

  31.           

  32.         /* 

  33.          * 再说回刚才的form, 假设我们在单个文件选框中上传了文件1, 多个文件选框中上传了文件2, 3, 4. 

  34.          * 那么对于后台接收到的, 可以这么理解, 就是一个Map的形式(实际上它后台真的是以Map来存储的). 

  35.          * 这个Map的Key是什么呢? 就是上面<input>标签中的name=""属性. Value则是我们刚才上传的 

  36.          * 文件, 通过下面的示例可以看出每一个Value就是一个包含对应文件集合的List 

  37.          *  

  38.          * 传到后台接收到的Map就是这样: 

  39.          * fileTest: 文件1 

  40.          * fileList: 文件2, 文件3, 文件4 

  41.          *  

  42.          * 虽然从方法名的表面意义来看是得到文件名, 但实际上这个文件名跟上传的文件本身并没有什么关系. 

  43.          * 刚才说了这个Map的Key就是<input>标签中的name=""属性, 所以得到的也就是这个属性的值 

  44.          */  

  45.         Iterator<String> fileNames = request.getFileNames();  

  46.           

  47.         while (fileNames.hasNext()) {  

  48.               

  49.             //把fileNames集合中的值打出来  

  50.             String fileName=fileNames.next();  

  51.             System.out.println("fileName: "+fileName);  

  52.               

  53.             /* 

  54.              * request.getFiles(fileName)方法即通过fileName这个Key, 得到对应的文件 

  55.              * 集合列表. 只是在这个Map中, 文件被包装成MultipartFile类型 

  56.              */  

  57.             List<MultipartFile> fileList=request.getFiles(fileName);  

  58.               

  59.             if (fileList.size()>0) {  

  60.                   

  61.                 //遍历文件列表  

  62.                 Iterator<MultipartFile> fileIte=fileList.iterator();  

  63.                   

  64.                 while (fileIte.hasNext()) {  

  65.                       

  66.                     //获得每一个文件  

  67.                     MultipartFile multipartFile=fileIte.next();  

  68.                       

  69.                     //获得原文件名  

  70.                     String originalFilename = multipartFile.getOriginalFilename();  

  71.                     System.out.println("originalFilename: "+originalFilename);  

  72.                       

  73.                     //设置保存路径.   

  74.                     String path ="G:/testUpload/";  

  75.                       

  76.                     //检查该路径对应的目录是否存在. 如果不存在则创建目录  

  77.                     File dir=new File(path);  

  78.                     if (!dir.exists()) {  

  79.                         dir.mkdirs();  

  80.                     }  

  81.                       

  82.                     String filePath = path + originalFilename;  

  83.                     System.out.println("filePath: "+filePath);  

  84.                       

  85.                     //保存文件  

  86.                     File dest = new File(filePath);  

  87.                     if (!(dest.exists())) {  

  88.                         /* 

  89.                          * MultipartFile提供了void transferTo(File dest)方法, 

  90.                          * 将获取到的文件以File形式传输至指定路径. 

  91.                          */  

  92.                         multipartFile.transferTo(dest);  

  93.                           

  94.                         /* 

  95.                          * 如果需对文件进行其他操作, MultipartFile也提供了 

  96.                          * InputStream getInputStream()方法获取文件的输入流 

  97.                          *  

  98.                          * 例如下面的语句即为通过 

  99.                          * org.apache.commons.io.FileUtils提供的 

  100.                          * void copyInputStreamToFile(InputStream source, File destination) 

  101.                          * 方法, 获取输入流后将其保存至指定路径 

  102.                          */  

  103.                         //FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), dest);  

  104.                     }  

  105.                       

  106.                     //MultipartFile也提供了其他一些方法, 用来获取文件的部分属性  

  107.                       

  108.                     //获取文件contentType  

  109.                     String contentType=multipartFile.getContentType();  

  110.                     System.out.println("contentType: "+contentType);  

  111.                       

  112.                     /* 

  113.                      * 获取name 

  114.                      * 其实这个name跟上面提到的getFileName值是一样的, 

  115.                      * 就是Map中Key的值. 即前台页面<input>中name="" 

  116.                      * 属性. 但是上面的getFileName只是得到这个Map的Key, 

  117.                      * 而Spring在处理上传文件的时候会把这个值以name属性 

  118.                      * 记录到对应的每一个文件. 如果需要从文件层面获取这个 

  119.                      * 值, 则可以使用该方法  

  120.                      */  

  121.                     String name=multipartFile.getName();  

  122.                     System.out.println("name: "+name);  

  123.                       

  124.                     //获取文件大小, 单位为字节  

  125.                     long size=multipartFile.getSize();  

  126.                     System.out.println("size: "+size);  

  127.                       

  128.                     System.out.println("---------------------------------------------------");  

  129.                 }  

  130.             }  

  131.         }  

  132.     }