• Java 单文件、多文件上传 / 实现上传进度条


    博客地址:https://ainyi.com/76

    日常,工作

    在这里总结一下上传吧(是以前做过的练习,就汇总到个人博客吧)

    java ssm 框架实现文件上传
    实现:单文件上传、多文件上传(单选和多选),并且用 ajax 异步刷新,在当前界面显示上传的文件

    后端

    首先 springmvc 的配置文件要配置上传文件解析器:

    <!-- 配置文件解析器 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
          p:defaultEncoding="utf-8">
      <property name="uploadTempDir" value="/temp"></property>
      <property name="maxUploadSize">
        <value>209715200</value><!-- 200MB -->
      </property>
      <property name="maxInMemorySize">
        <value>4096</value><!-- 4KB大小读写 -->
      </property>
    </bean>
    

    其次在 pom.xml 中要配置上传文件的依赖

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.3.2</version>
    </dependency>
    

    单文件上传

    /**
     * 单文件上传
     * @param file
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     * @throws JSONException
     */
    public static String simUpload(MultipartFile file, HttpServletRequest request) 
            throws IllegalStateException, IOException, JSONException{
        
        if(!file.isEmpty()){
            String path = request.getSession().getServletContext().getRealPath("/upload");
            //定义文件
            File parent = new File(path);
            if(!parent.exists()) parent.mkdirs();
            
            HashMap<String, Object> map = new HashMap<String,Object>();
            
            String oldName = file.getOriginalFilename();
            
            long size = file.getSize();
            
            //使用TmFileUtil文件上传工具获取文件的各种信息
            //优化文件大小
            String sizeString = TmFileUtil.countFileSize(size);
            //获取文件后缀名
            String ext = TmFileUtil.getExtNoPoint(oldName);
            //随机重命名,10位时间字符串
            String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
            
            String url = "upload/"+newFileName;
            
            //文件传输,parent文件
            file.transferTo(new File(parent, newFileName));
            
            map.put("oldname",oldName);//文件原名称
            map.put("ext",ext);
            map.put("size",sizeString);
            map.put("name",newFileName);//文件新名称
            map.put("url",url);
            
            //以json方式输出到页面
            return JSONUtil.serialize(map);
        }else{
            return null;
        }
    }
    

    多文件上传(整合了单选文件多选文件的两种)

    /**
     * 多文件上传
     * @param files
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     * @throws JSONException
     */
    public static List<HashMap<String, Object>> mutlUpload(MultipartFile[] files, HttpServletRequest request) 
            throws IllegalStateException, IOException, JSONException{
        
        if(files.length > 0){
            String path = request.getSession().getServletContext().getRealPath("/upload");
            //定义文件
            File parent = new File(path);
            if(!parent.exists()) parent.mkdirs();
            
            //创建这个集合保存所有文件的信息
            List<HashMap<String, Object>> listMap = new ArrayList<HashMap<String, Object>>();
            
            //循环多次上传多个文件
            for (MultipartFile file : files) {
                
                //创建map对象保存每一个文件的信息
                HashMap<String, Object> map = new HashMap<String,Object>();
                
                String oldName = file.getOriginalFilename();
    
                long size = file.getSize();
                
                //使用TmFileUtil文件上传工具获取文件的各种信息
                //优化文件大小
                String sizeString = TmFileUtil.countFileSize(size);
                //获取文件后缀名
                String ext = TmFileUtil.getExtNoPoint(oldName);
                //随机重命名,10位时间字符串
                String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
                
                String url = "upload/"+newFileName;
                
                //文件传输,parent文件
                file.transferTo(new File(parent, newFileName));
                
                map.put("oldname",oldName);//文件原名称
                map.put("ext",ext);
                map.put("size",sizeString);
                map.put("name",newFileName);//文件新名称
                map.put("url",url);
                
                listMap.add(map);
            }
            
            //以json方式输出到页面
            return listMap;
        }else{
            return null;
        }
    }
    

    前端

    前端代码:
    文件多选,实际上在

    <input type="file" 
           name="fileupmulti"
           accept="image/jpeg,image/png"
           onchange="mutiFiles(this)"
           multiple/>
    

    多加了一个 multiple 属性

    onchange 事件代码

    // 单文件上传
    function uploadFile(obj){
      // 创建一个 FormData 对象,用一些键值对来模拟一系列表单控件
      // 即把 form 中所有表单元素的 name 与 value 组装成一个 queryString
      let form = new FormData();
      let fileObj = obj.files[0];
      form.append('doc',fileObj);
      
      // ajax 代码...
    }
    
    // 多文件上传(多选)
    function mutiFiles(obj){
      let form = new FormData();
      let fileObj = obj.files;
      let length = fileObj.length;
      // 将 fileObj 转换成数组
      // let filese = Array.from(fileObj);
      for(let i = 0; i < length; i++){
        form.append('doc', fileObj[i]);
      }
    
      // ajax 代码...
    }
    
    // 多文件上传(单选:一个一个选择文件,最后点击提交按钮触发的方法)
    function multipartone(){
      let file1 = $('.fileupon11').get(0).files[0];
      let file2 = $('.fileupon12').get(0).files[0];
      let file3 = $('.fileupon13').get(0).files[0];
      //如果都是空,则直接退出
      isEmpty(file1) && isEmpty(file2) && isEmpty(file3) return;
            
      let form = new FormData();
      //用同一个名字,注入到controller层的参数数组
      form.append('doc', file1);
      form.append('doc', file2);
      form.append('doc', file3);
      
      // ajax 代码...
    }
    

    要想在当前界面显示上传的文件,而不跳转,就利用 ajax 异步请求

    不过需要注意的是,我这里使用 FormData() 储存文件对象, ajax 要配上这几个参数才可实现文件上传:

    $.ajax({
     type: "post",
     data: form,  // FormData()对象
      url: basePath+"/upload/mutl",
     contentType: false, // 必须false才会自动加上正确的Content-Type
     processData: false, // 必须false才会避开 jQuery 对 formdata 的默认处理, XMLHttpRequest会对 formdata 进行正确的处理
     success: function(data){
        // TODO
     }
    })
    

    controller 层调用

    package com.krry.controller;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.struts2.json.JSONException;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    import com.krry.util.UploadUtil;
    
    /**
     * 文件上传类
     * KrryUploadController
     * @author krry
     * @version 1.0.0
     *
     */
    @Controller
    @RequestMapping("/upload")
    public class KrryUploadController {
        
        /**
         * 单文件上传
         * @param file
         * @param request
         * @return
         * @throws IllegalStateException
         * @throws IOException
         * @throws JSONException
         */
        @ResponseBody
        @RequestMapping(value = "/file")
        public String krryupload(@RequestParam("doc") MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
    
            //调用工具类完成上传,返回相关数据到页面
            return UploadUtil.simUpload(file, request);
        }
        
        /**
         * 多文件上传
         * @param file
         * @param request
         * @return
         * @throws IllegalStateException
         * @throws IOException
         * @throws JSONException
         */
      // 这里的MultipartFile[] file表示前端页面上传过来的多个文件,file对应页面中多个file类型的input标签的name,但框架只会将一个文件封装进一个MultipartFile对象,
      // 并不会将多个文件封装进一个MultipartFile[]数组,直接使用会报[Lorg.springframework.web.multipart.MultipartFile;.<init>()错误,
      // 所以需要用@RequestParam校正参数(参数名与MultipartFile对象名一致),当然也可以这么写:@RequestParam("file") MultipartFile[] files。
        @ResponseBody
        @RequestMapping(value = "/mutl")
        public List<HashMap<String, Object>> krryuploadMutl(@RequestParam("doc") MultipartFile[] file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
            //调用工具类完成上传,返回相关数据到页面
            return UploadUtil.mutlUpload(file, request);
        }
    }
    

    进度条

    要显示上传进度条,我这里采用原生 ajax 方法

    function uploadFile(obj) {
      // ...
      // 一些获取上传对象的相关代码
    
      // 创建一个 ajax 对象
      var xhr = new XMLHttpRequest();
    
      // 规定请求的类型、URL 以及是否异步处理请求。true为异步
      // 请求是异步的。因为要实时获取到上传的进度,则请求需是异步的,如果是同步的话,会直到请求完成才能获取到响应
      xhr.open("post", basePath+"/upload/file", true);
    
      // 上传成功进入的回调函数
      xhr.onreadystatechange = function(){
      if(xhr.readyState==4 && xhr.status==200){ // 状态 4 和 200 代表和服务器端交互成功
        // 获取上传成功的返回数据
        var data = xhr.responseText.trim();
        jdata = eval("("+data+")");
        krry_uploadsuccess(jdata);
      }
      };
      // 监听文件上传的进度
      xhr.upload.addEventListener("progress", progressFunction, false);
      // 发送http请求:将请求发送到服务器,与后台交互
      xhr.send(form);
    }
    
    
    // 上传进度的回调函数
    function progressFunction(event) {
      let prograssbarDom = document.getElementById("prograssbar");
      let fileRea = document.getElementById("fileRea");
      if (prograssbarDom && event.lengthComputable) {
        let percent = event.loaded / event.total; //文件上传进度百分比
        let p = Math.floor(percent*100);
        prograssbarDom.style.width = p+"%";
        fileRea.innerHTML = p+"%";
      }
    }
    

    附上优化文件大小的代码:

    /**
     * 将文件的字节数转换成文件的大小
     * com.krry.uitl 
     * 方法名:format
     * @author krry 
     * @param size
     * @return String
     * @exception 
     * @since  1.0.0
     */
    public static String format(long size){
        float fsize = size;
        String fileSizeString;
        if (fsize < 1024) {
            fileSizeString = String.format("%.2f", fsize) + "B"; //2f表示保留两位小数
        } else if (fsize < 1048576) {
            fileSizeString = String.format("%.2f", fsize/1024) + "KB";
        } else if (fsize < 1073741824) {
            fileSizeString = String.format("%.2f", fsize/1024/1024) + "MB";
        } else if (fsize < 1024 * 1024 * 1024) {
            fileSizeString = String.format("%.2f", fsize/1024/1024/1024) + "GB";
        } else {
            fileSizeString = "0B";
        }
        return fileSizeString;
    }
    

    博客地址:https://ainyi.com/76

  • 相关阅读:
    springboot + quartz + mysql 实现持久化分布式调度
    魔改CNN对cifar-10分类
    网络文本情感计算(一)
    运用循环一致性对抗神经网络进行非配对图片翻译:Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks
    2020数学建模国赛C题思路(持续更新)
    2020数学建模国赛A题思路(持续更新)
    2020数学建模国赛B题思路(持续更新)
    图像处理学习日志(一)
    LinkedBlockingQueue 和 ConcurrentLinkedQueue的区别
    需求评审
  • 原文地址:https://www.cnblogs.com/ainyi/p/11345714.html
Copyright © 2020-2023  润新知