普通下载功能的实现
FileInputStream inputStream = null;
ServletOutputStream os = null;
try {
inputStream = new FileInputStream(file);
//设置响应状态200
response.setStatus(HttpServletResponse.SC_OK);
//设置内容类型
response.setContentType(getContentType(fileId));
//添加响应头 设置内容长度
response.addHeader("Content-Length", String.valueOf(file.length()));
//添加响应头 设置允许浏览器可尝试恢复中断的下载
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Cache-control", "private");
//添加响应头 设置浏览器另存为对话框的默认文件名
response.addHeader("Content-Disposition", "filename=" + file.getName());
response.addHeader("Last-Modified", new SimpleDateFormat("EEE, d MMM yyyy hh:mm:ss Z", Locale.ENGLISH).format(file.lastModified()) + " GMT");
os = response.getOutputStream();
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) != -1) {
os.write(buf, 0, len);
os.flush();
}
} catch (Exception e) {
//操作文件失败时返回响应状态 500
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
} finally {
//结束后释放资源
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
支持分片下载功能的实现
- 这里是因为测试中ios safari 浏览器无法正常打开播放视频文件,通过抓取分析浏览器访问静态资源视频过程实现的代码
//获取请求头
String range = request.getHeader("range");
String referer = request.getHeader("referer");
//处理range 计算请求的哪部分数据
String[] split = range.split("bytes=|-");
long begin = 0;
if (split.length >= 2) {
begin = Long.valueOf(split[1]);
}
long end = file.length() - 1;
if (split.length >= 3) {
end = Long.valueOf(split[2]);
}
long len = (end - begin) + 1;
//如果请求的文件长度超过文件实际长度 返回错误状态
if (end > file.length()) {
//返回状态 500
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
FileInputStream inputStream = null;
ServletOutputStream os = null;
try {
//创建文件流
inputStream = new FileInputStream(file);
//将指针移到请求片段的开始位置
inputStream.skip(begin);
//设置响应状态 206 部分内容
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
//设置内容类型
response.setContentType(getContentType(fileId));
//添加响应头 设置片段开始位置 结束位置 文件总长度
response.addHeader("Content-Range", "bytes " + begin + "-" + end + "/" + file.length());
//添加响应头 设置响应片段的长度
response.addHeader("Content-Length", String.valueOf(len));
//添加响应头 设置允许浏览器可尝试恢复中断的下载
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Cache-control", "private");
//添加响应头 设置浏览器另存为对话框的默认文件名
response.addHeader("Content-Disposition", "filename=" + file.getName());
response.addHeader("Last-Modified", new SimpleDateFormat("EEE, d MMM yyyy hh:mm:ss Z", Locale.ENGLISH).format(file.lastModified()) + " GMT");
os = response.getOutputStream();
//从文件流中读指定长度的片段输出
byte[] buf = new byte[1024];
while (len > 0) {
inputStream.read(buf);
long l = len > 1024 ? 1024 : len;
os.write(buf, 0, (int) l);
os.flush();
len -= l;
}
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
} finally {
//释放资源
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Github