转载:Struts2支持断点续传下载实现
转自:http://blog.sina.com.cn/s/blog_667ac0360102eckm.html
package com.ipan.core.controller.web.result; import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.dispatcher.StreamResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.opensymphony.xwork2.ActionInvocation; ///
// 支持断点续传文件输出流
//
// 对StreamResult做了增强,支持断点续传方式(多线程)下载同时也支持普通方式(单线程)下载;
//
// @author iPan
// @version 2014-3-19
//
public class MulitStreamResult extends StreamResult { private static final long serialVersionUID = -256643510497634924L;
protected static Logger LOG = LoggerFactory.getLogger(MulitStreamResult.class);
@Override
protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
// Find the Response in context
HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(HTTP_RESPONSE);
HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(HTTP_REQUEST);
// Override any parameters using values on the stack
resolveParamsFromStack(invocation.getStack(), invocation);
String rangeStr = ""; // 范围字符串(比如“bytes=27000-”或者“bytes=27000-39000”的内容)
long fromLength = 0; // 起点长度(比如bytes=27000-39000,则这个值为27000)
long toLength = 0; // 终点长度(比如bytes=27000-39000,则这个值为39000)
long rangeLength = 0; // 响应的字节总量(toLength - fromLength + 1)
OutputStream out = null; // 输出流 if (inputStream == null) {
// Find the inputstream from the invocation variable stack
inputStream = (InputStream) invocation.getStack().findValue(conditionalParse(inputName, invocation));
}
if (inputStream == null) {
String msg = ("Can not find a java.io.InputStream with the name [" + inputName + "] in the invocation stack. " +
"Check the tag specified for this action.");
LOG.error(msg);
throw new IllegalArgumentException(msg);
}
if (contentLength == null || contentLength.length() < 1) {
throw new IllegalArgumentException("支持断点续传时,[Content-Length]不能为空.");
}
// Set the content type
if (contentCharSet != null && !contentCharSet.equals("")) {
response.setContentType(conditionalParse(contentType, invocation) + ";charset=" + contentCharSet);
} else {
response.setContentType(conditionalParse(contentType, invocation));
} // Set the content-disposition
if (contentDisposition != null) {
response.addHeader("Content-Disposition", conditionalParse(contentDisposition, invocation));
}
// Set the cache control headers if neccessary
if (!allowCaching) {
response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache");
}
// Set the content length
String _contentLength = conditionalParse(contentLength, invocation);
// 文件长度
int fileLength = Integer.parseInt(_contentLength);
response.setContentLength(fileLength);
// 需要使用断点续传下载
if (isHeadOfRange(request)) {
LOG.debug("断点续传下载.");
// 设置状态 HTTP/1.1 206 Partial Content
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
// 表示使用了断点续传(默认是“none”,可以不指定)
response.setHeader("Accept-Ranges", "bytes");
// 设置Content-Range
StringBuilder crBuf = new StringBuilder("bytes ");
rangeStr = request.getHeader("Range").replaceAll("bytes=", "").trim();
if (rangeStr.endsWith("-")) {
LOG.debug("开区间下载.");
rangeStr = StringUtils.substringBefore(rangeStr, "-");
fromLength = Long.parseLong(rangeStr);
rangeLength = fileLength - fromLength + 1;
crBuf.append(rangeStr).append("-").append(fromLength - 1).append("/").append(fileLength);
} else {
LOG.debug("闭区间下载.");
String num1 = StringUtils.substringBefore(rangeStr, "-");
String num2 = StringUtils.substringAfter(rangeStr, "-");
fromLength = Long.parseLong(num1);
toLength = Long.parseLong(num2);
rangeLength = toLength - fromLength + 1;
crBuf.append(rangeStr).append("/").append(fileLength);
}
// Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
response.setHeader("Content-Range", crBuf.toString());
// 普通下载
} else {
LOG.debug("普通下载.");
// 默认返回 HTTP/1.1 200 OK
rangeLength = fileLength; // 客户端要求全文下载
}
// 输出文件操作
try {
out = response.getOutputStream();
byte[] outBuff = new byte[bufferSize];
int readLen = 0;
// 闭区间处理
if (toLength > 0) {
LOG.debug("闭区间下载开始...");
inputStream.skip(fromLength);
int readBufSize = (int) Math.min(bufferSize, rangeLength);
long pFrom = fromLength;
while (pFrom < toLength) {
readLen = inputStream.read(outBuff, 0, readBufSize);
pFrom += readBufSize;
readBufSize = (int) Math.min(readBufSize, toLength - pFrom + 1);
out.write(outBuff, 0, readLen);
}
// 开区间处理
} else {
LOG.debug("开区间下载开始...");
inputStream.skip(fromLength);
while ((readLen = inputStream.read(outBuff, 0, bufferSize)) != -1) {
out.write(outBuff, 0, readLen);
}
}
} catch (ClientAbortException e) {
// 忽略(迅雷等下载工具,支持多线程下载,但有些线程会被中途取消,导致异常。)
// LOG.debug(e.getMessage(), e);
} catch (SocketException e) {
// 忽略(迅雷等下载工具,支持多线程下载,但有些线程会被中途取消,导致异常。)
// LOG.debug(e.getMessage(), e);
} catch (Exception e) {
// 其他异常记录日志
LOG.error(e.getMessage(), e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
}
}
if (out != null) {
try {
out.flush();
} catch (Exception e1) {
}
try {
out.close();
} catch (Exception e) {
}
}
}
} private static boolean isHeadOfRange(HttpServletRequest request) {
return request.getHeader("Range") != null;
} }
个人补充:功能并未验证是否可行。
转载:Struts2支持断点续传下载实现的更多相关文章
- 在ASP.NET中支持断点续传下载大文件(ZT)
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交 ...
- 在ASP.NET中支持断点续传下载大文件
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下 ...
- 使用curl断点续传下载文件
办公网络网速不是很好,使用Chrome下载一些软件时不时会中断,恶心的是Chrome居然不支持断点续传下载(为什么chrome的下载不支持断点续传呢?),迅雷自然是不能装的,那怎么办?还好我有大名鼎鼎 ...
- 【FTP】FTP文件上传下载-支持断点续传
Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...
- ASIHTTPRequest下载示例(支持断点续传)
一.创建网络请求队列 首先,创建网络请求队列,如下: ASINetworkQueue *que = [[ASINetworkQueue alloc] init]; self.netWorkQueu ...
- ftp 操作,支持断点续传或者继续下载。
1.ftpclient 类 public class FTPClient:IDisposable { public static object _obj = new object(); #region ...
- C# http下载(支持断点续传)
分享下项目里面自己封装的一个http下载类 功能如下: 1.支持断点续传 2.下载失败自动重试 3.超时等异常处理 using System; using System.Collections.Gen ...
- 实现android支持多线程断点续传下载器功能
多线程断点下载流程图: 多线程断点续传下载原理介绍: 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度手机端下载数据时难免会出现无信号断线.电量不足等情况,所以需要断点续传功能根据下 ...
- 打印 上一主题 下一主题 利用cURL实现单个文件分多段同时下载,支持断点续传(修订版)
利用cURL实现单个文件分多段同时下载,支持断点续传(修订版) [复制链接] 摘自 http://bbs.chinaunix.net/thread-917952-1-1.html 在ubuntu下 ...
随机推荐
- Eddy's digital Roots
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission ...
- 转:【Linux】linux系统中find和whereis查找命令常用示例
转载至:wanqi博客园:http://www.cnblogs.com/wanqieddy/archive/2011/06/09/2076785.html whereis 命令,直接查找需要的文件名称 ...
- iOS开发:icon和启动图尺寸(转)
转至:http://www.cnblogs.com/shaoting/p/4941634.html 歪果仁的总结: Asset iPhone 6s Plus and iPhone 6 Plus (@3 ...
- centos 配置 samba 与windows共享文件夹
yum install samba /etc/samba/smb.conf directory mask = 0777 ← 指定新建目录的属性(以下4行) force directory mode = ...
- Redis总结(四)Redis 的持久化(转载)
前面已经总结了Redis 的安装和使用今天讲下Redis 的持久化. redis跟memcached类似,都是内存数据库,不过redis支持数据持久化,也就是说redis可以将内存中的数据同步到磁盘来 ...
- 统计时间段内周分类SQL语句
declare @datefrom as datetime,@dateto as datetime set @datefrom='2015-04-12' set @dateto='2015-08-13 ...
- 迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_iterator)}
一.迭代器适配器 反向迭代器 插入迭代器 IO流迭代器 其中反向迭代器可以参考以前的文章. 二.插入迭代器 插入迭代器实际上是一个输出迭代器(*it=; ++) back_insert_iterato ...
- JSON对象和JSON字符串以及JSON.parse 函数的使用
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 通过XmlDocument读写Xml文档参考地址
/// <summary> /// 获取一个报表的参数 http://blog.csdn.net/hdhai9451/article/details/12170069 /// </s ...
- SQL相关路径查询脚本
--1.查询机器名 SELECT @@servername AS 机器名称 --查询已安装的SQL实例名 SELECT * FROM Sys.Servers --2.查询SQL安装路径 DECLARE ...