转自: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支持断点续传下载实现的更多相关文章

  1. 在ASP.NET中支持断点续传下载大文件(ZT)

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag         客户端每次提交 ...

  2. 在ASP.NET中支持断点续传下载大文件

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag        客户端每次提交下 ...

  3. 使用curl断点续传下载文件

    办公网络网速不是很好,使用Chrome下载一些软件时不时会中断,恶心的是Chrome居然不支持断点续传下载(为什么chrome的下载不支持断点续传呢?),迅雷自然是不能装的,那怎么办?还好我有大名鼎鼎 ...

  4. 【FTP】FTP文件上传下载-支持断点续传

    Jar包:apache的commons-net包: 支持断点续传 支持进度监控(有时出不来,搞不清原因) 相关知识点 编码格式: UTF-8等; 文件类型: 包括[BINARY_FILE_TYPE(常 ...

  5. ASIHTTPRequest下载示例(支持断点续传)

    一.创建网络请求队列 首先,创建网络请求队列,如下: ASINetworkQueue   *que = [[ASINetworkQueue alloc] init]; self.netWorkQueu ...

  6. ftp 操作,支持断点续传或者继续下载。

    1.ftpclient 类 public class FTPClient:IDisposable { public static object _obj = new object(); #region ...

  7. C# http下载(支持断点续传)

    分享下项目里面自己封装的一个http下载类 功能如下: 1.支持断点续传 2.下载失败自动重试 3.超时等异常处理 using System; using System.Collections.Gen ...

  8. 实现android支持多线程断点续传下载器功能

    多线程断点下载流程图: 多线程断点续传下载原理介绍: 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度手机端下载数据时难免会出现无信号断线.电量不足等情况,所以需要断点续传功能根据下 ...

  9. 打印 上一主题 下一主题 利用cURL实现单个文件分多段同时下载,支持断点续传(修订版)

      利用cURL实现单个文件分多段同时下载,支持断点续传(修订版) [复制链接] 摘自 http://bbs.chinaunix.net/thread-917952-1-1.html 在ubuntu下 ...

随机推荐

  1. QtGui.QSplitter

    A QtGui.QSplitter lets the user control the size of child widgets by dragging the boundary between t ...

  2. 重置 radio 和 checkbox 的样式

    代码: <!doctype html> <html> <head> <meta charset="utf-8"> <title ...

  3. alitomcat maven以及Autoconfig

    maven概述 Maven的核心是POM(Project Object Model),即项目对象模型.最直观的,maven对项目依赖进行统一的管理,让开发者从纷杂错乱的jar包世界摆脱出来,更加专注于 ...

  4. android源码相关网站

    https://android.googlesource.com/ google的android源码网站 http://source.android.com/ android网站 git://code ...

  5. iOS-仿智联字符图片验证码

    概述 随机字符组成的图片验证码, 字符位数可改变, 字符可斜可正排列. 详细 代码下载:http://www.demodashi.com/demo/10850.html 项目中有时候会有这种需求: 获 ...

  6. javax.naming.NoInitialContextException: Need to specify class name in environment or system property

    javax.naming.NoInitialContextException: Need to specify class name in environment or system property ...

  7. dubbox rest协议jackson 反序列化的坑

    dubbox 相对于dubbo 对了 rest 协议的支持  而且默认序列化的协议 是json dubbox 内部是通过 RestEasy 处理 rpc 服务 而 RestEasy获取序列化是 是通过 ...

  8. python --批量重命名文件名

    # -*- coding: utf-8 -*- import os path = "d:\\curl\data\\" for file in os.listdir(path): p ...

  9. unity, Rigidbody.constraints

    一,同时施加多个限制: 用按位或(bitwise OR)实现,例如: GetComponent<Rigidbody>().constraints=RigidbodyConstraints. ...

  10. Android - 资源(resource)转换为String

    资源(resource)转换为String 本文地址: http://blog.csdn.net/caroline_wendy Android建议资源的动态绑定, 即把string写入资源内, 然后运 ...