热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java实现断点续传服务

java实现断点续传服务一:什么是断点续传客户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载




java 实现断点续传服务

一:什么是断点续传

客户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载

(将文件分片以及后续合并是一个不小的工作量,由于项目时间有限,我并没有做分片,只是实现了可断点下载)


二:实现原理


2.1 实现思路

需要前端和后端的配合,前端在请求头中 标明 下载开始的位置,后端重标记位置开始向前端输出文件剩余部分。

在简单模式下,前端不需要知道文件大小,也不许要知道文件是否已经下载完毕。当文件可以正常打开时即文件下载完毕。(若想知道文件是否下载完毕,可写个接口比较Range 值与文件大小)

一般服务请求头

GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive

响应头

200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

如果要服务器支持断点续传功能的话,需要在请求头中表明文件开始下载的位置

请求头

GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070- #表示文件从2000070处开始下载
# Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

响应头

206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

三:java代码实现


3.1 BreakPoinService类

import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@Service
public class BreakPoinService {
//断点续传
public void downLoadByBreakpoint(File file, long start, long end, HttpServletResponse response){
OutputStream stream = null;
RandomAccessFile fif = null;
try {
if (end <= 0) {
end = file.length() - 1;
}
stream = response.getOutputStream();
response.reset();
response.setStatus(206);
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment; filename=" + file.getName());
response.setHeader("Content-Length", String.valueOf(end - start + 1));
response.setHeader("file-size", String.valueOf(file.length()));
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Content-Range", String.format("bytes %s-%s/%s", start, end, file.length()));
fif = new RandomAccessFile(file, "r");
fif.seek(start);
long index = start;
int d;
byte[] buf = new byte[10240];
while (index <= end && (d = fif.read(buf)) != -1) {
if (index + d > end) {
d = (int)(end - index + 1);
}
index += d;
stream.write(buf, 0, d);
}
stream.flush();
} catch (Exception e) {
try {
if (stream != null)
stream.close();
if (fif != null)
fif.close();
} catch (Exception e11) {
}
}
}
//全量下载
public void downLoadAll(File file, HttpServletResponse response){
OutputStream stream = null;
BufferedInputStream fif = null;
try {
stream = response.getOutputStream();
response.reset();
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment; filename=" + file.getName());
response.setHeader("Content-Length", String.valueOf(file.length()));
fif = new BufferedInputStream(new FileInputStream(file));
int d;
byte[] buf = new byte[10240];
while ((d = fif.read(buf)) != -1) {
stream.write(buf, 0, d);
}
stream.flush();
} catch (Exception e) {
try {
if (stream != null)
stream.close();
if (fif != null)
fif.close();
} catch (Exception e11) {
}
}
}
}

3.2 断点续传控制类

import cn.ztuo.api.cos.QCloudStorageService;
import cn.ztuo.api.service.IBreakpointResumeService;
import cn.ztuo.api.service.impl.BreakPoinService;
import cn.ztuo.commons.annotation.PassToken;
import cn.ztuo.commons.response.CommonResult;
import cn.ztuo.mbg.entity.BreakpointResume;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 断点续传控制类
*/
@RestController
@RequestMapping("/breakpoint")
public class BreakPointController {
@Autowired
private IBreakpointResumeService breakpointResumeService;
@Autowired
private BreakPoinService breakPoinService;
@Autowired
private QCloudStorageService storageService;
@PassToken
@GetMapping(value = "resource")
public CommonResult download(HttpServletRequest request, HttpServletResponse response, @RequestParam("key") String key) {
LambdaQueryWrapper brWrapper=new LambdaQueryWrapper<>();
brWrapper.eq(BreakpointResume::getCodKey,key);
List list = breakpointResumeService.list(brWrapper);
String str=null;
//如果本地存在取本地文件
if(list.size()>0){
BreakpointResume breakpointResume = list.get(0);
str=breakpointResume.getFilePath();
}else{//本地不存在
try{
String download = storageService.download(key);
BreakpointResume breakpointResume=new BreakpointResume();
breakpointResume.setCodKey(key);
breakpointResume.setFilePath(download);
breakpointResume.setCreateTime(new Date());
breakpointResume.setUpdateTime(new Date());
boolean save = breakpointResumeService.save(breakpointResume);
if(save){
str=download;
}else{
return CommonResult.error();
}
}catch (Exception e){
return CommonResult.error();
}
}
if(str==null){
return CommonResult.error();
}
File file=new File(str);
if (file.exists()) {
String range = request.getHeader("Range");
if (range != null && (range = range.trim()).length() > 0) {
Pattern rangePattern = Pattern.compile("^bytes=([0-9]+)-([0-9]+)?$");
Matcher matcher = rangePattern.matcher(range);
if (matcher.find()) {
Integer start = Integer.valueOf(matcher.group(1));
Integer end = 0;
String endStr = matcher.group(2);
if (endStr != null && (endStr = endStr.trim()).length() > 0)
end = Integer.valueOf(endStr);
breakPoinService.downLoadByBreakpoint(file, start, end, response);
return null;
}
}
breakPoinService.downLoadAll(file, response);
return null;
}
return CommonResult.error();
}
}

3.3 自定义全局响应类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult {
private String code;
private String msg;
private T data;
public CommonResult(String code,String msg){
this.code=code;
this.msg=msg;
}
public static CommonResult success(){
return create("200","成功");
}
public static CommonResult success(T data){
CommonResult result = create("200", "成功");
result.setData(data);
return result;
}
public static CommonResult error(){
return create("500","服务器开小差了");
}
public static CommonResult create(String code,String msg){
return new CommonResult(code,msg);
}
}


推荐阅读
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在Android平台上,视频监控系统的优化与应用具有重要意义。尽管已有相关示例(如http:www.open-open.comlibviewopen1346400423609.html)展示了基本的监控功能实现,但若要提升系统的稳定性和性能,仍需进行深入研究和优化。本文探讨了如何通过改进算法、优化网络传输和增强用户界面来提高Android视频监控系统的整体效能,以满足更复杂的应用需求。 ... [详细]
  • 本文详细介绍了如何安全地手动卸载Exchange Server 2003,以确保系统的稳定性和数据的完整性。根据微软官方支持文档(https://support.microsoft.com/kb833396/zh-cn),在进行卸载操作前,需要特别注意备份重要数据,并遵循一系列严格的步骤,以避免对现有网络环境造成不利影响。此外,文章还提供了详细的故障排除指南,帮助管理员在遇到问题时能够迅速解决,确保整个卸载过程顺利进行。 ... [详细]
  • 通过以下步骤可以确定SharePoint网站集对应的W3WP进程及其运行状态:首先,打开命令提示符(CMD),然后输入 `iisapp` 命令,该命令将列出当前IIS中所有Web应用程序及其对应的w3wp.exe进程。此外,还可以使用任务管理器或PowerShell脚本来进一步检查这些进程的详细信息和运行状态,以确保网站集的正常运行。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 深入解析C语言中结构体的内存对齐机制及其优化方法
    为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。 ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
author-avatar
品格优良2003_645
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有