vue前端
// 下载
download (item) {
this.loadFlag = true
//outputFile是后端接口,接收来自response的数据
outputFile(item.entityId, encodeURIComponent(item.attPath)).then(response => {
this.loadFlag = false
const content = response.data
const blob = new Blob([content])
const fileName = item.attName
if ('download' in document.createElement('a')) { // 非IE下载
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // 释放URL 对象
document.body.removeChild(elink)
} else { // IE10+下载
navigator.msSaveBlob(blob, fileName)
}
})
}
后端接口
方案一
/**
* 回显图片信息
*
* @param path
* @param request
* @param response
* @throws IOException
*/
@GetMapping("/outputFile")
public void outputFile(@RequestParam(value = "entityId", required = false) String entityId,
@RequestParam(value = "path", required = false) String path,
@RequestParam(value = "att", required = false) Double att,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String QUOTATION = "\"";
String CLENGTH = "Content-Length";
String CDISPOSITION = "Content-Disposition";
String HEADNAME = "attachment;filename=";
String CONETNTTYPE = "application/octet-stream";
// 查询文件路径
NewsAttEntity attEntity = newsAttService.selectByPath(entityId, path, att);
// 读取文件
File file = new File(attEntity.getAttPath());
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(attEntity.getAttName(), "UTF-8"));
response.addHeader("Content-Length", "" + file.length());
try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
OutputStream out = response.getOutputStream();
) {
byte[] buffBytes = new byte[1024];
int read = 0;
while ((read = input.read(buffBytes)) != -1) {
out.write(buffBytes, 0, read);
}
out.flush();
} catch (Exception e) {
logger.error("文件处理异常:", e);
}
}
方案二
@GetMapping(value = "/outputFile")
public void outputFile(@RequestParam(value = "entityId", required = false) String enatityId,
@RequestParam(value = "businessType", required = false) String businessType,
@RequestParam(value = "path", required = false) String path, HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 查询文件路径
HrFileAttachmentEntity fileAttachment = hrFileAttachmentService.selectByPath(enatityId, businessType, path);
if (fileAttachment == null){
return;
}
// 读取文件
File file = new File(fileAttachment.getPath());
FileUtil.downloadSupport(request,response,fileAttachment.getName());
FileUtil.rangeSupport(request,response,file);
}
FileUtil
import com.foresealife.iam.client.bean.IamUserInfo;
import org.apache.commons.lang.StringUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
/**
* Servlet请求/下载文件资源的工具类
*/
public class FileUtil {
/**
* controller提供下载文件的方法,解决中文文件名乱码
*
* @param request
* @param response
* @param formFileName
* @throws IOException
*/
public static void downloadSupport(HttpServletRequest request, HttpServletResponse response, String formFileName) throws IOException {
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && (userAgent.contains("MSIE") || userAgent.contains("Trident"))) {
// 针对IE或者以IE为内核的浏览器:
formFileName = java.net.URLEncoder.encode(formFileName, "UTF-8");
} else {
// 非IE浏览器的处理:
formFileName = new String(formFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
}
response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", formFileName));
response.setCharacterEncoding("UTF-8");
}
public static boolean cacheSupport(HttpServletRequest request, HttpServletResponse response, File file) throws IOException{
response.setHeader("Cache-control", "public, max-age=31536000");
long reqTime = request.getDateHeader("If-Modified-Since");
long fileTime = file.lastModified();
try {
response.setContentType(Files.probeContentType(Paths.get(file.getPath())));
} catch (IOException e) {
//ignore this exception.
}
if (reqTime > 0 && Math.abs(reqTime - fileTime) < 1000) {
//如果文件没有修改,则直接返回304,不会读文件 也不会产生流,可提高访问速度
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return true;
}
response.setDateHeader("Last-Modified", fileTime);
return false;
}
/**
* 限制接口只能通过localhost访问
* @param request
* @return
*/
public static boolean isLocalhost(HttpServletRequest request){
String remoteAddress = request.getRemoteAddr();
if(remoteAddress != null && remoteAddress.indexOf(':') != -1){
//ipv6访问
return "0:0:0:0:0:0:0:1".equals(remoteAddress);
}
return "localhost".equals(remoteAddress) || "127.0.0.1".equals(remoteAddress);
}
public static void viewSupport(HttpServletRequest request, HttpServletResponse response, String formFileName) throws IOException {
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && (userAgent.contains("MSIE") || userAgent.contains("Trident"))) {
// 针对IE或者以IE为内核的浏览器:
formFileName = java.net.URLEncoder.encode(formFileName, "UTF-8");
} else {
// 非IE浏览器的处理:
formFileName = new String(formFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
}
response.setHeader("Content-Disposition", String.format("inline; filename=\"%s\"", formFileName));
response.setCharacterEncoding("UTF-8");
}
public static void rangeSupport(HttpServletRequest request, HttpServletResponse response, File file) throws IOException {
ServletOutputStream os = null;
BufferedOutputStream out = null;
byte[] b = new byte[1024];
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
long pos = headerSetting(request, response, file);
os = response.getOutputStream();
out = new BufferedOutputStream(os);
raf.seek(pos);
int n = 0;
while ((n = raf.read(b, 0, 1024)) != -1) {
out.write(b, 0, n);
}
out.flush();
}
}
private static long headerSetting(HttpServletRequest request, HttpServletResponse response,
File file) throws IOException {
long len = file.length();
response.setHeader("Accept-Ranges", "bytes");
String strRange = request.getHeader("Range");
if (strRange == null || strRange.isEmpty()) {
setResponse(new RangeSettings(len), response);
return 0;
}
String range = strRange.replace("bytes=", "");
RangeSettings settings = getSettings(len, range);
setResponse(settings, response);
return settings.getStart();
}
private static void setResponse(RangeSettings settings, HttpServletResponse response) {
if (!settings.isRange()) {
response.addHeader("Content-Length", String.valueOf(settings.getTotalLength()));
} else {
long start = settings.getStart();
long end = settings.getEnd();
long contentLength = settings.getContentLength();
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
response.addHeader("Content-Length", String.valueOf(contentLength));
String contentRange = "bytes " + start + "-" + end + "/" + settings.getTotalLength();
response.setHeader("Content-Range", contentRange);
}
}
private static RangeSettings getSettings(long len, String range) {
long contentLength = 0;
long start = 0;
long end = 0;
if (range.startsWith("-"))
// -500,最后500个
{
contentLength = Long.parseLong(range.substring(1));
//要下载的量
end = len - 1;
start = len - contentLength;
} else if (range.endsWith("-"))
//从哪个开始
{
start = Long.parseLong(range.replace("-", ""));
end = len - 1;
contentLength = len - start;
} else
//从a到b
{
String[] se = range.split("-");
start = Long.parseLong(se[0]);
end = Long.parseLong(se[1]);
contentLength = end - start + 1;
}
return new RangeSettings(start, end, contentLength, len);
}
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
return null;
}
// //使用代理,则获取第一个IP地址
// if(StringUtils.isEmpty(ip) && ip.length() > 15) {
// if(ip.indexOf(",") > 0) {
// ip = ip.substring(0, ip.indexOf(","));
// }
// }
return ip;
}
}
RangeSettings
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
class RangeSettings{
private long start;
private long end;
private long contentLength;
private long totalLength;
private boolean range;
public RangeSettings(){
super();
}
public RangeSettings(long start, long end, long contentLength,long totalLength) {
this.start = start;
this.end = end;
this.contentLength = contentLength;
this.totalLength = totalLength;
this.range = true;
}
public RangeSettings(long totalLength) {
this.totalLength = totalLength;
}
}