[파일 업로드] 파일업로드 뷰 & 다운로드
- 파일 뷰 & 다운로드 작업 커밋
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
package com.alist.api.common.modules.file;
|
||||
|
||||
import com.alist.api.common.modules.file.dto.FileUploadDto;
|
||||
import com.alist.api.common.modules.file.dto.UploadCancelDto;
|
||||
import com.alist.api.common.modules.file.dto.UploadStatusDto;
|
||||
import com.alist.api.common.modules.file.dto.UploadTokenDto;
|
||||
import com.alist.api.common.modules.file.dto.*;
|
||||
import com.alist.api.common.modules.file.form.FileUploadForm;
|
||||
import com.alist.api.common.modules.file.form.TusHookForm;
|
||||
import com.alist.api.common.modules.file.form.UploadCancelForm;
|
||||
@@ -17,13 +14,19 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Slf4j
|
||||
@Tag(
|
||||
name = "99. TUS 업로드",
|
||||
description = "TUS 기반 파일 업로드 초기화, 권한 검증, 상태 조회, 훅 처리, 취소 API"
|
||||
name = "99. TUS 업로드"
|
||||
, description = "TUS 기반 파일 업로드 초기화, 권한 검증, 상태 조회, 훅 처리, 취소 API"
|
||||
)
|
||||
@RestController
|
||||
@RequestMapping("/files")
|
||||
@@ -35,8 +38,8 @@ public class FileController {
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "파일 업로드 초기화",
|
||||
description = "업로드 대상 파일 정보를 DB에 등록하고 fileUuid/uploadToken을 발급합니다."
|
||||
summary = "파일 업로드 초기화"
|
||||
, description = "업로드 대상 파일 정보를 DB에 등록하고 fileUuid/uploadToken을 발급합니다."
|
||||
)
|
||||
@PostMapping("/uploadInit")
|
||||
public ResponseEntity<ApiResponse<FileUploadDto>> uploadInit(
|
||||
@@ -62,8 +65,8 @@ public class FileController {
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "업로드 권한 검증",
|
||||
description = "Bearer 업로드 토큰과 fileUuid(및 TUS 메타데이터)를 검증해 업로드 가능 여부를 확인합니다."
|
||||
summary = "업로드 권한 검증"
|
||||
, description = "Bearer 업로드 토큰과 fileUuid(및 TUS 메타데이터)를 검증해 업로드 가능 여부를 확인합니다."
|
||||
)
|
||||
@GetMapping("/uploadAuth")
|
||||
public ResponseEntity<ApiResponse<String>> uploadAuth(
|
||||
@@ -97,8 +100,8 @@ public class FileController {
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "업로드 상태 조회",
|
||||
description = "fileUuid 기준으로 Redis/DB 업로드 상태(진행률, 상태값)를 조회합니다."
|
||||
summary = "업로드 상태 조회"
|
||||
, description = "fileUuid 기준으로 Redis/DB 업로드 상태(진행률, 상태값)를 조회합니다."
|
||||
)
|
||||
@PostMapping("/uploadStatus")
|
||||
public ResponseEntity<ApiResponse<UploadStatusDto>> uploadStatus(
|
||||
@@ -112,8 +115,8 @@ public class FileController {
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "TUS 훅 수신",
|
||||
description = "tusd에서 전달되는 pre-create/post-receive/post-finish/post-terminate 이벤트를 반영합니다."
|
||||
summary = "TUS 훅 수신"
|
||||
, description = "tusd에서 전달되는 pre-create/post-receive/post-finish/post-terminate 이벤트를 반영합니다."
|
||||
)
|
||||
@PostMapping("/tusHook")
|
||||
public ResponseEntity<ApiResponse<String>> tusHook(@RequestBody TusHookForm tusHookForm) {
|
||||
@@ -127,8 +130,8 @@ public class FileController {
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "업로드 취소",
|
||||
description = "현재 로그인 사용자의 fileUuid 업로드를 취소(CANCELED) 처리합니다."
|
||||
summary = "업로드 취소"
|
||||
, description = "현재 로그인 사용자의 fileUuid 업로드를 취소(CANCELED) 처리합니다."
|
||||
)
|
||||
@PostMapping("/uploadCancel")
|
||||
public ResponseEntity<ApiResponse<String>> uploadCancel(
|
||||
@@ -155,4 +158,104 @@ public class FileController {
|
||||
|
||||
return ApiResponse.entity("", ApiResponseCode.CODE_200);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "파일 목록 조회"
|
||||
, description = "FILE_MASTER_IDX 기준으로 완료된 파일 목록을 조회합니다.")
|
||||
@GetMapping("/list/{fileMasterIdx}")
|
||||
public ResponseEntity<ApiResponse<FileDownloadListDto>> fileListByFileMasterIdx(
|
||||
@PathVariable Long fileMasterIdx
|
||||
) {
|
||||
|
||||
FileDownloadDto fileDownloadDto = new FileDownloadDto();
|
||||
fileDownloadDto.setFileMasterIdx(fileMasterIdx);
|
||||
|
||||
FileDownloadListDto fileDownloadList = fileService.selectFileDownloadListByFileMasterIdx(fileDownloadDto);
|
||||
|
||||
if (fileDownloadList.getResultCode() == 401) {
|
||||
return ApiResponse.entity(fileDownloadList, ApiResponseCode.CODE_401);
|
||||
}
|
||||
|
||||
return ApiResponse.entity(fileDownloadList, ApiResponseCode.CODE_2001, "파일");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "파일 보기"
|
||||
, description = "권한 확인 후 Nginx X-Accel-Redirect로 파일을 inline 조회합니다.")
|
||||
@GetMapping("/view/{fileUuid}")
|
||||
public ResponseEntity<Void> fileView(
|
||||
@PathVariable String fileUuid
|
||||
, HttpServletRequest request
|
||||
) {
|
||||
FileDownloadDto fileDownloadDto = new FileDownloadDto();
|
||||
fileDownloadDto.setFileUuid(fileUuid);
|
||||
fileDownloadDto.setEventType("VIEW");
|
||||
fileDownloadDto.setClientIp(request.getRemoteAddr());
|
||||
fileDownloadDto.setUserAgent(request.getHeader("User-Agent"));
|
||||
fileDownloadDto.setReferer(request.getHeader("Referer"));
|
||||
|
||||
FileDownloadDto target = fileService.selectFileViewOrDownload(fileDownloadDto);
|
||||
|
||||
if (target == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (fileService.isRedirectMode()) {
|
||||
return ResponseEntity.status(HttpStatus.FOUND)
|
||||
.location(URI.create(fileService.buildPublicViewUrl(target.getSavePath())))
|
||||
.build();
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-Accel-Redirect", fileService.buildAccelRedirectPath(target.getSavePath()));
|
||||
headers.add(HttpHeaders.CONTENT_TYPE,
|
||||
target.getContentType() == null ? "application/octet-stream" : target.getContentType());
|
||||
headers.add(HttpHeaders.CONTENT_DISPOSITION,
|
||||
ContentDisposition.inline()
|
||||
.filename(target.getOriginName(), StandardCharsets.UTF_8)
|
||||
.build()
|
||||
.toString());
|
||||
|
||||
return new ResponseEntity<>(headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "파일 다운로드"
|
||||
, description = "권한 확인 후 파일 다운로드 로그를 남기고 redirect 또는 Nginx X-Accel-Redirect로 파일 다운로드 합니다.")
|
||||
@GetMapping("/download/{fileUuid}")
|
||||
public ResponseEntity<Void> fileDownload(
|
||||
@PathVariable String fileUuid
|
||||
, HttpServletRequest request
|
||||
) {
|
||||
FileDownloadDto fileDownloadDto = new FileDownloadDto();
|
||||
fileDownloadDto.setFileUuid(fileUuid);
|
||||
fileDownloadDto.setEventType("DOWNLOAD");
|
||||
fileDownloadDto.setClientIp(request.getRemoteAddr());
|
||||
fileDownloadDto.setUserAgent(request.getHeader("User-Agent"));
|
||||
fileDownloadDto.setReferer(request.getHeader("Referer"));
|
||||
|
||||
FileDownloadDto target = fileService.selectFileViewOrDownload(fileDownloadDto);
|
||||
|
||||
if (target == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (fileService.isRedirectMode()) {
|
||||
return ResponseEntity.status(HttpStatus.FOUND)
|
||||
.location(URI.create(fileService.buildPublicDownloadUrl(target.getSavePath())))
|
||||
.build();
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-Accel-Redirect", fileService.buildAccelRedirectPath(target.getSavePath()));
|
||||
headers.add(HttpHeaders.CONTENT_TYPE,
|
||||
target.getContentType() == null ? "application/octet-stream" : target.getContentType());
|
||||
headers.add(HttpHeaders.CONTENT_DISPOSITION,
|
||||
ContentDisposition.attachment()
|
||||
.filename(target.getOriginName(), StandardCharsets.UTF_8)
|
||||
.build()
|
||||
.toString());
|
||||
|
||||
return new ResponseEntity<>(headers, HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.alist.api.common.modules.file.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileDownloadDto {
|
||||
private Long fileDetailIdx;
|
||||
private Long fileMasterIdx;
|
||||
private String fileUuid;
|
||||
private String originName;
|
||||
private String contentType;
|
||||
private Long sizeBytes;
|
||||
private String savePath;
|
||||
|
||||
private Integer userIdx;
|
||||
private Integer userTokenIdx;
|
||||
private String eventType;
|
||||
private String clientIp;
|
||||
private String userAgent;
|
||||
private String referer;
|
||||
|
||||
@JsonIgnore
|
||||
private Integer resultCode;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.alist.api.common.modules.file.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileDownloadItemDto {
|
||||
private Long fileDetailIdx;
|
||||
private Long fileMasterIdx;
|
||||
private String fileUuid;
|
||||
private String originName;
|
||||
private String contentType;
|
||||
private Long sizeBytes;
|
||||
private String viewUrl;
|
||||
private String downloadUrl;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.alist.api.common.modules.file.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class FileDownloadListDto {
|
||||
private Long fileMasterIdx;
|
||||
private List<FileDownloadItemDto> itemList;
|
||||
|
||||
@JsonIgnore
|
||||
private Integer resultCode;
|
||||
}
|
||||
@@ -13,6 +13,6 @@ public class TusHookDto {
|
||||
private String fileUuid;
|
||||
private String filename;
|
||||
private String filetype;
|
||||
private long uploadedBytes;
|
||||
private int status;
|
||||
private Long uploadedBytes;
|
||||
private Integer status;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.alist.api.common.modules.file.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UploadStartDto {
|
||||
private String fileMasterKey;
|
||||
private String tusEndpoint;
|
||||
private String uploadToken;
|
||||
|
||||
@JsonIgnore
|
||||
private String originName;
|
||||
@JsonIgnore
|
||||
private String contentType;
|
||||
@JsonIgnore
|
||||
private Long sizeBytes;
|
||||
@JsonIgnore
|
||||
private String fileCategory;
|
||||
@JsonIgnore
|
||||
private String folderPath;
|
||||
@JsonIgnore
|
||||
private Integer userIdx;
|
||||
@JsonIgnore
|
||||
private int status;
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import lombok.Setter;
|
||||
public class UploadStatusDto {
|
||||
private String fileUuid;
|
||||
private String status; // PENDING, UPLOADING, DONE, FAILED
|
||||
private long uploadedBytes;
|
||||
private long totalBytes;
|
||||
private int percent;
|
||||
private Long uploadedBytes;
|
||||
private Long totalBytes;
|
||||
private Integer percent;
|
||||
private String updatedAt;
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@ public class UploadTokenDto {
|
||||
private String contentType;
|
||||
|
||||
@JsonIgnore
|
||||
private int resultCode;
|
||||
private Integer resultCode;
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.alist.api.common.modules.file.form;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UploadCompleteForm {
|
||||
@NotBlank
|
||||
String fileMastryKey;
|
||||
|
||||
@NotBlank
|
||||
String tusUploadUrl;
|
||||
|
||||
@NotBlank
|
||||
String originName;
|
||||
|
||||
@NotBlank
|
||||
String saveName;
|
||||
|
||||
@NotBlank
|
||||
String savePath;
|
||||
|
||||
@NotBlank
|
||||
String contentType;
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
Long sizeBytes;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.alist.api.common.modules.file.form;
|
||||
|
||||
import com.alist.api.common.modules.file.dto.UploadStartDto;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UploadStartForm {
|
||||
@NotBlank
|
||||
private String originName;
|
||||
|
||||
@NotBlank
|
||||
private String contentType;
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
private Long sizeBytes;
|
||||
|
||||
@NotBlank
|
||||
private String fileCategory;
|
||||
|
||||
private String folderPath;
|
||||
|
||||
public UploadStartDto uploadStartDto() {
|
||||
UploadStartDto uploadStartDto = new UploadStartDto();
|
||||
|
||||
uploadStartDto.setOriginName(this.originName);
|
||||
uploadStartDto.setContentType(this.contentType);
|
||||
uploadStartDto.setSizeBytes(this.sizeBytes);
|
||||
uploadStartDto.setFileCategory(this.fileCategory);
|
||||
uploadStartDto.setFolderPath(this.folderPath);
|
||||
|
||||
return uploadStartDto;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.alist.api.common.modules.file.form;
|
||||
|
||||
import com.alist.api.common.modules.file.dto.UploadTokenDto;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class UploadTokenForm {
|
||||
private String fileUuid;
|
||||
private String uploadToken;
|
||||
|
||||
public UploadTokenDto uploadTokenDto() {
|
||||
UploadTokenDto uploadTokenDto = new UploadTokenDto();
|
||||
uploadTokenDto.setFileUuid(this.fileUuid);
|
||||
uploadTokenDto.setUploadToken(this.uploadToken);
|
||||
|
||||
return uploadTokenDto;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,10 @@ package com.alist.api.common.modules.file.mapper;
|
||||
import com.alist.api.common.modules.file.dto.*;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface FileMapper {
|
||||
void insertFileMasterUpload(UploadStartDto uploadStartDto);
|
||||
|
||||
int selectFileMasterCountByFileMasterKeyAndDelYnAndStatus(UploadTokenDto uploadTokenDto);
|
||||
|
||||
void insertFileMasterInit(FileUploadDto fileUploadDto);
|
||||
|
||||
void insertFileDetailInit(FileUploadItemDto item);
|
||||
@@ -38,4 +36,10 @@ public interface FileMapper {
|
||||
int updateFileMoveSuccess(FileMoveTaskDto task);
|
||||
|
||||
int updateFileMovePendingByFileUuid(FileMoveTaskDto task);
|
||||
|
||||
List<FileDownloadItemDto> selectFileDownloadListByFileMasterIdx(FileDownloadDto fileDownloadDto);
|
||||
|
||||
FileDownloadDto selectFileDetailByFileUuid(FileDownloadDto fileDownloadDto);
|
||||
|
||||
void insertFileDownloadEventLog(FileDownloadDto fileDetailInfo);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -19,6 +21,7 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HexFormat;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -43,6 +46,12 @@ public class FileService {
|
||||
@Value("${file.upload.final-root}")
|
||||
private String uploadFinalRoot;
|
||||
|
||||
@Value("${file.download.redirect-prefix:/protected-files}")
|
||||
private String fileDownloadRedirectPrefix;
|
||||
|
||||
@Value("${file.download.mode:accel}")
|
||||
private String fileDownloadMode;
|
||||
|
||||
private final FileMapper fileMapper;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
@@ -259,7 +268,7 @@ public class FileService {
|
||||
}
|
||||
}
|
||||
|
||||
tusHookDto.setUploadedBytes(offset);
|
||||
//tusHookDto.setUploadedBytes(offset); // 전체 사이즈 업데이트 삭제
|
||||
|
||||
Integer currentStatus = fileUploadMetaInfo.getStatus();
|
||||
if (currentStatus != null && (currentStatus == 3 || currentStatus == 5)) {
|
||||
@@ -276,6 +285,7 @@ public class FileService {
|
||||
return false;
|
||||
}
|
||||
|
||||
tusHookDto.setUploadedBytes(null);
|
||||
tusHookDto.setStatus(1); // UPLOADING
|
||||
break;
|
||||
|
||||
@@ -285,12 +295,13 @@ public class FileService {
|
||||
return false;
|
||||
}
|
||||
|
||||
tusHookDto.setUploadedBytes(null);
|
||||
tusHookDto.setStatus(1); // UPLOADING
|
||||
break;
|
||||
|
||||
case "post-finish":
|
||||
tusHookDto.setStatus(3); // DONE
|
||||
tusHookDto.setUploadedBytes(size);
|
||||
tusHookDto.setStatus(3); // DONE
|
||||
break;
|
||||
|
||||
case "post-terminate":
|
||||
@@ -298,6 +309,7 @@ public class FileService {
|
||||
if (currentStatus != null && currentStatus == 3) {
|
||||
return false;
|
||||
}
|
||||
tusHookDto.setUploadedBytes(offset);
|
||||
tusHookDto.setStatus(5); // CANCELED
|
||||
break;
|
||||
|
||||
@@ -309,7 +321,11 @@ public class FileService {
|
||||
return false;
|
||||
}
|
||||
|
||||
fileMapper.updateFileDetailStatus(tusHookDto);
|
||||
boolean shouldUpdateDetail = !"post-receive".equals(type);
|
||||
|
||||
if (shouldUpdateDetail) {
|
||||
fileMapper.updateFileDetailStatus(tusHookDto);
|
||||
}
|
||||
|
||||
if ("post-finish".equals(type) || "post-terminate".equals(type)) {
|
||||
fileMapper.updateFileMasterAggregateByFileUuid(tusHookDto.getFileUuid());
|
||||
@@ -319,7 +335,11 @@ public class FileService {
|
||||
try {
|
||||
tryMoveNowByFileUuid(tusHookDto.getFileUuid());
|
||||
} catch (NoSuchFileException e) {
|
||||
try { Thread.sleep(200); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
try {
|
||||
tryMoveNowByFileUuid(tusHookDto.getFileUuid()); // 1회 재시도
|
||||
} catch (Exception ex) {
|
||||
@@ -570,4 +590,109 @@ public class FileService {
|
||||
saveCanceledStatusRedis(uploadCancelDto.getFileUuid(), uploaded, total); // 필요하면 기존 bytes 조회해서 넣어도 됨
|
||||
return true;
|
||||
}
|
||||
|
||||
private Integer getLoginUserTokenIdx() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null || authentication.getPrincipal() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(authentication.getPrincipal().toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public FileDownloadListDto selectFileDownloadListByFileMasterIdx(FileDownloadDto fileDownloadDto) {
|
||||
FileDownloadListDto fileDownloadList = new FileDownloadListDto();
|
||||
|
||||
Integer userTokenIdx = getLoginUserTokenIdx();
|
||||
if (userTokenIdx == null) {
|
||||
fileDownloadList.setResultCode(401);
|
||||
return fileDownloadList;
|
||||
}
|
||||
|
||||
fileDownloadDto.setUserTokenIdx(userTokenIdx);
|
||||
|
||||
fileDownloadList.setFileMasterIdx(fileDownloadDto.getFileMasterIdx());
|
||||
|
||||
List<FileDownloadItemDto> itemList = fileMapper.selectFileDownloadListByFileMasterIdx(fileDownloadDto);
|
||||
|
||||
for (FileDownloadItemDto item : itemList) {
|
||||
item.setViewUrl("/files/view/" + item.getFileUuid());
|
||||
item.setDownloadUrl("/files/download/" + item.getFileUuid());
|
||||
}
|
||||
|
||||
fileDownloadList.setItemList(itemList);
|
||||
fileDownloadList.setResultCode(200);
|
||||
|
||||
return fileDownloadList;
|
||||
}
|
||||
|
||||
public FileDownloadDto selectFileViewOrDownload(FileDownloadDto fileDownloadDto) {
|
||||
Integer userTokenIdx = getLoginUserTokenIdx();
|
||||
if (userTokenIdx == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
fileDownloadDto.setUserTokenIdx(userTokenIdx);
|
||||
|
||||
FileDownloadDto fileDetailInfo = fileMapper.selectFileDetailByFileUuid(fileDownloadDto);
|
||||
|
||||
if (fileDetailInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
fileDetailInfo.setUserTokenIdx(fileDownloadDto.getUserTokenIdx());
|
||||
fileDetailInfo.setEventType(fileDownloadDto.getEventType());
|
||||
fileDetailInfo.setClientIp(fileDownloadDto.getClientIp());
|
||||
fileDetailInfo.setUserAgent(fileDownloadDto.getUserAgent());
|
||||
fileDetailInfo.setReferer(fileDownloadDto.getReferer());
|
||||
|
||||
fileMapper.insertFileDownloadEventLog(fileDetailInfo);
|
||||
return fileDetailInfo;
|
||||
}
|
||||
|
||||
public String buildAccelRedirectPath(String savePath) {
|
||||
if (savePath == null || savePath.isBlank()) {
|
||||
throw new IllegalArgumentException("savePath is empty");
|
||||
}
|
||||
|
||||
String prefix = (fileDownloadRedirectPrefix == null || fileDownloadRedirectPrefix.isBlank())
|
||||
? "/protected-files"
|
||||
: fileDownloadRedirectPrefix.trim();
|
||||
|
||||
if (!prefix.startsWith("/")) {
|
||||
prefix = "/" + prefix;
|
||||
}
|
||||
|
||||
return prefix + savePath;
|
||||
}
|
||||
|
||||
public boolean isRedirectMode() {
|
||||
return "redirect".equalsIgnoreCase(fileDownloadMode);
|
||||
}
|
||||
|
||||
public String buildPublicViewUrl(String savePath) {
|
||||
return buildPublicTestUrl("/public-test-view", savePath);
|
||||
}
|
||||
|
||||
public String buildPublicDownloadUrl(String savePath) {
|
||||
return buildPublicTestUrl("/public-test-download", savePath);
|
||||
}
|
||||
|
||||
private String buildPublicTestUrl(String prefix, String savePath) {
|
||||
if (savePath == null || savePath.isBlank()) {
|
||||
throw new IllegalArgumentException("savePath is empty");
|
||||
}
|
||||
|
||||
String baseUrl = publicBaseUrl == null ? "" : publicBaseUrl.trim();
|
||||
if (baseUrl.endsWith("/")) {
|
||||
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
|
||||
}
|
||||
|
||||
return baseUrl + prefix + savePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ file:
|
||||
interrupt-seconds: 30
|
||||
auth-cache:
|
||||
ttl-seconds: 20
|
||||
download:
|
||||
mode: redirect
|
||||
redirect-prefix: /public-test-files
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
|
||||
@@ -53,6 +53,9 @@ file:
|
||||
interrupt-seconds: 30
|
||||
auth-cache:
|
||||
ttl-seconds: 20
|
||||
download:
|
||||
mode: accel
|
||||
redirect-prefix: /protected-files
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
|
||||
@@ -21,15 +21,6 @@
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertFileMasterUpload">
|
||||
/*FileMapper.insertFileMasterUpload*/
|
||||
INSERT INTO ALISTLMS.FILE_MASTER2 (
|
||||
FILE_MASTER_KEY, USER_IDX, FILE_CATEGORY, FOLDER_PATH, STATUS, CREATE_MEMBER, UPDATE_MEMBER
|
||||
) values (
|
||||
#{fileMasterKey}, #{userIdx}, #{fileCategory}, #{folderPath}, #{status}, #{userIdx}, #{userIdx}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertFileUploadEventLog">
|
||||
/*FileMapper.insertFileUploadEventLog*/
|
||||
INSERT INTO ALISTLMS.FILE_UPLOAD_EVENT_LOG (
|
||||
@@ -47,6 +38,34 @@
|
||||
WHERE LFD.FILE_UUID = #{fileUuid}
|
||||
LIMIT 1
|
||||
</insert>
|
||||
<insert id="insertFileDownloadEventLog">
|
||||
/*FileMapper.insertFileDownloadEventLog*/
|
||||
INSERT INTO ALISTLMS.FILE_DOWNLOAD_EVENT_LOG (
|
||||
FILE_MASTER_IDX
|
||||
, FILE_DETAIL_IDX
|
||||
, FILE_UUID
|
||||
, EVENT_TYPE
|
||||
, USER_IDX
|
||||
, USER_TOKEN_IDX
|
||||
, CLIENT_IP
|
||||
, USER_AGENT
|
||||
, REFERER
|
||||
, DEL_YN
|
||||
, CREATE_MEMBER
|
||||
) VALUES (
|
||||
#{fileMasterIdx}
|
||||
, #{fileDetailIdx}
|
||||
, #{fileUuid}
|
||||
, #{eventType}
|
||||
, #{userIdx}
|
||||
, #{userTokenIdx}
|
||||
, #{clientIp}
|
||||
, #{userAgent}
|
||||
, #{referer}
|
||||
, 'N'
|
||||
, #{userIdx}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateFileDetailStatus">
|
||||
/*FileMapper.updateFileDetailStatus*/
|
||||
@@ -127,18 +146,6 @@
|
||||
AND LFD.STATUS IN (0,1,2)
|
||||
</update>
|
||||
|
||||
<select id="selectFileMasterCountByFileMasterKeyAndDelYnAndStatus" resultType="int">
|
||||
/*FileMapper.selectFileMasterCountByFileMasterKeyAndDelYnAndStatus*/
|
||||
SELECT COUNT(*)
|
||||
FROM ALISTLMS.FILE_MASTER2 LFM
|
||||
INNER JOIN ALISTLMS.test_user_token LTUT
|
||||
ON LTUT.user_idx = LFM.USER_IDX
|
||||
WHERE LFM.DEL_YN = 'N'
|
||||
AND LFM.FILE_MASTER_KEY = #{fileMasterKey}
|
||||
AND LFM.STATUS = 1
|
||||
AND LTUT.user_token_idx = #{userTokenIdx}
|
||||
</select>
|
||||
|
||||
<select id="selectFileDetailCountByFileUuidUserToKenIdx" resultType="java.lang.Integer">
|
||||
/*FileMapper.selectFileDetailCountByFileUuidUserToKenIdx*/
|
||||
SELECT COUNT(*)
|
||||
@@ -219,6 +226,52 @@
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectFileDownloadListByFileMasterIdx" resultType="com.alist.api.common.modules.file.dto.FileDownloadItemDto">
|
||||
/*FileMapper.selectFileDownloadListByFileMasterIdx*/
|
||||
SELECT LFD.FILE_DETAIL_IDX
|
||||
, LFD.FILE_MASTER_IDX
|
||||
, LFD.FILE_UUID
|
||||
, LFD.ORIGIN_NAME
|
||||
, LFD.CONTENT_TYPE
|
||||
, LFD.SIZE_BYTES
|
||||
FROM ALISTLMS.FILE_DETAIL LFD
|
||||
INNER JOIN ALISTLMS.FILE_MASTER LFM
|
||||
ON LFM.FILE_MASTER_IDX = LFD.FILE_MASTER_IDX
|
||||
AND LFM.DEL_YN = 'N'
|
||||
INNER JOIN ALISTLMS.test_user_token LTUT
|
||||
ON LTUT.user_idx = LFM.USER_IDX
|
||||
WHERE LFD.FILE_MASTER_IDX = #{fileMasterIdx}
|
||||
AND LTUT.user_token_idx = #{userTokenIdx}
|
||||
AND LFD.DEL_YN = 'N'
|
||||
AND LFD.STATUS = 3
|
||||
AND LFD.MOVE_YN = 'Y'
|
||||
ORDER BY LFD.FILE_SEQ ASC, LFD.FILE_DETAIL_IDX ASC
|
||||
</select>
|
||||
|
||||
<select id="selectFileDetailByFileUuid" resultType="com.alist.api.common.modules.file.dto.FileDownloadDto">
|
||||
/*FileMapper.selectFileDetailByFileUuid*/
|
||||
SELECT LFD.FILE_DETAIL_IDX
|
||||
, LFD.FILE_MASTER_IDX
|
||||
, LFD.FILE_UUID
|
||||
, LFD.ORIGIN_NAME
|
||||
, LFD.CONTENT_TYPE
|
||||
, LFD.SIZE_BYTES
|
||||
, LFD.SAVE_PATH
|
||||
, LTUT.user_idx
|
||||
FROM ALISTLMS.FILE_DETAIL LFD
|
||||
INNER JOIN ALISTLMS.FILE_MASTER LFM
|
||||
ON LFM.FILE_MASTER_IDX = LFD.FILE_MASTER_IDX
|
||||
AND LFM.DEL_YN = 'N'
|
||||
INNER JOIN ALISTLMS.test_user_token LTUT
|
||||
ON LTUT.user_idx = LFM.USER_IDX
|
||||
WHERE LFD.FILE_UUID = #{fileUuid}
|
||||
AND LTUT.user_token_idx = #{userTokenIdx}
|
||||
AND LFD.DEL_YN = 'N'
|
||||
AND LFD.STATUS = 3
|
||||
AND LFD.MOVE_YN = 'Y'
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<update id="updateFileMoveSuccess" parameterType="com.alist.api.common.modules.file.dto.FileMoveTaskDto">
|
||||
/*FileMapper.updateFileMoveSuccess*/
|
||||
UPDATE ALISTLMS.FILE_DETAIL
|
||||
|
||||
Reference in New Issue
Block a user