-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/chung step5 #12
Changes from 10 commits
dbdd8e9
4df23ee
fd17400
916c153
4f3be8a
3335d28
28c28d2
4432e2c
fc21cc3
733c6ad
dc7a49f
ada9402
4d1e597
b53fe7c
d87cae5
3949129
f3fd490
7c43fed
70010f1
a3be9b6
85002ab
26be5ed
38ed73f
32737ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
rootProject.name = 'mystorage' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,50 +13,55 @@ | |
@Service | ||
@RequiredArgsConstructor | ||
public class FileDataHandlerService { | ||
private final FileRepository fileRepository; | ||
|
||
@Transactional | ||
public void deleteBy(Long fileId) { | ||
existBy(fileId); | ||
fileRepository.deleteById(fileId); | ||
} | ||
|
||
private void existBy(Long fileId) { | ||
if (!fileRepository.existsById(fileId)) { | ||
throw ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}", fileId); | ||
} | ||
} | ||
|
||
public FileMetadata findBy(Long fileId, Long userId) { | ||
return fileRepository.findByIdAndUploaderId(fileId, userId) | ||
.orElseThrow(() -> ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}, userId : {}", fileId, | ||
userId)); | ||
} | ||
|
||
public void persist(FileMetadata fileMetadata) { | ||
fileRepository.save(fileMetadata); | ||
} | ||
|
||
public void duplicateBy(Long parentId, String fileName) { | ||
if (fileRepository.existsByParentIdAndOriginalFileName(parentId, fileName)) { | ||
throw ErrorCode.DUPLICATE_FILE_NAME.serviceException("fileName : {}", fileName); | ||
} | ||
} | ||
|
||
public List<FileMetadata> getFileList(Long parentId, Long cursorId, Long userId, Pageable page) { | ||
return cursorId == null ? fileRepository.findAllByParentIdAndUploaderIdOrderByIdDesc(parentId, userId, page) | ||
: fileRepository.findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(parentId, cursorId, userId, page); | ||
} | ||
|
||
public Boolean hashNext(Long parentId, Long userId, Long lastIdOfList) { | ||
return fileRepository.existsByParentIdAndUploaderIdAndIdLessThan(parentId, userId, lastIdOfList); | ||
} | ||
|
||
public List<FileMetadata> findAllBy(Long parentId) { | ||
return fileRepository.findAllByParentId(parentId); | ||
} | ||
|
||
public void deleteAll(List<FileMetadata> fileMetadataList) { | ||
fileRepository.deleteAll(fileMetadataList); | ||
} | ||
private final FileRepository fileRepository; | ||
|
||
@Transactional | ||
public void deleteBy(Long fileId) { | ||
existBy(fileId); | ||
fileRepository.deleteById(fileId); | ||
} | ||
|
||
private void existBy(Long fileId) { | ||
if (!fileRepository.existsById(fileId)) { | ||
throw ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}", fileId); | ||
} | ||
} | ||
|
||
public FileMetadata findBy(Long fileId, Long userId) { | ||
return fileRepository.findByIdAndUploaderId(fileId, userId) | ||
.orElseThrow(() -> ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}, userId : {}", fileId, | ||
userId)); | ||
} | ||
|
||
public void persist(FileMetadata fileMetadata) { | ||
fileRepository.save(fileMetadata); | ||
} | ||
|
||
public void duplicateBy(Long parentId, String fileName) { | ||
if (fileRepository.existsByParentIdAndOriginalFileName(parentId, fileName)) { | ||
throw ErrorCode.DUPLICATE_FILE_NAME.serviceException("fileName : {}", fileName); | ||
} | ||
} | ||
|
||
public List<FileMetadata> getFileList(Long parentId, Long cursorId, Long userId, Pageable page) { | ||
return cursorId == null ? fileRepository.findAllByParentIdAndUploaderIdOrderByIdDesc(parentId, userId, page) | ||
: fileRepository.findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(parentId, cursorId, userId, page); | ||
} | ||
|
||
public Boolean hashNext(Long parentId, Long userId, Long lastIdOfList) { | ||
return fileRepository.existsByParentIdAndUploaderIdAndIdLessThan(parentId, userId, lastIdOfList); | ||
} | ||
|
||
public List<FileMetadata> findAllBy(Long parentId) { | ||
return fileRepository.findAllByParentId(parentId); | ||
} | ||
|
||
public void deleteAll(List<FileMetadata> fileMetadataList) { | ||
fileRepository.deleteAll(fileMetadataList); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 공유된 이슈로 개행 문제가 있습니다. |
||
// 파일이 삭제된 경우에는 파일 공유 링크로 다운 받을 수 없다. | ||
public FileMetadata findBy(Long fileId) { | ||
return fileRepository.findById(fileId).orElseThrow(ErrorCode.CANNOT_FOUND_FILE::serviceException); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,23 +5,22 @@ | |
|
||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개행 수정했습니다. 로직 상 수정 사항은 없습니다. |
||
public interface FileRepository extends JpaRepository<FileMetadata, Long> { | ||
Optional<FileMetadata> findByIdAndUploaderId(Long id, Long uploaderId); | ||
Optional<FileMetadata> findByIdAndUploaderId(Long id, Long uploaderId); | ||
|
||
boolean existsByParentIdAndOriginalFileName(Long parentId, String fileName); | ||
boolean existsByParentIdAndOriginalFileName(Long parentId, String fileName); | ||
|
||
List<FileMetadata> findByParentIdAndUploaderId(Long parentId, Long userId); | ||
List<FileMetadata> findByParentIdAndUploaderId(Long parentId, Long userId); | ||
|
||
Boolean existsByIdAndUploaderId(Long parentId, Long userId); | ||
Boolean existsByIdAndUploaderId(Long parentId, Long userId); | ||
|
||
List<FileMetadata> findAllByParentIdAndUploaderIdOrderByIdDesc(Long parentId, Long uploaderId, Pageable page); | ||
List<FileMetadata> findAllByParentIdAndUploaderIdOrderByIdDesc(Long parentId, Long uploaderId, Pageable page); | ||
|
||
List<FileMetadata> findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(Long parentId, Long userId, Long cursorId, | ||
Pageable pageable); | ||
List<FileMetadata> findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(Long parentId, Long userId, Long cursorId, | ||
Pageable pageable); | ||
|
||
Boolean existsByParentIdAndUploaderIdAndIdLessThan(Long parentId, Long uploaderId, Long id); | ||
Boolean existsByParentIdAndUploaderIdAndIdLessThan(Long parentId, Long uploaderId, Long id); | ||
|
||
List<FileMetadata> findAllByParentId(Long parentId); | ||
List<FileMetadata> findAllByParentId(Long parentId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.c4cometrue.mystorage.fileshare; | ||
|
||
import java.time.ZoneOffset; | ||
import java.time.ZonedDateTime; | ||
import java.util.List; | ||
|
||
import org.springframework.data.domain.PageRequest; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Component; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class DeleteLinkScheduler { | ||
private final FileShareRepository fileShareRepository; | ||
private final static int deleteSize = 100; | ||
|
||
@Scheduled(cron = "0 0 3 * * ?") | ||
public void deleteExpiredLinks() { | ||
ZonedDateTime expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); | ||
List<Long> expirationLinkIds; | ||
|
||
do { | ||
expirationLinkIds = fileShareRepository.findExpirations(expirationTime, PageRequest.of(0, deleteSize)); | ||
if (!expirationLinkIds.isEmpty()) { | ||
fileShareRepository.deleteByIds(expirationLinkIds); | ||
} | ||
} while (expirationLinkIds.size() == deleteSize); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.c4cometrue.mystorage.fileshare; | ||
|
||
import java.time.ZoneOffset; | ||
import java.time.ZonedDateTime; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Index; | ||
import jakarta.persistence.PrePersist; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Table(name = "file_share", indexes = { | ||
@Index(name = "idx_share_link", columnList = "shareLink") | ||
}) | ||
public class FileShare { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
private Long fileId; | ||
@Column(nullable = false, unique = true) | ||
private String shareLink; | ||
@Column(updatable = false) | ||
private ZonedDateTime createdAt; | ||
|
||
@Builder | ||
public FileShare(Long fileId, String shareLink) { | ||
this.fileId = fileId; | ||
this.shareLink = shareLink; | ||
} | ||
|
||
@PrePersist | ||
public void prePersist() { | ||
createdAt = ZonedDateTime.now(ZoneOffset.UTC); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.c4cometrue.mystorage.fileshare; | ||
|
||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileReq; | ||
import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; | ||
import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileReq; | ||
import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileRes; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@RequestMapping("/files/share") | ||
@RequiredArgsConstructor | ||
public class FileShareController { | ||
private final FileShareService fileShareService; | ||
|
||
@PostMapping | ||
public ResponseEntity<CreateShareFileRes> createShareFile(@Valid @RequestBody CreateShareFileReq req) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 수정하였습니다 |
||
CreateShareFileRes res = fileShareService.createShareFileLink(req.fileId(), req.userId()); | ||
return ResponseEntity.ok(res); | ||
} | ||
|
||
@GetMapping("/download") | ||
public ResponseEntity<DownloadShareFileRes> downloadShareFile(@Valid @RequestBody DownloadShareFileReq req) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GetMapping에서는 RequestBody 보다는 PathVariable이나 RequestParam을 이용하는 것은 어떨까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
아 맞네요 ModelAttribute 로 수정하였습니다! |
||
DownloadShareFileRes res = fileShareService.downloadShareFile(req.shareLink(), req.userPath()); | ||
return ResponseEntity.ok(res); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.c4cometrue.mystorage.fileshare; | ||
|
||
import java.time.ZonedDateTime; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.repository.query.Param; | ||
|
||
public interface FileShareRepository extends JpaRepository<FileShare, Long> { | ||
boolean existsByShareLink(String shareLink); | ||
|
||
Optional<FileShare> findByShareLink(String shareLink); | ||
|
||
@Query("SELECT fs.id FROM FileShare fs WHERE fs.createdAt < :expirationTime") | ||
List<Long> findExpirations(@Param("expirationTime") ZonedDateTime expirationTime, Pageable pageable); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. createdAt에 index는 필요 없나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
인덱스 추가하였습니다 감사합니다~! |
||
|
||
@Query("DELETE FROM FileShare fs WHERE fs.id IN :ids") | ||
void deleteByIds(@Param("ids") List<Long> ids); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
공유된 이슈로 개행 문제가 있습니다.
아래 세 개가 이번 수정 사항에 반영된 것입니다.