• Java Web文件上传


    参考资料:http://www.cnblogs.com/xdp-gacl/p/4200090.html

    一、问题描述

    Java Web文件上传需要借助一些第三方库,常用的是借助Apache的包,有两个:

    commons-fileupload

    commons-io

    二、前端代码示例

        <form method="post" id="uploadApkForm" action="uploadapk"
            enctype="multipart/form-data">
            <p>
                文件:<input name="apkFile" type="file" /> <!--有multiple属性时支持选中多个文件同时上传-->
            </p>
            <p>
                版本:<input name="version" type="text" placeholder="请输入版本信息" />
            </p>
        </form>
    注:

     enctype="multipart/form-data" 是必须的,表示这是个含文件的form表单;

     若type="file" 的 input标签含有 multiple 属性,则能够在弹出框中同时选中多个文件上传

    三、后端代码示例

            try {
                // 判断enctype属性是否为multipart/form-data
                boolean isMultipart = ServletFileUpload.isMultipartContent(request);
                if (!isMultipart) {// 不是文件上传,用传统方法获取数据
                    // String userId = request.getParameter("userId");等
                    return;
                }
    
                // 为multipart/form-data
                int maxMemorySize = 1024 * 1000 * 50;// 50MB
                int maxRequestSize = 1024 * 1000 * 100;// 100MB
                String projAbsolutePath = request.getRealPath("");
                String uploadRelativeDir = "upload/apk/";
                String uploadTmpRelativeDir = uploadRelativeDir + "/tmp/";
                File uploadDirObj = new File(projAbsolutePath + uploadRelativeDir);
                if (!uploadDirObj.exists()) {
                    uploadDirObj.mkdirs();
                }
                File uploadTmpDirObj = new File(projAbsolutePath + uploadTmpRelativeDir);
                if (!uploadTmpDirObj.exists()) {
                    uploadTmpDirObj.mkdirs();
                }
    
                // Create a factory for disk-based file items
                DiskFileItemFactory factory = new DiskFileItemFactory();
    
                // 当上传文件太大时,因为虚拟机能使用的内存是有限的,所以此时要通过临时文件来实现上传文件的保存
                // 此方法是设置是否使用临时文件的临界值(单位:字节)
                factory.setSizeThreshold(maxMemorySize);
                // 与上一个结合使用,设置临时文件的路径(绝对路径)
                factory.setRepository(uploadTmpDirObj);
    
                // Create a new file upload handler
                ServletFileUpload upload = new ServletFileUpload(factory);
    
                // 解决上传文件名的中文乱码,tomcat8不需要了
                // upload.setHeaderEncoding("UTF-8");
    
                // 设置上传内容的大小限制(单位:字节)
                upload.setSizeMax(maxRequestSize);
    
                // Parse the request
                List<FileItem> items = upload.parseRequest(request);
                Iterator<?> iter = items.iterator();
                String fieldName = null;
                FileItem item = null;
                String fileName = null;
                String version = null;
                while (iter.hasNext()) {
                    item = (FileItem) iter.next();
                    fieldName = item.getFieldName();
                    if (item.isFormField()) {// 普通表单字段,版本信息
                        version = item.getString();
                        System.out.println(fieldName + " " + version);
                    } else {// 文件字段
                        fileName = item.getName();
                        if (!fileName.endsWith("apk")) {// 不是apk文件
                            System.out.println("不是apk文件");
                            return;
                        }
                        fileName = fileName.substring(fileName.lastIndexOf("\") + 1);
                        String contentType = item.getContentType();
                        boolean isInMemory = item.isInMemory();
                        long sizeInBytes = item.getSize();
                        System.out.println(fileName + " " + contentType + " " + isInMemory + " " + sizeInBytes);
                        item.write(new File(uploadDirObj, fileName));
                    }
                }
                apkInfoMapper.insertVersionInfo(version,
                        new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(System.currentTimeMillis()),
                        (uploadRelativeDir + fileName));
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    View Code

     注:

     为保证服务器安全,如果文件不提供下载,上传文件应该放在外界无法直接访问的目录下,如WEB-INF目录下;

     不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,而有些只是单纯的文件名,要处理获取到的上传文件的文件名的路径部分,只保留文件名部分;

     为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名

     四、扩展:利用SpringMVC实现单文件/多文件上传下载

      1 package com.mucfc;
      2 
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.FileOutputStream;
      6 import java.io.InputStream;
      7 import java.io.OutputStream;
      8 import java.net.URLEncoder;
      9 import java.util.ArrayList;
     10 import java.util.HashMap;
     11 import java.util.Iterator;
     12 import java.util.List;
     13 import java.util.Map;
     14 import java.util.UUID;
     15 
     16 import javax.servlet.ServletContext;
     17 import javax.servlet.http.HttpServletRequest;
     18 import javax.servlet.http.HttpServletResponse;
     19 
     20 import org.springframework.stereotype.Controller;
     21 import org.springframework.ui.ModelMap;
     22 import org.springframework.web.bind.annotation.RequestMapping;
     23 import org.springframework.web.bind.annotation.RequestParam;
     24 import org.springframework.web.multipart.MultipartFile;
     25 import org.springframework.web.multipart.MultipartHttpServletRequest;
     26 import org.springframework.web.multipart.commons.CommonsMultipartFile;
     27 import org.springframework.web.multipart.commons.CommonsMultipartResolver;
     28 
     29 @Controller
     30 @RequestMapping("/file")
     31 public class FileController {
     32 
     33     @RequestMapping("/toFile")
     34     public String toFileUpload() {
     35         return "fileUpload";
     36     }
     37 
     38     @RequestMapping("/toFile2")
     39     public String toFileUpload2() {
     40         return "fileUpload2";
     41     }
     42 
     43     /**
     44      * 方法一上传文件
     45      */
     46     @RequestMapping("/onefile")
     47     public String oneFileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request,
     48             ModelMap model) {
     49 
     50         // 获得原始文件名
     51         String fileName = file.getOriginalFilename();
     52         System.out.println("原始文件名:" + fileName);
     53 
     54         // 新文件名
     55         String newFileName = UUID.randomUUID() + fileName;
     56 
     57         // 获得项目的路径
     58         ServletContext sc = request.getSession().getServletContext();
     59         // 上传位置
     60         String path = request.getRealPath("/img") + "/"; // 设定文件保存的目录
     61 
     62         File f = new File(path);
     63         if (!f.exists())
     64             f.mkdirs();
     65         if (!file.isEmpty()) {
     66             try {
     67                 FileOutputStream fos = new FileOutputStream(path + newFileName);
     68                 InputStream in = file.getInputStream();
     69                 int b = 0;
     70                 while ((b = in.read()) != -1) {
     71                     fos.write(b);
     72                 }
     73                 fos.close();
     74                 in.close();
     75             } catch (Exception e) {
     76                 e.printStackTrace();
     77             }
     78         }
     79 
     80         System.out.println("上传图片到:" + path + newFileName);
     81         // 保存文件地址,用于JSP页面回显
     82         model.addAttribute("fileUrl", "img/" + newFileName);
     83         return "fileUpload";
     84     }
     85 
     86     /**
     87      * 方法二上传文件,一次一张
     88      */
     89     @RequestMapping("/onefile2")
     90     public String oneFileUpload2(HttpServletRequest request, HttpServletResponse response) throws Exception {
     91         CommonsMultipartResolver cmr = new CommonsMultipartResolver(request.getServletContext());
     92         if (cmr.isMultipart(request)) {
     93             MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) (request);
     94             Iterator<String> files = mRequest.getFileNames();
     95             while (files.hasNext()) {
     96                 MultipartFile mFile = mRequest.getFile(files.next());
     97                 if (mFile != null) {
     98                     String fileName = UUID.randomUUID() + mFile.getOriginalFilename();
     99                     String path = request.getRealPath("") + "/img/" + fileName;
    100                     System.out.println(path);
    101                     File localFile = new File(path);
    102                     if (!localFile.exists()) {
    103                         localFile.createNewFile();
    104                     }
    105                     mFile.transferTo(localFile);
    106                     request.setAttribute("fileUrl", "img/" + fileName);
    107                 }
    108             }
    109         }
    110         return "fileUpload";
    111     }
    112 
    113     /**
    114      * 一次上传多张图片
    115      */
    116     @RequestMapping("/threeFile")
    117     public String threeFileUpload(@RequestParam("file") CommonsMultipartFile files[], HttpServletRequest request,
    118             ModelMap model) {
    119 
    120         List<String> list = new ArrayList<String>();
    121         // 获得项目的路径
    122         ServletContext sc = request.getSession().getServletContext();
    123         // 上传位置
    124         String path = sc.getRealPath("/img") + "/"; // 设定文件保存的目录
    125         File f = new File(path);
    126         if (!f.exists())
    127             f.mkdirs();
    128 
    129         for (int i = 0; i < files.length; i++) {
    130             // 获得原始文件名
    131             String fileName = files[i].getOriginalFilename();
    132             System.out.println("原始文件名:" + fileName);
    133             // 新文件名
    134             String newFileName = UUID.randomUUID() + fileName;
    135             if (!files[i].isEmpty()) {
    136                 try {
    137                     FileOutputStream fos = new FileOutputStream(path + newFileName);
    138                     InputStream in = files[i].getInputStream();
    139                     int b = 0;
    140                     while ((b = in.read()) != -1) {
    141                         fos.write(b);
    142                     }
    143                     fos.close();
    144                     in.close();
    145                 } catch (Exception e) {
    146                     e.printStackTrace();
    147                 }
    148             }
    149             System.out.println("上传图片到:" + path + newFileName);
    150             list.add("img/" + newFileName);
    151 
    152         }
    153         // 保存文件地址,用于JSP页面回显
    154         model.addAttribute("fileList", list);
    155         return "fileUpload2";
    156 
    157     }
    158 
    159     /**
    160      * 列出所有的图片
    161      */
    162     @RequestMapping("/listFile")
    163     public String listFile(HttpServletRequest request, HttpServletResponse response) {
    164         // 获取上传文件的目录
    165         ServletContext sc = request.getSession().getServletContext();
    166         // 上传位置
    167         String uploadFilePath = sc.getRealPath("/img") + "/"; // 设定文件保存的目录
    168         // 存储要下载的文件名
    169         Map<String, String> fileNameMap = new HashMap<String, String>();
    170         // 递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
    171         listfile(new File(uploadFilePath), fileNameMap);// File既可以代表一个文件也可以代表一个目录
    172         // 将Map集合发送到listfile.jsp页面进行显示
    173         request.setAttribute("fileNameMap", fileNameMap);
    174         return "listFile";
    175     }
    176 
    177     public void listfile(File file, Map<String, String> map) {
    178         // 如果file代表的不是一个文件,而是一个目录
    179         if (!file.isFile()) {
    180             // 列出该目录下的所有文件和目录
    181             File files[] = file.listFiles();
    182             // 遍历files[]数组
    183             for (File f : files) {
    184                 // 递归
    185                 listfile(f, map);
    186             }
    187         } else {
    188             /**
    189              * 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
    190              * file.getName().indexOf
    191              * ("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:9349249849-88343-8344_阿_凡_达.avi
    192              * 那么file.getName().substring(file.getName().indexOf("_")+1)
    193              * 处理之后就可以得到
    194              */
    195             String realName = file.getName().substring(file.getName().indexOf("_") + 1);
    196             // file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
    197             map.put(file.getName(), realName);
    198         }
    199     }
    200 
    201     @RequestMapping("/downFile")
    202     public void downFile(HttpServletRequest request, HttpServletResponse response) {
    203         System.out.println("1");
    204         // 得到要下载的文件名
    205         String fileName = request.getParameter("filename");
    206         System.out.println("2");
    207         try {
    208             fileName = new String(fileName.getBytes("iso8859-1"), "UTF-8");
    209             System.out.println("3");
    210             // 获取上传文件的目录
    211             ServletContext sc = request.getSession().getServletContext();
    212             System.out.println("4");
    213             // 上传位置
    214             String fileSaveRootPath = sc.getRealPath("/img");
    215 
    216             System.out.println(fileSaveRootPath + "\" + fileName);
    217             // 得到要下载的文件
    218             File file = new File(fileSaveRootPath + "\" + fileName);
    219 
    220             // 如果文件不存在
    221             if (!file.exists()) {
    222                 request.setAttribute("message", "您要下载的资源已被删除!!");
    223                 System.out.println("您要下载的资源已被删除!!");
    224                 return;
    225             }
    226             // 处理文件名
    227             String realname = fileName.substring(fileName.indexOf("_") + 1);
    228             // 设置响应头,控制浏览器下载该文件
    229             response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
    230             // 读取要下载的文件,保存到文件输入流
    231             FileInputStream in = new FileInputStream(fileSaveRootPath + "\" + fileName);
    232             // 创建输出流
    233             OutputStream out = response.getOutputStream();
    234             // 创建缓冲区
    235             byte buffer[] = new byte[1024];
    236             int len = 0;
    237             // 循环将输入流中的内容读取到缓冲区当中
    238             while ((len = in.read(buffer)) > 0) {
    239                 // 输出缓冲区的内容到浏览器,实现文件下载
    240                 out.write(buffer, 0, len);
    241             }
    242             // 关闭文件输入流
    243             in.close();
    244             // 关闭输出流
    245             out.close();
    246         } catch (Exception e) {
    247 
    248         }
    249     }
    250 }
    View Code

    原理:Servlet或Spring(实际上也是依赖Servlet)将收到的文件持久化到默认的临时磁盘目录(用户也可以指定),代码中获取到的File对象即是存在该临时目录的文件对象

    另外,关于HTTP POST提交数据的三种常用方式(application/x-www-form-urlencoded、multipart/form-data、application/json)的区别可参阅:https://imququ.com/post/four-ways-to-post-data-in-http.html

    五、Spring文件上传

    两种方法:

    法1:通过@RequestParameter

    法2:通过@RequestPart

    两种都是用来接收multipart/form-data请求传来的数据,区别:前者可以同时接收文件(multipart)域和普通键值对参数,而后者可以同时接收文件域和更复杂的对象(如json、xml等)。

    可参阅:https://stackoverflow.com/questions/16230291/requestpart-with-mixed-multipart-request-spring-mvc-3-2

  • 相关阅读:
    VS2010插件及快捷键设置
    在Windows程序中启用console输出-2016.01.04
    使用VAssistX给文件和函数添加注释-2015.12.31
    windows在远程桌面连接中使用命令行参数
    windows网络编程-2015.12.29
    grep使用
    linux程序调试常用命令
    vim使用笔记
    infusion度量金字塔数据解释
    MVc Forms Membership rolemanage 角色权限验证管理
  • 原文地址:https://www.cnblogs.com/z-sm/p/4872004.html
Copyright © 2020-2023  润新知