java上传文件页面显示上传进度

本文介绍两种上传方式来获取进度条,第一种是论坛里写的比较用心的博客(我将这些博客又细分了一下,主要为了避坑),第二种方式是一base64的方式上传和接收的。

目录

第一种上传方式file对象的方式

1 准备SSM的Maven环境,也就是jar包的准备

2 前端页面

引入BootStrap的样式

3.上传页面(传统的上传组件,在上传过程中,你要获得上传文件对象)

JS代码部分

后端代码

Progress实体类

上传文件监听器

文件解析器

配置SpringMVC的配置文件解析器

Controller代码

第二种 base64方式


第一种上传方式file对象的方式

 

1 准备SSM的Maven环境,也就是jar包的准备

任意的ssm环境的项目,非maven的也可,但是注意在SpringMVC的Controller中使用@ResponseBody注解的时候必须引入jackson的依赖包,否则该注解无法使用.

<!-- jackson 版本 -->
<jackson.version>2.5.4</jackson.version>

<!-- springMVC依赖的jackson -->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>${jackson.version}</version>
 </dependency>
 <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>${jackson.version}</version>
 </dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-annotations</artifactId>
   <version>${jackson.version}</version>
 </dependency>

 

2 前端页面

前端页面的重点是ajax文件上传,因为一直无法获得文件的对象,所以在这里费的时间比较长,需要注意js获得文件对象的方式。

引入BootStrap的样式

此处非必须,不是BootStrap也不影响,可以自己去下载

<!-- 导入css样式 -->
<link href="${pageContext.request.contextPath}/static/bootstrap3/css/bootstrap.min.css" rel="stylesheet" />
<!-- 导入jQuery库 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/bootstrap3/jquery/jquery-1.11.3.min.js" ></script>
<!-- 导入js库 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/bootstrap3/js/bootstrap.min.js" ></script>

<style type="text/css">
fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}
legend{padding:.5em;border:0;width:auto}
</style>

3.上传页面(传统的上传组件,在上传过程中,你要获得上传文件对象

<fieldset>
<h1>Ajax文件上传进度条</h1>
<!-- 
ajax提交后form表单中如果存在button按钮的话ajax完成之后form表单
还是会自动提交
-->
<form action="${pageContext.request.contextPath}/pd/upload2.action" 
    method="post" id="form1" name="form1" 
    enctype="multipart/form-data" 
    onsubmit="return false;" role="form" class="form-inline">
<input type="file" name="fileObj"  id="fileObj" class="form-group" />
</form>

<!-- 动画进度条 -->
<div id="pgID" style="display:block;width:300px;" >
    <div class="progress progress-striped active" >
        <div id="pdBar" class="progress-bar progress-bar-success" role="progressbar"
             aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
             style="width:0%;">
            <span id="pdNum" class="sr-only">40% 完成</span>
        </div>
    </div>
</div>
<div>
<button class="btn btn-primary" id="upload" >上传</button>
<button class="btn btn-danger" id="cancel" >取消</button>
</div>
<p>开始时间:<font id="startTime" color="red"></font></p>
<p>现在时间:<font id="currentTime" color="red"></font></p>
<p>已经传输了的时间(s):<font id="time" color="red"></font></p>
<p>传输速度(byte/s):<font id="velocity" color="red"></font></p>
<p>估计总时间:<font id="totalTime" color="red"></font></p>
<p>估计剩余时间:<font id="timeLeft" color="red"></font></p>
<p>上传百分比:<font id="percent" color="red"></font></p>
<p>已完成数:<font id="length" color="red"></font></p>
<p>总长度(M):<font id="totalLength" color="red"></font></p>
</fieldset>

JS代码部分

需要注意的是JS获取文件的时候var fileObj = $("#fileObj")[0].files[0];
必须这样写,否则取不到文件     js可以根据自己的需求来改动

 


<script type="text/javascript">
var timeInfo = 0;

$(function(){
    $("#upload").click(function(){
        uploadFile();
        timeInfo = setInterval("getUploadInfo()",1000);
    });

    $("#cancel").click(function(){
        $("#pdBar").css({"width":"0%"});
        clearInterval(timeInfo);
    });

});

//文件上传
function uploadFile(){
    var fileObj = $("#fileObj")[0].files[0];//必须这样写,否则取不到文件
    console.log(fileObj);
    //$('#form1').serialize() 无法序列化二进制文件,这里采用formData上传
    //需要浏览器支持:Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+。
     var formData = new FormData(); // FormData 对象
//      formData.append("author", "hooyes"); // 可以增加表单数据
     formData.append("fileObj", fileObj); // 文件对象
     console.log("开始上传..."+formData);
    $.ajax({
        type:"POST",
        url:"${pageContext.request.contextPath}/pd/upload.action",
        data:formData,
        async: true,  
        cache: false, 
        dataType:"json",
        contentType: false,/*必须false才会自动加上正确的Content-Type */
        processData: false,/*必须false才会避开jQuery对 formdata 的默认处理XMLHttpRequest会对 formdata 进行正确的处理*/
        success:function(res){
            console.log(res);
            if(res.tag === true){
                clearInterval(timeInfo);
                getUploadInfo();//修正得到文件上传信息
                setPdWidth(100);//修正文件上传为100%
                alert("上传成功!");
            }else{
                clearInterval(timeInfo);
                alert("上传失败!");
            }
        },
        error:function(){
            clearInterval(timeInfo);
            alert("上传错误!");
        }
    });
}

//打开进度条
function openProgess(){
    /* var modalHeight=$(window).height() / 2 - $('#pgID').height() / 2; 
    $("#pgID").css({"display":"block","margin":modalHeight}); */
    $("#pgID").css({"display":"block","width":"300px"}); 
}

//关闭进度条
function closeProgess(){
    $("#pgID").css({"display":"none","width":"300px"});
    $("#pdBar").css({"width":"0%"});
}

//得到上传文件进度信息
function getUploadInfo(){
    $.ajax({
        url:"${pageContext.request.contextPath}/pd/getInfo.action",
        data:{time:new Date()},
        type:"post",
        dataType:"json",
        cache:false,
        success:function(res){
            if(res.percent == 100){
                clearInterval(timeInfo);
                return;
            }
            console.log(res);
            setPdWidth(res.percent);
            setUploadInfo(res);
        },
        error:function(){
            clearInterval(timeInfo);
            console.log("得到上传文件信息出错!");
        }
    });
}

//设置上传文件进度信息
function setUploadInfo(res){
    $("#startTime").text(res.startTime);
    $("#currentTime").text(res.currentTime);
    $("#time").text(res.time);
    $("#velocity").text(res.velocity);
    $("#totalTime").text(res.totalTime);
    $("#timeLeft").text(res.timeLeft);
    $("#percent").text(res.percent);
    $("#length").text(res.length);
    $("#totalLength").text(res.totalLength);
}

function setPdWidth(percent){
    $("#pdBar").css({"width":percent+"%"});
}

</script>

 

后端代码

Progress实体类

创建一个进度条的实体类,此处省略getter和setter方法

/**
 * 进度条的entity
 * @author 
 *
 */
public class Progress {

    private long bytesRead;
    private long contentLength;
    private long items;
    private long startTime = System.currentTimeMillis(); // 开始上传时间,用于计算上传速率

    public Progress() {
    }

    public long getBytesRead() {
        return bytesRead;
    }

    public void setBytesRead(long bytesRead) {
        this.bytesRead = bytesRead;
    }

    public long getContentLength() {
        return contentLength;
    }

    public void setContentLength(long contentLength) {
        this.contentLength = contentLength;
    }

    public long getItems() {
        return items;
    }

    public void setItems(long items) {
        this.items = items;
    }

    public long getStartTime() {
        return startTime;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
    }
}

上传文件监听器

我们要获得上传文件的实时详细信息,必须继承org.apache.commons.fileupload.ProgressListener类,获得信息的时候将进度条对象Progress放在该监听器的session对象中。

package com.bart.module.pb.listener;

import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.ProgressListener;
import org.springframework.stereotype.Component;
import com.bart.module.pb.entity.Progress;

@Component
public class FileUploadProgressListener implements ProgressListener {
    private HttpSession session;
    public void setSession(HttpSession session){
        this.session=session;
        Progress status = new Progress();//保存上传状态
        session.setAttribute("status", status);
    }

    @Override
    public void update(long bytesRead, long contentLength, int items) {
        Progress status = (Progress) session.getAttribute("status");
        status.setBytesRead(bytesRead);//已读取数据长度  
        status.setContentLength(contentLength);//文件总长度  
        status.setItems(items);//正在保存第几个文件  

    }


}

 

文件解析器

SpringMVC默认有一个文件解析器CommonsMultipartResolver用来解析上传的文件,我们需要重写该类,自己重写的监听器放到org.apache.commons.fileupload.FileUpload中,还需要将session放到自定义的监听器中。

package com.bart.module.pb.resolver;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.bart.module.pb.listener.FileUploadProgressListener;

public class CustomMultipartResolver extends CommonsMultipartResolver {

    // 注入第二步写的FileUploadProgressListener 
    @Autowired     // 此处一定要检查是否注入成功了,不成功的话会报错
    private FileUploadProgressListener progressListener;

    public void setFileUploadProgressListener(FileUploadProgressListener progressListener) {
        this.progressListener = progressListener;
    }

    @Override
    public MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
        String encoding = determineEncoding(request);
        FileUpload fileUpload = prepareFileUpload(encoding);
        progressListener.setSession(request.getSession());
        fileUpload.setProgressListener(progressListener);
        try {
            List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
            return parseFileItems(fileItems, encoding);
        } catch (FileUploadBase.SizeLimitExceededException ex) {
            throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
        } catch (FileUploadException ex) {
            throw new MultipartException("Could not parse multipart servlet request", ex);
        }
    }

}

配置SpringMVC的配置文件解析器

需要配置文件解析器为自定义的

 

<!-- ====================== 配置自定义的MutilpartResover解析器处理文件上传进度条 ====================== class后的路径放置你自定义的类路径   一定要指定正确,不然获取不到值 -->
    <bean id="multipartResolver" 
        class="com.bart.module.pb.resolver.CustomMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"></property>
        <property name="maxUploadSize" value="1024000000"></property>
    </bean> 

 

Controller代码

在开发时,将上传方法和得到上传文件详细信息的方法一个类里面

上传文件   

@ResponseBody
    @RequestMapping("/getInfo")
    public Map<String, Object> getUploadInfo(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> result = new HashMap<>();
        response.setHeader("Cache-Control", "no-store"); //禁止浏览器缓存  
        response.setHeader("Pragrma", "no-cache");  //禁止浏览器缓存  
        response.setDateHeader("Expires", 0);   //禁止浏览器缓存  

        Progress status = (Progress) request.getSession(true).getAttribute("status");//从session中读取上传信息  
        if(status == null){  
            result.put("error", "没发现上传文件!"); 
            return result;
        }  

        long startTime = status.getStartTime();  //上传开始时间  
        long currentTime = System.currentTimeMillis(); //现在时间  
        long time = (currentTime - startTime) /1000 +1;//已经传顺的时间 单位:s  
        double velocity = status.getBytesRead()/time; //传输速度:byte/s  
        double totalTime = status.getContentLength()/velocity; //估计总时间  
        double timeLeft = totalTime -time;    //估计剩余时间  
        int percent = (int)(100*(double)status.getBytesRead()/(double)status.getContentLength()); //百分比  
        double length = status.getBytesRead()/1024/1024; //已完成数  
        double totalLength = status.getContentLength()/1024/1024; //总长度  M 
        result.put("startTime",startTime);
        result.put("currentTime",currentTime);
        result.put("time",time);
        result.put("velocity",velocity);
        result.put("totalTime",totalTime);
        result.put("timeLeft",timeLeft);
        result.put("percent",percent);
        result.put("length",length);
        result.put("totalLength",totalLength);
        return result;
    }

 

 

到此第一种方法就全部完成了,第二种方式呢只是上的方式不一样其他配置都一样,主要变得地方就是Controller和JSP其他配置都一样的

第二种 base64方式

  这种方式和第一种方式差不多,只是后台接收方式变了而已,那我们就把Controller贴出来   ,因为是post提交,所以大家不用研究下面的代码,只看接受方式即可  

@Controller
@RequestMapping("/up")
public class UploadServlet extends HttpServlet {
 /*
  * 上传文件进度条
   * author:qzx
  */
    @RequestMapping("/uploadTest")
    public String codeList(@RequestParam(defaultValue="add")String type) {
        System.out.println("测试页面");
        String webpage = null;
        switch (type) {
            case "add":
                webpage = "WEB-INF/page/admin/code/uploadTest";
                break;

        }
        return webpage;
    }

    @ResponseBody
    @RequestMapping(value="/upload", method = RequestMethod.POST)
    public JSONObject index(HttpServletRequest request, HttpServletResponse response  ,@RequestParam("filename") String filename,@RequestParam("ImgData") String base64Img) throws IOException {
        Map<String, Object> map = new HashMap<String, Object>();
        System.out.println("开始上传照片");
        String customerId="";
        if(!StringUtils.isEmpty(filename)){
            customerId = "originalImage"+"/"+filename;
        }else{
            customerId = "originalImage";
        }
        String ret_fileName = null;// 返回给前端已修改的图片名称
        // 临时文件路径
        //String dirTemp = "\\upload\\temp";
        String dirTemp = "\\uploads";
        String uploadImg = "uploads";

        try {
            request.setCharacterEncoding("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            map.put("msg", "上传图片失败");
            map.put("status", "false");
        }
        // response.setContentType("text/html; charset=UTF-8");
        // PrintWriter out = response.getWriter();

        String realPath = request.getServletContext().getRealPath("");
        String tempPath = request.getServletContext().getRealPath("/")
                + dirTemp;
        File file_normer = new File(realPath + uploadImg + "/" + customerId);
        if (!file_normer.exists()) {
            file_normer.mkdirs();
        }
        // 用于设置图片过大,存入临时文件
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(20 * 1024 * 1024); // 设定使用内存超过5M时,将产生临时文件并存储于临时目录中。
        factory.setRepository(new File(tempPath)); // 设定存储临时文件的目录。

        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");
        if (base64Img == null) // 图像数据为空
            map.put("msg", "上传图片失败");
            map.put("status", false);
            map.put("tag",true);
//		base64Img = base64Img.replaceAll("data:image/jpeg;base64,", "");
        if (base64Img.contains("data:image/jpg;base64")) {
            base64Img = base64Img.replaceAll("data:image/jpg;base64,", "");
        } else if (base64Img.contains("data:image/jpeg;base64")) {
            base64Img = base64Img.replaceAll("data:image/jpeg;base64,", "");
        } else if (base64Img.contains("data:image/png;base64")) {
            base64Img = base64Img.replaceAll("data:image/png;base64,", "");
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] b = decoder.decodeBuffer(base64Img);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");

            String dateNowStr = sdf.format(new Date());

            System.out.println("格式化后的日期:" + dateNowStr);
            // 生成jpeg图片
            ret_fileName = new String((dateNowStr + ".jpg").getBytes("gb2312"), "ISO8859-1");
            System.out.println(realPath);
            File file = new File(realPath + uploadImg + "/" + customerId + "/" + ret_fileName);
            OutputStream out = new FileOutputStream(file);
            out.write(b);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String image_url = request.getSession().getServletContext() .getContextPath()+ "/uploads/" + customerId + "/" + ret_fileName;
        String uploadUrlWithfilename = FileHandlerZipUtils.getUploadUrlWithfilename(ret_fileName, customerId);
        System.out.print("image_url=  " +image_url);
        // 将已修改的图片url对应的id返回前端
        if(!StringUtils.isEmpty(uploadUrlWithfilename)){
            map.put("msg", "上传图片成功");
            map.put("status", "true");
            map.put("image_url",uploadUrlWithfilename);
            map.put("filepath",uploadUrlWithfilename.substring(0,uploadUrlWithfilename.length()-19));
            map.put("tag",true);
        }
        JSONObject json = JSONObject.fromObject(map);
        System.out.println(json.toString());
        return json;
    }
    @ResponseBody
    @RequestMapping("/getInfo")
    public JSONObject getUploadInfo(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> result = new HashMap<>();
        response.setHeader("Cache-Control", "no-store"); //禁止浏览器缓存
        response.setHeader("Pragrma", "no-cache");  //禁止浏览器缓存
        response.setDateHeader("Expires", 0);   //禁止浏览器缓存

        Progress status = (Progress) request.getSession(true).getAttribute("status");//从session中读取上传信息
        if(status == null){
            result.put("error", "没发现上传文件!");
            JSONObject json = JSONObject.fromObject(result);
            return json;
        }

        long startTime = status.getStartTime();  //上传开始时间
        long currentTime = System.currentTimeMillis(); //现在时间
        long time = (currentTime - startTime) /1000 +1;//已经传顺的时间 单位:s
        double velocity = status.getBytesRead()/time; //传输速度:byte/s
        int totalTime = (int)(status.getContentLength()/velocity); //估计总时间
        int timeLeft = (int)(totalTime -time);    //估计剩余时间
        int percent = (int)(100*(double)status.getBytesRead()/(double)status.getContentLength()); //百分比
        double length = status.getBytesRead()/1024/1024; //已完成数
        double totalLength = status.getContentLength()/1024/1024; //总长度  M
        // 传输速度的大小   转换成M   KB  B等
        String MB =getPrintSize(Math.round(status.getBytesRead()/time));
        result.put("startTime",startTime);
        result.put("currentTime",currentTime);
        result.put("time",time);
        result.put("velocity",MB);
        result.put("totalTime", totalTime);
        result.put("timeLeft",timeLeft);
        result.put("percent",percent);
        result.put("length",length);
        result.put("totalLength",totalLength);
        JSONObject json = JSONObject.fromObject(result);
        System.out.println("--------------------------------"+json.toString());
        return json;
    }



    public static String getPrintSize(long size) {
        //如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义
        if (size < 1024) {
            return String.valueOf(size) + "B";
        } else {
            size = size / 1024;
        }
        //如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位
        //因为还没有到达要使用另一个单位的时候
        //接下去以此类推
        if (size < 1024) {
            return String.valueOf(size) + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            //因为如果以MB为单位的话,要保留最后1位小数,
            //因此,把此数乘以100之后再取余
            size = size * 100;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "MB";
        } else {
            //否则如果要以GB为单位的,先除于1024再作同样的处理
            size = size * 100 / 1024;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "GB";
        }
    }
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值