JAVA 批量下载文件

最近项目有个需求,用户想对挂有附件的数据记录 实现一键下载全部附件(目前项目仅支持每次点击单条记录进行附件下载),下面记录我实现的解决方案。

项目框架基于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提前调用后台进行校验,确保满足下载条件再进行下载。

测试:

选中了两条记录,点击批量下载文件后 浏览器弹出文件下载相关信息。

下载文件正常。

注:window.location.href=url 可能会请求多次 导致下载后原界面(或浏览器)变成空白,针对此问题的解决方案,我后面记录下来。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值