springboot服务器文件读取工具类

本地文件和网络文件读取

一. SpringBoot的RestTemplate配置

二. 文件读取

  • RangeEntity 分片下载的封装对象
java 复制代码
package com.zzc.component.download;

import com.zzc.common.utils.StrUtils;
import lombok.Data;

import javax.servlet.http.HttpServletResponse;


public class RangeEntity {

    private String range;

    private long contentLength;

    private String contentRange;

    private Long firstPos;

    private Long lastPos;


    public RangeEntity(String range, long contentLength) {
        parseRange(range, contentLength);
    }

    private void parseRange(String range, long contentLength) {
        this.range = range;
        this.contentLength = contentLength;

        if (StrUtils.isBlank(range) || "null".equalsIgnoreCase(range)) {
            this.firstPos = 0L;
            this.contentLength = contentLength;
            this.contentRange = "bytes " + 0 + "-" + (contentLength - 1) + "/" + contentLength;
            return;
        }

        range = range.trim();
        String rangeBytes = range.replaceAll("bytes=", "").replaceAll(" ", "");
        if (rangeBytes.endsWith("-")) {//bytes=99999-
            rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf("-"));
            this.firstPos = Long.valueOf(rangeBytes.trim());
            this.contentLength = contentLength - this.firstPos;
            this.contentRange = "bytes " + this.firstPos + "-" + (contentLength - 1) + "/" + contentLength;
        } else {
            this.firstPos = Long.valueOf(rangeBytes.substring(0, rangeBytes.indexOf("-")));
            this.lastPos = Long.valueOf(rangeBytes.substring(rangeBytes.indexOf("-") + 1));
            this.contentLength = this.lastPos - this.firstPos + 1;
            this.contentRange = "bytes " + this.firstPos + "-" + this.lastPos + "/" + contentLength;
        }
    }

    public int getStatusCode(boolean isIeOrPlayer) {
        if (((StrUtils.isBlank(range) || "null".equalsIgnoreCase(range)) && isIeOrPlayer)
                || (this.firstPos == null && this.lastPos == null)) {
            return HttpServletResponse.SC_OK;
        } else {
            return HttpServletResponse.SC_PARTIAL_CONTENT;
        }
    }

    public String getRange() {
        return range;
    }

    public long getContentLength() {
        return contentLength;
    }

    public String getContentRange() {
        return contentRange;
    }

    public boolean isNotRange() {
        return lastPos == null || firstPos == 0;
    }

    public Long getFirstPos() {
        return firstPos;
    }
}
  • HeaderUtils 请求header判断类
java 复制代码
package com.zzc.component.download;

import com.zzc.common.utils.StrUtils;

import javax.servlet.http.HttpServletRequest;

public class HeaderUtils {

    public static boolean isIeBrowser(HttpServletRequest request) {
        String[] isSignals = {"MSIE", "Trident", "Edge", "Safari"};
        String userAgent = request.getHeader("User-Agent");
        if (StrUtils.isNotBlank(userAgent)) {
            for (String signal : isSignals) {
                if (userAgent.contains(signal)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isWinPlayer(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        if (StrUtils.isNotBlank(userAgent)) {
            return userAgent.contains("Windows-Media-Player");
        }
        return false;
    }
}
  • HeaderConstant请求header对应字段
java 复制代码
package com.zzc.component.download;

public class HeaderConstant {

    public static final String KEY_ACCEPT_RANGE = "Accept-Ranges";

    public static final String KEY_CONTENT_LENGTH = "Content-Length";

    public static final String KEY_CONTENT_RANGE = "Content-Range";

    public static final String KEY_CONTENT_TYPE = "Content-Type";

    public static final String KEY_CONTENT_DISPOSITION = "Content-Disposition";
}
  • 本地文件读取
java 复制代码
package com.zzc.component.download;

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

public interface FileComponent {

    void play(String path, HttpServletRequest request, HttpServletResponse response);

    void download(String path, HttpServletRequest request, HttpServletResponse response);

}
java 复制代码
package com.zzc.component.download;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;

@Slf4j
@Component
public class FileComponentImpl implements FileComponent {
    @Override
    public void play(String path, HttpServletRequest request, HttpServletResponse response) {
        RandomAccessFile raf = null;
        try {
            File file = new File(path);
            if (!file.exists()) {
                throw new RuntimeException();
            }
            long length = file.length();
            String range = request.getHeader("Range");
            String filename = file.getName();
            String contentType = "video/mp4";//文件类型
            RangeEntity rangeEntity = new RangeEntity(range, length);
            addHeader(request, response, rangeEntity, contentType, filename);
            raf = new RandomAccessFile(file, "r");
            OutputStream outputStream = response.getOutputStream();
            if (rangeEntity.isNotRange()) {
                channelCopy(raf.getChannel(), Channels.newChannel(outputStream), rangeEntity.getFirstPos(), length);
                outputStream.flush();
                return;
            }

            long contentLength = rangeEntity.getContentLength();
            channelCopy(raf.getChannel(), Channels.newChannel(outputStream), rangeEntity.getFirstPos(), contentLength);
            outputStream.flush();
            //outputStream.close();
        } catch (Exception e) {

        } finally {
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {

                }
            }
        }
    }

    private static void addHeader(HttpServletRequest request, HttpServletResponse response, RangeEntity rangeEntity, String contentType, String filename) {
        boolean isIeOrPlayer = HeaderUtils.isWinPlayer(request) || HeaderUtils.isIeBrowser(request);
        response.setStatus(rangeEntity.getStatusCode(isIeOrPlayer));
        response.setHeader(HeaderConstant.KEY_ACCEPT_RANGE, "bytes");
        response.setHeader(HeaderConstant.KEY_CONTENT_LENGTH, rangeEntity.getContentLength() + "");
        if (rangeEntity.getContentRange() != null) {
            response.setHeader(HeaderConstant.KEY_CONTENT_RANGE, rangeEntity.getContentRange());
        }
        response.setHeader(HeaderConstant.KEY_CONTENT_TYPE, contentType);
        //response.setHeader(HeaderConstant.KEY_CONTENT_DISPOSITION, "inline; filename=\"" + filename + "\"; filename*=utf-8''" + filename);
        if (isIeOrPlayer) {
            try {
                response.setHeader(HeaderConstant.KEY_CONTENT_DISPOSITION, "inline; filename=\"" + URLEncoder.encode(filename, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void download(String path, HttpServletRequest request, HttpServletResponse response) {
        FileInputStream is = null;
        try {
            File file = new File(path);
            if (!file.exists()) {
                throw new RuntimeException();
            }
            String name = file.getName();
            long length = file.length();
            String contentType = "video/mp4";
            is = new FileInputStream(file);
            response.setHeader(HeaderConstant.KEY_CONTENT_LENGTH,  length + "");
            response.setHeader(HeaderConstant.KEY_CONTENT_TYPE, contentType);
            response.setHeader(HeaderConstant.KEY_CONTENT_DISPOSITION, "attachment;filename=" + name);
            ServletOutputStream outputStream = response.getOutputStream();
            channelCopy(is.getChannel(), Channels.newChannel(outputStream), 0, length);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {

        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {

                }
            }
        }
    }

    private static void channelCopy(FileChannel readableChannel, WritableByteChannel writableByteChannel, long position, long size) {
        try {
            if (writableByteChannel.isOpen()) {
                readableChannel.transferTo(position, size, writableByteChannel);
            }
        } catch (Exception e) {

        } finally {
            try {
                readableChannel.close();
                writableByteChannel.close();
            } catch (IOException e) {

            }
        }
    }
}
  • 网络文件读取
java 复制代码
package com.zzc.component.download;

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

public interface OBSComponent {

    void download(String url, HttpServletRequest request, HttpServletResponse response);

}
java 复制代码
package com.zzc.component.download;

import com.zzc.component.http.RestTemplateComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.ResponseExtractor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class OBSComponentImpl implements OBSComponent {

    @Autowired
    private RestTemplateComponent restTemplateComponent;


    @Override
    public void download(String url, HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> headers = new HashMap<>();
        ResponseExtractor<Boolean> extractor = new ResponseExtractor<Boolean>() {
            @Override
            public Boolean extractData(ClientHttpResponse clientHttpResponse) throws IOException {
                HttpStatus statusCode = clientHttpResponse.getStatusCode();
                if (statusCode.isError()) {
                    return false;
                }
                //TODO head
                Map<String, String> header = new HashMap<>();
                return true;
            }
        };
        restTemplateComponent.transfer(url, headers, extractor);
    }

    private static void channelCopy(ReadableByteChannel readableByteChannel, WritableByteChannel writableByteChannel) {
        try {
            ByteBuffer buffer = ByteBuffer.allocateDirect(32 * 1024);
            while (writableByteChannel.isOpen() && readableByteChannel.read(buffer) != -1) {
                buffer.flip();
                writableByteChannel.write(buffer);
                buffer.compact();
            }
            buffer.flip();
            while (writableByteChannel.isOpen() && buffer.hasRemaining()) {
                writableByteChannel.write(buffer);
            }

        } catch (Exception e) {

        } finally {
            try {
                readableByteChannel.close();
                writableByteChannel.close();
            } catch (IOException e) {

            }
        }
    }
}
相关推荐
winks33 分钟前
Spring Task的使用
java·后端·spring
秋意钟13 分钟前
Spring新版本
java·后端·spring
椰椰椰耶15 分钟前
【文档搜索引擎】缓冲区优化和索引模块小结
java·spring·搜索引擎
mubeibeinv17 分钟前
项目搭建+图片(添加+图片)
java·服务器·前端
青莳吖18 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall25 分钟前
期末考学C
java·开发语言
重生之绝世牛码27 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行33 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
新手小袁_J1 小时前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
呆呆小雅1 小时前
C#关键字volatile
java·redis·c#