文件流下载网络文件

背景

需求

需要对外提供下载文件的API接口,为了安全对外接口下载接口使用流形式(平时我们会将文件服务器的文件URL返回前端使用)

思路

文件地址生成 本地File文件,流转换之后删除本地文件,响应前端。

环境

  • SpringBoot 2.1.2.RELEASE
  • JDK 1.8
  • Maven 3.5.0

正文

Service

package com.fang.industry.service.exce.impl;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

/**
 * @author: guochao.bj@fang.com
 * @createDate: 2021/6/22 10:26
 */
@Service
public class ILandServiceImpl implements ILandService {

    @Resource
    IndustryLandApi industryLandApi;


    @Resource
    ILandDao landDao;

    @Value("${landAfficheFilepath}")
    private String landAfficheFilepath;	
    //本地文件暂存位置,使用apollo配置方便修改,也可以在配置文件定义

    @Override
    public ResultDto getLandAfficheFile(LandDetailBo bo,HttpServletResponse response){

        ResultDto result = new ResultDto();
             /*---------------------------------具体业务逻辑开始,无关--------------------------------------------*/

        try {
            com.fang.industry.bo.land.land.LandDetailBo landDetailBo = new com.fang.industry.bo.land.land.LandDetailBo();
            BeanUtils.copyProperties(bo,landDetailBo);
            DtoResponse<com.fang.industry.dto.land.land.LandDetailDto> landDetail = industryLandApi.getLandDetail(landDetailBo);
            if (landDetail == null || landDetail.getData() == null) {
                result.setCode(0);
                result.setMessage("公告详情查询异常");
                return result;
            }
            com.fang.industry.dto.land.land.LandDetailDto data = landDetail.getData();


            /*---------------------------------以上部分为具体业务逻辑结束,无关--------------------------------------------*/

            File fileByurl=null;
            String announcementNo = data.getAnnouncementNo();   //文件名称
            String parcelAffiche = data.getParcelAffiche();     //网络文件地址URL
            String suffix=".pdf";               //文件后缀
            if (parcelAffiche.endsWith(".pdf")){
                suffix=".pdf";
            }else if (parcelAffiche.endsWith(".docx")){
                suffix=".docx";
            }
            //核心方法,网络文件地址URL转换为File文件
            fileByurl = getFileByurl(parcelAffiche, suffix, announcementNo);
            try {
                // 以流的形式下载文件。
                InputStream fis = new BufferedInputStream(new FileInputStream(fileByurl));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();
                // 清空response
                response.reset();
                // 设置response的Header
                String fileName = new String(("LandAfficheFile"+suffix).getBytes());
                response.setCharacterEncoding("UTF-8");
                response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
                response.addHeader("Content-Length", "" + fileByurl.length());
                OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                toClient.write(buffer);
                toClient.flush();
                toClient.close();
            }finally {
                /*
                * 重要,在将文件转换为文件流之后,要将本地暂存文件删除
                * */
                fileByurl.delete();


            }
            result.setCode(1);
            result.setMessage("土地公告文件下载成功");

        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(0);
            result.setMessage("土地公告文件下载异常");
        }
        return result;
    }


    /**
     * 网络文件URL转换为文件
     * @param url   网络文件URL
     * @param suffix    文件后缀
     * @param fileName  文件名
     * @return java.io.File
     * @author guochao.bj@fang.com
     * @date 2021/6/23
     */
    private File getFileByurl(String url,String suffix,String fileName){
        File file = null;
        URL urlfile;
        InputStream inputStream = null;
        OutputStream outputStream= null;
        try {
            String path = landAfficheFilepath;  //本地文件暂存位置,使用apollo配置方便修改,也可以在配置文件定义
            File file1 = new File(path);
            file = File.createTempFile(fileName, suffix,file1);
            //下载
            urlfile = new URL(url);
            inputStream = urlfile.openStream();
            outputStream= new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            return null;
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
            } catch (Exception e) {
                return null;
            }
        }
        return file;
    }



}

Controller

    @ApiSn("7435f8ec-ab8f-4801-b94e-bfa5763e5dd1")
    @PostMapping(value = "/getLandAfficheFile", produces = "application/json")
    @ApiOperation(value = "土地公告文件接口", notes = "guochao.bj@fang.com", httpMethod = "POST",
            produces = "application/json")
    void getLandAfficheFile(@RequestBody LandDetailBo bo) throws MalformedURLException;

 	@Resource
    HttpServletResponse response;
    
    @Override
    public void getLandAfficheFile(LandDetailBo bo){

        if (bo.getCityCode() == null || StringUtils.isBlank(bo.getCityCode().toString())) {
            throw new ApiRuntimeException(ApiExceptionEnum.PARAM_IS_BLANK, "城市Code不能为空!");
        }
        if (StringUtils.isBlank(bo.getLandId())) {
            throw new ApiRuntimeException(ApiExceptionEnum.PARAM_IS_BLANK, "土地ID不能为空!");
        }
        ResultDto resultDto = iLandService.getLandAfficheFile(bo, response);
        if (resultDto.getCode()==0){
            throw new ApiRuntimeException(ApiExceptionEnum.INTERFACE_INNER_INVOKE_ERROR, resultDto.getMessage());
        }
    }

补充

/**
     * 删除指定目录下面指定文件类型的文件
     *
     * @param path
     */
    public static void delSpecifyTheTypeFile(String path) {
        File dir = new File(path);
        // 该文件目录下文件全部放入数组
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String fileName = files[i].getName();
                // 判断是文件还是文件夹
                if (files[i].isDirectory()) {
                    // 获取文件绝对路径
                    delSpecifyTheTypeFile(files[i].getAbsolutePath());
                    // 判断文件名是否以.tif结尾
                } else if (fileName.endsWith(".tif")) {
                    String strFileName = files[i].getAbsolutePath();
                    System.out.println("删除文件名:" + strFileName);
                    files[i].delete();
                } else {
                    continue;
                }
            }
        }
    }

20210721补充

中文使用URLEncoder编码,前端配合decodeURI解码

编码之前:数据集-下载
之后:%E6%95%B0%E6%8D%AE%E9%9B%86-%E4%B8%8B%E8%BD%BD

URLEncoder编码

在这里插入图片描述


	@Resource
	HttpServletResponse response;

public void downloadData(DataIdDownloadBo bo) {
		DtoResponse<DataExcelDto> result=new DtoResponse<DataExcelDto>();
		try {
			DataExcel dataExcel = appDataService.getDataExcelDetails(bo);
			if (dataExcel==null){
				return;
			}
			ArrayList<List<String>> headList = dataExcel.getHeadList();
			final Integer[] startrow = {headList.size()};

			//ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			Workbook workBook = new XSSFWorkbook();
			ExportExcelPoiUtil.createHead(headList,"sheet",workBook);

			Map<Integer, ArrayList<List<String>>> bodyStringListMap = dataExcel.getBodyStringListMap();
			Set<Integer> keySet = bodyStringListMap.keySet();
			keySet.forEach(a->{
				ArrayList<List<String>> bodyList = bodyStringListMap.get(a);
				ExportExcelPoiUtil.fillBody(bodyList,"sheet", startrow[0],dataExcel.getMergeCellIndex(),workBook);
				int size = bodyList.size();
				startrow[0] = startrow[0] + size;

			});
			
			//---------------------------这里下载代码 Strat-------------------------------
			ServletOutputStream outputStream = response.getOutputStream();
			//URLEncoder编码
			String encode = URLEncoder.encode(dataExcel.getDataName(), "UTF-8");
			response.addHeader("Content-Disposition", "attachment;filename=" + encode+".xlsx");
			response.setContentType("application/vnd.ms-excel;charset=UTF-8");
			response.setCharacterEncoding("utf-8");
			ExportExcelPoiUtil.exportExcelByStream(workBook,outputStream);
			//---------------------------这里下载代码 end-------------------------------
		}catch (Exception e){
			e.printStackTrace();
			//return result.failure(0,"下载异常");
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abner G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值