转载: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下 ...
随机推荐
- python urllib2 httplib HTTPConnection
httplib实现了HTTP和HTTPS的客户端协议,一般不直接使用,在python更高层的封装模块中(urllib,urllib2)使用了它的http实现. import httplib conn ...
- 浅析CentOS和RedHat Linux的区别(转)
CentOS的简介 CentOS是Community ENTerprise Operating System的简称,我们有很多人叫它社区企业操作系统,不管你怎么叫它,它都是Linux操作系统的一个发行 ...
- Intellij Idea下搭建基于Spring+SpringMvc+MyBatis的WebApi接口架构
2018-08-16 09:27 更新 强烈推荐使用Springboot来搭建MVC框架! 强烈推荐使用Springboot来搭建MVC框架! 强烈推荐使用Springboot来搭建MVC框架! 后文 ...
- 如何修改浏览器默认的alert样式?
window.alert = function(str) { var shield = document.createElement("DIV"); shield.id = &qu ...
- EF Code First:使用T4模板生成相似代码
http://developer.51cto.com/art/201309/409948.htm
- IE提示console未定义问题解决
在页面加入如下代码: if (!window.console || !console.firebug){ var names = ["log", "debug&qu ...
- 类声明、类作用域、前向声明、this指针、嵌套类、PIMPL 技法 等
一.类声明 //类是一种用户自定义类型,声明形式: class 类名称 { public: 公有成员(外部接口) private: 私有 ...
- Chrome 浏览器端口的坑:ERR_UNSAFE_PORT
nodejs 启动了一个6000端口的服务 本来是打算测试用的,结果一直报以下错误 但我使用 curl 来请求该接口地址是正常的.这就很纳闷了. 经过一番折腾无果之后,百度才知道.这个6000端口是非 ...
- Spring Cloud(八):分布式配置中心服务化和高可用
在前两篇的介绍中,客户端都是直接调用配置中心的server端来获取配置文件信息.这样就存在了一个问题,客户端和服务端的耦合性太高,如果server端要做集群,客户端只能通过原始的方式来路由,serve ...
- Javascript中window.opener的一点小总结
以前一直认为window.opener只有在window.open方法打开下的窗口才可以访问,没想到即使是a链接打开的页面的照样可以访问.window.opener指向父窗口,也就是来源窗口.可以利用 ...