[파일 업로드] 파일업로드 뷰 & 다운로드

- 파일 뷰 & 다운로드 작업 커밋
This commit is contained in:
2026-03-10 14:00:33 +09:00
parent 7395ebfc79
commit 290c25aa21
16 changed files with 403 additions and 171 deletions
@@ -1,9 +1,6 @@
package com.alist.api.common.modules.file; package com.alist.api.common.modules.file;
import com.alist.api.common.modules.file.dto.FileUploadDto; import com.alist.api.common.modules.file.dto.*;
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.form.FileUploadForm; 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.TusHookForm;
import com.alist.api.common.modules.file.form.UploadCancelForm; 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.servlet.http.HttpSession;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j; 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.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
@Slf4j @Slf4j
@Tag( @Tag(
name = "99. TUS 업로드", name = "99. TUS 업로드"
description = "TUS 기반 파일 업로드 초기화, 권한 검증, 상태 조회, 훅 처리, 취소 API" , description = "TUS 기반 파일 업로드 초기화, 권한 검증, 상태 조회, 훅 처리, 취소 API"
) )
@RestController @RestController
@RequestMapping("/files") @RequestMapping("/files")
@@ -35,8 +38,8 @@ public class FileController {
} }
@Operation( @Operation(
summary = "파일 업로드 초기화", summary = "파일 업로드 초기화"
description = "업로드 대상 파일 정보를 DB에 등록하고 fileUuid/uploadToken을 발급합니다." , description = "업로드 대상 파일 정보를 DB에 등록하고 fileUuid/uploadToken을 발급합니다."
) )
@PostMapping("/uploadInit") @PostMapping("/uploadInit")
public ResponseEntity<ApiResponse<FileUploadDto>> uploadInit( public ResponseEntity<ApiResponse<FileUploadDto>> uploadInit(
@@ -62,8 +65,8 @@ public class FileController {
} }
@Operation( @Operation(
summary = "업로드 권한 검증", summary = "업로드 권한 검증"
description = "Bearer 업로드 토큰과 fileUuid(및 TUS 메타데이터)를 검증해 업로드 가능 여부를 확인합니다." , description = "Bearer 업로드 토큰과 fileUuid(및 TUS 메타데이터)를 검증해 업로드 가능 여부를 확인합니다."
) )
@GetMapping("/uploadAuth") @GetMapping("/uploadAuth")
public ResponseEntity<ApiResponse<String>> uploadAuth( public ResponseEntity<ApiResponse<String>> uploadAuth(
@@ -97,8 +100,8 @@ public class FileController {
} }
@Operation( @Operation(
summary = "업로드 상태 조회", summary = "업로드 상태 조회"
description = "fileUuid 기준으로 Redis/DB 업로드 상태(진행률, 상태값)를 조회합니다." , description = "fileUuid 기준으로 Redis/DB 업로드 상태(진행률, 상태값)를 조회합니다."
) )
@PostMapping("/uploadStatus") @PostMapping("/uploadStatus")
public ResponseEntity<ApiResponse<UploadStatusDto>> uploadStatus( public ResponseEntity<ApiResponse<UploadStatusDto>> uploadStatus(
@@ -112,8 +115,8 @@ public class FileController {
} }
@Operation( @Operation(
summary = "TUS 훅 수신", summary = "TUS 훅 수신"
description = "tusd에서 전달되는 pre-create/post-receive/post-finish/post-terminate 이벤트를 반영합니다." , description = "tusd에서 전달되는 pre-create/post-receive/post-finish/post-terminate 이벤트를 반영합니다."
) )
@PostMapping("/tusHook") @PostMapping("/tusHook")
public ResponseEntity<ApiResponse<String>> tusHook(@RequestBody TusHookForm tusHookForm) { public ResponseEntity<ApiResponse<String>> tusHook(@RequestBody TusHookForm tusHookForm) {
@@ -127,8 +130,8 @@ public class FileController {
} }
@Operation( @Operation(
summary = "업로드 취소", summary = "업로드 취소"
description = "현재 로그인 사용자의 fileUuid 업로드를 취소(CANCELED) 처리합니다." , description = "현재 로그인 사용자의 fileUuid 업로드를 취소(CANCELED) 처리합니다."
) )
@PostMapping("/uploadCancel") @PostMapping("/uploadCancel")
public ResponseEntity<ApiResponse<String>> uploadCancel( public ResponseEntity<ApiResponse<String>> uploadCancel(
@@ -155,4 +158,104 @@ public class FileController {
return ApiResponse.entity("", ApiResponseCode.CODE_200); 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 fileUuid;
private String filename; private String filename;
private String filetype; private String filetype;
private long uploadedBytes; private Long uploadedBytes;
private int status; 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 { public class UploadStatusDto {
private String fileUuid; private String fileUuid;
private String status; // PENDING, UPLOADING, DONE, FAILED private String status; // PENDING, UPLOADING, DONE, FAILED
private long uploadedBytes; private Long uploadedBytes;
private long totalBytes; private Long totalBytes;
private int percent; private Integer percent;
private String updatedAt; private String updatedAt;
} }
@@ -19,5 +19,5 @@ public class UploadTokenDto {
private String contentType; private String contentType;
@JsonIgnore @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 com.alist.api.common.modules.file.dto.*;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper @Mapper
public interface FileMapper { public interface FileMapper {
void insertFileMasterUpload(UploadStartDto uploadStartDto);
int selectFileMasterCountByFileMasterKeyAndDelYnAndStatus(UploadTokenDto uploadTokenDto);
void insertFileMasterInit(FileUploadDto fileUploadDto); void insertFileMasterInit(FileUploadDto fileUploadDto);
void insertFileDetailInit(FileUploadItemDto item); void insertFileDetailInit(FileUploadItemDto item);
@@ -38,4 +36,10 @@ public interface FileMapper {
int updateFileMoveSuccess(FileMoveTaskDto task); int updateFileMoveSuccess(FileMoveTaskDto task);
int updateFileMovePendingByFileUuid(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.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -19,6 +21,7 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.HexFormat; import java.util.HexFormat;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@@ -43,6 +46,12 @@ public class FileService {
@Value("${file.upload.final-root}") @Value("${file.upload.final-root}")
private String uploadFinalRoot; 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 FileMapper fileMapper;
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
private final StringRedisTemplate stringRedisTemplate; private final StringRedisTemplate stringRedisTemplate;
@@ -259,7 +268,7 @@ public class FileService {
} }
} }
tusHookDto.setUploadedBytes(offset); //tusHookDto.setUploadedBytes(offset); // 전체 사이즈 업데이트 삭제
Integer currentStatus = fileUploadMetaInfo.getStatus(); Integer currentStatus = fileUploadMetaInfo.getStatus();
if (currentStatus != null && (currentStatus == 3 || currentStatus == 5)) { if (currentStatus != null && (currentStatus == 3 || currentStatus == 5)) {
@@ -276,6 +285,7 @@ public class FileService {
return false; return false;
} }
tusHookDto.setUploadedBytes(null);
tusHookDto.setStatus(1); // UPLOADING tusHookDto.setStatus(1); // UPLOADING
break; break;
@@ -285,12 +295,13 @@ public class FileService {
return false; return false;
} }
tusHookDto.setUploadedBytes(null);
tusHookDto.setStatus(1); // UPLOADING tusHookDto.setStatus(1); // UPLOADING
break; break;
case "post-finish": case "post-finish":
tusHookDto.setStatus(3); // DONE
tusHookDto.setUploadedBytes(size); tusHookDto.setUploadedBytes(size);
tusHookDto.setStatus(3); // DONE
break; break;
case "post-terminate": case "post-terminate":
@@ -298,6 +309,7 @@ public class FileService {
if (currentStatus != null && currentStatus == 3) { if (currentStatus != null && currentStatus == 3) {
return false; return false;
} }
tusHookDto.setUploadedBytes(offset);
tusHookDto.setStatus(5); // CANCELED tusHookDto.setStatus(5); // CANCELED
break; break;
@@ -309,7 +321,11 @@ public class FileService {
return false; return false;
} }
boolean shouldUpdateDetail = !"post-receive".equals(type);
if (shouldUpdateDetail) {
fileMapper.updateFileDetailStatus(tusHookDto); fileMapper.updateFileDetailStatus(tusHookDto);
}
if ("post-finish".equals(type) || "post-terminate".equals(type)) { if ("post-finish".equals(type) || "post-terminate".equals(type)) {
fileMapper.updateFileMasterAggregateByFileUuid(tusHookDto.getFileUuid()); fileMapper.updateFileMasterAggregateByFileUuid(tusHookDto.getFileUuid());
@@ -319,7 +335,11 @@ public class FileService {
try { try {
tryMoveNowByFileUuid(tusHookDto.getFileUuid()); tryMoveNowByFileUuid(tusHookDto.getFileUuid());
} catch (NoSuchFileException e) { } catch (NoSuchFileException e) {
try { Thread.sleep(200); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } try {
Thread.sleep(200);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
try { try {
tryMoveNowByFileUuid(tusHookDto.getFileUuid()); // 1회 재시도 tryMoveNowByFileUuid(tusHookDto.getFileUuid()); // 1회 재시도
} catch (Exception ex) { } catch (Exception ex) {
@@ -570,4 +590,109 @@ public class FileService {
saveCanceledStatusRedis(uploadCancelDto.getFileUuid(), uploaded, total); // 필요하면 기존 bytes 조회해서 넣어도 됨 saveCanceledStatusRedis(uploadCancelDto.getFileUuid(), uploaded, total); // 필요하면 기존 bytes 조회해서 넣어도 됨
return true; 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 interrupt-seconds: 30
auth-cache: auth-cache:
ttl-seconds: 20 ttl-seconds: 20
download:
mode: redirect
redirect-prefix: /public-test-files
springdoc: springdoc:
api-docs: api-docs:
+3
View File
@@ -53,6 +53,9 @@ file:
interrupt-seconds: 30 interrupt-seconds: 30
auth-cache: auth-cache:
ttl-seconds: 20 ttl-seconds: 20
download:
mode: accel
redirect-prefix: /protected-files
springdoc: springdoc:
api-docs: api-docs:
@@ -21,15 +21,6 @@
) )
</insert> </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"> <insert id="insertFileUploadEventLog">
/*FileMapper.insertFileUploadEventLog*/ /*FileMapper.insertFileUploadEventLog*/
INSERT INTO ALISTLMS.FILE_UPLOAD_EVENT_LOG ( INSERT INTO ALISTLMS.FILE_UPLOAD_EVENT_LOG (
@@ -47,6 +38,34 @@
WHERE LFD.FILE_UUID = #{fileUuid} WHERE LFD.FILE_UUID = #{fileUuid}
LIMIT 1 LIMIT 1
</insert> </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"> <update id="updateFileDetailStatus">
/*FileMapper.updateFileDetailStatus*/ /*FileMapper.updateFileDetailStatus*/
@@ -127,18 +146,6 @@
AND LFD.STATUS IN (0,1,2) AND LFD.STATUS IN (0,1,2)
</update> </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"> <select id="selectFileDetailCountByFileUuidUserToKenIdx" resultType="java.lang.Integer">
/*FileMapper.selectFileDetailCountByFileUuidUserToKenIdx*/ /*FileMapper.selectFileDetailCountByFileUuidUserToKenIdx*/
SELECT COUNT(*) SELECT COUNT(*)
@@ -219,6 +226,52 @@
LIMIT 1 LIMIT 1
</select> </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"> <update id="updateFileMoveSuccess" parameterType="com.alist.api.common.modules.file.dto.FileMoveTaskDto">
/*FileMapper.updateFileMoveSuccess*/ /*FileMapper.updateFileMoveSuccess*/
UPDATE ALISTLMS.FILE_DETAIL UPDATE ALISTLMS.FILE_DETAIL