限速、多线程加速、ZIP、导Excel

267 阅读4分钟
  1. 限速下载 通过设置请求头来限制下载速度,可以防止服务器过于快速地传输文件,保护带宽和服务器资源。我们可以使用HttpServletResponse对象的setHeader方法来设置相应的请求头。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.pdf";
    String contentType = "application/octet-stream";
  
    // 设置限速速率
    int rate = 1024; // 1KB/s
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 获取文件输入流
        InputStream inputStream = new FileInputStream(new File("path/to/file"));
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
  
        byte[] buff = new byte[1024];
        int bytesRead;
  
        // 设置限速
        long startTime = System.currentTimeMillis();
        while ((bytesRead = inputStream.read(buff)) != -1) {
            outputStream.write(buff, 0, bytesRead);
  
            // 计算下载速度
            long currentTime = System.currentTimeMillis();
            long elapsedTime = currentTime - startTime;
            int downloadRate = (int) ((outputStream.getChannel().position() / elapsedTime) * 1000);
  
            // 如果当前下载速度大于限速速率,进行限速
            if (downloadRate > rate) {
                Thread.sleep(1000);
                startTime = System.currentTimeMillis();
            }
        }
  
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 多线程加速下载 通过创建多个线程来同时下载文件的不同部分,从而提高下载速度。我们可以使用Java的多线程技术来实现。以下是一个实现多线程下载的示例代码。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.pdf";
    String contentType = "application/octet-stream";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 获取文件输入流
        InputStream inputStream = new FileInputStream(new File("path/to/file"));
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
  
        byte[] buff = new byte[1024];
        int bytesRead;
  
        // 创建下载线程
        DownloadThread[] threads = new DownloadThread[3];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new DownloadThread(inputStream, outputStream, buff);
            threads[i].start();
        }
  
        // 等待所有线程下载完成
        for (DownloadThread thread : threads) {
            thread.join();
        }
  
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

class DownloadThread extends Thread {
    private InputStream inputStream;
    private OutputStream outputStream;
    private byte[] buff;
  
    public DownloadThread(InputStream inputStream, OutputStream outputStream, byte[] buff) {
        this.inputStream = inputStream;
        this.outputStream = outputStream;
        this.buff = buff;
    }
  
    @Override
    public void run() {
        int bytesRead;
        try {
            while ((bytesRead = inputStream.read(buff)) != -1) {
                outputStream.write(buff, 0, bytesRead);
            }
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. ZIP压缩下载 将文件压缩成ZIP格式,然后提供下载链接。我们可以使用java.util.zip包中提供的类来实现文件的压缩和下载。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.zip";
    String contentType = "application/octet-stream";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
        // 创建ZIP输出流
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
  
        // 添加文件到ZIP压缩文件
        File file1 = new File("path/to/file1");
        File file2 = new File("path/to/file2");
  
        addToZipFile(file1, zipOutputStream);
        addToZipFile(file2, zipOutputStream);
  
        zipOutputStream.close();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void addToZipFile(File file, ZipOutputStream zipOutputStream) throws IOException {
    FileInputStream fileInputStream = new FileInputStream(file);
    ZipEntry zipEntry = new ZipEntry(file.getName());
  
    zipOutputStream.putNextEntry(zipEntry);
 
    byte[] buff = new byte[1024];
    int bytesRead;
    while ((bytesRead = fileInputStream.read(buff)) != -1) {
        zipOutputStream.write(buff, 0, bytesRead);
    }
  
    fileInputStream.close();
}
  1. 导出Excel 将数据导出为Excel文件,并提供下载链接。我们可以使用开源库Apache POI来操作Excel文件。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.xlsx";
    String contentType = "application/octet-stream";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();
  
        // 创建工作表
        Sheet sheet = workbook.createSheet("Sheet1");
  
        // 创建单元格并设置数据
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Name");
        headerRow.createCell(1).setCellValue("Age");
  
        Row dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue("John");
        dataRow.createCell(1).setCellValue(25);
  
        // 将工作簿写入输出流
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
  
        workbook.close();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 使用byte数组 直接将文件内容存储在byte数组中,然后通过输出流将byte数组写入响应。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.txt";
    String contentType = "text/plain";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 读取文件内容到byte数组
        byte[] fileContent = Files.readAllBytes(Paths.get("path/to/file"));
  
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
  
        // 将byte数组写入输出流
        outputStream.write(fileContent);
  
        outputStream.flush();
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 使用文件流 使用文件流直接将文件内容写入响应。
@GetMapping("/download")
public void download(HttpServletResponse response) {
    // 设置文件名和内容类型
    String fileName = "example.txt";
    String contentType = "text/plain";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 获取文件输入流
        InputStream inputStream = new FileInputStream(new File("path/to/file"));
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
  
        // 将文件内容写入输出流
        IOUtils.copy(inputStream, outputStream);
  
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 使用ResourceLoader 使用Spring提供的ResourceLoader来加载文件,并将文件内容写入响应。
@GetMapping("/download")
public void download(HttpServletResponse response, ResourceLoader resourceLoader) {
    // 设置文件名和内容类型
    String fileName = "example.txt";
    String contentType = "text/plain";
  
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
    response.setContentType(contentType);
  
    try {
        // 使用ResourceLoader加载文件
        Resource resource = resourceLoader.getResource("classpath:path/to/file");
        // 获取文件输入流
        InputStream inputStream = resource.getInputStream();
        // 获取文件输出流
        OutputStream outputStream = response.getOutputStream();
  
        // 将文件内容写入输出流
        IOUtils.copy(inputStream, outputStream);
  
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 使用StreamingResponseBody 使用Spring提供的StreamingResponseBody接口来实现异步下载,提高系统的并发能力。
@GetMapping("/download")
public ResponseEntity<StreamingResponseBody> download() {
    // 设置文件名和内容类型
    String fileName = "example.txt";
    String contentType = "text/plain";
  
    return ResponseEntity
            .ok()
            .header("Content-Disposition", "attachment; filename="" + fileName + """)
            .contentType(MediaType.parseMediaType(contentType))
            .body(outputStream -> {
                try {
                    // 获取文件输入流
                    InputStream inputStream = new FileInputStream(new File("path/to/file"));
  
                    byte[] buff = new byte[1024];
                    int bytesRead;
  
                    while ((bytesRead = inputStream.read(buff)) != -1) {
                        outputStream.write(buff, 0, bytesRead);
                    }
  
                    inputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
}
  1. 使用ResponseEntity 使用Spring提供的ResponseEntity类来实现下载,将文件内容包装为HttpEntity对象返回。
@GetMapping("/download")
public ResponseEntity<byte[]> download() {
    // 设置文件名和内容类型
    String fileName = "example.txt";
    String contentType = "text/plain";
  
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "attachment; filename="" + fileName + """);
    headers.setContentType(MediaType.parseMediaType(contentType));
  
    try {
        // 读取文件内容到byte数组
        byte[] fileContent = Files.readAllBytes(Paths.get("path/to/file"));
  
        return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}