zoukankan      html  css  js  c++  java
  • 批量下载文件JSP

    最近项目有个需求,用户想对挂有附件的数据记录 实现一键下载全部附件(目前项目仅支持每次点击单条记录进行附件下载),下面记录我实现的解决方案。
    项目框架基于SSM
    service业务实现层(impl):
    //获取配置的文件夹默认位置 (我的properties配的是E:\work\files) 
    @Value("#{configProperties['FILE.DOCUMENT_PATH']}")
    private String documentPath;
     
    //获取附件信息需要调用的mapper
    @Autowired
    JcglSystemHelpMapper jcglSystemHelpMapper;
     
    //参数ids : 为前台传的记录id集 (格式:12345,12346,12347)
    @Override
    public void downloadPlanFile(String ids,HttpServletRequest request,HttpServletResponse response){
    //响应头的设置
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            //设置压缩包的名字
            String dates = DateFormatUtils.formatJxp2(new Date());//获取时间戳
            String billname = "附件包-"+dates;
            String downloadName = billname+".zip";
            //返回客户端浏览器的版本号、类型
            String agent = request.getHeader("USER-AGENT");  
            try {
            //针对IE或者以IE为内核的浏览器:  
                if (agent.contains("MSIE")||agent.contains("Trident")) {
                    downloadName = java.net.URLEncoder.encode(downloadName, "UTF-8");
                } else {
                //非IE浏览器的处理:
                    downloadName = new String(downloadName.getBytes("UTF-8"),"ISO-8859-1");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            response.setHeader("Content-Disposition", "attachment;fileName="" + downloadName + """);
            
            //设置压缩流:直接写入response,实现边压缩边下载
            ZipOutputStream zipos = null;
            try {
                zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
                zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法 
            } catch (Exception e) {
                e.printStackTrace();
            }
     
            //循环将文件写入压缩流
            DataOutputStream os = null;
            
           
            //查询数据库获取文件信息
            Map<String,Object> map = new HashMap<String, Object>();
            map.put("ids", ids);
            List<AuthAttachmentDetail> list = jcglSystemHelpMapper.queryAllDetailByDataIds(map);
            //遍历文件信息(主要获取文件名/文件路径等)
            for (AuthAttachmentDetail authAttachmentDetail : list) {
            //文件路径
                String filePath = documentPath + File.separator + authAttachmentDetail.getFilePath();
            System.out.println("filePath==="+filePath);
            File file = new File(filePath);
            if (!file.exists()) {
                throw new BusinessException("文件已不存在");
            }else{
            try {
        //添加ZipEntry,并ZipEntry中写入文件流
            String fileName = authAttachmentDetail.getFileName();//.substring(0,authAttachmentDetail.getFileName().indexOf("."));
        zipos.putNextEntry(new ZipEntry(fileName));
        os = new DataOutputStream(zipos);
        InputStream is = new FileInputStream(file);
        byte[] b = new byte[100];
        int length = 0;
        while((length = is.read(b))!= -1){
        os.write(b, 0, length);
        }
        is.close();
        zipos.closeEntry();
        } catch (IOException e) {
        e.printStackTrace();
        } 
            }
    }
            
            //关闭流
            try {
                os.flush();
                os.close();
                zipos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }    
    }
    调用的dao层(mapper) 以及前台传的参数 根据自己业务来定,目的就是为了能拿到需要批量下载的文件信息(文件名/文件路径等),再进行遍历 做文件流处理。
    controller 及 service 做过渡及调用工作。
    controller代码如下:
    /**
    * 批量下载
    * @param ids 业务记录id集(格式xx,xx2,xx3) 用于查询相关表获取文件信息
    * @param request
    * @param response
    */
    @RequestMapping(value = "downloadPlanFile")
    public void downloadPlanFile(String ids,HttpServletRequest request,HttpServletResponse response){
    reqPlanService.downloadPlanFile(ids,request,response);
    }
    service代码如下:
    /**
    * 批量下载
    * @param ids  记录id集合
    * @return
    */
    public void downloadPlanFile(String ids,HttpServletRequest request,HttpServletResponse response);
    前端在进行下载前可用ajax做一些校验工作,只要不满足下载就提前抛业务异常。
    前端代码如下:(前端框架采用的easyui)
    //批量下载附件
    attachmentMore:function(){
        //获取选择的记录
    var rows = $('#xqglReqPlanGrid').datagrid('getChecked');
        if(rows.length <1){
            _alert('请选择记录');
            return false;
        }
        //开启遮罩(进度条)
        $.messager.progress();
        //ids参数准备 用逗号隔开id
        var ids = '';
        $.each(rows,function(index,data){
        if(rows.length == index+1){
        ids += data.id;
        }else{
        ids += data.id + ",";
        }
        })
        console.log(ids);
        //下载前的一个业务校验
        $.ajax({
    type : "POST",
    url : Config.sysUrl +'/xqglReqPlan/isDownloadPlanFile',
    data:{"ids":ids},
    cache : false,
    success : function(data) {
                            //关闭遮罩(进度条)
    $.messager.progress('close');
                            //回调成功进行下载
    if(data.success){
    window.location.href=Config.sysUrl+ "/xqglReqPlan/downloadPlanFile?ids="+ids;
    }

    }); 
    }
    前端调用后台下载 我采用的是window.location.href=url 的方式输出。采用这种方式输出流的话,如果期间后台报错抛异常了 前台是不会返回错误信息的,因此我把必要的业务校验用一个ajax提前调用后台进行校验,确保满足下载条件再进行下载。
    详细配置信息可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/28/java%e6%89%b9%e9%87%8f%e4%b8%8b%e8%bd%bd/
  • 相关阅读:
    记:关于反演
    记:关于费马平方和定理的证明
    【2021集训队互测一】愚蠢的在线法官 题解
    CSP/NOIP2021 赛前集训
    20220108 省选组 总结
    Atcoder比赛总结
    Python读取execl数据写入到mysql
    大家都可以拖动的web小方块——Node.js摸石头系列之七
    创建一个Mybatis工程
    Spring整合Mybatis
  • 原文地址:https://www.cnblogs.com/songsu/p/11457761.html
Copyright © 2011-2022 走看看