转载:Struts2支持断点续传下载实现

摘要:
=空&&!contentCharSet.equals(“”)){response.setContentType(conditionalParse(contentType,调用)+“;charset=”+contentCharSet);}否则{response.setContentType(conditionalParse(contentType,调用));}//设置内容处置(contentDisposition!

转自: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;
}

}

个人补充:功能并未验证是否可行。

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇一个简单的MDI示范程序(Delphi)【科研】之毕业论文排版技巧分享下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

.net断点续传

IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头。   一. 两个必要响应头Accept-Ranges、ETag         客户端每次提交下载请求时,服务端都要添加这两个响应头,以保证客户端和服务端将此下载识别为可以断点续传的下载: Accept-Ranges:告知下载客户端这是一个可以恢复...

文件下载之断点续传(客户端与服务端的实现)

原文:http://www.cnblogs.com/zhaopei/p/download.html 阅读目录   文件下载-服务端 使用a标签提供文件下载 使用Response.TransmitFile提供文件下载 其他方式文件下载 文件下载-客户端 直接下载 异步下载 断点续传 断点续传(服务端的支持) 多线程同时下载(分片下载) 前面讲了文件...

在Apache Struts中利用OGNL注入

前言 本文简要介绍了Apache Struts的OGNL注入缺陷,文章中介绍使用简单的应用程序复现OGNL注入。深入研究针对公共漏洞,并理解这类漏洞。 内容 安装Apache Tomcat服务器(入门) 熟悉Java应用程序在服务器上的工作方式(Web服务器基础知识) Struts应用程序示例(Struts应用程序示例) 表达语言注入(表达式语言注入) 了...

hibernate必须知道的知识

Hibernate经典知识:   1、Hibernate工作原理及为什么要用?     1.       答:hibernate,通过对jdbc进行封装,对 java类和关系数据库进行mapping,实现了对关系数据库的面向对象方式的操作. 1.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。 hibernate的性能非常好...

idea配置struts2.5环境

struts2不是struts1的下一代产品,是在struts1和WebWork技术的基础上进行合并后的全新框架,虽然两个名字相似,但是设计思想却有很大的不同。 使用本地的l ib 或者download都可以,这里我使用本地的包,后期比较方便,需要什么包可以直接在本地找到,并拷贝,不需要再去网络上下载 工程命名以及存放位置 新建好工程之后,自行在 WE...

struts 2 时间控件

在使用struts2框架时,为我们提供了时间选择器控件:datetimepicker。但是在使用过程中会出现一些问题,主要就是struts2版本更新时做了一些修改。在struts2.0时,使用<s:datetimepicker/>时,需要在<head></head>标签中申明:<s:head theme="ajax...