Java 服务器端支持断点续传的源代码【支持快车、迅雷】(仅支持 HTTP 协议)

网上关于 Java 支持 HTTP 断点续传的文章不少,但关于 Java 服务器端支持 HTTP 断点续传的却比较少。
        本文是 Java 服务器端支持 HTTP 断点续传的源代码,支持快车、迅雷。
        本文使用一个简单的 Servlet 来作为支持断点续传的下载示例,在 Java Web 项目下部署好后,可以使用诸如 http://localhost/cds/http 的链接来调用 Servlet,进而被快车/迅雷监听进行下载。

ArcSyncHttpDownloadServlet 源代码:

package com.defonds.cds.common;import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;import com.defonds.cds.common.util.CommonUtil;//HTTP 断点续传 demo(客户端测试工具:快车、迅雷)
public class ArcSyncHttpDownloadServlet extends HttpServlet {private static final long serialVersionUID = 1L;final static Log log = LogFactory.getLog(ArcSyncHttpDownloadServlet.class);@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) {File downloadFile = new File("D:/defonds/book/pattern/SteveJobsZH.pdf");//要下载的文件long fileLength = downloadFile.length();//记录文件大小long pastLength = 0;//记录已下载文件大小int rangeSwitch = 0;//0:从头开始的全文下载;1:从某字节开始的下载(bytes=27000-);2:从某字节开始到某字节结束的下载(bytes=27000-39000)long toLength = 0;//记录客户端需要下载的字节段的最后一个字节偏移量(比如bytes=27000-39000,则这个值是为39000)long contentLength = 0;//客户端请求的字节总量String rangeBytes = "";//记录客户端传来的形如“bytes=27000-”或者“bytes=27000-39000”的内容 RandomAccessFile raf = null;//负责读取数据OutputStream os = null;//写出数据OutputStream out = null;//缓冲byte b[] = new byte[1024];//暂存容器if (request.getHeader("Range") != null) {// 客户端请求的下载的文件块的开始字节response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);log.info("request.getHeader(\"Range\")=" + request.getHeader("Range"));rangeBytes = request.getHeader("Range").replaceAll("bytes=", "");if (rangeBytes.indexOf('-') == rangeBytes.length() - 1) {//bytes=969998336-rangeSwitch = 1;rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));pastLength = Long.parseLong(rangeBytes.trim());contentLength = fileLength - pastLength + 1;//客户端请求的是 969998336 之后的字节} else {//bytes=1275856879-1275877358rangeSwitch = 2;String temp0 = rangeBytes.substring(0,rangeBytes.indexOf('-'));String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());pastLength = Long.parseLong(temp0.trim());//bytes=1275856879-1275877358,从第 1275856879 个字节开始下载toLength = Long.parseLong(temp2);//bytes=1275856879-1275877358,到第 1275877358 个字节结束contentLength = toLength - pastLength + 1;//客户端请求的是 1275856879-1275877358  之间的字节}} else {//从开始进行下载contentLength = fileLength;//客户端要求全文下载}/*** 如果设设置了Content-Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。* 响应的格式是:* Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]* ServletActionContext.getResponse().setHeader("Content-Length",* new Long(file.length() - p).toString());*/response.reset();//告诉客户端允许断点续传多线程连接下载,响应的格式是:Accept-Ranges: bytesresponse.setHeader("Accept-Ranges", "bytes");//如果是第一次下,还没有断点续传,状态是默认的 200,无需显式设置;响应的格式是:HTTP/1.1 200 OKif (pastLength != 0) {//不是从最开始下载,//响应的格式是://Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]log.info("----------------------------不是从开始进行下载!服务器即将开始断点续传...");switch (rangeSwitch) {case 1 : {//针对 bytes=27000- 的请求String contentRange = new StringBuffer("bytes ").append(new Long(pastLength).toString()).append("-").append(new Long(fileLength - 1).toString()).append("/").append(new Long(fileLength).toString()).toString();response.setHeader("Content-Range", contentRange);break;}case 2 : {//针对 bytes=27000-39000 的请求String contentRange = rangeBytes + "/" + new Long(fileLength).toString();response.setHeader("Content-Range", contentRange);break;}default : {break;}}} else {//是从开始下载log.info("----------------------------是从开始进行下载!");}try {response.addHeader("Content-Disposition", "attachment; filename=\"" + downloadFile.getName() + "\"");response.setContentType( CommonUtil.setContentType(downloadFile.getName()));// set the MIME type.response.addHeader("Content-Length", String.valueOf(contentLength));os = response.getOutputStream();out = new BufferedOutputStream(os);raf = new RandomAccessFile(downloadFile, "r");try {switch (rangeSwitch) {case 0 : {//普通下载,或者从头开始的下载//同1}case 1 : {//针对 bytes=27000- 的请求raf.seek(pastLength);//形如 bytes=969998336- 的客户端请求,跳过 969998336  个字节int n = 0;while ((n = raf.read(b, 0, 1024)) != -1) {out.write(b, 0, n);}break;}case 2 : {//针对 bytes=27000-39000 的请求raf.seek(pastLength - 1);//形如 bytes=1275856879-1275877358 的客户端请求,找到第 1275856879 个字节int n = 0;long readLength = 0;//记录已读字节数while (readLength <= contentLength - 1024) {//大部分字节在这里读取n = raf.read(b, 0, 1024);readLength += 1024;out.write(b, 0, n);}if (readLength <= contentLength) {//余下的不足 1024 个字节在这里读取n = raf.read(b, 0, (int)(contentLength - readLength));out.write(b, 0, n);}
//
//                      raf.seek(pastLength);//形如 bytes=1275856879-1275877358 的客户端请求,找到第 1275856879 个字节
//                      while (raf.getFilePointer() < toLength) {
//                          out.write(raf.read());
//                      }break;}default : {break;}}out.flush();} catch(IOException ie) {/*** 在写数据的时候,* 对于 ClientAbortException 之类的异常,* 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时,* 抛出这个异常,这个是正常的。* 尤其是对于迅雷这种吸血的客户端软件,* 明明已经有一个线程在读取 bytes=1275856879-1275877358,* 如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段,* 直到有一个线程读取完毕,迅雷会 KILL 掉其他正在下载同一字节段的线程,* 强行中止字节读出,造成服务器抛 ClientAbortException。* 所以,我们忽略这种异常*///ignore}} catch (Exception e) {log.error(e.getMessage(), e);} finally {if (out != null) {try {out.close();} catch (IOException e) {log.error(e.getMessage(), e);}}if (raf != null) {try {raf.close();} catch (IOException e) {log.error(e.getMessage(), e);}}}}
}

ArcSyncHttpDownloadServlet 的 web.xml 配置清单:

     <!-- HTTP 断点续传 demo:127.0.0.1/cds/http --><servlet><servlet-name>httpServlet</servlet-name><servlet-class>com.defonds.cds.common.ArcSyncHttpDownloadServlet</servlet-class></servlet> <servlet-mapping><servlet-name>httpServlet</servlet-name><url-pattern>/http</url-pattern></servlet-mapping> 

ArcSyncHttpDownloadServlet 调用到的工具类 com.defonds.cds.common.util.CommonUtil 源代码:

package com.defonds.cds.common.util;public class CommonUtil {public static String setContentType(String returnFileName){String contentType = "application/octet-stream";if (returnFileName.lastIndexOf(".") < 0)return contentType;returnFileName = returnFileName.toLowerCase();returnFileName = returnFileName.substring(returnFileName.lastIndexOf(".")+1);if (returnFileName.equals("html") || returnFileName.equals("htm") || returnFileName.equals("shtml")){contentType = "text/html";} else if (returnFileName.equals("css")){contentType = "text/css";} else if (returnFileName.equals("xml")){contentType = "text/xml";} else if (returnFileName.equals("gif")){contentType = "image/gif";} else if (returnFileName.equals("jpeg") || returnFileName.equals("jpg")){contentType = "image/jpeg";} else if (returnFileName.equals("js")){contentType = "application/x-javascript";} else if (returnFileName.equals("atom")){contentType = "application/atom+xml";} else if (returnFileName.equals("rss")){contentType = "application/rss+xml";} else if (returnFileName.equals("mml")){contentType = "text/mathml"; } else if (returnFileName.equals("txt")){contentType = "text/plain";} else if (returnFileName.equals("jad")){contentType = "text/vnd.sun.j2me.app-descriptor";} else if (returnFileName.equals("wml")){contentType = "text/vnd.wap.wml";} else if (returnFileName.equals("htc")){contentType = "text/x-component";} else if (returnFileName.equals("png")){contentType = "image/png";} else if (returnFileName.equals("tif") || returnFileName.equals("tiff")){contentType = "image/tiff";} else if (returnFileName.equals("wbmp")){contentType = "image/vnd.wap.wbmp";} else if (returnFileName.equals("ico")){contentType = "image/x-icon";} else if (returnFileName.equals("jng")){contentType = "image/x-jng";} else if (returnFileName.equals("bmp")){contentType = "image/x-ms-bmp";} else if (returnFileName.equals("svg")){contentType = "image/svg+xml";} else if (returnFileName.equals("jar") || returnFileName.equals("var") || returnFileName.equals("ear")){contentType = "application/java-archive";} else if (returnFileName.equals("doc")){contentType = "application/msword";} else if (returnFileName.equals("pdf")){contentType = "application/pdf";} else if (returnFileName.equals("rtf")){contentType = "application/rtf";} else if (returnFileName.equals("xls")){contentType = "application/vnd.ms-excel"; } else if (returnFileName.equals("ppt")){contentType = "application/vnd.ms-powerpoint";} else if (returnFileName.equals("7z")){contentType = "application/x-7z-compressed";} else if (returnFileName.equals("rar")){contentType = "application/x-rar-compressed";} else if (returnFileName.equals("swf")){contentType = "application/x-shockwave-flash";} else if (returnFileName.equals("rpm")){contentType = "application/x-redhat-package-manager";} else if (returnFileName.equals("der") || returnFileName.equals("pem") || returnFileName.equals("crt")){contentType = "application/x-x509-ca-cert";} else if (returnFileName.equals("xhtml")){contentType = "application/xhtml+xml";} else if (returnFileName.equals("zip")){contentType = "application/zip";} else if (returnFileName.equals("mid") || returnFileName.equals("midi") || returnFileName.equals("kar")){contentType = "audio/midi";} else if (returnFileName.equals("mp3")){contentType = "audio/mpeg";} else if (returnFileName.equals("ogg")){contentType = "audio/ogg";} else if (returnFileName.equals("m4a")){contentType = "audio/x-m4a";} else if (returnFileName.equals("ra")){contentType = "audio/x-realaudio";} else if (returnFileName.equals("3gpp") || returnFileName.equals("3gp")){contentType = "video/3gpp";} else if (returnFileName.equals("mp4") ){contentType = "video/mp4";} else if (returnFileName.equals("mpeg") || returnFileName.equals("mpg") ){contentType = "video/mpeg";} else if (returnFileName.equals("mov")){contentType = "video/quicktime";} else if (returnFileName.equals("flv")){contentType = "video/x-flv";} else if (returnFileName.equals("m4v")){contentType = "video/x-m4v";} else if (returnFileName.equals("mng")){contentType = "video/x-mng";} else if (returnFileName.equals("asx") || returnFileName.equals("asf")){contentType = "video/x-ms-asf";} else if (returnFileName.equals("wmv")){contentType = "video/x-ms-wmv";} else if (returnFileName.equals("avi")){contentType = "video/x-msvideo";}return contentType;}}

本文示例代码在客户端使用快车(FlashGet)3、迅雷7 进行断点续传的环境下测试 OK。

本文仅为用来技术交流的演示 Demo,技术水平及知识面所限,其中错误和不当之处在所难免,敬请谅解。欢迎联系作者进行批评指正,技术交流 MSN:defonds(at)hotmail(dot)com,也可以给我发邮件,email:defonds(at)163(dot)com。

Java 服务器端支持断点续传的源代码【支持快车、迅雷】相关推荐

  1. Java 服务器端支持断点续传的源代码【支持快车 迅雷】

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Java ...

  2. Java 服务器端支持断点续传的源代码

    2019独角兽企业重金招聘Python工程师标准>>> Java 服务器端支持断点续传的源代码[支持快车.迅雷](仅支持 HTTP 协议) 网上关于 Java 支持 HTTP 断点续 ...

  3. Python 3.8实现支持断点续传的网络文件下载功能

    功能描述: 下载URL指定的网络文件,支持断点续传.代码支持Python 3.5/3.6/3.7/3.8以及更新的版本. 所谓断点续传,是指因为各种原因下载过程被中断之后,再次下载时会继续之前的工作, ...

  4. java ftp分片续传_Java写的支持断点续传的FTP

    Java写的支持断点续传的FTP 很不错的值得研究一下,结构比较清楚. 基类一: package ming.ftpsearch; public class FileInfo { public Stri ...

  5. java ipv6校验_Java对IPv6的支持详解:支持情况、相关API、演示代码等

    本文由朱益盛.杨晖.傅啸分享,来自IBM Developer社区,原题"使用 Java 开发兼容 IPv6 的网络应用程序",本次收录时有改动. 1.引言 前几天,有个群友跟我讨论 ...

  6. 那些ftp服务器支持断点续传,ftp服务器 断点续传

    浅谈FTP服务的几个知识点 实现断点续传的条件有三个:1.FTP服务器要能提供断点续传的功能.目前包括IIS和大部分的FTP架设软件都有了这个功能.2.FTP的登录软件要有断点续传的功能.像Flash ...

  7. Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持

    Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持 1.设置 document.domain为一致  推荐1 2.Apache 反向代理 推荐1 3. ...

  8. 面向Java应用的快速Web服务支持工具 - Netrifex

    面向Java应用的快速Web服务支持工具 - Netrifex Proxisoft今天宣布Netrifex 1.0版. Netrifex可以立即把Web Services添加到现有的Java SE和J ...

  9. Java 9中的HTTP / 2支持简介

    1.简介 IETF流媒体小组于2015年(即HTTP / 1.1发布后的16年) 批准了HTTP / 2协议. HTTP / 2有望降低延迟,并且使许多替代方法变得过时,而这些替代方法是HTTP / ...

最新文章

  1. python性能优化的一些建议(一)
  2. 拉取数据_如何拉取公网RTSP/RTMP流在内网多客户端播放
  3. JAVA——仿Linux命令行文件管理系统命令的简单实现
  4. CMarkup类在VC中的使用
  5. Hopsan完全编译构建指南
  6. tron区块链php对接,Tron区块链技术 - Tron智能合约概述
  7. 浙江等高等学校计算机,2010年浙江省高等学校计算机等级考试
  8. 感谢Adobe,用上了Silverlight RC0版本
  9. 关于在Windows下AndroidStudio.使用React-Native开发android报错红屏“run react-native start”解决
  10. java时间规划书_【计算机本科补全计划】Java学习笔记(九) Java日期时间
  11. html框架里面怎么填写内容_还不会Python高级框架?进来,速学
  12. springboot----热部署
  13. qtreewidget点击空白处时取消以选项_手机APP自动续费,我们要如何取消?
  14. [SinGuLaRiTy] 二分图匈牙利算法
  15. Cache之全相连映射
  16. 【前端模板之路】二、人肉非智举,让代码帮我们写代码才是王道
  17. 企业微信之网页授权登录
  18. android10一键root权限获取,完美root方法教你如何一键获取手机ROOT权限
  19. bug提单 java_bug提单规范
  20. 高音符號的由來是怎樣的

热门文章

  1. SDN控制器之OVN实验三:从OVN虚拟网络访问物理网络
  2. 韩语学习笔记(1)音标与输入法
  3. 龙应台谈莫言获诺贝尔文学奖:最泥土最国际-龙应台-莫言-诺贝尔文学奖
  4. react父子组件之间的传值
  5. 齐博CMS个模板目录
  6. python食品安全网络舆情毕业设计_毕业设计(论文)-基于物联网的食品安全信息追溯系统的设计与实现精选.docx...
  7. 云电脑-kvm环境下云服务器配置常见命令
  8. 如何对母线接头测温进行采集并实时监控
  9. cc1101载波监听 Carrier Sensor
  10. java和office二级证书用处_计算机二级证书有用吗