From 84f5cc7f0a03576e6f40089b0dc83da12710ec30 Mon Sep 17 00:00:00 2001 From: YerimSW Date: Fri, 2 Aug 2024 17:06:09 +0900 Subject: [PATCH 1/3] =?UTF-8?q?Feature:=20Log=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=83=9D=EC=84=B1,=20File=20=EC=97=B0=EA=B4=80?= =?UTF-8?q?=EA=B4=80=EA=B3=84=20=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acc/hotsix/file_share/domain/QFile.java | 3 + .../acc/hotsix/file_share/domain/QLog.java | 55 +++++++++++++++++++ .../acc/hotsix/file_share/domain/File.java | 4 ++ .../acc/hotsix/file_share/domain/Log.java | 44 +++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/main/generated/acc/hotsix/file_share/domain/QLog.java create mode 100644 src/main/java/acc/hotsix/file_share/domain/Log.java diff --git a/src/main/generated/acc/hotsix/file_share/domain/QFile.java b/src/main/generated/acc/hotsix/file_share/domain/QFile.java index 573434a..0e1e085 100644 --- a/src/main/generated/acc/hotsix/file_share/domain/QFile.java +++ b/src/main/generated/acc/hotsix/file_share/domain/QFile.java @@ -7,6 +7,7 @@ import com.querydsl.core.types.PathMetadata; import javax.annotation.processing.Generated; import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; /** @@ -33,6 +34,8 @@ public class QFile extends EntityPathBase { public final StringPath link = createString("link"); + public final ListPath logs = this.createList("logs", Log.class, QLog.class, PathInits.DIRECT2); + public final StringPath name = createString("name"); public final StringPath password = createString("password"); diff --git a/src/main/generated/acc/hotsix/file_share/domain/QLog.java b/src/main/generated/acc/hotsix/file_share/domain/QLog.java new file mode 100644 index 0000000..39eaae1 --- /dev/null +++ b/src/main/generated/acc/hotsix/file_share/domain/QLog.java @@ -0,0 +1,55 @@ +package acc.hotsix.file_share.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QLog is a Querydsl query type for Log + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QLog extends EntityPathBase { + + private static final long serialVersionUID = -26769568L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QLog log = new QLog("log"); + + public final DateTimePath createdAt = createDateTime("createdAt", java.time.LocalDateTime.class); + + public final QFile file; + + public final NumberPath logId = createNumber("logId", Long.class); + + public final EnumPath type = createEnum("type", Log.Type.class); + + public QLog(String variable) { + this(Log.class, forVariable(variable), INITS); + } + + public QLog(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QLog(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QLog(PathMetadata metadata, PathInits inits) { + this(Log.class, metadata, inits); + } + + public QLog(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.file = inits.isInitialized("file") ? new QFile(forProperty("file")) : null; + } + +} + diff --git a/src/main/java/acc/hotsix/file_share/domain/File.java b/src/main/java/acc/hotsix/file_share/domain/File.java index 04ceec6..c3f5f8b 100644 --- a/src/main/java/acc/hotsix/file_share/domain/File.java +++ b/src/main/java/acc/hotsix/file_share/domain/File.java @@ -8,6 +8,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.LocalDateTime; +import java.util.List; @Entity @Getter @@ -52,6 +53,9 @@ public class File { private String link; + @OneToMany(mappedBy = "file", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) + private List logs; + @Builder public File(Long fileId, String name, LocalDateTime createdAt, String resource, String fileType, Double fileSize, String path, LocalDateTime lastModifiedAt, Long download, Long view, boolean uploaded, String password, String link) { this.fileId = fileId; diff --git a/src/main/java/acc/hotsix/file_share/domain/Log.java b/src/main/java/acc/hotsix/file_share/domain/Log.java new file mode 100644 index 0000000..4554bc3 --- /dev/null +++ b/src/main/java/acc/hotsix/file_share/domain/Log.java @@ -0,0 +1,44 @@ +package acc.hotsix.file_share.domain; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Log { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long logId; + + @Enumerated(EnumType.STRING) + private Type type; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name="file_id") + private File file; + + @CreatedDate + private LocalDateTime createdAt; + + public enum Type { + CREATE, READ, UPDATE, DOWNLOAD + } + + @Builder + private Log(Type type, File file) { + this.type = type; + this.file = file; + } +} + +// file 생성(완), 조회(완), 업데이트(완), 다운로드(완) 시 Log 생성해야 함. +// log 조회 -> file id 별, type 별 From 4737f21f47e6c31ab9c167984939ba4b5bda4e17 Mon Sep 17 00:00:00 2001 From: YerimSW Date: Fri, 2 Aug 2024 17:06:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?Feature:=20File=20CRUD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20Log=20=EA=B8=B0=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file_share/api/FileDeleteController.java | 2 +- .../application/FileDownloadService.java | 19 +++++++++++++------ .../application/FileServiceImpl.java | 12 ++++++++++++ .../application/FileUpdateServiceImpl.java | 11 +++++++++++ .../application/FileUploadServiceImpl.java | 14 ++++++++++++++ .../hotsix/file_share/dao/LogRepository.java | 8 ++++++++ .../global/config/SecurityConfig.java | 4 +++- 7 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 src/main/java/acc/hotsix/file_share/dao/LogRepository.java diff --git a/src/main/java/acc/hotsix/file_share/api/FileDeleteController.java b/src/main/java/acc/hotsix/file_share/api/FileDeleteController.java index fe792bf..af89c6b 100644 --- a/src/main/java/acc/hotsix/file_share/api/FileDeleteController.java +++ b/src/main/java/acc/hotsix/file_share/api/FileDeleteController.java @@ -22,7 +22,7 @@ public class FileDeleteController { private final FileService fileService; private final FileDeleteService fileDeleteService; - @PostMapping("/files/delete/{id}") + @PostMapping("/files/{id}/delete") public ResponseEntity> deleteFile( @PathVariable("id")Long fileId, @Valid @ModelAttribute DeleteFileReq req, BindingResult bindingResult diff --git a/src/main/java/acc/hotsix/file_share/application/FileDownloadService.java b/src/main/java/acc/hotsix/file_share/application/FileDownloadService.java index ba3ec6e..c96cdda 100644 --- a/src/main/java/acc/hotsix/file_share/application/FileDownloadService.java +++ b/src/main/java/acc/hotsix/file_share/application/FileDownloadService.java @@ -1,7 +1,9 @@ package acc.hotsix.file_share.application; import acc.hotsix.file_share.dao.FileRepository; +import acc.hotsix.file_share.dao.LogRepository; import acc.hotsix.file_share.domain.File; +import acc.hotsix.file_share.domain.Log; import acc.hotsix.file_share.dto.FileDownloadDto; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.S3Object; @@ -16,21 +18,26 @@ public class FileDownloadService { private final AmazonS3Client amazonS3Client; private final FileRepository fileRepository; + private final LogRepository logRepository; @Value("${cloud.aws.s3.bucket}") private String bucketName; @Transactional public FileDownloadDto downloadFile(Long fileId) { - updateDownloadCount(fileId); + File file = fileRepository.findById(fileId).get(); + file.updateDownloadCount(); + + Log log = Log.builder() + .type(Log.Type.DOWNLOAD) + .file(file) + .build(); + + logRepository.save(log); + S3Object object = amazonS3Client.getObject(bucketName, fileId.toString()); String filename = fileRepository.findNameById(fileId); return new FileDownloadDto(object.getObjectContent(), filename); } - private void updateDownloadCount(Long fileId) { - File file = fileRepository.findById(fileId).get(); - file.updateDownloadCount(); - } - } diff --git a/src/main/java/acc/hotsix/file_share/application/FileServiceImpl.java b/src/main/java/acc/hotsix/file_share/application/FileServiceImpl.java index 1b31dd8..8d5153b 100644 --- a/src/main/java/acc/hotsix/file_share/application/FileServiceImpl.java +++ b/src/main/java/acc/hotsix/file_share/application/FileServiceImpl.java @@ -1,7 +1,9 @@ package acc.hotsix.file_share.application; import acc.hotsix.file_share.dao.FileRepository; +import acc.hotsix.file_share.dao.LogRepository; import acc.hotsix.file_share.domain.File; +import acc.hotsix.file_share.domain.Log; import acc.hotsix.file_share.dto.FileMetadataResponseDto; import acc.hotsix.file_share.global.error.FileNotFoundException; import acc.hotsix.file_share.global.error.InvalidShareLinkException; @@ -21,6 +23,8 @@ public class FileServiceImpl implements FileService { private final PasswordEncoder passwordEncoder; + private final LogRepository logRepository; + // ID를 통한 파일 메타데이터 조회 public File getFileById(Long fileId) throws FileNotFoundException { Optional result = fileRepository.findById(fileId); @@ -77,6 +81,14 @@ public String getResourceByLink(String link) throws InvalidShareLinkException { public FileMetadataResponseDto getMetadataById(Long fileId) { File file = fileRepository.findById(fileId).get(); file.updateViewCount(); + + Log log = Log.builder() + .type(Log.Type.READ) + .file(file) + .build(); + + logRepository.save(log); + return FileMetadataResponseDto.toFileResponseDto(file); } } diff --git a/src/main/java/acc/hotsix/file_share/application/FileUpdateServiceImpl.java b/src/main/java/acc/hotsix/file_share/application/FileUpdateServiceImpl.java index 49be767..83c4213 100644 --- a/src/main/java/acc/hotsix/file_share/application/FileUpdateServiceImpl.java +++ b/src/main/java/acc/hotsix/file_share/application/FileUpdateServiceImpl.java @@ -1,6 +1,8 @@ package acc.hotsix.file_share.application; +import acc.hotsix.file_share.dao.LogRepository; import acc.hotsix.file_share.domain.File; +import acc.hotsix.file_share.domain.Log; import acc.hotsix.file_share.global.error.FileDuplicateException; import acc.hotsix.file_share.global.error.FileNotFoundException; import acc.hotsix.file_share.global.error.FileTypeMismatchException; @@ -20,6 +22,7 @@ public class FileUpdateServiceImpl implements FileUpdateService { private final FileService fileService; private final FileUploadService fileUploadService; + private final LogRepository logRepository; // 파일 업데이트 public void updateFile(String fileId, String newDirectory, MultipartFile file) @@ -57,5 +60,13 @@ public void updateFile(String fileId, String newDirectory, MultipartFile file) // 업데이트된 메타 데이터 저장 fileService.saveMetaData(fileMetaData); + + // 수정 로그 생성 + Log log = Log.builder() + .type(Log.Type.UPDATE) + .file(fileMetaData) + .build(); + + logRepository.save(log); } } diff --git a/src/main/java/acc/hotsix/file_share/application/FileUploadServiceImpl.java b/src/main/java/acc/hotsix/file_share/application/FileUploadServiceImpl.java index becb6d0..af7fb0d 100644 --- a/src/main/java/acc/hotsix/file_share/application/FileUploadServiceImpl.java +++ b/src/main/java/acc/hotsix/file_share/application/FileUploadServiceImpl.java @@ -1,5 +1,7 @@ package acc.hotsix.file_share.application; +import acc.hotsix.file_share.dao.LogRepository; +import acc.hotsix.file_share.domain.Log; import acc.hotsix.file_share.global.error.FileDuplicateException; import acc.hotsix.file_share.global.error.UploadFileException; import com.amazonaws.services.s3.AmazonS3Client; @@ -11,6 +13,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; @@ -31,6 +34,8 @@ public class FileUploadServiceImpl implements FileUploadService { private final PasswordEncoder passwordEncoder; + private final LogRepository logRepository; + @Value("${cloud.aws.s3.bucket}") private String bucketName; @@ -63,6 +68,7 @@ public String uploadFileToS3(MultipartFile file, String key) throws UploadFileEx } // 파일 업로드 프로세스 + @Transactional public void uploadFile(MultipartFile file, String directory, String password) throws UploadFileException, FileDuplicateException { List duplicateFiles = fileService.getSameNameAndPathFileList(file.getOriginalFilename(), directory); if (duplicateFiles.size() > 0) { // 중복 파일 처리 @@ -109,5 +115,13 @@ public void uploadFile(MultipartFile file, String directory, String password) th fileService.removeFileMetaData(savedFile); throw new UploadFileException(); } + + // 파일 등록 로그 생성 + Log log = Log.builder() + .file(savedFile) + .type(Log.Type.CREATE) + .build(); + + logRepository.save(log); } } diff --git a/src/main/java/acc/hotsix/file_share/dao/LogRepository.java b/src/main/java/acc/hotsix/file_share/dao/LogRepository.java new file mode 100644 index 0000000..fa8822e --- /dev/null +++ b/src/main/java/acc/hotsix/file_share/dao/LogRepository.java @@ -0,0 +1,8 @@ +package acc.hotsix.file_share.dao; + +import acc.hotsix.file_share.domain.Log; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface LogRepository extends JpaRepository { + +} diff --git a/src/main/java/acc/hotsix/file_share/global/config/SecurityConfig.java b/src/main/java/acc/hotsix/file_share/global/config/SecurityConfig.java index 8810f2c..b36f99d 100644 --- a/src/main/java/acc/hotsix/file_share/global/config/SecurityConfig.java +++ b/src/main/java/acc/hotsix/file_share/global/config/SecurityConfig.java @@ -18,9 +18,11 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests((authorizeRequests) -> + .headers(headers -> headers.frameOptions(frame -> frame.disable())) + .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().permitAll()) .formLogin(AbstractHttpConfigurer::disable); + return http.build(); } From 3cab04cc5fd3baf7cd2ab3cf773695b19ea91555 Mon Sep 17 00:00:00 2001 From: YerimSW Date: Fri, 2 Aug 2024 18:02:29 +0900 Subject: [PATCH 3/3] =?UTF-8?q?Feature:=20Log=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hotsix/file_share/api/LogController.java | 40 +++++++++++++++++ .../file_share/application/LogService.java | 43 +++++++++++++++++++ .../hotsix/file_share/dao/LogRepository.java | 6 +++ .../acc/hotsix/file_share/domain/Log.java | 3 -- .../hotsix/file_share/dto/LogResponseDto.java | 30 +++++++++++++ 5 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/main/java/acc/hotsix/file_share/api/LogController.java create mode 100644 src/main/java/acc/hotsix/file_share/application/LogService.java create mode 100644 src/main/java/acc/hotsix/file_share/dto/LogResponseDto.java diff --git a/src/main/java/acc/hotsix/file_share/api/LogController.java b/src/main/java/acc/hotsix/file_share/api/LogController.java new file mode 100644 index 0000000..e6d2d09 --- /dev/null +++ b/src/main/java/acc/hotsix/file_share/api/LogController.java @@ -0,0 +1,40 @@ +package acc.hotsix.file_share.api; + +import acc.hotsix.file_share.application.LogService; +import acc.hotsix.file_share.dto.LogResponseDto; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +@Slf4j +@RestController +@AllArgsConstructor +@RequestMapping("/files") +public class LogController { + + private final LogService logService; + +// @GetMapping("/{file-id}/logs") +// public ResponseEntity> getFileLogs(@PathVariable("file-id") Long fileId, +// @RequestParam(defaultValue = "0") int page, +// @RequestParam(defaultValue = "10") int size) { +// +// return ResponseEntity.ok().body(logService.findLogsByFileId(fileId, page, size)); +// } + + @GetMapping("/{file-id}/logs") + public ResponseEntity> getFileLogsByType(@PathVariable("file-id") Long fileId, + @RequestParam(required = false,defaultValue = "none") String type, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size) { + + return ResponseEntity.ok().body(logService.findLogsByFileIdAndType(fileId, type, page, size)); + } +} + +// 로그 파일id로 조회, +// 로그 타입으로 조회, 로그 생성 시각으로 조회 \ No newline at end of file diff --git a/src/main/java/acc/hotsix/file_share/application/LogService.java b/src/main/java/acc/hotsix/file_share/application/LogService.java new file mode 100644 index 0000000..237c0c4 --- /dev/null +++ b/src/main/java/acc/hotsix/file_share/application/LogService.java @@ -0,0 +1,43 @@ +package acc.hotsix.file_share.application; + +import acc.hotsix.file_share.dao.LogRepository; +import acc.hotsix.file_share.domain.Log; +import acc.hotsix.file_share.dto.LogResponseDto; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class LogService { + private final LogRepository logRepository; + +// public List findLogsByFileId(Long fileId, int page, int size) { +// Pageable pageable = PageRequest.of(page, size); +// List content = logRepository.findByFileFileId(fileId, pageable).getContent(); +// +// return content.stream() +// .map(log -> LogResponseDto.toLogResponseDto(log)) +// .collect(Collectors.toList()); +// } + + public List findLogsByFileIdAndType(Long fileId, String type, int page, int size) { + Pageable pageable = PageRequest.of(page, size); + List content; + + if(type.equals("none")) + content = logRepository.findByFileFileId(fileId, pageable).getContent(); + else + content = logRepository.findByFileFileIdAndType(fileId, Log.Type.valueOf(type), pageable).getContent(); + + return content.stream() + .map(log -> LogResponseDto.toLogResponseDto(log)) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/acc/hotsix/file_share/dao/LogRepository.java b/src/main/java/acc/hotsix/file_share/dao/LogRepository.java index fa8822e..9b86870 100644 --- a/src/main/java/acc/hotsix/file_share/dao/LogRepository.java +++ b/src/main/java/acc/hotsix/file_share/dao/LogRepository.java @@ -1,8 +1,14 @@ package acc.hotsix.file_share.dao; import acc.hotsix.file_share.domain.Log; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface LogRepository extends JpaRepository { + Page findByFileFileId(Long fileId, Pageable pageable); + Page findByFileFileIdAndType(Long fileId, Log.Type type, Pageable pageable); } diff --git a/src/main/java/acc/hotsix/file_share/domain/Log.java b/src/main/java/acc/hotsix/file_share/domain/Log.java index 4554bc3..b6677e8 100644 --- a/src/main/java/acc/hotsix/file_share/domain/Log.java +++ b/src/main/java/acc/hotsix/file_share/domain/Log.java @@ -39,6 +39,3 @@ private Log(Type type, File file) { this.file = file; } } - -// file 생성(완), 조회(완), 업데이트(완), 다운로드(완) 시 Log 생성해야 함. -// log 조회 -> file id 별, type 별 diff --git a/src/main/java/acc/hotsix/file_share/dto/LogResponseDto.java b/src/main/java/acc/hotsix/file_share/dto/LogResponseDto.java new file mode 100644 index 0000000..afd1cb6 --- /dev/null +++ b/src/main/java/acc/hotsix/file_share/dto/LogResponseDto.java @@ -0,0 +1,30 @@ +package acc.hotsix.file_share.dto; + +import acc.hotsix.file_share.domain.Log; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class LogResponseDto { + private Long logId; + private Long fileId; + private String type; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Asia/Seoul") + private LocalDateTime createdAt; + + public static LogResponseDto toLogResponseDto(Log log) { + return LogResponseDto.builder() + .logId(log.getLogId()) + .fileId(log.getFile().getFileId()) + .type(log.getType().toString()) + .createdAt(log.getCreatedAt()) + .build(); + } +}