栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot 之 PDF大文件分片加载(后端)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot 之 PDF大文件分片加载(后端)

业务需求:前端集成pdf.js 实现在线阅读pdf 文件,但pdf 文件过大时(大于100M)会出现浏览器内存溢出导出程序崩溃的场景发生。针对这个情况,后端给出的解决方案是:分片加载pdf 文件流。

约定:与前端约定在header 头部参数中追加rang 参数:表示需要加载文件片数,后台动态计算起始字节位置,流式输出指定文件内容。

SpringBoot源码:

pom.xml:


	4.0.0
	com.single
	Single
	0.0.1-SNAPSHOT

	
		org.springframework.boot
		spring-boot-starter-parent
		2.1.9.RELEASE
		 
	

	
		1.8
		3.1.1
	

	
		
			org.springframework.boot
			spring-boot-starter-web
		

		
			org.springframework.boot
			spring-boot-starter-test
			test
		
	

	
		
			
				org.springframework.boot
				spring-boot-maven-plugin
			
		
	


application 程序启动窗口

package com.single;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SingleApplication {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SpringApplication.run(SingleApplication.class, args);
	}

}

Controller

package com.single.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;



@Controller
@RequestMapping("/api/file")
public class FileController {
	public static final Logger logger = LoggerFactory.getLogger(FileController.class);

	
	@RequestMapping(value = "/showpdf", method = RequestMethod.GET)
	public void showpdf(HttpServletRequest req, HttpServletResponse res) {
		try {
			this.download(req, res);
		} catch (Exception e) {
			// e.printStackTrace();
			logger.error("错误信息:{}", e.getMessage(), e);
		}
	}

	

	public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
		// 从文件存储服务器下载文件到本地
		File file = new File("D:/test.pdf");
		BufferedInputStream bis = null;
		OutputStream os = null;
		BufferedOutputStream bos = null;
		InputStream is = null;
		try {
			is = new FileInputStream(file);
			bis = new BufferedInputStream(is);
			os = response.getOutputStream();
			bos = new BufferedOutputStream(os);
			// 下载的字节范围
			int startByte, endByte, totalByte;
			if (request != null && request.getHeader("range") != null) {
				// 起始字节大小
				String[] range = request.getHeader("range").replaceAll("[^0-9\-]", "").split("-");
				// 文件总大小
				totalByte = is.available();
				 // 下载起始位置
                startByte = Integer.parseInt(range[0]);
                // 下载结束位置
                if (range.length > 1) {
                    endByte = Integer.parseInt(range[1]);
                } else {
                    endByte = totalByte - 1;
                }

				
				// 返回http状态
				response.setStatus(206);
			} else {
				// 正常下载
				// 文件总大小
				totalByte = is.available();

				// 下载起始位置
				startByte = 0;
				// 下载结束位置
				endByte = totalByte - 1;
				// 返回http状态
				response.setHeader("Accept-Ranges", "bytes");
				response.setStatus(206);
			}
			// 需要下载字节数
			int length = endByte - startByte;
			// 响应头
			response.setHeader("Accept-Ranges", "bytes");
			response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);
			response.setContentType("Content-Type: application/octet-stream");
			response.setContentLength(length);
			// 响应内容
			bis.skip(startByte);
			int len = 0;
			byte[] buff = new byte[1024 * 64];
			while ((len = bis.read(buff, 0, buff.length)) != -1) {
				if (length <= len) {
					bos.write(buff, 0, length);
					break;
				} else {
					length -= len;
					bos.write(buff, 0, len);
				}
			}
		} catch (IOException e) {
			System.out.println("下载中断!");
			logger.error("错误信息:{}", e.getMessage(), e);
		} finally {
			bos.close();
			os.close();
			bis.close();
			is.close();
		}

	}

}

Filter

package com.single.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;



@Component
public class CROSFilter implements Filter {
	public static final Logger logger = LoggerFactory.getLogger(CROSFilter.class);
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletResponse response = (HttpServletResponse) res;  
		  
        HttpServletRequest reqs = (HttpServletRequest) req;  
        
        response.setHeader("Access-Control-Allow-Origin","*");  
        response.setHeader("Access-Control-Allow-Credentials", "true");  
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "Content-Type");  
        if (((HttpServletRequest) req).getMethod().equals("OPTIONS")) {
            response.getWriter().println("ok");
            return;
        }

        chain.doFilter(req, res);  
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

application.properties

# 指定服务端口
server.port=9092
# 指定日志文件配置
logging.config=classpath:logback.xml

logback.xml

 
  
  
  
  
  
  
  
  
      
      
      
      
  
  
      
      
          
          
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n  
          
      
      
      
      
      
      
          
          
            ERROR  
            ACCEPT  
            DENY  
          
          
          
              
            ${log_dir}/%d{yyyy-MM-dd}/error.log  
              
            ${maxHistory}  
          
                  
          
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n  
          
      
      
      
      
      
          
          
            WARN  
            ACCEPT  
            DENY  
          
          
            ${log_dir}/%d{yyyy-MM-dd}/warn.log  
              
            ${maxHistory}  
          
          
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n  
          
      
      
      
      
      
          
          
            INFO  
            ACCEPT  
            DENY  
          
          
            ${log_dir}/%d{yyyy-MM-dd}/info.log  
              
            ${maxHistory}  
          
          
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n  
          
      
      
      
      
      
          
            DEBUG  
            ACCEPT  
            DENY  
          
          
            ${log_dir}/%d{yyyy-MM-dd}/debug.log  
              
            ${maxHistory}  
          
          
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n  
          
      
    
    
    
		
      
      
      
          
          
          
          
          
          
          
      

PostMan 模拟工具效果展示:

 

基本功能已经完成,静待前端工程师的对接。 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425073.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号