增加文件V2直接下载功能
This commit is contained in:
parent
40d103963b
commit
596fe32678
@ -14,6 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @ClassName: FileAppCenterController
|
||||
* @Description: APP文件远程
|
||||
@ -97,7 +100,17 @@ public class FileCenterAppController extends DefaultBaseController {
|
||||
return new SuccessResultData<>(fileCenterService.uploadSingleByUserId(creator, audio, UploadTypeEnum.AUDIO));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "文件下载", notes = "文件下载(用于直接下载)接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "fileId", value = "文件ID", paramType = "path")
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@GetMapping("download/{fileId}")
|
||||
public void download(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("fileId") String fileId) {
|
||||
fileCenterService.download(request, response, fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验Key与Secret
|
||||
|
@ -35,7 +35,7 @@ public class FileRouteController {
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "文件下载", notes = "文件下载接口")
|
||||
@ApiOperation(value = "文件重定向下载(浏览器)", notes = "文件重定向下载(适用于浏览器访问图片)接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "isOpen", value = "是否打开,true和false", paramType = "path"),
|
||||
@ApiImplicitParam(name = "fileId", value = "文件ID", paramType = "path")
|
||||
@ -46,7 +46,19 @@ public class FileRouteController {
|
||||
HttpServletResponse response,
|
||||
@PathVariable("isOpen") Boolean isOpen,
|
||||
@PathVariable("fileId") String fileId) {
|
||||
fileService.download(request, response, isOpen, fileId);
|
||||
fileService.downloadRedirect(request, response, isOpen, fileId);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "文件下载", notes = "文件下载(用于直接下载)接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "fileId", value = "文件ID", paramType = "path")
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@GetMapping("download/{fileId}")
|
||||
public void download(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("fileId") String fileId) {
|
||||
fileService.download(request, response, fileId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @ClassName: IFileCenterService
|
||||
* @Description: 文件中心
|
||||
@ -23,5 +26,13 @@ public interface IFileCenterService {
|
||||
*/
|
||||
FileUploadSuccessDTO uploadSingleByUserId(String userId, MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param fileId
|
||||
*/
|
||||
void download(HttpServletRequest request, HttpServletResponse response, String fileId);
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,12 @@
|
||||
package ink.wgink.module.file.service.filecenter.impl;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.exceptions.FileException;
|
||||
import ink.wgink.exceptions.SearchException;
|
||||
import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileSaveVO;
|
||||
import ink.wgink.module.file.service.filecenter.IFileCenterService;
|
||||
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
|
||||
import ink.wgink.module.file.service.v2.IFileService;
|
||||
import ink.wgink.pojo.pos.FilePO;
|
||||
import ink.wgink.util.request.StaticResourceRequestUtil;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -21,12 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
/**
|
||||
* @ClassName: FileCenterServiceImpl
|
||||
@ -40,8 +28,6 @@ public class FileCenterServiceImpl extends DefaultBaseService implements IFileCe
|
||||
|
||||
@Autowired
|
||||
private IFileService fileService;
|
||||
@Autowired
|
||||
private IFileDownloadService fileDownloadService;
|
||||
|
||||
@Override
|
||||
public FileUploadSuccessDTO uploadSingleByUserId(String userId, MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
|
||||
@ -49,50 +35,9 @@ public class FileCenterServiceImpl extends DefaultBaseService implements IFileCe
|
||||
return fileService.saveFile(fileSaveVO);
|
||||
}
|
||||
|
||||
private void download(HttpServletRequest request, HttpServletResponse response, String fileId) {
|
||||
FilePO filePO = fileService.getPO(fileId);
|
||||
try (
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(filePO.getFilePath(), "r");
|
||||
FileChannel fileChannel = randomAccessFile.getChannel();
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
WritableByteChannel writableByteChannel = Channels.newChannel(outputStream);
|
||||
) {
|
||||
response.setHeader("Content-Length", filePO.getFileSize().toString());
|
||||
response.setContentType(StaticResourceRequestUtil.getContentType(filePO.getFileType()));
|
||||
response.setHeader("Content-Disposition", "inline;fileName=" + URLEncoder.encode(filePO.getFileName(), "UTF-8"));
|
||||
String rangeString = request.getHeader("Range");
|
||||
long contentLength = filePO.getFileSize();
|
||||
long startRange = 0;
|
||||
long endRange = contentLength - 1;
|
||||
if (!StringUtils.isBlank(rangeString)) {
|
||||
response.setContentType("multipart/byteranges");
|
||||
String[] rangeArray = rangeString.substring(rangeString.indexOf("=") + 1).split("-");
|
||||
startRange = Long.parseLong(rangeArray[0]);
|
||||
if (rangeArray.length > 1) {
|
||||
endRange = Long.parseLong(rangeArray[1]);
|
||||
}
|
||||
response.setHeader("Content-Length", String.valueOf(endRange - startRange + 1));
|
||||
response.setHeader("Content-Range", String.format("bytes %d-%d/%d", startRange, endRange, contentLength));
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
response.setHeader("Etag", fileId);
|
||||
response.setStatus(206);
|
||||
randomAccessFile.seek(startRange);
|
||||
}
|
||||
LOG.debug("startRange: {}, endRange: {}", startRange, endRange);
|
||||
long totalOutputLength = endRange - startRange + 1;
|
||||
fileChannel.transferTo(startRange, totalOutputLength, writableByteChannel);
|
||||
outputStream.flush();
|
||||
if (endRange >= contentLength - 1) {
|
||||
fileDownloadService.handle(request, false, fileId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof ClientAbortException) {
|
||||
LOG.debug("客户端断开连接");
|
||||
} else {
|
||||
throw new FileException("文件输出异常", e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, String fileId) {
|
||||
fileService.download(request, response, fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,9 +3,11 @@ package ink.wgink.module.file.service.filedownload;
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import ink.wgink.module.file.pojo.vos.filedownload.FileDownloadVO;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.pos.FilePO;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -68,12 +70,22 @@ public interface IFileDownloadService {
|
||||
Integer countByFileId(String fileId);
|
||||
|
||||
/**
|
||||
* 下载
|
||||
* 文件下载
|
||||
*
|
||||
* @param httpServletRequest
|
||||
* @param isOpen 是否打开
|
||||
* @param fileId
|
||||
* @param request
|
||||
* @param response
|
||||
* @param filePO
|
||||
*/
|
||||
void handle(HttpServletRequest httpServletRequest, boolean isOpen, String fileId);
|
||||
void download(HttpServletRequest request, HttpServletResponse response, FilePO filePO);
|
||||
|
||||
/**
|
||||
* 文件重定向下载
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param isOpen
|
||||
* @param filePO
|
||||
*/
|
||||
void downloadRedirect(HttpServletRequest request, HttpServletResponse response, boolean isOpen, FilePO filePO);
|
||||
|
||||
}
|
||||
|
@ -3,22 +3,36 @@ package ink.wgink.module.file.service.filedownload.impl;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.exceptions.FileException;
|
||||
import ink.wgink.module.file.dao.filedownload.IFileDownloadDao;
|
||||
import ink.wgink.module.file.manager.FilesManager;
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import ink.wgink.module.file.pojo.vos.filedownload.FileDownloadVO;
|
||||
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.pos.FilePO;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import ink.wgink.util.UUIDUtil;
|
||||
import ink.wgink.util.date.DateUtil;
|
||||
import ink.wgink.util.map.HashMapUtil;
|
||||
import ink.wgink.util.request.RequestUtil;
|
||||
import ink.wgink.util.request.StaticResourceRequestUtil;
|
||||
import ink.wgink.util.thread.CachedThreadPoolUtil;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -77,8 +91,74 @@ public class FileDownloadServiceImpl extends DefaultBaseService implements IFile
|
||||
return fileDownloadDao.count(params);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest httpServletRequest, boolean isOpen, String fileId) {
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, FilePO filePO) {
|
||||
String fileId = filePO.getFileId();
|
||||
try (
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(filePO.getFilePath(), "r");
|
||||
FileChannel fileChannel = randomAccessFile.getChannel();
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
WritableByteChannel writableByteChannel = Channels.newChannel(outputStream);
|
||||
) {
|
||||
response.setHeader("Content-Length", filePO.getFileSize().toString());
|
||||
response.setContentType(StaticResourceRequestUtil.getContentType(filePO.getFileType()));
|
||||
response.setHeader("Content-Disposition", "inline;fileName=" + URLEncoder.encode(filePO.getFileName(), "UTF-8"));
|
||||
String rangeString = request.getHeader("Range");
|
||||
long contentLength = filePO.getFileSize();
|
||||
long startRange = 0;
|
||||
long endRange = contentLength - 1;
|
||||
if (!StringUtils.isBlank(rangeString)) {
|
||||
response.setContentType("multipart/byteranges");
|
||||
String[] rangeArray = rangeString.substring(rangeString.indexOf("=") + 1).split("-");
|
||||
startRange = Long.parseLong(rangeArray[0]);
|
||||
if (rangeArray.length > 1) {
|
||||
endRange = Long.parseLong(rangeArray[1]);
|
||||
}
|
||||
response.setHeader("Content-Length", String.valueOf(endRange - startRange + 1));
|
||||
response.setHeader("Content-Range", String.format("bytes %d-%d/%d", startRange, endRange, contentLength));
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
response.setHeader("Etag", fileId);
|
||||
response.setStatus(206);
|
||||
randomAccessFile.seek(startRange);
|
||||
}
|
||||
LOG.debug("startRange: {}, endRange: {}", startRange, endRange);
|
||||
long totalOutputLength = endRange - startRange + 1;
|
||||
fileChannel.transferTo(startRange, totalOutputLength, writableByteChannel);
|
||||
outputStream.flush();
|
||||
if (endRange >= contentLength - 1) {
|
||||
handle(request, false, fileId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof ClientAbortException) {
|
||||
LOG.debug("客户端断开连接");
|
||||
} else {
|
||||
throw new FileException("文件输出异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadRedirect(HttpServletRequest request, HttpServletResponse response, boolean isOpen, FilePO filePO) {
|
||||
if (filePO == null) {
|
||||
throw new FileException("查询失败");
|
||||
}
|
||||
File file = new File(filePO.getFilePath());
|
||||
if (!file.exists()) {
|
||||
throw new FileException("文件不存在");
|
||||
}
|
||||
String fileId = filePO.getFileId();
|
||||
try {
|
||||
String code = FilesManager.getInstance().generateCode(fileId, filePO.getFileName());
|
||||
response.sendRedirect(String.format("%s/%s?file=%s&code=%s&open=%d", request.getContextPath(), filePO.getFileUrl(), fileId, code, isOpen ? 1 : 0));
|
||||
handle(request, isOpen, fileId);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handle(HttpServletRequest httpServletRequest, boolean isOpen, String fileId) {
|
||||
String requestIp = RequestUtil.getRequestIp(httpServletRequest);
|
||||
if (!isOpen && !StringUtils.isBlank(requestIp)) {
|
||||
// 记录下载历史
|
||||
@ -88,5 +168,4 @@ public class FileDownloadServiceImpl extends DefaultBaseService implements IFile
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ public class MinIoFileServiceImpl extends DefaultBaseService implements IMinIoFi
|
||||
} else {
|
||||
inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(filePO.getFileUrl()).object(objectName).offset(0L).length(contentLength).build());
|
||||
}
|
||||
if (endRange == contentLength) {
|
||||
if (endRange >= (contentLength - 1)) {
|
||||
isDownloadComplete = true;
|
||||
}
|
||||
byte[] readBuf = new byte[IFileService.INPUT_STREAM_SIZE];
|
||||
|
@ -129,14 +129,24 @@ public interface IFileService {
|
||||
FilePO getPO(String fileId);
|
||||
|
||||
/**
|
||||
* 下载
|
||||
* 重定向下载
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param isOpen 是否打开
|
||||
* @param fileId 文件ID
|
||||
*/
|
||||
void download(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId);
|
||||
void downloadRedirect(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId);
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param fileId
|
||||
*/
|
||||
void download(HttpServletRequest request, HttpServletResponse response, String fileId);
|
||||
|
||||
|
||||
/**
|
||||
* 文件列表
|
||||
|
@ -9,7 +9,6 @@ import ink.wgink.exceptions.SearchException;
|
||||
import ink.wgink.module.file.components.FileComponent;
|
||||
import ink.wgink.module.file.dao.IFileDao;
|
||||
import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.manager.FilesManager;
|
||||
import ink.wgink.module.file.pojo.dtos.FileInfoDTO;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileSaveVO;
|
||||
@ -169,7 +168,7 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId) {
|
||||
public void downloadRedirect(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId) {
|
||||
FilePO filePO = getPO(fileId);
|
||||
if (filePO == null) {
|
||||
throw new FileException("查询失败");
|
||||
@ -178,13 +177,20 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
if (!file.exists()) {
|
||||
throw new FileException("文件不存在");
|
||||
}
|
||||
try {
|
||||
String code = FilesManager.getInstance().generateCode(fileId, filePO.getFileName());
|
||||
response.sendRedirect(String.format("%s/%s?file=%s&code=%s&open=%d", request.getContextPath(), filePO.getFileUrl(), fileId, code, isOpen ? 1 : 0));
|
||||
fileDownloadService.handle(request, isOpen, fileId);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
fileDownloadService.downloadRedirect(request, response, isOpen, filePO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, String fileId) {
|
||||
FilePO filePO = getPO(fileId);
|
||||
if (filePO == null) {
|
||||
throw new FileException("查询失败");
|
||||
}
|
||||
File file = new File(filePO.getFilePath());
|
||||
if (!file.exists()) {
|
||||
throw new FileException("文件不存在");
|
||||
}
|
||||
fileDownloadService.download(request, response, filePO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -181,7 +181,7 @@
|
||||
yes: function (index) {
|
||||
top.dialog.close(index);
|
||||
var layIndex;
|
||||
top.restAjax.delete(top.restAjax.path('api/file-remote/remove/{ids}', [ids]), {}, null, function (code, data) {
|
||||
top.restAjax.delete(top.restAjax.path('api/file-client/remove/{ids}', [ids]), {}, null, function (code, data) {
|
||||
top.dialog.msg(top.dataMessage.deleteSuccess, {time: 1000});
|
||||
reloadTable();
|
||||
}, function (code, data) {
|
||||
@ -208,7 +208,7 @@
|
||||
area: ['100%', '100%'],
|
||||
shadeClose: true,
|
||||
anim: 2,
|
||||
content: top.restAjax.path('route/file-remote/save', []),
|
||||
content: top.restAjax.path('route/file-client/save', []),
|
||||
end: function() {
|
||||
reloadTable();
|
||||
}
|
||||
@ -226,7 +226,7 @@
|
||||
area: ['100%', '100%'],
|
||||
shadeClose: true,
|
||||
anim: 2,
|
||||
content: top.restAjax.path('route/file-remote/update?fileRemoteId={fileRemoteId}', [checkDatas[0].fileRemoteId]),
|
||||
content: top.restAjax.path('route/file-client/update?fileClientId={fileClientId}', [checkDatas[0].fileClientId]),
|
||||
end: function() {
|
||||
reloadTable();
|
||||
}
|
||||
@ -241,7 +241,7 @@
|
||||
if(i > 1) {
|
||||
ids += '_';
|
||||
}
|
||||
ids += item['fileRemoteId'];
|
||||
ids += item['fileClientId'];
|
||||
}
|
||||
removeData(ids);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user