From 267ef2279a07c19d3a6314d445583d74bba81e27 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Tue, 21 May 2024 12:19:15 +0900 Subject: [PATCH 01/59] =?UTF-8?q?chore:=20QuizControllerDocs=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/controller/docs/QuizControllerDocs.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java index cb95709f..8a342df8 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java @@ -55,4 +55,13 @@ public interface QuizControllerDocs { @GetMapping("/code/{quizGameId}") public ResponseEntity> getQuizUrl( @PathVariable("quizGameId") long quizGameId); + + @Operation(summary = "퀴즈 게임 실시간 랭킹 보기", + responses = { + @ApiResponse(responseCode = "200", description = "(message : \"Success\")", + content = @Content), + @ApiResponse(responseCode = "400", description = "(message : \"해당 퀴즈는 종료되었습니다.\")") + }) + public ResponseEntity> getRanking( + @PathVariable("quizGameId") long quizGameId); } From 74dc00827e9f687accee471165b0a800b3c32fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Tue, 21 May 2024 19:28:47 +0900 Subject: [PATCH 02/59] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=EC=9A=A9=20=EA=B7=B8=EB=A3=B9=EB=A7=A4?= =?UTF-8?q?=ED=95=91=20=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/controller/GroupController.java | 2 +- .../challenge/service/GroupService.java | 2 +- .../challenge/service/GroupServiceImpl.java | 85 +++++++++---------- 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java index a3e566fb..b51a0910 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java @@ -55,7 +55,7 @@ public ResponseEntity> getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest) { List autoGroupMatchingResponse = // groupService.getGroupMatching(autoGroupMatchingRequest); - groupService.testMethod(); + groupService.testMethod(autoGroupMatchingRequest); return ResponseEntity.ok(ResultResponse.success(autoGroupMatchingResponse)); } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java index 317bdbaa..28f22ec8 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java @@ -20,5 +20,5 @@ public interface GroupService { List getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest); - List testMethod(); + List testMethod(AutoGroupMatchingRequest autoGroupMatchingRequest); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 762dfe94..5428b955 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -216,56 +215,50 @@ public List getGroupMatching( // TODO : 테스트 끝나고 해당 코드 지우기 // 테스트를 위해서 강제 그룹 형성 // 차성원(15), 홍유준(10), 정철주(9) - public List testMethod() { + public List testMethod( + AutoGroupMatchingRequest autoGroupMatchingRequest) { // 하드코딩된 멤버들을 포함하는 그룹을 생성 List group1 = List.of(15L, 10L, 9L); - // 단체에 있는 모든 멤버 ID - List allMembers = List.of(5L, 6L, 7L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L); - - // 하드코딩된 그룹 멤버를 제외한 나머지 멤버들 - List remainingMembers = new ArrayList<>(allMembers); - remainingMembers.removeAll(group1); - - // 나머지 멤버들을 균등하게 그룹화 - List> groups = new ArrayList<>(); - groups.add(group1); // 하드코딩된 그룹 추가 - - // 임의의 그룹으로 나머지 멤버들 배분 - int groupSize = 3; // 그룹당 최대 인원수 설정 - List currentGroup = new ArrayList<>(); - for (Long member : remainingMembers) { - if (currentGroup.size() < groupSize) { - currentGroup.add(member); - } else { - groups.add(new ArrayList<>(currentGroup)); - currentGroup.clear(); - currentGroup.add(member); + List members = autoGroupMatchingRequest.members().stream() + .map(memberRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .filter(member -> !group1.contains(member.getId())) + .map(memberMapper::memberToMemberSimpleDTO) + .collect(Collectors.toList()); + Collections.shuffle(members); + List> groups = new ArrayList<>(); + int groupSize = autoGroupMatchingRequest.minCount(); + int groupCount = members.size() / groupSize; + int left = members.size() % groupSize; + int addCount = left / groupCount; + int start = 0; + for (int i = 0; i < groupCount; i++) { + int size = groupSize; + if (i < left) { + if (left >= addCount) { + size += left; + } else { + size += addCount; + left -= addCount; + } } + groups.add(members.subList(start, start + size)); + start += size; } - if (!currentGroup.isEmpty()) { - groups.add(currentGroup); - } - - // 그룹 정보를 AutoGroupMatchingResponse로 변환 - List responses = new ArrayList<>(); - for (List group : groups) { - List members = group.stream() - .map(memberId -> memberRepository.findById(memberId) - .map(memberMapper::memberToMemberSimpleDTO) - .orElse(null)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - AutoGroupMatchingResponse response = AutoGroupMatchingResponse.builder() - .members(members) - .headCount(members.size()) - .build(); - - responses.add(response); - } - - return responses; + List testGroup = group1.stream() + .map(memberRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .map(memberMapper::memberToMemberSimpleDTO) + .collect(Collectors.toList()); + groups.add(testGroup); + return groups.stream().map(group -> AutoGroupMatchingResponse.builder() + .members(group) + .headCount(group.size()) + .build()) + .toList(); } private List getRandomGroup( From c908b177d95d3ee6da28f6d2b1ef2cf104913c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Tue, 21 May 2024 20:28:01 +0900 Subject: [PATCH 03/59] =?UTF-8?q?hotfix:=20=EB=9E=9C=EB=8D=A4=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EB=A7=A4=EC=B9=AD=20=EC=95=8C=EA=B3=A0=EB=A6=AC?= =?UTF-8?q?=EC=A6=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/service/GroupServiceImpl.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 5428b955..8e6b5ea3 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -236,13 +236,9 @@ public List testMethod( int start = 0; for (int i = 0; i < groupCount; i++) { int size = groupSize; - if (i < left) { - if (left >= addCount) { - size += left; - } else { - size += addCount; - left -= addCount; - } + if (left > 0) { + size += Math.min(left, addCount); + left -= addCount; } groups.add(members.subList(start, start + size)); start += size; @@ -278,13 +274,9 @@ private List getRandomGroup( int start = 0; for (int i = 0; i < groupCount; i++) { int size = groupSize; - if (i < left) { - if (left >= addCount) { - size += left; - } else { - size += addCount; - left -= addCount; - } + if (left > 0) { + size += Math.min(left, addCount); + left -= addCount; } groups.add(members.subList(start, start + size)); start += size; From f4b4986f2e9ea3719dde6afb85059e972d9b4850 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Wed, 22 May 2024 12:45:48 +0900 Subject: [PATCH 04/59] =?UTF-8?q?chore:=20StreamingController=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=EC=9C=A0=EC=A0=80=20=EB=8F=99=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=9E=A0=EC=8B=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/controller/StreamingController.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/StreamingController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/StreamingController.java index 7fefb95a..d8ed3367 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/StreamingController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/StreamingController.java @@ -9,8 +9,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.annotation.SendToUser; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -43,14 +41,4 @@ public void sendAnswer(final AnswerRequest request, streamingService.sendAnswer(request, accessToken); } - // 3. 서버 <-> 클라이언트 시간 동기화 (React 화면 마운트 시에 서버에 요청, 서버는 남은 카운트 다운 수 전송) - @MessageMapping("/current") - @SendToUser("/queue/time") // 이 어노테이션은 요청을 보낸 클라이언트의 해당 주소로만 값을 보냄! - public String currentTime(StompHeaderAccessor sha) { - log.info("여기까지 왔다!={}", sha.getSessionId()); - log.info("Destination={}", sha.getDestination()); - return String.valueOf(countdownService.getCurrentCountDown()); - } - - } From 4a4f36a9040ec0abb2ea9c0e74a17437a72a73ad Mon Sep 17 00:00:00 2001 From: Jeon Soo Min <102154788+dalcheonroadhead@users.noreply.github.com> Date: Wed, 22 May 2024 15:17:44 +0900 Subject: [PATCH 05/59] =?UTF-8?q?chore:=20gitLab=5FAccessToken=20=EB=A7=8C?= =?UTF-8?q?=EB=A3=8C=EC=97=90=20=EB=94=B0=EB=A5=B8=20main.yml=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b8e7438b..786c99c5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,8 +19,8 @@ jobs: - name: Configure Git run: | - git config user.name "차성원" - git config user.email "sungwon4728@naver.com" + git config user.name "전수민" + git config user.email "wjsaos2081@gmail.com" - name: Push to GitLab env: From fe75f9b9a8783386b82a1625daeb44f45334387e Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 12:23:37 +0900 Subject: [PATCH 06/59] =?UTF-8?q?refactor:=20=EC=99=80=EC=9D=BC=EB=93=9C?= =?UTF-8?q?=20=EC=B9=B4=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 와일드 카드 제거하고 반환 타입을 제대로 명시했습니다. - 메소드명을 더 명확하게 수정했습니다. --- .../board/controller/CommentController.java | 8 ++++---- .../board/controller/CommentControllerDocs.java | 8 ++++---- .../domain/board/controller/PostController.java | 15 ++++++++------- .../board/controller/PostControllerDocs.java | 12 ++++++------ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java index e3c2e9d0..804ca9db 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java @@ -22,14 +22,14 @@ public class CommentController implements CommentControllerDocs { private final CommentService commentService; @PostMapping - public ResponseEntity> write( + public ResponseEntity> commentWrite( @RequestBody CommentRequest request) { Long commentId = commentService.write(request); return ResponseEntity.ok(ResultResponse.success(commentId)); } @PatchMapping("/{id}") - public ResponseEntity> modify( + public ResponseEntity> commentModify( @PathVariable(value = "id") Long id, @RequestBody UpdateCommentRequest request) { Long commentId = commentService.modify(id, request); @@ -37,14 +37,14 @@ public ResponseEntity> modify( } @DeleteMapping("/{id}") - public ResponseEntity> delete( + public ResponseEntity> commentDelete( @PathVariable(value = "id") Long id) { Boolean isDelete = commentService.delete(id); return ResponseEntity.ok(ResultResponse.success(isDelete)); } @PostMapping("/{id}/report") - public ResponseEntity> report( + public ResponseEntity> commentReport( @PathVariable(value = "id") Long id) { Boolean isReport = commentService.report(id); return ResponseEntity.ok(ResultResponse.success(isReport)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentControllerDocs.java index f1174d8f..c7e8295c 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentControllerDocs.java @@ -42,7 +42,7 @@ public interface CommentControllerDocs { } ) @PostMapping - ResponseEntity> write( + ResponseEntity> commentWrite( @Parameter(name = "request", description = "댓글 작성 DTO", required = true, in = ParameterIn.DEFAULT) @RequestBody CommentRequest request ); @@ -61,7 +61,7 @@ ResponseEntity> write( } ) @PatchMapping("/{id}") - ResponseEntity> modify( + ResponseEntity> commentModify( @Parameter(name = "id", description = "댓글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id, @Parameter(name = "request", description = "댓글 수정 DTO", required = true, in = ParameterIn.DEFAULT) @@ -82,7 +82,7 @@ ResponseEntity> modify( } ) @DeleteMapping("/{id}") - ResponseEntity> delete( + ResponseEntity> commentDelete( @Parameter(name = "id", description = "댓글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ); @@ -106,7 +106,7 @@ ResponseEntity> delete( } ) @PostMapping("/{id}/report") - ResponseEntity> report( + ResponseEntity> commentReport( @Parameter(name = "id", description = "댓글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java index c3ab33bf..b02781a0 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java @@ -29,7 +29,7 @@ public class PostController implements PostControllerDocs { private final PostService postService; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity> write( + public ResponseEntity> postWrite( @RequestParam("organizationId") Long organizationId, @RequestPart(value = "request") PostRequest request, @RequestPart(value = "file", required = false) MultipartFile file) { @@ -38,7 +38,7 @@ public ResponseEntity> write( } @PatchMapping(value = "/{id}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity> modify( + public ResponseEntity> postModify( @PathVariable(value = "id") Long id, @RequestPart(value = "request") UpdatePostRequest request, @RequestPart(value = "file", required = false) MultipartFile file) { @@ -47,26 +47,27 @@ public ResponseEntity> modify( } @DeleteMapping(value = "{id}") - public ResponseEntity> delete(@PathVariable(value = "id") Long id) { - return ResponseEntity.ok(ResultResponse.success(postService.delete(id))); + public ResponseEntity> postDelete(@PathVariable(value = "id") Long id) { + Boolean isDelete = postService.delete(id); + return ResponseEntity.ok(ResultResponse.success(isDelete)); } @GetMapping(value = "/{id}") - public ResponseEntity> detailView( + public ResponseEntity> postDetailView( @PathVariable(value = "id") Long id) { PostDetailResponse response = postService.detailView(id); return ResponseEntity.ok(ResultResponse.success(response)); } @PostMapping(value = "/{id}/report") - public ResponseEntity> report( + public ResponseEntity> postReport( @PathVariable(value = "id") Long id) { boolean isReport = postService.report(id); return ResponseEntity.ok(ResultResponse.success(isReport)); } @GetMapping - public ResponseEntity> listView( + public ResponseEntity> postListView( PostSliceRequest request) { PostListResponse response = postService.listView(request); return ResponseEntity.ok(ResultResponse.success(response)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostControllerDocs.java index 1060875d..5c0edabf 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostControllerDocs.java @@ -39,7 +39,7 @@ public interface PostControllerDocs { @ApiResponse(responseCode = "500", description = "(message : \"첨부한 파일이 S3에 업로드 되지 않았습니다.\")", content = @Content) }) @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - ResponseEntity> write( + ResponseEntity> postWrite( @Parameter(name = "organizationId", description = "단체 PK 값", required = true, in = ParameterIn.QUERY) @RequestParam("organizationId") Long classId, @Parameter(name = "request", description = "게시글 작성 DTO", required = true, in = ParameterIn.DEFAULT) @@ -60,7 +60,7 @@ ResponseEntity> write( } ) @PatchMapping(value = "/{id}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - ResponseEntity> modify( + ResponseEntity> postModify( @Parameter(name = "id", description = "게시글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id, @Parameter(name = "request", description = "게시글 작성 DTO", required = true, in = ParameterIn.DEFAULT) @@ -80,7 +80,7 @@ ResponseEntity> modify( } ) @DeleteMapping(value = "{id}") - ResponseEntity> delete( + ResponseEntity> postDelete( @Parameter(name = "id", description = "게시글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ); @@ -99,7 +99,7 @@ ResponseEntity> delete( } ) @GetMapping(value = "/{id}") - ResponseEntity> detailView( + ResponseEntity> postDetailView( @Parameter(name = "id", description = "게시글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ); @@ -123,7 +123,7 @@ ResponseEntity> detailView( } ) @PostMapping(value = "/{id}/report") - ResponseEntity> report( + ResponseEntity> postReport( @Parameter(name = "id", description = "게시글 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ); @@ -138,7 +138,7 @@ ResponseEntity> report( } ) @GetMapping - ResponseEntity> listView( + ResponseEntity> postListView( PostSliceRequest request ); } From e47768a172da47698b61a60cf52c5dbd93a7553b Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 12:27:34 +0900 Subject: [PATCH 07/59] =?UTF-8?q?refactor:=20service=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - service 메소드 명을 좀 더 명확하게 수정했습니다. --- .../domain/board/controller/CommentController.java | 8 ++++---- .../domain/board/controller/PostController.java | 12 ++++++------ .../ourclass/domain/board/sevice/CommentService.java | 10 +++++----- .../domain/board/sevice/CommentServiceImpl.java | 8 ++++---- .../ourclass/domain/board/sevice/PostService.java | 12 ++++++------ .../domain/board/sevice/PostServiceImpl.java | 12 ++++++------ 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java index 804ca9db..1f4c5dea 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/CommentController.java @@ -24,7 +24,7 @@ public class CommentController implements CommentControllerDocs { @PostMapping public ResponseEntity> commentWrite( @RequestBody CommentRequest request) { - Long commentId = commentService.write(request); + Long commentId = commentService.commentWrite(request); return ResponseEntity.ok(ResultResponse.success(commentId)); } @@ -32,21 +32,21 @@ public ResponseEntity> commentWrite( public ResponseEntity> commentModify( @PathVariable(value = "id") Long id, @RequestBody UpdateCommentRequest request) { - Long commentId = commentService.modify(id, request); + Long commentId = commentService.commentModify(id, request); return ResponseEntity.ok(ResultResponse.success(commentId)); } @DeleteMapping("/{id}") public ResponseEntity> commentDelete( @PathVariable(value = "id") Long id) { - Boolean isDelete = commentService.delete(id); + Boolean isDelete = commentService.commentDelete(id); return ResponseEntity.ok(ResultResponse.success(isDelete)); } @PostMapping("/{id}/report") public ResponseEntity> commentReport( @PathVariable(value = "id") Long id) { - Boolean isReport = commentService.report(id); + Boolean isReport = commentService.commentReport(id); return ResponseEntity.ok(ResultResponse.success(isReport)); } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java index b02781a0..f8cd82fd 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/controller/PostController.java @@ -33,7 +33,7 @@ public ResponseEntity> postWrite( @RequestParam("organizationId") Long organizationId, @RequestPart(value = "request") PostRequest request, @RequestPart(value = "file", required = false) MultipartFile file) { - Long postId = postService.write(organizationId, file, request); + Long postId = postService.postWrite(organizationId, file, request); return ResponseEntity.ok(ResultResponse.success(postId)); } @@ -42,34 +42,34 @@ public ResponseEntity> postModify( @PathVariable(value = "id") Long id, @RequestPart(value = "request") UpdatePostRequest request, @RequestPart(value = "file", required = false) MultipartFile file) { - Long postId = postService.modify(id, file, request); + Long postId = postService.postModify(id, file, request); return ResponseEntity.ok(ResultResponse.success(postId)); } @DeleteMapping(value = "{id}") public ResponseEntity> postDelete(@PathVariable(value = "id") Long id) { - Boolean isDelete = postService.delete(id); + Boolean isDelete = postService.postDelete(id); return ResponseEntity.ok(ResultResponse.success(isDelete)); } @GetMapping(value = "/{id}") public ResponseEntity> postDetailView( @PathVariable(value = "id") Long id) { - PostDetailResponse response = postService.detailView(id); + PostDetailResponse response = postService.postDetailView(id); return ResponseEntity.ok(ResultResponse.success(response)); } @PostMapping(value = "/{id}/report") public ResponseEntity> postReport( @PathVariable(value = "id") Long id) { - boolean isReport = postService.report(id); + boolean isReport = postService.postReport(id); return ResponseEntity.ok(ResultResponse.success(isReport)); } @GetMapping public ResponseEntity> postListView( PostSliceRequest request) { - PostListResponse response = postService.listView(request); + PostListResponse response = postService.postListView(request); return ResponseEntity.ok(ResultResponse.success(response)); } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentService.java index a1cd12f8..628b51b6 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentService.java @@ -5,11 +5,11 @@ public interface CommentService { - Long write(CommentRequest request); + Long commentWrite(CommentRequest request); - Long modify(Long commentId, UpdateCommentRequest request); + Long commentModify(Long commentId, UpdateCommentRequest request); - Boolean delete(Long commentId); - - Boolean report(Long commentId); + Boolean commentDelete(Long commentId); + + Boolean commentReport(Long commentId); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java index c4de826a..90193f45 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java @@ -39,7 +39,7 @@ public class CommentServiceImpl implements CommentService { @Transactional @Override - public Long write(CommentRequest request) { + public Long commentWrite(CommentRequest request) { Member commentWriter = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); //게시글 찾기 @@ -93,7 +93,7 @@ public Long write(CommentRequest request) { @Transactional @Override - public Long modify(Long commentId, UpdateCommentRequest request) { + public Long commentModify(Long commentId, UpdateCommentRequest request) { Member member = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); @@ -119,7 +119,7 @@ public Long modify(Long commentId, UpdateCommentRequest request) { */ @Transactional @Override - public Boolean delete(Long commentId) { + public Boolean commentDelete(Long commentId) { Member member = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); @@ -147,7 +147,7 @@ public Boolean delete(Long commentId) { @Transactional @Override - public Boolean report(Long commentId) { + public Boolean commentReport(Long commentId) { Member member = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostService.java index 86e1c5d2..2a0f0ebc 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostService.java @@ -10,15 +10,15 @@ public interface PostService { - Long write(Long organizationId, MultipartFile file, PostRequest request); + Long postWrite(Long organizationId, MultipartFile file, PostRequest request); - Long modify(Long postId, MultipartFile file, UpdatePostRequest request); + Long postModify(Long postId, MultipartFile file, UpdatePostRequest request); - Boolean delete(Long postId); + Boolean postDelete(Long postId); - PostDetailResponse detailView(Long postId); + PostDetailResponse postDetailView(Long postId); - Boolean report(Long postId); + Boolean postReport(Long postId); - PostListResponse listView(PostSliceRequest request); + PostListResponse postListView(PostSliceRequest request); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java index 9d66506a..07dd18b3 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java @@ -59,7 +59,7 @@ public class PostServiceImpl implements PostService { @Transactional @Override - public Long write(Long organizationId, MultipartFile file, PostRequest request) { + public Long postWrite(Long organizationId, MultipartFile file, PostRequest request) { LocalDateTime now = LocalDateTime.now(); //멤버가 존재하는지 확인 Member member = userAccessUtil.getMember() @@ -140,7 +140,7 @@ public Long write(Long organizationId, MultipartFile file, PostRequest request) * */ @Transactional @Override - public Long modify(Long postId, MultipartFile file, UpdatePostRequest request) { + public Long postModify(Long postId, MultipartFile file, UpdatePostRequest request) { LocalDateTime now = LocalDateTime.now(); //멤버 존재 여부 확인 Member member = userAccessUtil.getMember() @@ -186,7 +186,7 @@ public Long modify(Long postId, MultipartFile file, UpdatePostRequest request) { @Transactional @Override - public Boolean delete(Long postId) { + public Boolean postDelete(Long postId) { Member member = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); @@ -209,7 +209,7 @@ public Boolean delete(Long postId) { } @Override - public PostDetailResponse detailView(Long postId) { + public PostDetailResponse postDetailView(Long postId) { //게시글 조회 Post post = postRepository.fetchPostWithDetails(postId); if (post == null) { //게시글 없으면 예외처리 @@ -225,7 +225,7 @@ public PostDetailResponse detailView(Long postId) { @Transactional @Override - public Boolean report(Long postId) { + public Boolean postReport(Long postId) { Member member = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); @@ -282,7 +282,7 @@ private List buildParentComments(List comments) { } @Override - public PostListResponse listView(PostSliceRequest request) { + public PostListResponse postListView(PostSliceRequest request) { return postRepository.getPostList(request); } } From a5c77853effbe666ee8c5c200165833d336494a1 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 14:01:09 +0900 Subject: [PATCH 08/59] =?UTF-8?q?refactor:=20mapper=20method=20name=20?= =?UTF-8?q?=EC=86=8C=EB=AC=B8=EC=9E=90=20=EC=8B=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mapper 메소드 명 첫 시작을 소문자로 수정했습니다. --- .../com/quiz/ourclass/domain/board/mapper/CommentMapper.java | 2 +- .../quiz/ourclass/domain/board/sevice/CommentServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/mapper/CommentMapper.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/mapper/CommentMapper.java index b6b97d1b..92015dee 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/mapper/CommentMapper.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/mapper/CommentMapper.java @@ -21,7 +21,7 @@ public interface CommentMapper { CommentDTO commentToCommentDTOWithChildren(Comment comment, List children); @Mapping(source = "boardId", target = "post.id") - Comment CommentRequestTocomment(CommentRequest commentRequest); + Comment commentRequestTocomment(CommentRequest commentRequest); void updateCommentFromRequest(UpdateCommentRequest request, @MappingTarget Comment comment); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java index 90193f45..85da4bca 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java @@ -83,7 +83,7 @@ public Long commentWrite(CommentRequest request) { } //게시글 댓글 저장 (부모 댓글이면 0L로 저장됩니다.) - Comment comment = commentMapper.CommentRequestTocomment(request); + Comment comment = commentMapper.commentRequestTocomment(request); comment.setCreateTime(LocalDateTime.now()); comment.setMember(commentWriter); comment.setPost(post); From ac08464cfa31b14aca601e7995630155cc4022b0 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 14:03:06 +0900 Subject: [PATCH 09/59] =?UTF-8?q?refactor:=20Post=20Query=20DSL=20limit=20?= =?UTF-8?q?=EB=8D=94=ED=95=98=EB=8A=94=20=EB=B6=80=EB=B6=84=20long=20?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - int 를 long 으로 수정했습니다. --- .../board/repository/querydsl/PostRepositoryQuerydslImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/repository/querydsl/PostRepositoryQuerydslImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/repository/querydsl/PostRepositoryQuerydslImpl.java index bd09e6fc..fa9b742b 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/repository/querydsl/PostRepositoryQuerydslImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/repository/querydsl/PostRepositoryQuerydslImpl.java @@ -50,7 +50,7 @@ public PostListResponse getPostList(PostSliceRequest request) { .leftJoin(post.comments, comment) .groupBy(post.id) .where(postCondition) - .limit(pageable.getPageSize() + 1) + .limit(pageable.getPageSize() + 1L) .offset(pageable.getOffset()) .orderBy(post.id.desc()) .fetch(); From 7925353a18ba30dcfef9d676bd5c2027dc9ff855 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 14:44:15 +0900 Subject: [PATCH 10/59] =?UTF-8?q?refactor:=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=98=EA=B8=B0=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=9D=B8=EC=A7=80=20=EB=B3=B5=EC=9E=A1=EB=8F=84=20=EC=A4=84?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인지 복잡도 17에서 15로 수정했습니다. --- .../board/sevice/CommentServiceImpl.java | 117 ++++++++++-------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java index 85da4bca..54e5c9f0 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java @@ -42,47 +42,13 @@ public class CommentServiceImpl implements CommentService { public Long commentWrite(CommentRequest request) { Member commentWriter = userAccessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); - //게시글 찾기 Post post = postRepository.findById(request.boardId()) .orElseThrow(() -> new GlobalException(ErrorCode.POST_NOT_FOUND)); - long orgId = post.getOrganization().getId(); + validateOrganizationAccess(commentWriter, post); + handleCommentInteractions(request, commentWriter, post); - //게시글을 작성한 사용자 단체와 댓글 작성자의 단체가 같은지 확인 - if (commentWriter.getRole() == Role.STUDENT) { - boolean isSameOrganization = post.getOrganization().getMemberOrganizations().stream() - .anyMatch(p -> p.getMember().getId() == commentWriter.getId()); - - if (!isSameOrganization) { - throw new GlobalException(ErrorCode.COMMENT_EDIT_PERMISSION_DENIED); - } - } else if (commentWriter.getRole() == Role.TEACHER) { - userAccessUtil.isOrganizationManager(commentWriter, post.getOrganization().getId()) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); - } - - if (post.getAuthor().getId() != commentWriter.getId() && - post.getAuthor().getRole() == Role.STUDENT) { - //해당 게시글에 반응(댓글 작성)을 하였는지 확인 - boolean isFirstComment = request.parentId() == 0L - && !commentRepository.existsByPostAndMember(post, commentWriter); - if (isFirstComment) { - Member member1 = post.getAuthor().getId() < commentWriter.getId() ? - post.getAuthor() : commentWriter; - Member member2 = post.getAuthor().getId() < commentWriter.getId() ? - commentWriter : post.getAuthor(); - - updateSocialCount(orgId, member1, member2); - } - //해당 댓글에 반응(대댓글 작성)을 하였는지 확인 - if (request.parentId() > 0L) { - Comment parentComment = commentRepository.findById(request.parentId()) - .orElseThrow(() -> new GlobalException(ErrorCode.COMMENT_NOT_FOUND)); - checkAndUpdateFirstResponse(post, commentWriter, parentComment); - } - } - - //게시글 댓글 저장 (부모 댓글이면 0L로 저장됩니다.) + // 게시글 댓글 저장 Comment comment = commentMapper.commentRequestTocomment(request); comment.setCreateTime(LocalDateTime.now()); comment.setMember(commentWriter); @@ -188,6 +154,18 @@ public Boolean commentReport(Long commentId) { return true; } + private void validateOrganizationAccess(Member commentWriter, Post post) { + if (commentWriter.getRole() == Role.STUDENT && + post.getOrganization().getMemberOrganizations().stream() + .noneMatch(p -> p.getMember().getId() == commentWriter.getId())) { + throw new GlobalException(ErrorCode.COMMENT_EDIT_PERMISSION_DENIED); + } else if (commentWriter.getRole() == Role.TEACHER && + userAccessUtil.isOrganizationManager( + commentWriter, post.getOrganization().getId()).isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } + } + /* * 부모 댓글 작성자가 게시글 작성자일 때 * 대댓글 작성자가 게시글에 댓글로 반응을 한 적이 없을 때 @@ -195,25 +173,58 @@ public Boolean commentReport(Long commentId) { * 부모 댓글 작성자가 게시글 작성자랑 다를 떄 * 대댓글 작성자가 부모 댓글 작성자에게 반응을 하지 않았을 때 */ - private void checkAndUpdateFirstResponse( - Post post, Member commentWriter, Comment parentComment) { - if ((post.getAuthor().getId() == parentComment.getMember().getId() && - !commentRepository.existsByPostAndMember(post, commentWriter)) - || - (post.getAuthor().getId() != parentComment.getMember().getId() && - !commentRepository.existsByParentIdAndMember(parentComment.getId(), - commentWriter))) { - long orgId = post.getOrganization().getId(); - - Member member1 = post.getAuthor().getId() < commentWriter.getId() ? - post.getAuthor() : commentWriter; - Member member2 = post.getAuthor().getId() < commentWriter.getId() ? - commentWriter : post.getAuthor(); - - updateSocialCount(orgId, member1, member2); + private void handleCommentInteractions( + CommentRequest request, Member commentWriter, Post post) { + // 첫 번째 댓글 확인 및 처리 + checkAndHandleFirstComment(request, commentWriter, post); + + // 대댓글 확인 및 처리 + if (request.parentId() > 0L) { + Comment parentComment = commentRepository.findById(request.parentId()) + .orElseThrow(() -> new GlobalException(ErrorCode.COMMENT_NOT_FOUND)); + checkAndUpdateFirstResponse(post, commentWriter, parentComment); } } + /* + * 첫 댓글인지 확인하고, 게시글 작성자가 학생이며, + * 댓글 작성자가 게시글 작성자가 아닌 경우에만 소셜 카운트 업데이트 + * */ + private void checkAndHandleFirstComment(CommentRequest request, Member commentWriter, + Post post) { + // 첫 댓글인지 확인하고, 게시글 작성자가 학생이며, 댓글 작성자가 게시글 작성자가 아닌 경우에만 소셜 카운트 업데이트 + if (post.getAuthor().getRole() == Role.STUDENT && + post.getAuthor().getId() != commentWriter.getId() && + isFirstComment(request, commentWriter, post)) { + updateSocialCount(post.getOrganization().getId(), + determineLowerMember(post.getAuthor(), commentWriter), + determineHigherMember(post.getAuthor(), commentWriter)); + } + } + + private boolean isFirstComment(CommentRequest request, Member commentWriter, Post post) { + return request.parentId() == 0L && + !commentRepository.existsByPostAndMember(post, commentWriter); + } + + private void checkAndUpdateFirstResponse(Post post, Member commentWriter, + Comment parentComment) { + if (post.getAuthor().getId() != parentComment.getMember().getId() + && !commentRepository.existsByParentIdAndMember(parentComment.getId(), commentWriter)) { + updateSocialCount(post.getOrganization().getId(), + determineLowerMember(post.getAuthor(), commentWriter), + determineHigherMember(post.getAuthor(), commentWriter)); + } + } + + private Member determineLowerMember(Member member1, Member member2) { + return member1.getId() < member2.getId() ? member1 : member2; + } + + private Member determineHigherMember(Member member1, Member member2) { + return member1.getId() < member2.getId() ? member2 : member1; + } + private void updateSocialCount(Long orgId, Member member1, Member member2) { Relationship relationship = relationshipRepository.findByOrganizationIdAndMember1IdAndMember2Id( From 496cc931936ffaa4ce8f46ecd55a1c5301c732a6 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 14:49:07 +0900 Subject: [PATCH 11/59] =?UTF-8?q?refactor:=20userAccessUtil=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EB=B0=9B=EC=95=84=EC=84=9C=20Exception=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - userAccessUtil 반환 받지 않고 Exception 처리하는 부분 반환 받고 예외 처리하는 것으로 수정했습니다. --- .../board/sevice/CommentServiceImpl.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java index 54e5c9f0..45f4a820 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/CommentServiceImpl.java @@ -12,6 +12,8 @@ import com.quiz.ourclass.domain.notice.entity.Notice; import com.quiz.ourclass.domain.notice.entity.NoticeType; import com.quiz.ourclass.domain.notice.repository.NoticeRepository; +import com.quiz.ourclass.domain.organization.entity.MemberOrganization; +import com.quiz.ourclass.domain.organization.entity.Organization; import com.quiz.ourclass.domain.organization.entity.Relationship; import com.quiz.ourclass.domain.organization.repository.RelationshipRepository; import com.quiz.ourclass.global.dto.FcmDTO; @@ -21,6 +23,7 @@ import com.quiz.ourclass.global.util.FcmUtil; import com.quiz.ourclass.global.util.UserAccessUtil; import java.time.LocalDateTime; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -98,9 +101,13 @@ public Boolean commentDelete(Long commentId) { throw new GlobalException(ErrorCode.COMMENT_DELETE_STUDENT_PERMISSION_DENIED); } } else if (requesterRole == Role.TEACHER) { - Long orgId = comment.getPost().getOrganization().getId(); - userAccessUtil.isOrganizationManager(member, orgId) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); + Optional organization = + userAccessUtil.isOrganizationManager( + member, comment.getPost().getOrganization().getId()); + + if (organization.isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } } //자식 댓글 삭제하기 @@ -124,8 +131,12 @@ public Boolean commentReport(Long commentId) { Comment comment = commentRepository.findById(commentId) .orElseThrow(() -> new GlobalException(ErrorCode.POST_NOT_FOUND)); - userAccessUtil.isMemberOfOrganization(member, comment.getPost().getOrganization().getId()) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); + Optional memberOrganization = + userAccessUtil.isMemberOfOrganization( + member, comment.getPost().getOrganization().getId()); + if (memberOrganization.isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } String reportMember = member.getName(); String authorMember = comment.getPost().getAuthor().getName(); From 14d25df6894465ac8d153d9ee53724114dca5d3e Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 14:53:40 +0900 Subject: [PATCH 12/59] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=82=AD=EC=A0=9C=20=EC=B2=98=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=B6=80=EB=B6=84=20if=EB=AC=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8A=94=20=EB=B6=80=EB=B6=84=20primitive=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - request 에서 바로 꺼내서 쓰는 것이 아니라 boolean 타입 변수로 넘겨받아서 사용하는 것으로 수정했습니다. --- .../com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java index 07dd18b3..d08a3037 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java @@ -152,7 +152,8 @@ public Long postModify(Long postId, MultipartFile file, UpdatePostRequest reques //이미지 관련 처리 부분 Image image = post.getImage(); - if (request.imageDelete() && image != null) { //이미지를 삭제하는 경우 + boolean imageDelete = request.imageDelete(); + if (imageDelete && image != null) { //이미지를 삭제하는 경우 awsS3ObjectStorage.deleteFile(image.getPath()); imageRepository.delete(image); post.setImage(null); From 317f00c9a5fa7114bd4e0d918cc1813962b6b642 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 15:09:23 +0900 Subject: [PATCH 13/59] =?UTF-8?q?refactor:=20userAccessUtil=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EB=B0=9B=EA=B3=A0=20=EC=98=88=EC=99=B8=20=EB=8D=98?= =?UTF-8?q?=EC=A7=80=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20ConstantUti?= =?UTF-8?q?l=20private=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - userAccessUtil 반환 받고 예외 던지기 - 상수 선언 클래스 인스턴스화 방지를 위한 예외 생성자 추가 --- .../domain/board/sevice/PostServiceImpl.java | 15 +++++++++++---- .../domain/chat/service/ChatRoomServiceImpl.java | 8 ++++++-- .../quiz/ourclass/global/util/ConstantUtil.java | 9 +++++++-- .../quiz/ourclass/OurClassApplicationTests.java | 5 ----- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java index 9d66506a..eecd50b2 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/board/sevice/PostServiceImpl.java @@ -34,6 +34,7 @@ import com.quiz.ourclass.global.util.UserAccessUtil; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; @@ -200,8 +201,11 @@ public Boolean delete(Long postId) { } } else if (requesterRole == Role.TEACHER) { Long orgId = post.getOrganization().getId(); - userAccessUtil.isOrganizationManager(member, orgId) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); + Optional organization = + userAccessUtil.isOrganizationManager(member, orgId); + if (organization.isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } } commentRepository.deleteByPostId(post.getId()); postRepository.delete(post); @@ -236,8 +240,11 @@ public Boolean report(Long postId) { Post post = postRepository.findById(postId) .orElseThrow(() -> new GlobalException(ErrorCode.POST_NOT_FOUND)); - userAccessUtil.isMemberOfOrganization(member, post.getOrganization().getId()) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); + Optional memberOrganization = + userAccessUtil.isMemberOfOrganization(member, post.getOrganization().getId()); + if (memberOrganization.isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } String reportMember = member.getName(); String authorMember = post.getAuthor().getName(); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatRoomServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatRoomServiceImpl.java index f1b75e98..20bcbceb 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatRoomServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatRoomServiceImpl.java @@ -11,6 +11,7 @@ import com.quiz.ourclass.global.exception.GlobalException; import com.quiz.ourclass.global.util.RedisUtil; import com.quiz.ourclass.global.util.UserAccessUtil; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -60,8 +61,11 @@ public void isMemberAuthorizedToJoinRoom(Long memberId, Long chatRoomId) { throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); } } else if (member.getRole() == Role.TEACHER) { - userAccessUtil.isOrganizationManager(member, chatRoomId) - .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION)); + Optional organization = + userAccessUtil.isOrganizationManager(member, chatRoomId); + if (organization.isEmpty()) { + throw new GlobalException(ErrorCode.MEMBER_NOT_IN_ORGANIZATION); + } } } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index 7a0a439d..c68ffae7 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -14,11 +14,16 @@ public abstract class ConstantUtil { public static final int RELAY_REWARD = 50; public static final Long RELAY_TIMEOUT_DAY = 1L; public static final String FCM_KEY_PREFIX = "FCM_"; - public static final int MAX_RETRIES = 5; //최대 재시도 횟수 - public static final long INITIAL_BACKOFF = 1000L; //초기 백오프 시간 (1초) + public static final int MAX_RETRIES = 5; + public static final long INITIAL_BACKOFF = 1000L; public static final String QUIZ_GAMER = "gamer"; public static final String QUIZ_QUESTION = "question"; public static final String RANKING = "ranking"; public static final String QUIZ_ANSWER = "answer"; + // 인스턴스화 방지 + private ConstantUtil() { + throw new UnsupportedOperationException( + "This is a utility class and cannot be instantiated"); + } } diff --git a/backEnd/src/test/java/com/quiz/ourclass/OurClassApplicationTests.java b/backEnd/src/test/java/com/quiz/ourclass/OurClassApplicationTests.java index e4528293..9dbdeb05 100644 --- a/backEnd/src/test/java/com/quiz/ourclass/OurClassApplicationTests.java +++ b/backEnd/src/test/java/com/quiz/ourclass/OurClassApplicationTests.java @@ -1,13 +1,8 @@ package com.quiz.ourclass; -import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest(classes = OurClassApplicationTests.class) class OurClassApplicationTests { - @Test - void contextLoads() { - } - } From 226fce1e5bdeae2c9f698a41a54fefe3364fbc94 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 15:28:55 +0900 Subject: [PATCH 14/59] =?UTF-8?q?refactor:=20switch=20=EB=AC=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20chatFilterMapper=20method=20name=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - chatHandler switch 문 default 추가 - switch 쉼표로 통합 - mapper 메소드 이름 첫 글자 소문자로 수정 --- .../quiz/ourclass/domain/chat/interceptor/ChatHandler.java | 4 ++-- .../quiz/ourclass/domain/chat/mapper/ChatFilterMapper.java | 2 +- .../ourclass/domain/chat/service/ChatFilterServiceImpl.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/interceptor/ChatHandler.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/interceptor/ChatHandler.java index 9e807834..c948e0d8 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/interceptor/ChatHandler.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/interceptor/ChatHandler.java @@ -48,10 +48,10 @@ private void handleMessage( } connectToChatRoom(accessor, memberId); break; - case SUBSCRIBE: - case SEND: + case SUBSCRIBE, SEND: verifyAccessToken(getAccessToken(accessor)); break; + default: } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/mapper/ChatFilterMapper.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/mapper/ChatFilterMapper.java index fb616e12..37b3c649 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/mapper/ChatFilterMapper.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/mapper/ChatFilterMapper.java @@ -15,7 +15,7 @@ public interface ChatFilterMapper { @Mapping(target = "id", ignore = true) - ChatFilter RequestToChatFilter(Organization organization, String badWord); + ChatFilter requestToChatFilter(Organization organization, String badWord); ChatFilter updateChatFilterFromRequest( ChatFilterRequest request, diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatFilterServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatFilterServiceImpl.java index ae0888fe..0f030084 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatFilterServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/service/ChatFilterServiceImpl.java @@ -34,7 +34,7 @@ public Long register(Long organizationId, ChatFilterRequest request) { duplicateWordCheck(organization, request.badWord()); return chatFilterRepository.save( - chatFilterMapper.RequestToChatFilter(organization, request.badWord()) + chatFilterMapper.requestToChatFilter(organization, request.badWord()) ).getId(); } From 6bcc2eb2bb752d614773a9ba198af992990e641c Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 15:31:25 +0900 Subject: [PATCH 15/59] =?UTF-8?q?refactor:=20chat,=20chatFilter=20?= =?UTF-8?q?=EC=99=80=EC=9D=BC=EB=93=9C=20=EC=B9=B4=EB=93=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 컨트롤러 반환 값 명확하게 명시하는 것으로 수정 --- .../ourclass/domain/chat/controller/ChatController.java | 3 ++- .../domain/chat/controller/ChatControllerDocs.java | 2 +- .../domain/chat/controller/ChatFilterController.java | 8 ++++---- .../domain/chat/controller/ChatFilterControllerDocs.java | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatController.java index 1e894255..e845209e 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatController.java @@ -39,7 +39,8 @@ public void exitChatRoom(@PathVariable(value = "id") Long id) { } @GetMapping - public ResponseEntity> chatListView(MessageSliceRequest request) { + public ResponseEntity> chatListView( + MessageSliceRequest request) { MessageResponse messageResponse = chatService.chatListView(request); return ResponseEntity.ok(ResultResponse.success(messageResponse)); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatControllerDocs.java index e58c1f75..463864ff 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatControllerDocs.java @@ -52,7 +52,7 @@ void exitChatRoom( } ) @GetMapping - ResponseEntity> chatListView( + ResponseEntity> chatListView( MessageSliceRequest request ); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterController.java index 4363ffce..16970793 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterController.java @@ -24,7 +24,7 @@ public class ChatFilterController implements ChatFilterControllerDocs { private final ChatFilterService chatFilterService; @PostMapping("/{organizationId}") - public ResponseEntity> register( + public ResponseEntity> register( @PathVariable(value = "organizationId") Long organizationId, @RequestBody ChatFilterRequest request ) { @@ -33,7 +33,7 @@ public ResponseEntity> register( } @PatchMapping("/{organizationId}/{id}") - public ResponseEntity> modify( + public ResponseEntity> modify( @PathVariable(value = "organizationId") Long organizationId, @PathVariable(value = "id") Long id, @RequestBody ChatFilterRequest request @@ -43,7 +43,7 @@ public ResponseEntity> modify( } @DeleteMapping("/{id}") - public ResponseEntity> delete( + public ResponseEntity> delete( @PathVariable(value = "id") Long id ) { Boolean isDelete = chatFilterService.delete(id); @@ -51,7 +51,7 @@ public ResponseEntity> delete( } @GetMapping - public ResponseEntity> select( + public ResponseEntity> select( ChatFilterSliceRequest request ) { ChatFilterResponse response = chatFilterService.select(request); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterControllerDocs.java index 4a27890c..24afbda6 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/chat/controller/ChatFilterControllerDocs.java @@ -34,7 +34,7 @@ public interface ChatFilterControllerDocs { } ) @PostMapping("/{organizationId}") - ResponseEntity> register( + ResponseEntity> register( @Parameter(name = "organizationId", description = "단체 ID 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "organizationId") Long organizationId, @Parameter(name = "request", description = "필터링 단어 DTO", required = true, in = ParameterIn.DEFAULT) @@ -57,7 +57,7 @@ ResponseEntity> register( } ) @PatchMapping("/{organizationId}/{id}") - ResponseEntity> modify( + ResponseEntity> modify( @Parameter(name = "organizationId", description = "단체 ID", required = true, in = ParameterIn.PATH) @PathVariable(value = "organizationId") Long organizationId, @Parameter(name = "id", description = "단어 필터링 ID 값", required = true, in = ParameterIn.PATH) @@ -77,7 +77,7 @@ ResponseEntity> modify( } ) @DeleteMapping("/{id}") - ResponseEntity> delete( + ResponseEntity> delete( @Parameter(name = "id", description = "단어 필터링 ID 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long chatFilterId ); @@ -96,7 +96,7 @@ ResponseEntity> delete( } ) @GetMapping - ResponseEntity> select( + ResponseEntity> select( ChatFilterSliceRequest request ); } From a5f0b708ee7f2f3544ffb03a78dde5a58cf7ad20 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 15:37:26 +0900 Subject: [PATCH 16/59] =?UTF-8?q?refactor:=20swaggerConfig=20AUTHORIZATION?= =?UTF-8?q?=20=EC=83=81=EC=88=98=ED=99=94,=20FcmType=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EC=B2=AB=20=EC=8B=9C=EC=9E=91=20?= =?UTF-8?q?=EC=86=8C=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - swagger Config Authorization 문자열 상수화로 변경 - FCM TYPE 변수 이름 소문자로 변경 --- .../ourclass/global/config/SwaggerConfig.java | 33 +++---------------- .../ourclass/global/util/ConstantUtil.java | 2 ++ .../quiz/ourclass/global/util/FcmType.java | 2 +- .../quiz/ourclass/global/util/FcmUtil.java | 27 --------------- 4 files changed, 8 insertions(+), 56 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/SwaggerConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/SwaggerConfig.java index 9c33ec47..51ff4743 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/SwaggerConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/SwaggerConfig.java @@ -1,5 +1,6 @@ package com.quiz.ourclass.global.config; +import com.quiz.ourclass.global.util.ConstantUtil; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -15,37 +16,13 @@ public class SwaggerConfig { @Bean - public GroupedOpenApi Api() { + public GroupedOpenApi api() { return GroupedOpenApi.builder() .group("all-api") .pathsToMatch("/**") .build(); } - @Bean - public GroupedOpenApi memberApi() { - return GroupedOpenApi.builder() - .group("member-api") - .pathsToMatch("/members/**") - .build(); - } - - @Bean - public GroupedOpenApi boardApi() { - return GroupedOpenApi.builder() - .group("board-api") - .pathsToMatch("/board/**") - .build(); - } - - @Bean - public GroupedOpenApi ChallengeApi() { - return GroupedOpenApi.builder() - .group("challenge-api") - .pathsToMatch("/challenge/**") - .build(); - } - @Bean public OpenAPI openAPI() { Info info = new Info() @@ -56,16 +33,16 @@ public OpenAPI openAPI() { SecurityScheme bearer = new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") - .bearerFormat("Authorization") + .bearerFormat(ConstantUtil.AUTHORIZATION) .in(SecurityScheme.In.HEADER) .name(HttpHeaders.AUTHORIZATION); // Security 요청 설정 SecurityRequirement addSecurityItem = new SecurityRequirement(); - addSecurityItem.addList("Authorization"); + addSecurityItem.addList(ConstantUtil.AUTHORIZATION); Components components = new Components() - .addSecuritySchemes("Authorization", bearer); + .addSecuritySchemes(ConstantUtil.AUTHORIZATION, bearer); return new OpenAPI() .components(components) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index c68ffae7..2cb34eea 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -21,6 +21,8 @@ public abstract class ConstantUtil { public static final String RANKING = "ranking"; public static final String QUIZ_ANSWER = "answer"; + public static final String AUTHORIZATION = "Authorization"; + // 인스턴스화 방지 private ConstantUtil() { throw new UnsupportedOperationException( diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmType.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmType.java index 4bd95d3e..8810bfb5 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmType.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmType.java @@ -12,5 +12,5 @@ public enum FcmType { CHALLENGE("함께달리기"), RELAY("이어달리기"), ; - private final String Type; + private final String type; } diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmUtil.java index abb0c172..d7aca043 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/FcmUtil.java @@ -58,33 +58,6 @@ public void sendMessage(Message message) { } catch (FirebaseMessagingException e) { log.error("fcm send error"); } -// int attempt = 0; -// long backoff = ConstantUtil.INITIAL_BACKOFF; -// -// while (attempt < ConstantUtil.MAX_RETRIES) { //지수 백오프 전략 -// try { -// FirebaseMessaging.getInstance().send(message); -// log.info("FCM Send Success"); -// break; // 성공 시 루프 종료 -// } catch (FirebaseMessagingException e) { -// log.error("FCM Send Error: {}", e.getMessage()); -// attempt++; -// if (attempt >= ConstantUtil.MAX_RETRIES) { -// // 최대 재시도 횟수 도달 시 루프 종료 -// // 다른 메시지 시스템으로 알림을 전송하는 방법을 고려해볼 수 있음 -// log.error("Reached Maximum Retry Attempts"); -// break; -// } -// try { -// Thread.sleep(backoff); // 지수 백오프를 위한 대기 -// } catch (InterruptedException ie) { -// Thread.currentThread().interrupt(); -// log.error("Interrupted While Waiting For Retry"); -// break; // 인터럽트 발생 시 루프 종료 -// } -// backoff *= 2; -// } -// } } public FcmDTO makeFcmDTO(String title, String body) { From 063e1591c23cbf307423e7005755e471bf67f566 Mon Sep 17 00:00:00 2001 From: HABIN Date: Sun, 26 May 2024 15:39:22 +0900 Subject: [PATCH 17/59] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=83=81=EC=88=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ConstantUtil 사용하지 않는 상수 제거 --- .../main/java/com/quiz/ourclass/global/util/ConstantUtil.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index 2cb34eea..87f4a5a1 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -6,7 +6,6 @@ public abstract class ConstantUtil { public static final String REDIS_ORG_KEY = "ORGANIZATION:"; public static final int REDIS_ORG_ALIVE_MINUTE = 10; public static final String REDIS_CHAT_ROOM_KEY = "chatRoom:"; - public static final String MONGO_DB_NAME = "chat"; public static final long HOME_FRIEND_COUNT = 3L; public static final String BLACKLIST_ACCESS_TOKEN = "AT:"; public static final String QUIZ_GAME = "quiz:"; @@ -14,13 +13,10 @@ public abstract class ConstantUtil { public static final int RELAY_REWARD = 50; public static final Long RELAY_TIMEOUT_DAY = 1L; public static final String FCM_KEY_PREFIX = "FCM_"; - public static final int MAX_RETRIES = 5; - public static final long INITIAL_BACKOFF = 1000L; public static final String QUIZ_GAMER = "gamer"; public static final String QUIZ_QUESTION = "question"; public static final String RANKING = "ranking"; public static final String QUIZ_ANSWER = "answer"; - public static final String AUTHORIZATION = "Authorization"; // 인스턴스화 방지 From 0c8d1ed904c171307262d0e33967cc4c175defca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:05:15 +0900 Subject: [PATCH 18/59] =?UTF-8?q?refactor=20#386:=20=ED=8A=B8=EB=9E=9C?= =?UTF-8?q?=EC=9E=AD=EC=85=94=EB=84=90=20=EB=A9=94=EC=84=9C=EB=93=9C=20pub?= =?UTF-8?q?lic=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/ChallengeServiceImpl.java | 2 +- .../quiz/ourclass/domain/relay/service/RelayServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/ChallengeServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/ChallengeServiceImpl.java index 1b79f13f..70d9a308 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/ChallengeServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/ChallengeServiceImpl.java @@ -233,7 +233,7 @@ protected void challengeClosing(Challenge challenge) { @EventListener(ApplicationReadyEvent.class) @Transactional - protected void challengeClosingReload() { + public void challengeClosingReload() { List challenges = challengeRepository.findAllByEndStatusIsFalse(); challenges.forEach(challenge -> { log.info(challenge.getEndTime().toString()); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java index a2f83d3e..64b71c23 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java @@ -208,7 +208,7 @@ protected void relayClosing(RelayMember relayMember) { @EventListener(ApplicationReadyEvent.class) @Transactional - protected void relayClosingReload() { + public void relayClosingReload() { List relays = relayRepository.findAllByEndStatusIsFalse(); relays.forEach(relay -> { RelayMember lastRunner = relay.getLastRunner(); From 7cd87ccc6e8ea9ed50a441ccb9c49bacdc6a1f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:07:03 +0900 Subject: [PATCH 19/59] =?UTF-8?q?refactor=20#386:=20long=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EB=81=BC=EB=A6=AC=20=EB=8D=94=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/repository/ChallengeRepositoryQuerydslImpl.java | 2 +- .../domain/relay/repository/RelayRepositoryQuerydslImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/repository/ChallengeRepositoryQuerydslImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/repository/ChallengeRepositoryQuerydslImpl.java index fc371505..1654b5de 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/repository/ChallengeRepositoryQuerydslImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/repository/ChallengeRepositoryQuerydslImpl.java @@ -51,7 +51,7 @@ public ChallengeSliceResponse getChallenges(ChallengeSliceRequest request) { .from(challenge) .where(challengeCondition) .offset(pageable.getOffset()) - .limit(pageable.getPageSize() + 1) + .limit(pageable.getPageSize() + 1L) .orderBy(challenge.id.desc()) .fetch(); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepositoryQuerydslImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepositoryQuerydslImpl.java index aba485bf..cc487ae3 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepositoryQuerydslImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepositoryQuerydslImpl.java @@ -46,7 +46,7 @@ public RelaySliceResponse getRelays(RelaySliceRequest request) { .join(relay.relayRunners, relayMember) .where(relayCondition) .offset(pageable.getOffset()) - .limit(pageable.getPageSize() + 1) + .limit(pageable.getPageSize() + 1L) .orderBy(relay.id.desc()) .fetch(); From 76da65fb31519a2cb4224b85c98882a35b73e6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:12:47 +0900 Subject: [PATCH 20/59] =?UTF-8?q?refactor=20#386:=20random=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=9E=AC=EC=82=AC=EC=9A=A9=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SecureRandom객체 사용 --- .../domain/organization/service/OrganizationServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/OrganizationServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/OrganizationServiceImpl.java index 429e8185..2d46d931 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/OrganizationServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/OrganizationServiceImpl.java @@ -26,6 +26,7 @@ import com.quiz.ourclass.global.util.ConstantUtil; import com.quiz.ourclass.global.util.RedisUtil; import com.quiz.ourclass.global.util.UserAccessUtil; +import java.security.SecureRandom; import java.time.Duration; import java.time.LocalDate; import java.util.List; @@ -48,6 +49,7 @@ public class OrganizationServiceImpl implements OrganizationService { private final MemberMapper memberMapper; private final RedisUtil redisUtil; private final UserAccessUtil accessUtil; + private final Random rand = new SecureRandom(); @Transactional @Override @@ -98,8 +100,7 @@ public InviteCodeDTO getOrganizationCode(long id) { String redisKey = ConstantUtil.REDIS_ORG_KEY + id; String code = redisUtil.valueGet(redisKey); if (code == null || code.isEmpty()) { - Random random = new Random(); - code = String.valueOf(random.nextInt(1000000)); + code = String.valueOf(rand.nextInt(1000000)); redisUtil.valueSet(redisKey, code, Duration.ofMinutes(ConstantUtil.REDIS_ORG_ALIVE_MINUTE)); } From 889b5070192501b1a45457c46050afb7b3509205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:24:26 +0900 Subject: [PATCH 21/59] =?UTF-8?q?refactor=20#386:=20controller=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=EA=B0=9D=EC=B2=B4=20=EC=A0=9C=EB=84=A4=EB=A6=AD?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ChallengeController.java | 20 ++++++++++--------- .../controller/ChallengeControllerDocs.java | 16 +++++++-------- .../challenge/controller/GroupController.java | 19 ++++++++++-------- .../controller/GroupControllerDocs.java | 13 ++++++------ .../controller/MemberOrgController.java | 13 ++++++------ .../controller/MemberOrgControllerDocs.java | 13 ++++++------ .../controller/OrganizationController.java | 20 +++++++++++-------- .../OrganizationControllerDocs.java | 17 ++++++++-------- .../relay/controller/RelayController.java | 16 ++++++++------- .../relay/controller/RelayControllerDocs.java | 15 +++++++------- 10 files changed, 89 insertions(+), 73 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java index a247ec6f..bc1fea00 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java @@ -33,7 +33,7 @@ public class ChallengeController implements ChallengeControllerDocs { private final ChallengeService challengeService; @GetMapping - public ResponseEntity> getChallenges( + public ResponseEntity> getChallenges( ChallengeSliceRequest challengeSliceRequest) { ChallengeSliceResponse challengeSliceResponse = challengeService.getChallenges( challengeSliceRequest); @@ -41,28 +41,28 @@ public ResponseEntity> getChallenges( } @PostMapping - public ResponseEntity> createChallenge( + public ResponseEntity> createChallenge( @RequestBody ChallengeRequest challengeRequest) { return ResponseEntity.ok( ResultResponse.success(challengeService.createChallenge(challengeRequest))); } @PostMapping(value = "/reports", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity> createReport( + public ResponseEntity> createReport( @RequestPart ReportRequest reportRequest, @RequestPart MultipartFile file) { long reportId = challengeService.createReport(reportRequest, file); return ResponseEntity.ok(ResultResponse.success(reportId)); } @PatchMapping(value = "/reports/{id}") - public ResponseEntity> confirmReport(@PathVariable long id, + public ResponseEntity> confirmReport(@PathVariable long id, ReportType reportType) { challengeService.confirmReport(id, reportType); - return ResponseEntity.ok(ResultResponse.success(null)); + return ResponseEntity.ok(ResultResponse.success(true)); } @GetMapping("/running") - public ResponseEntity> getRunningChallenge( + public ResponseEntity> getRunningChallenge( @RequestParam(required = true) long organizationId) { RunningChallengeResponse runningChallengeResponse = challengeService.getRunningChallenge( organizationId); @@ -70,7 +70,7 @@ public ResponseEntity> getRunningChallenge( } @GetMapping("/running/member") - public ResponseEntity> getRunningMemberChallenge( + public ResponseEntity> getRunningMemberChallenge( @RequestParam(required = true) long organizationId) { RunningMemberChallengeResponse runningMemberChallenge = challengeService.getRunningMemberChallenge( organizationId); @@ -78,14 +78,16 @@ public ResponseEntity> getRunningMemberChallenge( } @GetMapping("/{id}") - public ResponseEntity> getChallengeDetail(@PathVariable long id, + public ResponseEntity> getChallengeDetail( + @PathVariable long id, @RequestParam(required = false) Long groupId) { ChallengeResponse challengeResponse = challengeService.getChallengeDetail(id, groupId); return ResponseEntity.ok(ResultResponse.success(challengeResponse)); } @GetMapping("/{id}/simple") - public ResponseEntity> getChallengeSimple(@PathVariable long id) { + public ResponseEntity> getChallengeSimple( + @PathVariable long id) { ChallengeSimpleResponse challengeSimple = challengeService.getChallengeSimple(id); return ResponseEntity.ok(ResultResponse.success(challengeSimple)); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java index 22589b1b..4988f3a6 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java @@ -38,7 +38,7 @@ public interface ChallengeControllerDocs { content = @Content(schema = @Schema(implementation = ChallengeSliceResponse.class))) }) @GetMapping - ResponseEntity> getChallenges( + ResponseEntity> getChallenges( ChallengeSliceRequest challengeSliceRequest ); @@ -51,7 +51,7 @@ ResponseEntity> getChallenges( @ApiResponse(responseCode = "404", description = "(message : \"학급을 찾을 수 없습니다.\")", content = @Content) }) @PostMapping - public ResponseEntity> createChallenge( + public ResponseEntity> createChallenge( @RequestBody ChallengeRequest challengeRequest ); @@ -65,7 +65,7 @@ public ResponseEntity> createChallenge( @ApiResponse(responseCode = "500", description = "(message : \"AWS 서버 에러입니다.\")", content = @Content) }) @PostMapping(value = "/reports", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - ResponseEntity> createReport( + ResponseEntity> createReport( @RequestPart ReportRequest reportRequest, @RequestPart @@ -79,7 +79,7 @@ ResponseEntity> createReport( @ApiResponse(responseCode = "404", description = "(message : \"레포트를 찾을 수 없습니다.\")", content = @Content) }) @PatchMapping(value = "/reports/{id}") - public ResponseEntity> confirmReport( + ResponseEntity> confirmReport( @Schema(description = "레포트 id") @PathVariable long id, @@ -102,7 +102,7 @@ public ResponseEntity> confirmReport( """, content = @Content) }) @GetMapping("/running") - public ResponseEntity> getRunningChallenge( + public ResponseEntity> getRunningChallenge( @RequestParam(required = true) @Parameter(description = "학급 ID", required = true, in = ParameterIn.QUERY) long organizationId @@ -125,7 +125,7 @@ public ResponseEntity> getRunningChallenge( """, content = @Content) }) @GetMapping("/running/member") - ResponseEntity> getRunningMemberChallenge( + ResponseEntity> getRunningMemberChallenge( @RequestParam(required = true) @Parameter(description = "학급 ID", required = true, in = ParameterIn.QUERY) long organizationId @@ -139,7 +139,7 @@ ResponseEntity> getRunningMemberChallenge( content = @Content(schema = @Schema(implementation = ChallengeResponse.class))) }) @GetMapping("/{id}") - public ResponseEntity> getChallengeDetail( + public ResponseEntity> getChallengeDetail( @PathVariable @Parameter(description = "함께달리기 ID", required = true, in = ParameterIn.PATH) long id, @@ -153,7 +153,7 @@ public ResponseEntity> getChallengeDetail( content = @Content(schema = @Schema(implementation = ChallengeSimpleResponse.class))) }) @GetMapping("/{id}/simple") - ResponseEntity> getChallengeSimple( + ResponseEntity> getChallengeSimple( @PathVariable @Parameter(description = "함께달리기 ID", required = true, in = ParameterIn.PATH) long id diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java index b51a0910..b4611321 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java @@ -2,6 +2,7 @@ import com.quiz.ourclass.domain.challenge.dto.request.AutoGroupMatchingRequest; import com.quiz.ourclass.domain.challenge.dto.response.AutoGroupMatchingResponse; +import com.quiz.ourclass.domain.challenge.dto.response.MatchingRoomResponse; import com.quiz.ourclass.domain.challenge.service.GroupService; import com.quiz.ourclass.global.dto.ResultResponse; import java.util.List; @@ -21,37 +22,39 @@ public class GroupController implements GroupControllerDocs { private final GroupService groupService; @PostMapping("/groups/matchingroom") - public ResponseEntity> createMatchingRoom(long challengeId) { + public ResponseEntity> createMatchingRoom( + long challengeId) { return ResponseEntity.ok( ResultResponse.success(groupService.createMatchingRoom(challengeId))); } @PostMapping("/groups/join") - public ResponseEntity> joinMatchingRoom(String key, boolean joinStatus) { + public ResponseEntity> joinMatchingRoom(String key, + boolean joinStatus) { return ResponseEntity.ok( ResultResponse.success(groupService.joinMatchingRoom(key, joinStatus))); } @PostMapping("/groups") - public ResponseEntity> createGroup(String key) { + public ResponseEntity> createGroup(String key) { return ResponseEntity.ok( ResultResponse.success(groupService.createGroup(key))); } @DeleteMapping("/groups/matching") - public ResponseEntity> deleteMatchingMember(String key, Long memberId) { + public ResponseEntity> deleteMatchingMember(String key, Long memberId) { groupService.deleteMatchingMember(key, memberId); - return ResponseEntity.ok(ResultResponse.success(null)); + return ResponseEntity.ok(ResultResponse.success(true)); } @GetMapping("/groups/invite") - public ResponseEntity> inviteMatchingRoom(String key, Long memberId) { + public ResponseEntity> inviteMatchingRoom(String key, Long memberId) { groupService.inviteMatchingRoom(key, memberId); - return ResponseEntity.ok(ResultResponse.success(null)); + return ResponseEntity.ok(ResultResponse.success(true)); } @GetMapping("/groups/matching") - public ResponseEntity> getGroupMatching( + public ResponseEntity>> getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest) { List autoGroupMatchingResponse = // groupService.getGroupMatching(autoGroupMatchingRequest); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupControllerDocs.java index 26b601cd..34574b66 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupControllerDocs.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -27,7 +28,7 @@ public interface GroupControllerDocs { content = @Content(schema = @Schema(implementation = MatchingRoomResponse.class))) }) @PostMapping("/groups/matchingroom") - ResponseEntity> createMatchingRoom( + ResponseEntity> createMatchingRoom( @Parameter(description = "함께달리기 ID", required = true, in = ParameterIn.QUERY) long challengeId ); @@ -44,7 +45,7 @@ ResponseEntity> createMatchingRoom( content = @Content(schema = @Schema(implementation = Boolean.class, description = "초대 응답"))) }) @PostMapping("/groups/join") - ResponseEntity> joinMatchingRoom( + ResponseEntity> joinMatchingRoom( @Parameter(description = "그룹 대기방 KEY", required = true, in = ParameterIn.QUERY) String key, @Parameter(description = "초대 수락 여부", required = true, in = ParameterIn.QUERY) @@ -61,7 +62,7 @@ ResponseEntity> joinMatchingRoom( }) @PostMapping("/groups") - ResponseEntity> createGroup( + ResponseEntity> createGroup( @Parameter(description = "그룹 대기방 KEY", required = true, in = ParameterIn.QUERY) String key ); @@ -73,7 +74,7 @@ ResponseEntity> createGroup( @ApiResponse(responseCode = "200", description = "(message : \"Success\")") }) @DeleteMapping("/groups/matching") - ResponseEntity> deleteMatchingMember( + ResponseEntity> deleteMatchingMember( @Parameter(description = "그룹 대기방 KEY", required = true, in = ParameterIn.QUERY) String key, @Parameter(description = "추방 멤버 ID", required = true, in = ParameterIn.QUERY) @@ -87,7 +88,7 @@ ResponseEntity> deleteMatchingMember( @ApiResponse(responseCode = "200", description = "(message : \"Success\")") }) @GetMapping("/groups/invite") - ResponseEntity> inviteMatchingRoom( + ResponseEntity> inviteMatchingRoom( @Parameter(description = "그룹 대기방 KEY", required = true, in = ParameterIn.QUERY) String key, @Parameter(description = "초대 멤버 ID", required = true, in = ParameterIn.QUERY) @@ -101,7 +102,7 @@ ResponseEntity> inviteMatchingRoom( content = @Content(schema = @Schema(implementation = AutoGroupMatchingResponse.class))) }) @GetMapping("/groups/matching") - ResponseEntity> getGroupMatching( + ResponseEntity>> getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest ); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgController.java index 6b8fe489..0b637dac 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgController.java @@ -32,7 +32,7 @@ public class MemberOrgController implements MemberOrgControllerDocs { private final MemberOrgService memberOrgService; @PatchMapping("/{id}/point") - public ResponseEntity> updateMemberExp(@PathVariable long id, + public ResponseEntity> updateMemberExp(@PathVariable long id, @RequestBody UpdateExpRequest updateExpRequest) { UpdateExpResponse updateExpResponse = memberOrgService.updateMemberExp( id, updateExpRequest); @@ -40,7 +40,7 @@ public ResponseEntity> updateMemberExp(@PathVariable long id, } @GetMapping("/{id}/relation") - public ResponseEntity> getMemberRelation( + public ResponseEntity> getMemberRelation( @PathVariable long id, RelationRequest relationRequest) { RelationResponse relationResponse = memberOrgService.getMemberRelation( id, relationRequest); @@ -48,14 +48,14 @@ public ResponseEntity> getMemberRelation( } @GetMapping("/{id}") - public ResponseEntity> getMemberDetail( + public ResponseEntity> getMemberDetail( @PathVariable long id, long memberId) { MemberDetailResponse memberDetail = memberOrgService.getMemberDetail(id, memberId); return ResponseEntity.ok(ResultResponse.success(memberDetail)); } @GetMapping("/{id}/relations") - public ResponseEntity> getMemberRelations( + public ResponseEntity>> getMemberRelations( @PathVariable long id, long memberId, @RequestParam(required = false) Long limit) { List relations = memberOrgService.getMemberRelations( id, memberId, limit); @@ -63,13 +63,14 @@ public ResponseEntity> getMemberRelations( } @GetMapping("/{id}/home") - public ResponseEntity> getOrganizationHome(@PathVariable long id) { + public ResponseEntity> getOrganizationHome( + @PathVariable long id) { OrganizationHomeResponse homeResponse = memberOrgService.getOrganizationHome(id); return ResponseEntity.ok(ResultResponse.success(homeResponse)); } @PostMapping("/tag") - public ResponseEntity> tagGreet( + public ResponseEntity> tagGreet( @RequestBody TagGreetingRequest tagGreetingRequest) { int tagGreetingCount = memberOrgService.tagGreeting(tagGreetingRequest); return ResponseEntity.ok(ResultResponse.success(tagGreetingCount)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java index 4459d9f2..e36d5467 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -35,7 +36,7 @@ public interface MemberOrgControllerDocs { @ApiResponse(responseCode = "404", description = "(message : \"학급 멤버를 찾을 수 없습니다.\")", content = @Content) }) @PatchMapping("/{id}/point") - ResponseEntity> updateMemberExp( + ResponseEntity> updateMemberExp( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -50,7 +51,7 @@ ResponseEntity> updateMemberExp( @ApiResponse(responseCode = "404", description = "(message : \"두 멤버간의 관계를 찾을 수 없습니다.\")", content = @Content) }) @GetMapping("/{id}/relation") - ResponseEntity> getMemberRelation( + ResponseEntity> getMemberRelation( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -64,7 +65,7 @@ ResponseEntity> getMemberRelation( @ApiResponse(responseCode = "404", description = "(message : \"학급 멤버를 찾을 수 없습니다.\")", content = @Content) }) @GetMapping("/{id}") - ResponseEntity> getMemberDetail( + ResponseEntity> getMemberDetail( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -79,7 +80,7 @@ ResponseEntity> getMemberDetail( content = @Content(schema = @Schema(implementation = RelationSimpleResponse.class))) }) @GetMapping("/{id}/relations") - ResponseEntity> getMemberRelations( + ResponseEntity>> getMemberRelations( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -97,7 +98,7 @@ ResponseEntity> getMemberRelations( content = @Content(schema = @Schema(implementation = OrganizationHomeResponse.class))) }) @GetMapping("/{id}/home") - ResponseEntity> getOrganizationHome( + ResponseEntity> getOrganizationHome( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id @@ -110,7 +111,7 @@ ResponseEntity> getOrganizationHome( @ApiResponse(responseCode = "404", description = "(message : \"두 멤버간의 관계를 찾을 수 없습니다.\")", content = @Content) }) @PostMapping("/tag") - ResponseEntity> tagGreet( + ResponseEntity> tagGreet( @RequestBody TagGreetingRequest tagGreetingRequest ); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationController.java index fa55796a..0286901f 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationController.java @@ -29,39 +29,42 @@ public class OrganizationController implements OrganizationControllerDocs { private final OrganizationService organizationService; @PostMapping - public ResponseEntity> createOrganization( + public ResponseEntity> createOrganization( @RequestBody OrganizationRequest organizationRequest) { Long organizationId = organizationService.createOrganization(organizationRequest); return ResponseEntity.ok(ResultResponse.success(organizationId)); } @GetMapping - public ResponseEntity> getOrganizations() { + public ResponseEntity>> getOrganizations() { List organizations = organizationService.getOrganizations(); return ResponseEntity.ok(ResultResponse.success(organizations)); } @GetMapping("/{id}/code") - public ResponseEntity> getOrganizationCode(@PathVariable long id) { + public ResponseEntity> getOrganizationCode( + @PathVariable long id) { InviteCodeDTO code = organizationService.getOrganizationCode(id); return ResponseEntity.ok(ResultResponse.success(code)); } @PostMapping("/{id}/join") - public ResponseEntity> joinOrganization(@PathVariable long id, + public ResponseEntity> joinOrganization(@PathVariable long id, @RequestBody InviteCodeDTO inviteCodeDTO) { Long organizationId = organizationService.joinOrganization(id, inviteCodeDTO); return ResponseEntity.ok(ResultResponse.success(organizationId)); } @GetMapping("/{id}/members") - public ResponseEntity> getOrganizationMembers(@PathVariable long id) { + public ResponseEntity>> getOrganizationMembers( + @PathVariable long id) { List members = organizationService.getOrganizationMembers(id); return ResponseEntity.ok(ResultResponse.success(members)); } @PatchMapping("/{id}") - public ResponseEntity> updateOrganizationName(@PathVariable long id, + public ResponseEntity> updateOrganizationName( + @PathVariable long id, @RequestBody UpdateOrganizationRequest updateOrganizationRequest) { UpdateOrganizationResponse updateOrganizationResponse = organizationService.updateOrganizationName( id, updateOrganizationRequest); @@ -69,13 +72,14 @@ public ResponseEntity> updateOrganizationName(@PathVariable lo } @GetMapping("/{id}/rank") - public ResponseEntity> getRanking(@PathVariable long id) { + public ResponseEntity>> getRanking(@PathVariable long id) { List memberRankPoints = organizationService.getRanking(id); return ResponseEntity.ok(ResultResponse.success(memberRankPoints)); } @GetMapping("/{id}/summary") - public ResponseEntity> getSummary(@PathVariable long id) { + public ResponseEntity> getSummary( + @PathVariable long id) { OrganizationSummaryResponse summaryResponse = organizationService.getSummary(id); return ResponseEntity.ok(ResultResponse.success(summaryResponse)); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationControllerDocs.java index a49b3f15..76595537 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/OrganizationControllerDocs.java @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -33,7 +34,7 @@ public interface OrganizationControllerDocs { content = @Content(schema = @Schema(implementation = Long.class))) }) @PostMapping - ResponseEntity> createOrganization( + ResponseEntity> createOrganization( @RequestBody OrganizationRequest organizationRequest ); @@ -44,7 +45,7 @@ ResponseEntity> createOrganization( content = @Content(schema = @Schema(implementation = OrganizationResponse.class))) }) @GetMapping - ResponseEntity> getOrganizations( + ResponseEntity>> getOrganizations( ); @Operation(summary = "학급 가입코드 생성", @@ -56,7 +57,7 @@ ResponseEntity> getOrganizations( @ApiResponse(responseCode = "404", description = "(message : \"멤버가 존재하지 않습니다.\")", content = @Content) }) @GetMapping("/{id}/code") - ResponseEntity> getOrganizationCode( + ResponseEntity> getOrganizationCode( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id @@ -81,7 +82,7 @@ ResponseEntity> getOrganizationCode( """, content = @Content) }) @PostMapping("/{id}/join") - ResponseEntity> joinOrganization( + ResponseEntity> joinOrganization( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -96,7 +97,7 @@ ResponseEntity> joinOrganization( @ApiResponse(responseCode = "404", description = "(message : \"학급을 찾을 수 없습니다.\")", content = @Content) }) @GetMapping("/{id}/members") - ResponseEntity> getOrganizationMembers( + ResponseEntity>> getOrganizationMembers( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id @@ -110,7 +111,7 @@ ResponseEntity> getOrganizationMembers( @ApiResponse(responseCode = "404", description = "(message : \"멤버가 존재하지 않습니다.\")", content = @Content) }) @PatchMapping("/{id}") - ResponseEntity> updateOrganizationName( + ResponseEntity> updateOrganizationName( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id, @@ -124,7 +125,7 @@ ResponseEntity> updateOrganizationName( content = @Content(schema = @Schema(implementation = MemberRankPoint.class))) }) @GetMapping("/{id}/rank") - ResponseEntity> getRanking( + ResponseEntity>> getRanking( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id @@ -136,7 +137,7 @@ ResponseEntity> getRanking( content = @Content(schema = @Schema(implementation = OrganizationSummaryResponse.class))) }) @GetMapping("/{id}/summary") - ResponseEntity> getSummary( + ResponseEntity> getSummary( @PathVariable @Parameter(description = "학급 ID", required = true, in = ParameterIn.PATH) long id diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java index 05c0d526..a2e85ea4 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java @@ -28,25 +28,27 @@ public class RelayController implements RelayControllerDocs { private final RelayService relayService; @PostMapping - public ResponseEntity> createRelay(@RequestBody RelayRequest relayRequest) { + public ResponseEntity> createRelay( + @RequestBody RelayRequest relayRequest) { long relayId = relayService.createRelay(relayRequest); return ResponseEntity.ok(ResultResponse.success(relayId)); } @GetMapping - public ResponseEntity> getRelays(RelaySliceRequest relaySliceRequest) { + public ResponseEntity> getRelays( + RelaySliceRequest relaySliceRequest) { RelaySliceResponse relays = relayService.getRelays(relaySliceRequest); return ResponseEntity.ok(ResultResponse.success(relays)); } @GetMapping("/{id}") - public ResponseEntity> getRelayDetail(@PathVariable long id) { + public ResponseEntity> getRelayDetail(@PathVariable long id) { RelayResponse relay = relayService.getRelayDetail(id); return ResponseEntity.ok(ResultResponse.success(relay)); } @GetMapping("/running") - public ResponseEntity> getRunningRelay( + public ResponseEntity> getRunningRelay( @RequestParam(required = true) long organizationId) { RunningRelayResponse runningChallengeResponse = relayService.getRunningRelay( organizationId); @@ -54,7 +56,7 @@ public ResponseEntity> getRunningRelay( } @PostMapping("/{id}/receive") - public ResponseEntity> receiveRelay(@PathVariable long id, + public ResponseEntity> receiveRelay(@PathVariable long id, @RequestBody ReceiveRelayRequest receiveRelayRequest) { ReceiveRelayResponse receiveRelayResponse = relayService.receiveRelay( id, receiveRelayRequest); @@ -62,13 +64,13 @@ public ResponseEntity> receiveRelay(@PathVariable long id, } @PostMapping("/{id}/send") - public ResponseEntity> sendRelay(@PathVariable long id) { + public ResponseEntity> sendRelay(@PathVariable long id) { SendRelayResponse sendRelayResponse = relayService.sendRelay(id); return ResponseEntity.ok(ResultResponse.success(sendRelayResponse)); } @GetMapping("/{id}/question") - public ResponseEntity> getRelayQuestion(@PathVariable long id) { + public ResponseEntity> getRelayQuestion(@PathVariable long id) { String question = relayService.getRelayQuestion(id); return ResponseEntity.ok(ResultResponse.success(question)); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java index 246827c6..50377950 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java @@ -5,6 +5,7 @@ import com.quiz.ourclass.domain.relay.dto.request.RelaySliceRequest; import com.quiz.ourclass.domain.relay.dto.response.ReceiveRelayResponse; import com.quiz.ourclass.domain.relay.dto.response.RelayResponse; +import com.quiz.ourclass.domain.relay.dto.response.RelaySliceResponse; import com.quiz.ourclass.domain.relay.dto.response.RunningRelayResponse; import com.quiz.ourclass.domain.relay.dto.response.SendRelayResponse; import com.quiz.ourclass.global.dto.ResultResponse; @@ -38,7 +39,7 @@ public interface RelayControllerDocs { """, content = @Content) }) @PostMapping - ResponseEntity> createRelay( + ResponseEntity> createRelay( @RequestBody RelayRequest relayRequest ); @@ -50,7 +51,7 @@ ResponseEntity> createRelay( content = @Content(schema = @Schema(implementation = RelaySliceRequest.class))) }) @GetMapping - ResponseEntity> getRelays(RelaySliceRequest relaySliceRequest + ResponseEntity> getRelays(RelaySliceRequest relaySliceRequest ); @Operation(summary = "이어달리기 상세 조회", @@ -60,7 +61,7 @@ ResponseEntity> getRelays(RelaySliceRequest relaySliceRequest content = @Content(schema = @Schema(implementation = RelayResponse.class))) }) @GetMapping("/{id}") - ResponseEntity> getRelayDetail( + ResponseEntity> getRelayDetail( @PathVariable @Parameter(description = "이어달리기 id", required = true, in = ParameterIn.PATH) long id @@ -78,7 +79,7 @@ ResponseEntity> getRelayDetail( """, content = @Content) }) @GetMapping("/running") - ResponseEntity> getRunningRelay( + ResponseEntity> getRunningRelay( @RequestParam(required = true) @Parameter(description = "학급 id", required = true, in = ParameterIn.QUERY) long organizationId @@ -95,7 +96,7 @@ ResponseEntity> getRunningRelay( """, content = @Content) }) @PostMapping("/{id}/receive") - ResponseEntity> receiveRelay( + ResponseEntity> receiveRelay( @PathVariable @Parameter(description = "이어달리기 id", required = true, in = ParameterIn.PATH) long id, @@ -116,7 +117,7 @@ ResponseEntity> receiveRelay( """, content = @Content) }) @PostMapping("/{id}/send") - ResponseEntity> sendRelay( + ResponseEntity> sendRelay( @PathVariable @Parameter(description = "이어달리기 id", required = true, in = ParameterIn.PATH) long id @@ -135,7 +136,7 @@ ResponseEntity> sendRelay( """, content = @Content) }) @GetMapping("/{id}/question") - ResponseEntity> getRelayQuestion( + ResponseEntity> getRelayQuestion( @PathVariable long id ); From 9b3aef1de3a5fdf87def3ed02b52ab55a1709176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:26:04 +0900 Subject: [PATCH 22/59] =?UTF-8?q?refactor=20#386:=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/challenge/mapper/ChallengeMapper.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/mapper/ChallengeMapper.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/mapper/ChallengeMapper.java index 336193cd..f316d90a 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/mapper/ChallengeMapper.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/mapper/ChallengeMapper.java @@ -25,7 +25,6 @@ public interface ChallengeMapper { @Mapping(target = "createTime", source = "challengeGroup.createTime") @Mapping(target = "endStatus", source = "challengeGroup.completeStatus") @Mapping(target = "memberNames", source = "challengeGroup.groupMembers") -//, qualifiedByName = "MemberToString") RunningMemberChallengeResponse groupToRunningMember(ChallengeSimpleDTO challengeSimpleDTO, ChallengeGroup challengeGroup, boolean leaderStatus); @@ -33,13 +32,4 @@ RunningMemberChallengeResponse groupToRunningMember(ChallengeSimpleDTO challenge @Mapping(target = "name", source = "member.name") @Mapping(target = "photo", source = "member.profileImage") MemberSimpleDTO groupMemberToMemberSimpleDTO(GroupMember groupMember); - -// @Named("MemberToString") -// static List memberToString(List groupMembers) { -// return groupMembers.stream() -// .map(groupMember -> { -// MemberSimpleDTO -// }) -// .collect(Collectors.toList()); -// } } From c489846fcbcc2103c867baa89bafba9f25a55858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:30:20 +0900 Subject: [PATCH 23/59] =?UTF-8?q?refactor=20#386:=20=EC=83=81=EC=88=98?= =?UTF-8?q?=EB=93=A4=20=EC=83=81=EC=88=98=EC=9C=A0=ED=8B=B8=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/challenge/service/GroupServiceImpl.java | 4 ++-- .../ourclass/domain/notice/service/SseServiceImpl.java | 8 ++++---- .../java/com/quiz/ourclass/global/util/ConstantUtil.java | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 8e6b5ea3..7789bc72 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -26,6 +26,7 @@ import com.quiz.ourclass.global.dto.MemberSimpleDTO; import com.quiz.ourclass.global.exception.ErrorCode; import com.quiz.ourclass.global.exception.GlobalException; +import com.quiz.ourclass.global.util.ConstantUtil; import com.quiz.ourclass.global.util.RedisUtil; import com.quiz.ourclass.global.util.UserAccessUtil; import java.time.LocalDateTime; @@ -56,7 +57,6 @@ public class GroupServiceImpl implements GroupService { private final RedisUtil redisUtil; private final MemberMapper memberMapper; private final FriendlyGroup friendlyGroup; - private final static String REDIS_GROUP_KEY = "CHALLENGE_LEADER:"; @Transactional @Override @@ -313,7 +313,7 @@ private List getUnfriendlyGroup( } private static String makeGroupKey(long challengeId, long MemberId) { - return REDIS_GROUP_KEY + challengeId + "_" + MemberId; + return ConstantUtil.REDIS_GROUP_KEY + challengeId + "_" + MemberId; } private static long getChallengeIdFromKey(String key) { diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java index e928dc84..d4280b5a 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java @@ -5,6 +5,7 @@ import com.quiz.ourclass.domain.notice.repository.SseRepository; import com.quiz.ourclass.global.exception.ErrorCode; import com.quiz.ourclass.global.exception.GlobalException; +import com.quiz.ourclass.global.util.ConstantUtil; import com.quiz.ourclass.global.util.UserAccessUtil; import java.io.IOException; import java.time.LocalDateTime; @@ -19,8 +20,6 @@ @Service public class SseServiceImpl implements SseService { - private static final Long DEFAULT_TIMEOUT = 60L * 1000 * 20; - private static final Long REDIRECT_TIME = 5L * 1000; private final SseRepository sseRepository; private final UserAccessUtil accessUtil; @@ -29,7 +28,8 @@ public SseEmitter subscribe(String lastEventId) { long loginUserId = accessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)).getId(); String emitterId = makeTimeIncludeId(String.valueOf(loginUserId)); - SseEmitter emitter = sseRepository.save(emitterId, new SseEmitter(DEFAULT_TIMEOUT)); + SseEmitter emitter = sseRepository.save(emitterId, + new SseEmitter(ConstantUtil.DEFAULT_TIMEOUT)); // emitter의 상태를 체크함, 완료되었는지 타임아웃이 났는지 checkEmitterStatus(emitter, emitterId); @@ -75,7 +75,7 @@ private void sendSse(SseEmitter emitter, String eventId, String emitterId, SseDT try { emitter.send(SseEmitter.event() .id(eventId) - .reconnectTime(REDIRECT_TIME) + .reconnectTime(ConstantUtil.REDIRECT_TIME) .name(dto.eventType().toString()) .data(dto)); } catch (IOException exception) { diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index 87f4a5a1..3403d53d 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -18,6 +18,9 @@ public abstract class ConstantUtil { public static final String RANKING = "ranking"; public static final String QUIZ_ANSWER = "answer"; public static final String AUTHORIZATION = "Authorization"; + public static final String REDIS_GROUP_KEY = "CHALLENGE_LEADER:"; + public static final Long DEFAULT_TIMEOUT = 60L * 1000 * 20; + public static final Long REDIRECT_TIME = 5L * 1000; // 인스턴스화 방지 private ConstantUtil() { From 0b4b0bb747a700e4148dba4a11690a832c1a8146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:31:18 +0900 Subject: [PATCH 24/59] =?UTF-8?q?refactor=20#386:=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EC=A4=80=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/GroupServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 7789bc72..89030988 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -61,14 +61,14 @@ public class GroupServiceImpl implements GroupService { @Transactional @Override public MatchingRoomResponse createMatchingRoom(long challengeId) { - long MemberId = accessUtil.getMember() + long memberId = accessUtil.getMember() .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)).getId(); - String dataKey = makeGroupKey(challengeId, MemberId); + String dataKey = makeGroupKey(challengeId, memberId); Set redisMembers = redisUtil.setMembers(dataKey); if (redisMembers != null && !redisMembers.isEmpty()) { redisUtil.delete(dataKey); } - redisUtil.setAdd(dataKey, String.valueOf(MemberId)); + redisUtil.setAdd(dataKey, String.valueOf(memberId)); Challenge challenge = challengeRepository.findById(challengeId) .orElseThrow(() -> new GlobalException(CHALLENGE_NOT_FOUND)); int minCount = challenge.getMinCount(); From 81a6efc6f2c7acebf8658fb472b4c8f423bf3af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:32:57 +0900 Subject: [PATCH 25/59] =?UTF-8?q?refactor=20#386:=20=EB=B9=88=20list=20?= =?UTF-8?q?=EB=A6=AC=ED=84=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/GroupServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 89030988..1124d749 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -209,7 +209,7 @@ public List getGroupMatching( return getUnfriendlyGroup(autoGroupMatchingRequest); } } - return null; + return new ArrayList<>(); } // TODO : 테스트 끝나고 해당 코드 지우기 From a7193c6a234109a1d8ffffd8a16c1cacb5562516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:34:15 +0900 Subject: [PATCH 26/59] =?UTF-8?q?refactor=20#386:=20=EB=B6=88=EB=B3=80?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20toList()=EB=A1=9C=20=EB=A7=8C=EB=93=A4?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/GroupServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 1124d749..8363dbe2 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -248,7 +248,7 @@ public List testMethod( .filter(Optional::isPresent) .map(Optional::get) .map(memberMapper::memberToMemberSimpleDTO) - .collect(Collectors.toList()); + .toList(); groups.add(testGroup); return groups.stream().map(group -> AutoGroupMatchingResponse.builder() .members(group) From 4b26636347cc1ac1469d7426e31b293b7d202c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:36:19 +0900 Subject: [PATCH 27/59] =?UTF-8?q?refactor=20#386:=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EC=A4=80=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/GroupServiceImpl.java | 4 ++-- .../com/quiz/ourclass/domain/notice/service/SseService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 8363dbe2..5e5fda87 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -312,8 +312,8 @@ private List getUnfriendlyGroup( return null; } - private static String makeGroupKey(long challengeId, long MemberId) { - return ConstantUtil.REDIS_GROUP_KEY + challengeId + "_" + MemberId; + private static String makeGroupKey(long challengeId, long memberId) { + return ConstantUtil.REDIS_GROUP_KEY + challengeId + "_" + memberId; } private static long getChallengeIdFromKey(String key) { diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseService.java index 9648a812..4b08b991 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseService.java @@ -7,5 +7,5 @@ public interface SseService { SseEmitter subscribe(String lastEventId); - void send(SseDTO SseDto); + void send(SseDTO sseDto); } From 8c31ca73a341c0260f6295e17030e08869961f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:37:20 +0900 Subject: [PATCH 28/59] =?UTF-8?q?refactor=20#386:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=9A=A9=20=EB=A1=9C=EA=B7=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/ourclass/domain/notice/service/SseServiceImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java index d4280b5a..b2334ed1 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java @@ -47,7 +47,6 @@ public SseEmitter subscribe(String lastEventId) { if (lastEventId != null && !lastEventId.isEmpty()) { sendLostData(lastEventId, String.valueOf(loginUserId), emitterId, emitter); } - log.info("SSE연결 요청 : 유저 " + loginUserId + ", 에미터 " + emitterId); return emitter; } @@ -91,15 +90,12 @@ private String makeTimeIncludeId(String userId) { //종료 상태 private void checkEmitterStatus(SseEmitter emitter, String emitterId) { emitter.onCompletion(() -> { - log.info("SSE연결 해제 : 에미터 " + emitter.toString() + ", 에미터 " + emitterId); sseRepository.deleteById(emitterId); }); emitter.onTimeout(() -> { - log.info("SSE연결 타임아웃 : 에미터 " + emitter.toString() + ", 에미터 " + emitterId); sseRepository.deleteById(emitterId); }); emitter.onError((e) -> { - log.info("SSE연결 에러 : 에미터 " + emitter.toString() + ", 에미터 " + emitterId); sseRepository.deleteById(emitterId); }); } From 81a7e3e4a6e38c2854f54a654ea3ddc5bec91cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:38:10 +0900 Subject: [PATCH 29/59] =?UTF-8?q?refactor=20#386:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B4=84=ED=98=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/domain/notice/service/SseServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java index b2334ed1..b9e79f08 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java @@ -95,7 +95,7 @@ private void checkEmitterStatus(SseEmitter emitter, String emitterId) { emitter.onTimeout(() -> { sseRepository.deleteById(emitterId); }); - emitter.onError((e) -> { + emitter.onError(e -> { sseRepository.deleteById(emitterId); }); } From c7235e5d106b9a19a06416537f2c5d8e8bb65a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:38:56 +0900 Subject: [PATCH 30/59] =?UTF-8?q?refactor=20#386:=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=9D=B8=EB=9D=BC=EC=9D=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/organization/service/MemberOrgServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/MemberOrgServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/MemberOrgServiceImpl.java index eddf7d2d..1a27bd83 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/MemberOrgServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/service/MemberOrgServiceImpl.java @@ -142,8 +142,7 @@ public int tagGreeting(TagGreetingRequest tagGreetingRequest) { TagGreeting tagGreeting = TagGreeting.builder() .relationship(relationship).date(LocalDateTime.now()).build(); tagGreetingRepository.save(tagGreeting); - int tagGreetingCount = relationship.updateTagGreetingCount(); - return tagGreetingCount; + return relationship.updateTagGreetingCount(); } private List getFriendlyResponse(long organizationId, long memberId, From 7234159776780a216d4fce491a1e556cb2b62202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:40:47 +0900 Subject: [PATCH 31/59] =?UTF-8?q?refactor=20#386:=20exist=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=9B=90=EC=8B=9C=ED=83=80=EC=9E=85=20boolean=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/ourclass/domain/relay/repository/RelayRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepository.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepository.java index 332fe481..cb816d09 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepository.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/repository/RelayRepository.java @@ -8,7 +8,7 @@ public interface RelayRepository extends JpaRepository, RelayRepositoryQuerydsl { - Boolean existsByOrganizationAndEndStatusIsFalse(Organization organization); + boolean existsByOrganizationAndEndStatusIsFalse(Organization organization); Optional findByOrganizationIdAndEndStatusIsFalse(long organizationId); From f5af4bce895b5a0b013e674245d14984bb890db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:42:33 +0900 Subject: [PATCH 32/59] =?UTF-8?q?refactor=20#386:=20Math.random=EB=8C=80?= =?UTF-8?q?=EC=8B=A0=20=EB=9E=9C=EB=8D=A4=EA=B0=9D=EC=B2=B4=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/ourclass/domain/relay/service/RelayServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java index 64b71c23..e4b4cbb7 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java @@ -24,8 +24,10 @@ import com.quiz.ourclass.global.util.FcmUtil; import com.quiz.ourclass.global.util.UserAccessUtil; import com.quiz.ourclass.global.util.scheduler.SchedulingService; +import java.security.SecureRandom; import java.time.LocalDateTime; import java.util.List; +import java.util.Random; import lombok.RequiredArgsConstructor; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; @@ -44,6 +46,7 @@ public class RelayServiceImpl implements RelayService { private final UserAccessUtil accessUtil; private final SchedulingService schedulingService; private final FcmUtil fcmUtil; + private final Random random = new SecureRandom(); @Transactional @@ -54,7 +57,7 @@ public long createRelay(RelayRequest relayRequest) { Organization organization = organizationRepository.findById(relayRequest.organizationId()) .orElseThrow(() -> new GlobalException(ErrorCode.ORGANIZATION_NOT_FOUND)); int randomCount = organization.getMemberCount() / 2; - int totalCount = (int) (Math.random() * (randomCount + 1) + randomCount); + int totalCount = (int) (random.nextInt() * (randomCount + 1) + randomCount); if (relayRepository.existsByOrganizationAndEndStatusIsFalse(organization)) { throw new GlobalException(ErrorCode.EXIST_PROGRESS_RELAY); } From dc81663b0b73521e30eadb93af4015f3ff7e01f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:43:54 +0900 Subject: [PATCH 33/59] =?UTF-8?q?refactor=20#386:=20=EB=9E=8C=EB=8B=A4=20?= =?UTF-8?q?=ED=91=9C=ED=98=84=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notice/service/SseServiceImpl.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java index b9e79f08..c7c58bc4 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/notice/service/SseServiceImpl.java @@ -89,15 +89,9 @@ private String makeTimeIncludeId(String userId) { //종료 상태 private void checkEmitterStatus(SseEmitter emitter, String emitterId) { - emitter.onCompletion(() -> { - sseRepository.deleteById(emitterId); - }); - emitter.onTimeout(() -> { - sseRepository.deleteById(emitterId); - }); - emitter.onError(e -> { - sseRepository.deleteById(emitterId); - }); + emitter.onCompletion(() -> sseRepository.deleteById(emitterId)); + emitter.onTimeout(() -> sseRepository.deleteById(emitterId)); + emitter.onError(e -> sseRepository.deleteById(emitterId)); } private void sendLostData(String lastEventId, String userId, String emitterId, From ab25a5f58f3b0f1259c0eff4dc3c840477921e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:44:19 +0900 Subject: [PATCH 34/59] =?UTF-8?q?refactor=20#386:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=98=95=EB=B3=80=ED=99=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/ourclass/domain/relay/service/RelayServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java index e4b4cbb7..e59a7992 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/service/RelayServiceImpl.java @@ -57,7 +57,7 @@ public long createRelay(RelayRequest relayRequest) { Organization organization = organizationRepository.findById(relayRequest.organizationId()) .orElseThrow(() -> new GlobalException(ErrorCode.ORGANIZATION_NOT_FOUND)); int randomCount = organization.getMemberCount() / 2; - int totalCount = (int) (random.nextInt() * (randomCount + 1) + randomCount); + int totalCount = random.nextInt() * (randomCount + 1) + randomCount; if (relayRepository.existsByOrganizationAndEndStatusIsFalse(organization)) { throw new GlobalException(ErrorCode.EXIST_PROGRESS_RELAY); } From e8f471b671ab77289e213f5f6930890f7a027a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:44:50 +0900 Subject: [PATCH 35/59] =?UTF-8?q?refactor=20#386:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=EC=95=8A=EB=8A=94=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/challenge/service/GroupServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 5e5fda87..526f7d71 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -21,7 +21,6 @@ import com.quiz.ourclass.domain.notice.service.SseService; import com.quiz.ourclass.domain.organization.entity.Relationship; import com.quiz.ourclass.domain.organization.repository.MemberOrganizationRepository; -import com.quiz.ourclass.domain.organization.repository.OrganizationRepository; import com.quiz.ourclass.domain.organization.repository.RelationshipRepository; import com.quiz.ourclass.global.dto.MemberSimpleDTO; import com.quiz.ourclass.global.exception.ErrorCode; @@ -51,7 +50,6 @@ public class GroupServiceImpl implements GroupService { private final MemberRepository memberRepository; private final ChallengeRepository challengeRepository; private final RelationshipRepository relationshipRepository; - private final OrganizationRepository organizationRepository; private final MemberOrganizationRepository memberOrganizationRepository; private final UserAccessUtil accessUtil; private final RedisUtil redisUtil; From 709c0dda84daca89d9cda80f89e2d0249ff2e9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=84=B1=EC=9B=90?= Date: Sun, 26 May 2024 17:45:52 +0900 Subject: [PATCH 36/59] =?UTF-8?q?refactor=20#386:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/controller/ChallengeController.java | 4 ++-- .../controller/ChallengeControllerDocs.java | 12 ++++++------ .../controller/MemberOrgControllerDocs.java | 2 +- .../domain/relay/controller/RelayController.java | 2 +- .../domain/relay/controller/RelayControllerDocs.java | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java index bc1fea00..5fe1589d 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeController.java @@ -63,7 +63,7 @@ public ResponseEntity> confirmReport(@PathVariable long @GetMapping("/running") public ResponseEntity> getRunningChallenge( - @RequestParam(required = true) long organizationId) { + @RequestParam long organizationId) { RunningChallengeResponse runningChallengeResponse = challengeService.getRunningChallenge( organizationId); return ResponseEntity.ok(ResultResponse.success(runningChallengeResponse)); @@ -71,7 +71,7 @@ public ResponseEntity> getRunningChalle @GetMapping("/running/member") public ResponseEntity> getRunningMemberChallenge( - @RequestParam(required = true) long organizationId) { + @RequestParam long organizationId) { RunningMemberChallengeResponse runningMemberChallenge = challengeService.getRunningMemberChallenge( organizationId); return ResponseEntity.ok(ResultResponse.success(runningMemberChallenge)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java index 4988f3a6..77e398b2 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/ChallengeControllerDocs.java @@ -51,7 +51,7 @@ ResponseEntity> getChallenges( @ApiResponse(responseCode = "404", description = "(message : \"학급을 찾을 수 없습니다.\")", content = @Content) }) @PostMapping - public ResponseEntity> createChallenge( + ResponseEntity> createChallenge( @RequestBody ChallengeRequest challengeRequest ); @@ -102,8 +102,8 @@ ResponseEntity> confirmReport( """, content = @Content) }) @GetMapping("/running") - public ResponseEntity> getRunningChallenge( - @RequestParam(required = true) + ResponseEntity> getRunningChallenge( + @RequestParam @Parameter(description = "학급 ID", required = true, in = ParameterIn.QUERY) long organizationId ); @@ -126,7 +126,7 @@ public ResponseEntity> getRunningChalle }) @GetMapping("/running/member") ResponseEntity> getRunningMemberChallenge( - @RequestParam(required = true) + @RequestParam @Parameter(description = "학급 ID", required = true, in = ParameterIn.QUERY) long organizationId ); @@ -139,12 +139,12 @@ ResponseEntity> getRunningMemberC content = @Content(schema = @Schema(implementation = ChallengeResponse.class))) }) @GetMapping("/{id}") - public ResponseEntity> getChallengeDetail( + ResponseEntity> getChallengeDetail( @PathVariable @Parameter(description = "함께달리기 ID", required = true, in = ParameterIn.PATH) long id, @RequestParam(required = false) - @Parameter(description = "그룹 ID", required = false, in = ParameterIn.QUERY) + @Parameter(description = "그룹 ID", in = ParameterIn.QUERY) Long groupId); @Operation(summary = "함께달리기 요약 조회", diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java index e36d5467..6f053f03 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/organization/controller/MemberOrgControllerDocs.java @@ -87,7 +87,7 @@ ResponseEntity>> getMemberRelations( @Parameter(description = "멤버 ID", required = true, in = ParameterIn.QUERY) long memberId, @RequestParam(required = false) - @Parameter(description = "상위 n개만 조회 시 추가", required = false, in = ParameterIn.QUERY) + @Parameter(description = "상위 n개만 조회 시 추가", in = ParameterIn.QUERY) Long limit ); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java index a2e85ea4..8b5e4dc3 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayController.java @@ -49,7 +49,7 @@ public ResponseEntity> getRelayDetail(@PathVariabl @GetMapping("/running") public ResponseEntity> getRunningRelay( - @RequestParam(required = true) long organizationId) { + @RequestParam long organizationId) { RunningRelayResponse runningChallengeResponse = relayService.getRunningRelay( organizationId); return ResponseEntity.ok(ResultResponse.success(runningChallengeResponse)); diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java index 50377950..289784ec 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/relay/controller/RelayControllerDocs.java @@ -80,7 +80,7 @@ ResponseEntity> getRelayDetail( }) @GetMapping("/running") ResponseEntity> getRunningRelay( - @RequestParam(required = true) + @RequestParam @Parameter(description = "학급 id", required = true, in = ParameterIn.QUERY) long organizationId ); From d61f4ea4207686e5b5c219bf505f86eac258559e Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:18:18 +0900 Subject: [PATCH 37/59] =?UTF-8?q?refactoring:=20KafkaUtil=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=EC=93=B0=EB=A0=88=EB=93=9C=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=EB=9F=BD=ED=8A=B8=20=EC=98=88=EC=99=B8=20=EC=BA=90=EC=B9=98?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=B4,=20=EC=9D=B8=ED=84=B0=EB=9F=BD?= =?UTF-8?q?=ED=8A=B8=20=EC=A0=95=EB=B3=B4=EA=B0=80=20=EC=82=AC=EB=9D=BC?= =?UTF-8?q?=EC=A7=80=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/global/util/KafkaUtil.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java index 8a38ca50..fafdd931 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java @@ -32,7 +32,17 @@ public void getTopicMeta(String topic) { descriptions.forEach((name, description) -> { log.info("Topic: {} \nPartitions: {}", name, description.partitions().size()); }); - } catch (InterruptedException | ExecutionException e) { + // 현재 쓰레드가 인터럽트 되면, 발생하는 예외 + // 인터럽트 되었다 => 다른 쓰레드가 현재 쓰레드에게 작업을 중단하고 가능한 빨리 종료하라는 신호를 보냈다. + // 지금은 InterruptedException 예외를 잡아서 서버 자체 예외만 던지고, 쓰레드 처리에 대한 조치를 하지 않고 있다. + // 이렇게 되면, 쓰레드가 정상 종료되지 않아 문제가 된다. + // 따라서 정상 종료 절차를 수행하고, 원래대로 우리 식의 예외를 수행해야 한다. + } catch (InterruptedException e) { + // InterruptedException 이 발생하면, 현재 쓰레드를 다시 인터럽트 시킨다. + // InterruptedException 으로 인터럽트를 캐치하면, 현재 쓰레드가 인터럽트 되었다는 정보를 잃기 때문이다. + Thread.currentThread().interrupt(); + throw new GlobalException(ErrorCode.CANT_LOAD_KAFKA); + } catch (ExecutionException e) { throw new GlobalException(ErrorCode.CANT_LOAD_KAFKA); } } From 60de9501b2960873d8b6473379a2d0bdb14e1162 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:31:37 +0900 Subject: [PATCH 38/59] =?UTF-8?q?refactoring:=20Parameter=20Checker=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EA=B0=92=20=EC=B2=B4=ED=82=B9=20=EC=8B=9C,?= =?UTF-8?q?=20=EB=B0=98=ED=99=98=EA=B0=92=EC=9D=B4=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/global/config/AopConfig.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java index b3421c78..a353d8c3 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java @@ -58,11 +58,22 @@ public Object logging(ProceedingJoinPoint pjp) throws Throwable { ResponseEntity> result = (ResponseEntity>) pjp.proceed(); // 끝시간 check afterTime = System.currentTimeMillis(); - if (result != null) { + if (result != null && result.getBody() != null) { log.info("-----------> RESPONSE : {}({}) = {} ({}ms)" , pjp.getSignature().getDeclaringTypeName(), pjp.getSignature().getName(), result.getBody().getData(), (afterTime - beforeTime) / 1000.0); + } else if (result != null) { + log.warn("-----------> RESPONSE : {}({}) = BODY 없음 ({}ms)", + pjp.getSignature().getDeclaringTypeName(), + pjp.getSignature().getName(), + (afterTime - beforeTime) / 1000.0); + } else { + // 어떠한 에러로 인해 Pjp 실행이 끝난 후 ResponseEntity 자체가 생성되지 않은 상황을 의미 + log.warn("-----------> RESPONSE : {}({}) = 에러로 인해 결과 반환 안됨. ({}ms)", + pjp.getSignature().getDeclaringTypeName(), + pjp.getSignature().getName(), + (afterTime - beforeTime) / 1000.0); } return result; } From 524950266252084b593b4409c8de3316648eedb8 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:37:07 +0900 Subject: [PATCH 39/59] =?UTF-8?q?refactoring:=20kafkaUtil=20deleteTopic=20?= =?UTF-8?q?=EB=98=90=ED=95=9C=20=EA=B0=99=EC=9D=80=20=EC=9D=B4=EC=9C=A0?= =?UTF-8?q?=EC=97=90=EC=84=9C=20re-Interrupt()=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/quiz/ourclass/global/util/KafkaUtil.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java index fafdd931..583dc216 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/KafkaUtil.java @@ -55,7 +55,11 @@ public void deleteTopic(String topicName) { try { future.get(); log.info("Topic {} 가 성공적으로 삭제 되었습니다.", topicName); - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException e) { + // 마찬가지의 이유로 interrupt 를 한번 더 던진다. + Thread.currentThread().interrupt(); + throw new GlobalException(ErrorCode.CANT_LOAD_KAFKA); + } catch (ExecutionException e) { throw new GlobalException(ErrorCode.CANT_LOAD_KAFKA); } } From 460623d32aa5edd07481a23e8e788d999b884bbe Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:39:45 +0900 Subject: [PATCH 40/59] =?UTF-8?q?refactoring:=20=EB=B3=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=8B=A4=ED=96=89=ED=95=98=EB=8B=A4=EA=B0=80=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EA=B0=80=20=EB=82=AC=EC=9D=84=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0,=20=ED=95=B4=EB=8B=B9=20=EC=97=90=EB=9F=AC=EB=A5=BC?= =?UTF-8?q?=20Parameter=20Checker=20=EA=B0=80=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=ED=9B=84=20=EB=A1=9C=EA=B7=B8=20=EB=9D=84=EC=9A=B8=20=EC=88=98?= =?UTF-8?q?=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/global/config/AopConfig.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java index a353d8c3..58d45f71 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java @@ -54,8 +54,18 @@ public Object logging(ProceedingJoinPoint pjp) throws Throwable { , pjp.getSignature().getDeclaringTypeName() , pjp.getSignature().getName() , logMsg); + // 결과 확인 - ResponseEntity> result = (ResponseEntity>) pjp.proceed(); + ResponseEntity> result = null; + + try { + result = (ResponseEntity>) pjp.proceed(); + } catch (Exception e) { + log.error("다음의 메소드 실행 중 에러가 발생함: {}({})", + pjp.getSignature().getDeclaringTypeName(), + pjp.getSignature().getName(), e); + } + // 끝시간 check afterTime = System.currentTimeMillis(); if (result != null && result.getBody() != null) { From f8509ba8c516b1c9fdff2273849d3b62abe32dcb Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:42:04 +0900 Subject: [PATCH 41/59] =?UTF-8?q?refactoring:=20@Transactional=20=EB=8B=A8?= =?UTF-8?q?=20=EB=A7=A4=EC=86=8C=EB=93=9C=EB=A5=BC=20public=20=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=A0=EC=B9=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @Transactional 은 비공개 메서드에는 사용 불가. Spring은 비공개 매서드에 대해 트랜잭션 관리를 적용하지 않는다. --- .../ourclass/global/util/scheduler/SchedulingService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/scheduler/SchedulingService.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/scheduler/SchedulingService.java index 3748b22c..dc769ae5 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/scheduler/SchedulingService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/scheduler/SchedulingService.java @@ -46,7 +46,7 @@ public void scheduleTask(T target, Consumer action, LocalDateTime executi @Transactional @Scheduled(cron = "0 0 3 * * *") - protected void relationShipScore() { + public void relationShipScore() { List organizations = organizationRepository.findAll(); @@ -64,7 +64,7 @@ protected void relationShipScore() { @Transactional @Scheduled(cron = "0 15 3 * * *") - protected void isolationScore() { + public void isolationScore() { List organizations = organizationRepository.findAll(); for (Organization organization : organizations) { From 3b5a7e28841efe7cf5786cc5638f6eceda87ce20 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 00:59:11 +0900 Subject: [PATCH 42/59] refactoring: deleting MemberController wildCard --- .../member/controller/MemberController.java | 41 +++++++++---------- .../controller/docs/MemberControllerDocs.java | 31 ++++++++++---- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/MemberController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/MemberController.java index 6a0b28b8..0ebbb231 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/MemberController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/MemberController.java @@ -1,15 +1,21 @@ package com.quiz.ourclass.domain.member.controller; import com.quiz.ourclass.domain.member.controller.docs.MemberControllerDocs; +import com.quiz.ourclass.domain.member.dto.TokenDTO; import com.quiz.ourclass.domain.member.dto.request.DefaultImageRequest; import com.quiz.ourclass.domain.member.dto.request.DeveloperAtRtRequest; import com.quiz.ourclass.domain.member.dto.request.MemberSignInRequest; import com.quiz.ourclass.domain.member.dto.request.MemberSignUpRequest; import com.quiz.ourclass.domain.member.dto.request.MemberUpdateRequest; import com.quiz.ourclass.domain.member.dto.request.UpdateFcmTokenRequest; +import com.quiz.ourclass.domain.member.dto.response.DefaultImagesResponse; +import com.quiz.ourclass.domain.member.dto.response.MemberMeResponse; +import com.quiz.ourclass.domain.member.dto.response.MemberUpdateResponse; +import com.quiz.ourclass.domain.member.dto.response.OIDCPublicKeysResponse; import com.quiz.ourclass.domain.member.service.MemberService; import com.quiz.ourclass.domain.member.service.client.KakaoOicdClient; import com.quiz.ourclass.domain.quiz.dto.request.QuizStartRequest; +import com.quiz.ourclass.domain.quiz.dto.response.QuizStartResponse; import com.quiz.ourclass.global.dto.MemberSimpleDTO; import com.quiz.ourclass.global.dto.ResultResponse; import io.swagger.v3.oas.annotations.Parameter; @@ -26,7 +32,6 @@ 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -41,37 +46,31 @@ public class MemberController implements MemberControllerDocs { /* 1. 회원가입 */ @PostMapping(value = "/", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) - public ResponseEntity> signUp(@ModelAttribute MemberSignUpRequest request) { + public ResponseEntity> signUp( + @ModelAttribute MemberSignUpRequest request) { return ResponseEntity.ok(ResultResponse.success(memberService.signUpProcess(request))); } /* 2. 로그인 */ @PostMapping("/sign-in") - public ResponseEntity> signIn(@RequestBody MemberSignInRequest request) { + public ResponseEntity> signIn( + @RequestBody MemberSignInRequest request) { return ResponseEntity.ok(ResultResponse.success(memberService.signInProcess(request))); } /* 4. 테스트용 */ @GetMapping("/kakao-keys") - public ResponseEntity> getKakaoKeys() { + public ResponseEntity> getKakaoKeys() { return ResponseEntity.ok(ResultResponse.success(kakaoOicdClient.getKakaoOIDCOpenKeys())); } - /* 5. id-Token 받아서 Decoding 하기 */ - @PostMapping("/decode-id-token") - public ResponseEntity> decodeIdToken(@RequestParam String idToken) { - log.info(idToken); -// return ResponseEntity.ok(ResultResponse.success(oicdUtil.getUnsignedTokenClaims(idToken,"https://kauth.kakao.com", "edbf10bd8627e6eb676872109e996a9e"))); - return null; - } - - /* 6 개발자용 Access, RefreshToken 발급 */ @PostMapping("/developer-At") - public ResponseEntity> getAtRt(@RequestBody DeveloperAtRtRequest request) { + public ResponseEntity> getAtRt( + @RequestBody DeveloperAtRtRequest request) { return ResponseEntity.ok( ResultResponse.success(memberService.giveDeveloperAccessToken(request))); @@ -88,7 +87,7 @@ public ResponseEntity> saveFcmToken( /* 8. 기본 이미지 업데이트 */ @PatchMapping("/default-image") - public ResponseEntity> updateDefaultImage( + public ResponseEntity> updateDefaultImage( @ModelAttribute DefaultImageRequest request) { return ResponseEntity.ok( ResultResponse.success(memberService.updateDefaultImage(request).getPhoto())); @@ -97,13 +96,13 @@ public ResponseEntity> updateDefaultImage( /* 8. 기본 이미지 조회 */ @GetMapping("/default-image") - public ResponseEntity> getDefaultImages() { + public ResponseEntity> getDefaultImages() { return ResponseEntity.ok(ResultResponse.success(memberService.getDefaultImages())); } /* 9. 현 유저의 회원 정보 주기 */ @GetMapping("/") - public ResponseEntity> rememberMe() { + public ResponseEntity> rememberMe() { return ResponseEntity.ok( ResultResponse.success(memberService.rememberMe())); @@ -111,25 +110,25 @@ public ResponseEntity> rememberMe() { /* 10. 멤버 프로필 이미지 수정 */ @PatchMapping("/photo") - public ResponseEntity> updateProfile( + public ResponseEntity> updateProfile( @ModelAttribute MemberUpdateRequest request) { return ResponseEntity.ok(ResultResponse.success(memberService.updateProfile(request))); } @PostMapping("/start") - public ResponseEntity> certificatingUser( + public ResponseEntity> certificatingUser( @RequestBody QuizStartRequest request) { return ResponseEntity.ok(ResultResponse.success(memberService.certificatingUser(request))); } @DeleteMapping("/") - public ResponseEntity> deleteMe() { + public ResponseEntity> deleteMe() { memberService.deleteMe(); return ResponseEntity.ok(ResultResponse.success(null)); } @GetMapping("/{id}") - public ResponseEntity> select( + public ResponseEntity> select( @Parameter(name = "id", description = "멤버 PK 값", required = true, in = ParameterIn.PATH) @PathVariable(value = "id") Long id ) { diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/docs/MemberControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/docs/MemberControllerDocs.java index 057cec09..81a2115c 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/docs/MemberControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/member/controller/docs/MemberControllerDocs.java @@ -1,12 +1,16 @@ package com.quiz.ourclass.domain.member.controller.docs; +import com.quiz.ourclass.domain.member.dto.TokenDTO; import com.quiz.ourclass.domain.member.dto.request.DefaultImageRequest; import com.quiz.ourclass.domain.member.dto.request.MemberSignInRequest; import com.quiz.ourclass.domain.member.dto.request.MemberSignUpRequest; import com.quiz.ourclass.domain.member.dto.request.MemberUpdateRequest; import com.quiz.ourclass.domain.member.dto.request.UpdateFcmTokenRequest; +import com.quiz.ourclass.domain.member.dto.response.DefaultImagesResponse; +import com.quiz.ourclass.domain.member.dto.response.MemberMeResponse; import com.quiz.ourclass.domain.member.dto.response.MemberUpdateResponse; import com.quiz.ourclass.domain.quiz.dto.request.QuizStartRequest; +import com.quiz.ourclass.domain.quiz.dto.response.QuizStartResponse; import com.quiz.ourclass.global.dto.MemberSimpleDTO; import com.quiz.ourclass.global.dto.ResultResponse; import io.swagger.v3.oas.annotations.Operation; @@ -40,7 +44,7 @@ public interface MemberControllerDocs { description = "OIDC 토큰 인증에 실패했습니다.") }) @PostMapping - ResponseEntity> signUp(MemberSignUpRequest request); + ResponseEntity> signUp(MemberSignUpRequest request); @Operation(summary = "로그인", @@ -55,7 +59,7 @@ public interface MemberControllerDocs { description = "OIDC 토큰 인증에 실패했습니다.") }) @PostMapping - ResponseEntity> signIn(MemberSignInRequest request); + ResponseEntity> signIn(MemberSignInRequest request); @Operation(summary = "FCM 토큰 저장 및 갱신", description = "입력으로 들어오는 FCM 토큰을 저장 및 갱신 합니다.", @@ -74,8 +78,17 @@ ResponseEntity> saveFcmToken( description = "기본 이미지 조회에 성공하였습니다." ) }) + @GetMapping("/default-image") + public ResponseEntity> getDefaultImages(); + + @Operation(summary = "기본 이미지 정보 수정", + responses = { + @ApiResponse(responseCode = "200", + description = "기본 이미지 수정에 성공하였습니다." + ) + }) @PatchMapping("/default-image") - public ResponseEntity> updateDefaultImage( + public ResponseEntity> updateDefaultImage( @ModelAttribute DefaultImageRequest request); @Operation(summary = "현 유저의 회원정보 가져오기", @@ -84,7 +97,7 @@ public ResponseEntity> updateDefaultImage( description = "유저 정보 확인에 성공하였습니다.") }) @GetMapping("/") - public ResponseEntity> rememberMe(); + public ResponseEntity> rememberMe(); @Operation(summary = "프로필 이미지 수정", responses = { @@ -94,7 +107,8 @@ public ResponseEntity> updateDefaultImage( ) @PatchMapping("/photo") - public ResponseEntity> updateProfile(MemberUpdateRequest request); + public ResponseEntity> updateProfile( + MemberUpdateRequest request); @Operation(summary = "멤버 조회", description = "ID 값에 해당하는 멤버 Simple 정보(id, name, iamgeUrl)를 조회합니다.", responses = { @@ -104,14 +118,15 @@ public ResponseEntity> updateDefaultImage( } ) @GetMapping("{id}") - ResponseEntity> select( + ResponseEntity> select( @PathVariable(value = "id") Long id ); @PostMapping("/start") - public ResponseEntity> certificatingUser(QuizStartRequest request); + public ResponseEntity> certificatingUser( + QuizStartRequest request); @DeleteMapping("/") - public ResponseEntity> deleteMe(); + public ResponseEntity> deleteMe(); } From c2c67d663f69cb91cdaa6425f2c40485f2ad0457 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 01:00:37 +0900 Subject: [PATCH 43/59] =?UTF-8?q?refactoring:=20AOP=20Config=20controller?= =?UTF-8?q?=20Method=20=EA=B0=80=EB=8F=85=EC=84=B1=20=EB=A7=9E=EC=B6=94?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/quiz/ourclass/global/config/AopConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java index 58d45f71..6f671930 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java @@ -29,7 +29,7 @@ public class AopConfig { private double afterTime = 0L; @Pointcut("execution(* com..controller..*(..))") - public void ControllerMethod() { + public void controllerMethod() { } // 컨트롤러 내의 모든 매소드에 대하여 Logging을 실행한다. 다만 어노테이션이 붙은 매소드는 실행하지 않는다. @@ -54,7 +54,7 @@ public Object logging(ProceedingJoinPoint pjp) throws Throwable { , pjp.getSignature().getDeclaringTypeName() , pjp.getSignature().getName() , logMsg); - + // 결과 확인 ResponseEntity> result = null; From f2c5518eeac90a4d94107fc53ad025b92ccfae10 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 01:12:57 +0900 Subject: [PATCH 44/59] =?UTF-8?q?refactoring:=20AOP=20private=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EC=A0=9C=EC=96=B4=EC=9E=90=EC=9D=98=20=EC=A0=9C?= =?UTF-8?q?=EC=96=B4=EB=A5=BC=20=EB=AC=B4=EC=8B=9C=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=B0=8D=EB=8D=98=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit private 이면 찍지 못하도록 막음 -> private을 찍으려면 아예 코드를 뜯어고쳐야함. 다음에 리팩토링 해야할 듯 --- .../quiz/ourclass/global/config/AopConfig.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java index 6f671930..837381bf 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java @@ -99,13 +99,16 @@ private String getObjectDetails(Object arg) { if (Modifier.isPrivate(modifiers) && Modifier.isFinal(modifiers)) { continue; } - // private 멤버 변수도 접근 할 수 있도록 허용 - field.setAccessible(true); + // 멤버 변수가 접근 가능한지 체크한다. try { - details.append((field.getName())).append("="); - details.append((field.get(arg))).append(", "); + // 만약 접근이 가능하다면 값을 가져온다. + if (field.trySetAccessible()) { + details.append(field.getName()).append("=").append(field.get(arg)).append(", "); + } + // 만약 private 접근 제어자여서 접근이 불가하면 해당 로그를 띄운다. } catch (IllegalAccessException e) { - throw new RuntimeException("특정 필드 접근에 실패했습니다.", e); + log.warn("Failed to access field: {} of class: {}", field.getName(), + arg.getClass().getName(), e); } } @@ -130,7 +133,7 @@ private StringBuilder getHeaderDetail() { } else { - System.out.println("No HTTP request details available"); + log.warn("No HTTP request details available"); } return ans; From da751921a6bfb88d3f65046d302208a324876eb5 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 01:18:51 +0900 Subject: [PATCH 45/59] =?UTF-8?q?refactoring:=20JwtUtil=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 매소드, 변수명 카멜 케이스로 통일, static 선언 안되어 있는 final 변수 모두 static으로 처리 --- .../ourclass/global/util/jwt/JwtUtil.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java index dc9999ab..3360bc0f 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java @@ -45,8 +45,8 @@ public class JwtUtil { * * (3) signatureAlgorithm: JWT의 전자서명 파트를 만들 때 쓰이는 알고리즘이다. * - * (4) ACCESS_TOKEN_TIME: 접근 토큰 수명 - * (5) REFRESH_TOKEN_TIME: 갱신 토큰 수명 + * (4) accessTokenTime: 접근 토큰 수명 + * (5) refreshTokenTime: 갱신 토큰 수명 * (6) Bearer Token Prefix * */ @@ -54,13 +54,18 @@ public class JwtUtil { @Value("${jwt.secret}") private String ingredient; private Key key; - private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512; + + // final 필드를 static으로 선언하지 않으면, 클래스의 각 인스턴스 마다 해당 필드의 값이 복사됨. + // 이는 불필요하게 메모리가 사용된다. + // static 없이 final로 선언된 필드는 각 인스턴스가 고유한 값을 가질 수 있다는 의미를 내포 + // static으로 선언하면 클래스 수준에서 값을 공유한다는 의도가 명확해짐 + private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512; @Value("#{new Integer('${jwt.token.access-expiration-time}')}") - private Integer ACCESS_TOKEN_TIME; + private Integer accessTokenTime; @Value("#{new Integer('${jwt.token.refresh-expiration-time}')}") - private Integer REFRESH_TOKEN_TIME; + private Integer refreshTokenTime; private static final String BEARER_PREFIX = "Bearer "; private final UserDetailsServiceImpl userDetailsService; @@ -101,7 +106,7 @@ public String createToken(long memberId, String role, boolean isAccess) { .claim("ROLE", role) .setIssuedAt(new Date(now.getTime())) .setExpiration( - new Date(now.getTime() + (isAccess ? ACCESS_TOKEN_TIME : REFRESH_TOKEN_TIME))) + new Date(now.getTime() + (isAccess ? accessTokenTime : refreshTokenTime))) .signWith(key, signatureAlgorithm) .compact(); @@ -178,7 +183,7 @@ public Authentication createAuthentication(String id) { public void saveRefresh(long memberId, String accessToken, String refreshToken) { refreshRepository.save( - Refresh.of(memberId, accessToken, refreshToken, REFRESH_TOKEN_TIME / 1000)); + Refresh.of(memberId, accessToken, refreshToken, refreshTokenTime / 1000)); } /* From c58f6bac90a76076117a04ee7baa62d5acc7bf07 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 01:22:22 +0900 Subject: [PATCH 46/59] =?UTF-8?q?refactoring:=20JwtUtil=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 매소드, 변수명 카멜 케이스로 통일, static 선언 안되어 있는 final 변수 모두 static으로 처리 중복 제거 --- .../java/com/quiz/ourclass/global/util/jwt/JwtUtil.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java index 3360bc0f..b64f841a 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtUtil.java @@ -142,20 +142,20 @@ public int validateToken(String token) { return 0; } catch (ExpiredJwtException e) { log.error("Expired JWT token, 만료된 JWT token 입니다."); - log.error("관련에러: {}", e.getMessage()); + log.error(e.getMessage()); return -1; } catch (io.jsonwebtoken.security.SignatureException | SecurityException | MalformedJwtException e) { log.error("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다."); - log.error("관련에러: {}", e.getMessage()); + log.error(e.getMessage()); return -2; } catch (UnsupportedJwtException e) { log.error("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다."); - log.error("관련에러: {}", e.getMessage()); + log.error(e.getMessage()); return -3; } catch (IllegalArgumentException e) { log.error("JWT claims is empty, 잘못된 JWT 토큰 입니다."); - log.error("관련에러: {}", e.getMessage()); + log.error(e.getMessage()); return -4; } } @@ -221,5 +221,4 @@ public void deleteToken(Member member) { refreshRepository.deleteById(member.getId()); } - } From a21b0f916b21a273a3855fb31f5e420503ff303a Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:02:31 +0900 Subject: [PATCH 47/59] =?UTF-8?q?refactoring:=20AOP=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=82=B4=EB=A6=AC=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=B4=20=EB=8B=A4=EC=8B=9C=20private=20=EB=98=90?= =?UTF-8?q?=ED=95=9C=20=EC=A0=91=EA=B7=BC=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20Reflection=20API=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 나중에 reflection API 쓰지 않는 방향으로 개선 필요 --- .../quiz/ourclass/global/config/AopConfig.java | 15 +++++++-------- .../quiz/ourclass/global/exception/ErrorCode.java | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java index 837381bf..72b14863 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/AopConfig.java @@ -1,6 +1,8 @@ package com.quiz.ourclass.global.config; import com.quiz.ourclass.global.dto.ResultResponse; +import com.quiz.ourclass.global.exception.ErrorCode; +import com.quiz.ourclass.global.exception.GlobalException; import jakarta.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -99,16 +101,13 @@ private String getObjectDetails(Object arg) { if (Modifier.isPrivate(modifiers) && Modifier.isFinal(modifiers)) { continue; } - // 멤버 변수가 접근 가능한지 체크한다. + // private 멤버 변수도 접근 할 수 있도록 허용 + field.setAccessible(true); try { - // 만약 접근이 가능하다면 값을 가져온다. - if (field.trySetAccessible()) { - details.append(field.getName()).append("=").append(field.get(arg)).append(", "); - } - // 만약 private 접근 제어자여서 접근이 불가하면 해당 로그를 띄운다. + details.append((field.getName())).append("="); + details.append((field.get(arg))).append(", "); } catch (IllegalAccessException e) { - log.warn("Failed to access field: {} of class: {}", field.getName(), - arg.getClass().getName(), e); + throw new GlobalException(ErrorCode.FAILED_TO_ACCESS_VARIABLE); } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/exception/ErrorCode.java b/backEnd/src/main/java/com/quiz/ourclass/global/exception/ErrorCode.java index eae43c8e..7bd2bcdd 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/exception/ErrorCode.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/exception/ErrorCode.java @@ -20,6 +20,7 @@ public enum ErrorCode { CANT_LOAD_KAFKA(HttpStatus.INTERNAL_SERVER_ERROR, "카프카 메타 데이터를 조회할 수 없습니다."), FAILED_TO_SENDING_MESSAGE(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED, "메세지를 카프카로 전송하는데 실패했습니다. 재시도 중..."), + FAILED_TO_ACCESS_VARIABLE(HttpStatus.BAD_REQUEST, "특정 필드 접근에 실패했습니다."), //member From 9f8902db815529df316eefb2a2af438c1231fe3b Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:02:59 +0900 Subject: [PATCH 48/59] =?UTF-8?q?refactoring:=20QuizController=20wild=20ca?= =?UTF-8?q?rd=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/quiz/controller/QuizController.java | 12 ++++++++---- .../quiz/controller/docs/QuizControllerDocs.java | 11 +++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/QuizController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/QuizController.java index 7a30b446..8f9b64ad 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/QuizController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/QuizController.java @@ -1,9 +1,12 @@ package com.quiz.ourclass.domain.quiz.controller; import com.quiz.ourclass.domain.quiz.controller.docs.QuizControllerDocs; +import com.quiz.ourclass.domain.quiz.dto.GamerDTO; +import com.quiz.ourclass.domain.quiz.dto.QuizGameDTO; import com.quiz.ourclass.domain.quiz.dto.request.MakingQuizRequest; import com.quiz.ourclass.domain.quiz.service.QuizServiceImpl; import com.quiz.ourclass.global.dto.ResultResponse; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -23,24 +26,25 @@ public class QuizController implements QuizControllerDocs { public final QuizServiceImpl quizService; @PutMapping("") - public ResponseEntity> makingQuiz(@RequestBody MakingQuizRequest request) { + public ResponseEntity> makingQuiz(@RequestBody MakingQuizRequest request) { quizService.makingQuiz(request); return ResponseEntity.ok(ResultResponse.success(null)); } @GetMapping("/{orgId}") - public ResponseEntity> getQuizList(@PathVariable("orgId") long orgId) { + public ResponseEntity>> getQuizList( + @PathVariable("orgId") long orgId) { return ResponseEntity.ok(ResultResponse.success(quizService.getQuizList(orgId))); } @GetMapping("/code/{quizGameId}") - public ResponseEntity> getQuizUrl( + public ResponseEntity> getQuizUrl( @PathVariable("quizGameId") long quizGameId) { return ResponseEntity.ok(ResultResponse.success(quizService.getQuizUrl(quizGameId))); } @GetMapping("/ranking/{quizGameId}") - public ResponseEntity> getRanking( + public ResponseEntity>> getRanking( @PathVariable("quizGameId") long quizGameId) { return ResponseEntity.ok(ResultResponse.success(quizService.getRanking(quizGameId))); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java index 8a342df8..c3cf9678 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/controller/docs/QuizControllerDocs.java @@ -1,5 +1,6 @@ package com.quiz.ourclass.domain.quiz.controller.docs; +import com.quiz.ourclass.domain.quiz.dto.GamerDTO; import com.quiz.ourclass.domain.quiz.dto.QuizGameDTO; import com.quiz.ourclass.domain.quiz.dto.request.MakingQuizRequest; import com.quiz.ourclass.global.dto.ResultResponse; @@ -8,6 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,7 +29,7 @@ public interface QuizControllerDocs { """, content = @Content) }) @PutMapping("") - public ResponseEntity> makingQuiz(@RequestBody MakingQuizRequest request); + public ResponseEntity> makingQuiz(@RequestBody MakingQuizRequest request); @Operation(summary = "퀴즈 리스트 불러오기", @@ -38,7 +40,8 @@ public interface QuizControllerDocs { content = @Content) }) @GetMapping("/{orgId}") - public ResponseEntity> getQuizList(@PathVariable("orgId") long orgId); + public ResponseEntity>> getQuizList( + @PathVariable("orgId") long orgId); @Operation(summary = "퀴즈 URL 생성 및 전송", responses = { @@ -53,7 +56,7 @@ public interface QuizControllerDocs { @ApiResponse(responseCode = "403", description = "(message : \"해당 퀴즈의 [URL]을 생성할 권한이 없습니다.\")") }) @GetMapping("/code/{quizGameId}") - public ResponseEntity> getQuizUrl( + public ResponseEntity> getQuizUrl( @PathVariable("quizGameId") long quizGameId); @Operation(summary = "퀴즈 게임 실시간 랭킹 보기", @@ -62,6 +65,6 @@ public ResponseEntity> getQuizUrl( content = @Content), @ApiResponse(responseCode = "400", description = "(message : \"해당 퀴즈는 종료되었습니다.\")") }) - public ResponseEntity> getRanking( + public ResponseEntity>> getRanking( @PathVariable("quizGameId") long quizGameId); } From 87915b310d7b95a9a32e0d6f5432eb5ba2bc2e7f Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:05:28 +0900 Subject: [PATCH 49/59] =?UTF-8?q?refactoring:=20QuizReceive=20replaceAll?= =?UTF-8?q?=20->=20replace=20=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/domain/quiz/service/QuizReceive.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizReceive.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizReceive.java index 3aa4cc1b..71a1bc27 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizReceive.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizReceive.java @@ -63,11 +63,12 @@ public void receivedQuestion(QuestionRequest request) { @KafkaListener(topics = ConstantUtil.QUIZ_ANSWER, containerFactory = "answerResponseContainerFactory") public void receivedAnswer(AnswerResponse response) { log.info("보내줘야할 답 상세={}", response.toString()); - - if (response.submit().replaceAll(" ", "").equals(response.ans().replaceAll(" ", ""))) { + // replaceAll 은 항상 정규 표현식을 컴파일하므로 성능 오버헤드가 발생할 수 있음 + // replaceAll 은 정규 표현식을 사용하여 문자열을 대체하지만, replace는 정규 표현식을 사용하지 않고 단순히 문자열을 대체 + if (response.submit().replace(" ", "").equals(response.ans().replaceAll(" ", ""))) { log.info(String.valueOf( - response.submit().replaceAll(" ", "").equals(response.ans().replaceAll(" ", "")))); + response.submit().replace(" ", "").equals(response.ans().replaceAll(" ", "")))); int score = redisUtil From 235b87e82f3ed1fff4c8a443705d4141164fb29e Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:11:53 +0900 Subject: [PATCH 50/59] =?UTF-8?q?refactoring:=20JwtAuthFilter=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/quiz/ourclass/global/util/ConstantUtil.java | 2 ++ .../com/quiz/ourclass/global/util/jwt/JwtAuthFilter.java | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index 3403d53d..d34b3e69 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -22,6 +22,8 @@ public abstract class ConstantUtil { public static final Long DEFAULT_TIMEOUT = 60L * 1000 * 20; public static final Long REDIRECT_TIME = 5L * 1000; + public static final String EXCEPTION_ATTRIBUTE = "exception"; + // 인스턴스화 방지 private ConstantUtil() { throw new UnsupportedOperationException( diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtAuthFilter.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtAuthFilter.java index d8be2813..b60f46d2 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtAuthFilter.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/jwt/JwtAuthFilter.java @@ -2,6 +2,7 @@ import com.quiz.ourclass.global.dto.FilterResponse; import com.quiz.ourclass.global.exception.ErrorCode; +import com.quiz.ourclass.global.util.ConstantUtil; import io.jsonwebtoken.Claims; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -42,13 +43,13 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // 토큰 유효성 체크 -> 통과 못하면 바로 다음 filter 로 넘어간다. switch (jwtUtil.validateToken(token)) { case -1: - request.setAttribute("exception", ErrorCode.EXPIRED_TOKEN); + request.setAttribute(ConstantUtil.EXCEPTION_ATTRIBUTE, ErrorCode.EXPIRED_TOKEN); filterChain.doFilter(request, response); return; case -2: case -3: case -4: - request.setAttribute("exception", ErrorCode.INVALID_TOKEN); + request.setAttribute(ConstantUtil.EXCEPTION_ATTRIBUTE, ErrorCode.INVALID_TOKEN); filterChain.doFilter(request, response); return; case -5: @@ -65,7 +66,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse try { setAuthentication(info.getSubject()); } catch (UsernameNotFoundException e) { - request.setAttribute("exception", ErrorCode.NOT_FOUND_MEMBER.getMessage()); + request.setAttribute(ConstantUtil.EXCEPTION_ATTRIBUTE, + ErrorCode.NOT_FOUND_MEMBER.getMessage()); log.error("관련 에러: {}", e.getMessage()); } From 25287d1751eb58c74c810acefbac5350503e694c Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:12:49 +0900 Subject: [PATCH 51/59] =?UTF-8?q?refactoring:=20OidcService=20=EC=95=88=20?= =?UTF-8?q?=EC=93=B0=EB=8A=94=20import=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/OidcService.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/member/service/OidcService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/member/service/OidcService.java index 9705ffc9..88c3071e 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/member/service/OidcService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/member/service/OidcService.java @@ -3,13 +3,10 @@ import com.quiz.ourclass.domain.member.dto.OIDCDecodePayload; import com.quiz.ourclass.domain.member.dto.OIDCPublicKeyDTO; import com.quiz.ourclass.domain.member.dto.response.OIDCPublicKeysResponse; -import com.quiz.ourclass.domain.member.repository.MemberRepository; import com.quiz.ourclass.domain.member.service.client.KakaoOicdClient; import com.quiz.ourclass.domain.member.service.oidc.OidcUtilImpl; import com.quiz.ourclass.global.exception.ErrorCode; import com.quiz.ourclass.global.exception.GlobalException; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -31,20 +28,23 @@ public class OidcService { private final KakaoOicdClient kakaoOicdClient; /* - * 1. 유효성 검증 - * (1) 토큰 디코딩 -> (2) kid 값 알아내기 -> (3) kid 이용, RSA key 재료 얻어내기 -> RSA를 통한 유효성 검증 - * */ + * 1. 유효성 검증 + * (1) 토큰 디코딩 -> (2) kid 값 알아내기 -> (3) kid 이용, RSA key 재료 얻어내기 -> RSA를 통한 유효성 검증 + * */ - public OIDCDecodePayload certificatingIdToken (String idToken) { + public OIDCDecodePayload certificatingIdToken(String idToken) { // 해당 토큰의 서명 인증 할 수 있는 공개 키의 id (kid) 특정 String kid = oicdUtil.getKidFromUnsignedTokenHeader(idToken, iss, aud); // 카카오 인증 서버에서 이번 주기에 사용한 공개키 목록 전체 받아오기 -> 캐시화 필요!!! 너무 많이 요청하면 차단 당함! OIDCPublicKeysResponse keys = kakaoOicdClient.getKakaoOIDCOpenKeys(); // 이번 주에 카카오가 제공하는 공개키 중에 내 Resource Owner 의 id-token 인증 가능한 key 받아오기 - OIDCPublicKeyDTO nowKey = keys.getKeys().stream().filter(key -> key.getKid().equals(kid)).findFirst().orElseThrow(null); + OIDCPublicKeyDTO nowKey = keys.getKeys().stream().filter(key -> key.getKid().equals(kid)) + .findFirst().orElseThrow(null); - if(nowKey == null) throw new GlobalException(ErrorCode.CERTIFICATION_FAILED); + if (nowKey == null) { + throw new GlobalException(ErrorCode.CERTIFICATION_FAILED); + } // 해당 키로 서명 인증, 예외 안 터지고 인증 되면 Body 가져옴 return oicdUtil.getOIDCTokenBody(idToken, nowKey.getN(), nowKey.getE()); From 90d8024611f440a320d25b902247d5d4e1d55c76 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:20:54 +0900 Subject: [PATCH 52/59] =?UTF-8?q?refactoring:=20ProducerConfig=20Naming=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/global/config/kafka/ProducerConfig.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ProducerConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ProducerConfig.java index 4a773b97..b9531c82 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ProducerConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ProducerConfig.java @@ -52,32 +52,32 @@ public KafkaTemplate kafkaTemplate() { // Gamer Template -> 총 게이머에 대한 명세(이름, id, 프로필 사진), 게이머의 랭킹 @Bean - public ProducerFactory GamerProducerFactory() { + public ProducerFactory gamerProducerFactory() { return new DefaultKafkaProducerFactory<>(producerConfigurations()); } @Bean public KafkaTemplate gamerTemplate() { - return new KafkaTemplate<>(GamerProducerFactory()); + return new KafkaTemplate<>(gamerProducerFactory()); } @Bean - public ProducerFactory QuestionProducerFactory() { + public ProducerFactory questionProducerFactory() { return new DefaultKafkaProducerFactory<>(producerConfigurations()); } @Bean public KafkaTemplate questionTemplate() { - return new KafkaTemplate<>(QuestionProducerFactory()); + return new KafkaTemplate<>(questionProducerFactory()); } @Bean - public ProducerFactory AnswerProducerFactory() { + public ProducerFactory answerProducerFactory() { return new DefaultKafkaProducerFactory<>(producerConfigurations()); } @Bean public KafkaTemplate answerTemplate() { - return new KafkaTemplate<>(AnswerProducerFactory()); + return new KafkaTemplate<>(answerProducerFactory()); } } From 1cf81f218f029eebd66553afb846f46281adf6ff Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:22:21 +0900 Subject: [PATCH 53/59] =?UTF-8?q?refactoring:=20URL=20=EB=AA=85=EB=AA=85?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quiz/ourclass/domain/quiz/service/QuizServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizServiceImpl.java index c023cec7..54325e22 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/service/QuizServiceImpl.java @@ -40,7 +40,7 @@ public class QuizServiceImpl implements QuizService { private final CountdownService countdownService; @Value("${ulvan.url}") - private String UlvanUrl; + private String ulvanUrl; @Transactional @@ -88,7 +88,7 @@ public String getQuizUrl(long quizGameId) { .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); // 1. [UUID]를 이용해 퀴즈 게임 [URL]을 생성합니다. UUID uuid = UUID.randomUUID(); - String url = UlvanUrl + quizGameId + "/" + uuid; + String url = ulvanUrl + quizGameId + "/" + uuid; // 2. [URL]을 [REDIS]에 수명을 10분으로 두고 저장합니다. (퀴즈 방 입장할 때 체크용) redisUtil.setQuizGame(quizGameId, uuid); // 3. [URL]을 요청 당사자는 물론, 단체에 속한 모두에게 전송 합니다. From aa3347ccd55c62dad8b445cd79712b001ba7fabd Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:23:41 +0900 Subject: [PATCH 54/59] =?UTF-8?q?refactoring:=20SecurityConfig=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=20=EC=97=86=EB=8A=94=20=EA=B4=84=ED=98=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/global/config/SecurityConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/SecurityConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/SecurityConfig.java index d2c98ef6..2eb46ee8 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/SecurityConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/SecurityConfig.java @@ -86,7 +86,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { (corsCustomizer -> corsCustomizer.configurationSource(corsConfigurationSource()))); http - .headers((headers) -> headers.frameOptions( + .headers(headers -> headers.frameOptions( HeadersConfigurer.FrameOptionsConfig::sameOrigin )); // (5) @@ -98,13 +98,13 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ); http - .sessionManagement((sessionManagement) -> + .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) ); // (7) http .authorizeHttpRequests( - (auth) -> + auth -> auth // (8) .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll() .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll() From 78581dfc600296cc9d4b0a27e3c564576602a984 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:24:28 +0900 Subject: [PATCH 55/59] =?UTF-8?q?refactoring:=20CacheConfig=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=20=EC=97=86=EB=8A=94=20=EA=B4=84=ED=98=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/quiz/ourclass/global/config/CacheConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/CacheConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/CacheConfig.java index c1668f56..aab4113e 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/CacheConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/CacheConfig.java @@ -43,7 +43,7 @@ public RedisCacheConfiguration redisCacheConfiguration() { * */ @Bean public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { - return (builder) -> builder + return builder -> builder .withCacheConfiguration("OIDC", RedisCacheConfiguration.defaultCacheConfig() .computePrefixWith(cacheName -> "OIDC:") From 3f87e0dbb2147ae2ca0c7987684e3890654cc88e Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:27:34 +0900 Subject: [PATCH 56/59] =?UTF-8?q?refactoring:=20ListenerConfig=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EB=A1=9C=20=EC=9E=AC=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/global/config/kafka/ListenerConfig.java | 9 +++++---- .../java/com/quiz/ourclass/global/util/ConstantUtil.java | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ListenerConfig.java b/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ListenerConfig.java index 15afd9b9..88e4e195 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ListenerConfig.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/config/kafka/ListenerConfig.java @@ -5,6 +5,7 @@ import com.quiz.ourclass.domain.quiz.dto.GamerDTO; import com.quiz.ourclass.domain.quiz.dto.request.QuestionRequest; import com.quiz.ourclass.domain.quiz.dto.response.AnswerResponse; +import com.quiz.ourclass.global.util.ConstantUtil; import java.util.Map; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; @@ -49,7 +50,7 @@ public ConsumerFactory consumerFactory() { .put(ConsumerConfig.GROUP_ID_CONFIG, kafkaGroup) .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class) .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, deserializer) - .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") + .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, ConstantUtil.LATEST) .build(); return new DefaultKafkaConsumerFactory<>( @@ -75,7 +76,7 @@ public ConsumerFactory gamerDTOConsumerFactory() { .put(ConsumerConfig.GROUP_ID_CONFIG, "group-2") .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class) .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, deserializer) - .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") + .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, ConstantUtil.LATEST) .build(); return new DefaultKafkaConsumerFactory<>( @@ -102,7 +103,7 @@ public ConsumerFactory questionRequestConsumerFactory() .put(ConsumerConfig.GROUP_ID_CONFIG, "group-3") .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class) .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, deserializer) - .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") + .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, ConstantUtil.LATEST) .build(); return new DefaultKafkaConsumerFactory<>( @@ -128,7 +129,7 @@ public ConsumerFactory answerResponseConsumerFactory() { .put(ConsumerConfig.GROUP_ID_CONFIG, "group-4") .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class) .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, deserializer) - .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") + .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, ConstantUtil.LATEST) .build(); return new DefaultKafkaConsumerFactory<>( consumerConfigurations, new StringDeserializer(), deserializer diff --git a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java index d34b3e69..613414ec 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java +++ b/backEnd/src/main/java/com/quiz/ourclass/global/util/ConstantUtil.java @@ -21,8 +21,8 @@ public abstract class ConstantUtil { public static final String REDIS_GROUP_KEY = "CHALLENGE_LEADER:"; public static final Long DEFAULT_TIMEOUT = 60L * 1000 * 20; public static final Long REDIRECT_TIME = 5L * 1000; - public static final String EXCEPTION_ATTRIBUTE = "exception"; + public static final String LATEST = "latest"; // 인스턴스화 방지 private ConstantUtil() { From 6a51f7627154d5acd319a64b84a4c0f264da895b Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:29:08 +0900 Subject: [PATCH 57/59] =?UTF-8?q?refactoring:=20MemberSignInRequest=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20Import=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ourclass/domain/member/dto/request/MemberSignInRequest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/member/dto/request/MemberSignInRequest.java b/backEnd/src/main/java/com/quiz/ourclass/domain/member/dto/request/MemberSignInRequest.java index 2ba4f39a..8a88d2f9 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/member/dto/request/MemberSignInRequest.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/member/dto/request/MemberSignInRequest.java @@ -1,6 +1,5 @@ package com.quiz.ourclass.domain.member.dto.request; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; From 7cfda110858f98516e69200a9d744ea65723e622 Mon Sep 17 00:00:00 2001 From: JeonSooMin Date: Mon, 27 May 2024 02:30:50 +0900 Subject: [PATCH 58/59] =?UTF-8?q?refactoring:=20QuizGameMapper=20=EB=AA=85?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/quiz/ourclass/domain/quiz/mapper/QuizGameMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/mapper/QuizGameMapper.java b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/mapper/QuizGameMapper.java index 428f2dce..e518a19e 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/mapper/QuizGameMapper.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/quiz/mapper/QuizGameMapper.java @@ -23,7 +23,7 @@ public interface QuizGameMapper { @Transactional Quiz toQuiz(QuizGame quizGame, QuizDTO quizDTO); - QuizGameDTO toQuizGameDTO(QuizGame QuizGame); + QuizGameDTO toQuizGameDTO(QuizGame quizGame); FcmDTO toFcmDTO(String title, String body); From ed763db214f1a90102198aaef23e0b7930a3fe92 Mon Sep 17 00:00:00 2001 From: HABIN Date: Mon, 27 May 2024 17:24:02 +0900 Subject: [PATCH 59/59] =?UTF-8?q?feat:=20=EA=B7=B8=EB=A3=B9=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20-=20=EC=B9=9C=ED=95=9C=EC=B9=9C=EA=B5=AC=20-=20?= =?UTF-8?q?=EC=8A=A4=ED=8E=99=ED=8A=B8=EB=9F=BC=20=ED=81=B4=EB=9F=AC?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 친한 친구끼리 그룹 매칭 부분을 스펙트럼 클러스터링으로 구현했습니다. - testMethod 제거했습니다. --- backEnd/build.gradle | 6 +- .../challenge/algorithm/FriendlyGroup.java | 578 ++++++++++-------- .../challenge/controller/GroupController.java | 3 +- .../challenge/service/GroupService.java | 2 - .../challenge/service/GroupServiceImpl.java | 46 -- 5 files changed, 339 insertions(+), 296 deletions(-) diff --git a/backEnd/build.gradle b/backEnd/build.gradle index c127d28e..286bb3a4 100644 --- a/backEnd/build.gradle +++ b/backEnd/build.gradle @@ -101,7 +101,11 @@ dependencies { implementation 'org.apache.kafka:kafka-clients' implementation 'org.springframework.retry:spring-retry' - implementation 'org.ojalgo:ojalgo:51.4.1' + // K-means 클러스터링 라이브러리 + implementation 'org.apache.commons:commons-math3:3.6.1' + + // 행렬 연산 + implementation 'org.ejml:ejml-simple:0.41' } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/algorithm/FriendlyGroup.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/algorithm/FriendlyGroup.java index aa617cc5..88e63f71 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/algorithm/FriendlyGroup.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/algorithm/FriendlyGroup.java @@ -1,27 +1,28 @@ package com.quiz.ourclass.domain.challenge.algorithm; import com.quiz.ourclass.domain.challenge.dto.response.AutoGroupMatchingResponse; -import com.quiz.ourclass.domain.member.entity.Member; import com.quiz.ourclass.domain.member.mapper.MemberMapper; import com.quiz.ourclass.domain.member.repository.MemberRepository; import com.quiz.ourclass.domain.organization.entity.Relationship; -import com.quiz.ourclass.domain.organization.repository.MemberOrganizationRepository; import com.quiz.ourclass.domain.organization.repository.RelationshipRepository; import com.quiz.ourclass.global.dto.MemberSimpleDTO; -import com.quiz.ourclass.global.exception.ErrorCode; -import com.quiz.ourclass.global.exception.GlobalException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.ojalgo.optimisation.Expression; -import org.ojalgo.optimisation.ExpressionsBasedModel; -import org.ojalgo.optimisation.Variable; +import org.apache.commons.math3.ml.clustering.CentroidCluster; +import org.apache.commons.math3.ml.clustering.DoublePoint; +import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer; +import org.ejml.dense.row.decomposition.eig.SwitchingEigenDecomposition_DDRM; +import org.ejml.simple.SimpleMatrix; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Slf4j @@ -30,297 +31,384 @@ public class FriendlyGroup { private final RelationshipRepository relationshipRepository; - private final MemberOrganizationRepository memberOrganizationRepository; private final MemberRepository memberRepository; private final MemberMapper memberMapper; - // 이 메소드는 트랜잭션을 지원하는 설정에서 읽기 전용으로 실행됩니다. - // 읽기 전용이기 때문에 데이터를 변경할 수 없고, - // Propagation.SUPPORTS 설정은 현재 진행 중인 트랜잭션이 있을 경우 그 트랜잭션에 참여하며, - // 없을 경우 비트랜잭션 상태로 실행됩니다. - @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) - public List makeFriendlyGroup( - long organizationId, int studentsPerGroup, List members) { - // 주어진 단체 ID에 해당하는 학생 수를 데이터베이스에서 조회 - int totalStudentCount = memberOrganizationRepository.countByOrganizationId(organizationId); - - // 단체 ID, 입력된 멤버 ID에 따라서 모든 관계 데이터를 조회 - List relationships = - relationshipRepository.findAllByOrganizationIdAndMemberIds( - organizationId, members - ); - - if ((relationships.size() % studentsPerGroup) == 1) { - throw new GlobalException(ErrorCode.BAD_REQUEST); - } + // 클래스 변수로 memberIds 선언 + private List memberIds; + + /** + * 조직의 학생들을 친밀도에 따라 그룹으로 나누는 메서드입니다. Spectral Clustering 알고리즘을 사용하여 그룹을 생성하고, + *

+ * 각 그룹의 최소 및 최대 크기를 유지합니다. + * + * @param organizationId 그룹화할 학생들이 속한 조직의 ID + * @param studentsPerGroup 각 그룹에 포함될 학생 수 + * @param memberIds 그룹화할 학생들의 ID 리스트 + * @return 그룹화된 학생들의 정보를 담은 AutoGroupMatchingResponse 리스트 + */ + @Transactional + public List makeFriendlyGroup(long organizationId, + int studentsPerGroup, List memberIds) { + + // 클래스 변수로 memberIds 를 설정 + this.memberIds = memberIds; - // 학생 ID를 배열 인덱스로 매핑하기 위한 HashMap을 생성 + // 학생 ID를 인덱스로 매핑하는 맵 생성 Map studentIdToIndex = new HashMap<>(); + memberIds.forEach(id -> studentIdToIndex.put(id, studentIdToIndex.size())); + + // 친밀도 매트릭스 계산 + double[][] adjacencyMatrix = precomputeRelationshipMatrix(organizationId, memberIds, + studentIdToIndex); + + // 그룹의 수 계산 + int numGroups = (int) Math.ceil((double) memberIds.size() / studentsPerGroup); - // 현재 인덱스를 추적하기 위한 변수 - int currentIndex = 0; - for (Relationship relationship : relationships) { - // 각 관계에 대해 두 멤버의 ID를 맵에 없으면 추가하고, 인덱스를 증가 - if (!studentIdToIndex.containsKey(relationship.getMember1().getId())) { - studentIdToIndex.put(relationship.getMember1().getId(), currentIndex++); + // Spectral Clustering 을 사용하여 그룹 생성 + List> groups = spectralClustering(adjacencyMatrix, numGroups, memberIds.size()); + + // 학생이 그룹에 중복 배치되지 않도록 재배치 + redistributeMembers(groups); + + // 결과 로그 출력 + logGroupResults(groups, adjacencyMatrix, studentIdToIndex); + + // 그룹화된 학생들에 대한 응답 생성 + return buildResponse(groups); + } + + + /** + * 주어진 조직의 학생들 간의 친밀도 점수를 기반으로 관계 매트릭스를 생성하는 메서드입니다. + * + * @param organizationId 관계를 조회할 조직의 ID + * @param members 관계 매트릭스를 계산할 학생들의 ID 리스트 + * @param studentIdToIndex 학생 ID를 인덱스로 매핑하는 맵 + * @return 학생들 간의 친밀도 점수를 저장한 2차원 배열 (관계 매트릭스) + */ + private double[][] precomputeRelationshipMatrix(long organizationId, List members, + Map studentIdToIndex) { + + // 주어진 조직 ID와 학생 ID 리스트를 기반으로 모든 관계 데이터를 조회 + List relationships = relationshipRepository.findAllByOrganizationIdAndMemberIds( + organizationId, members); + + // 학생 수에 맞는 2차원 배열(매트릭스)을 초기화 + double[][] matrix = new double[members.size()][members.size()]; + + // 각 관계에 대해 친밀도 점수를 매트릭스에 설정 + relationships.forEach(relationship -> { + // 관계의 첫 번째 학생의 인덱스를 조회 + Integer index1 = studentIdToIndex.get(relationship.getMember1().getId()); + // 관계의 두 번째 학생의 인덱스를 조회 + Integer index2 = studentIdToIndex.get(relationship.getMember2().getId()); + // 두 학생의 인덱스가 모두 존재하는 경우에만 매트릭스에 값을 설정 + if (index1 != null && index2 != null) { + // 첫 번째 학생과 두 번째 학생 간의 친밀도 점수를 매트릭스에 설정 + matrix[index1][index2] = relationship.getRelationPoint(); + // 대칭성 유지: 두 번째 학생과 첫 번째 학생 간의 친밀도 점수를 동일하게 설정 + matrix[index2][index1] = relationship.getRelationPoint(); } - if (!studentIdToIndex.containsKey(relationship.getMember2().getId())) { - studentIdToIndex.put(relationship.getMember2().getId(), currentIndex++); + }); + // 생성된 관계 매트릭스를 반환 + return matrix; + } + + + /** + * 스펙트럼 클러스터링을 사용하여 주어진 인접 행렬로부터 학생들을 그룹으로 나누는 메서드입니다. + * + * @param adjacencyMatrix 학생들 간의 관계를 나타내는 인접 행렬 + * @param numClusters 생성할 그룹(클러스터)의 수 + * @param n 전체 학생 수 + * @return 학생들을 그룹으로 나눈 결과 리스트 + */ + private List> spectralClustering( + double[][] adjacencyMatrix, int numClusters, int n) { + // 학위 행렬 계산 + double[][] degreeMatrix = new double[n][n]; + for (int i = 0; i < n; i++) { + double sum = 0; + for (int j = 0; j < n; j++) { + sum += adjacencyMatrix[i][j]; } + degreeMatrix[i][i] = sum; } - // 학생 간의 관계 점수를 저장할 2차원 배열을 초기화 - double[][] relationshipMatrix = new double[totalStudentCount][totalStudentCount]; - for (Relationship relationship : relationships) { - int index1 = studentIdToIndex.get(relationship.getMember1().getId()); - int index2 = studentIdToIndex.get(relationship.getMember2().getId()); - relationshipMatrix[index1][index2] = relationship.getRelationPoint(); - relationshipMatrix[index2][index1] = relationship.getRelationPoint(); // 대칭성 유지 + // 라플라시안 행렬 계산: L = D - A + SimpleMatrix L = new SimpleMatrix(degreeMatrix).minus(new SimpleMatrix(adjacencyMatrix)); + + // 고유값 및 고유벡터 계산 + // SwitchingEigenDecomposition_DDRM 클래스의 인스턴스를 생성 + // 첫 번째 매개변수 n은 행렬의 크기를 나타내며, 두 번째 매개변수는 대칭 여부를 나타낸다. + // 세 번째 매개변수는 고유값 분해의 허용 오차를 설정함 + SwitchingEigenDecomposition_DDRM eightDecompose = + new SwitchingEigenDecomposition_DDRM(n, true, 1e-6); + + // 생성한 eightDecompose 인스턴스를 사용하여 라플라시안 행렬 L의 고유값 분해를 수행 + // eightDecompose.decompose 메서드는 행렬의 고유값과 고유벡터를 계산 + eightDecompose.decompose(L.getMatrix()); + + // 고유값 정렬 및 해당 고유벡터 가져오기 + // 고유값을 저장할 리스트를 초기화 + List eigenValues = new ArrayList<>(); + + // 고유벡터를 고유값과 매핑하여 저장할 맵을 초기화 + Map eigenVectorsMap = new HashMap<>(); + + // 고유값 분해 결과로부터 고유값과 고유벡터를 추출 + for (int i = 0; i < n; i++) { + // 현재 인덱스 i의 고유값을 가져오기 + double eigValue = eightDecompose.getEigenvalue(i).getReal(); + // 현재 인덱스 i의 고유벡터를 가져오기 + SimpleMatrix eigVector = SimpleMatrix.wrap(eightDecompose.getEigenVector(i)); + // 고유값 리스트에 현재 고유값을 추가 + eigenValues.add(eigValue); + // 고유값을 키로, 해당 고유벡터를 값으로 하여 맵에 추가 + eigenVectorsMap.put(eigValue, eigVector); } - // 필요한 그룹 수를 계산합니다. 총 학생 수를 그룹당 학생 수로 나누어 올림 처리 - int numGroups = (int) Math.ceil((double) totalStudentCount / studentsPerGroup); + // 고유값 리스트를 오름차순으로 정렬 + Collections.sort(eigenValues); + + // 가장 작은 numClusters 개의 고유벡터로부터 행렬 구성 + // 'features' 라는 새로운 행렬을 생성 + // 이 행렬의 크기는 n x numClusters 이며, + // 여기서 n은 데이터 포인트의 수, numClusters 는 클러스터의 수이다. + SimpleMatrix features = new SimpleMatrix(n, numClusters); + + // 가장 작은 고유값에 해당하는 고유벡터들을 'features' 행렬에 삽입 + // 'eigenVectorsMap' 에서 가장 작은 고유값에 해당하는 고유벡터를 가져와 'features' 행렬의 열에 삽입 + for (int i = 0; i < numClusters; i++) { + // 고유값을 오름차순으로 정렬했으므로, 'eigenValues.get(i)'는 가장 작은 고유값 중 i번째 값입니다. + // 이 고유값에 해당하는 고유벡터를 'eigenVectorsMap' 에서 가져와 'features' 행렬의 i번째 열에 삽입 + features.insertIntoThis(0, i, eigenVectorsMap.get(eigenValues.get(i))); + } - // 최적화 모델을 생성 - ExpressionsBasedModel model = new ExpressionsBasedModel(); - // 각 학생이 각 그룹에 할당되는 변수를 2차원 배열로 초기화 - Variable[][] x = new Variable[totalStudentCount][numGroups]; - for (int i = 0; i < totalStudentCount; i++) { - for (int j = 0; j < numGroups; j++) { - // 변수를 이진 변수로 선언하여, 학생이 특정 그룹에 속하는지를 나타냅니다. - x[i][j] = Variable.make("x[" + i + "][" + j + "]").binary(); + /* 각 포인트를 단위 길이로 정규화하여 KMeans 클러스터링을 수행하기 위한 준비 단계 */ - // 모델에 변수를 추가 - model.addVariable(x[i][j]); + // 행을 단위 길이로 정규화 + // 각 행을 단위 길이로 정규화하기 위해 'features' 행렬의 모든 행에 대해 반복 + for (int i = 0; i < n; i++) { + // 'features' 행렬의 i번째 행을 벡터로 추출하여 그 노름(norm)을 계산 + double norm = features.extractVector(true, i).normF(); + // i번째 행의 각 요소를 해당 행의 노름으로 나누어 단위 길이로 만든다. + for (int j = 0; j < numClusters; j++) { + // 'features' 행렬의 i번째 행, j번째 열의 요소를 그 노름으로 나누어 정규화한다. + features.set(i, j, features.get(i, j) / norm); } } - // 제약 조건 추가 - applyConstraints(model, x, numGroups, totalStudentCount, studentsPerGroup); - // 목표 함수 설정 - setObjectiveFunction(model, x, relationshipMatrix, numGroups, totalStudentCount); + /* KMeans++를 사용하여 데이터를 클러스터로 분할하는 단계 */ - // 모델 최적화 - model.maximise(); + // KMeans 를 사용하여 정규화된 행을 클러스터링 + // KMeans++ 클러스터러를 초기화합니다. 클러스터의 수는 numClusters 이다. + // KMeans++는 초기 클러스터 중심을 더 신뢰성 있게 선택하기 위한 방법 + KMeansPlusPlusClusterer kMeans = new KMeansPlusPlusClusterer<>(numClusters); - // 결과 출력 - printSolution(x, numGroups, totalStudentCount, studentIdToIndex, relationshipMatrix); - - // 결과 반환 - return extractSolution(x, numGroups, totalStudentCount, studentIdToIndex); - } + // 클러스터링을 위한 입력 데이터를 저장할 리스트를 초기화 + List clusterInput = new ArrayList<>(); - /** - * 모델에 필요한 제약 조건을 적용합니다. 이 메서드는 두 가지 주요 제약을 설정합니다: 1. 각 학생은 하나의 그룹에만 속해야 합니다. 2. 각 그룹은 최대 지정된 수의 - * 학생만 포함할 수 있습니다. - * - * @param model 최적화 모델 객체 - * @param x 학생들이 그룹에 할당되는 상태를 나타내는 이진 변수 배열 - * @param numGroups 전체 그룹 수 - * @param totalStudentCount 전체 학생 수 - * @param studentsPerGroup 각 그룹에 할당될 수 있는 최대 학생 수 - */ - private void applyConstraints(ExpressionsBasedModel model, Variable[][] x, int numGroups, - int totalStudentCount, int studentsPerGroup) { - // 각 학생은 정확히 하나의 그룹에만 할당되어야 함을 보장하는 제약 조건을 설정합니다. - // 이를 위해 모든 학생에 대해 '학생 제약 조건'을 추가합니다. - for (int i = 0; i < totalStudentCount; i++) { - // 학생 i가 정확히 한 그룹에만 속하도록 하는 제약식을 생성합니다. - // 이 제약식은 각 학생 변수의 합이 정확히 1이 되도록 요구합니다. - Expression studentConstraint = model.addExpression("studentConstraint" + i).lower(1) - .upper(1); - for (int j = 0; j < numGroups; j++) { - // 각 그룹 j에 대해 학생 i가 그룹에 포함되면 1, 아니면 0의 값을 갖는 변수 x[i][j]를 설정합니다. - studentConstraint.set(x[i][j], 1); + // 각 데이터를 클러스터링을 위한 형식으로 변환 + for (int i = 0; i < n; i++) { + // 'features' 행렬의 i번째 행을 복사하여 'row' 배열에 저장 + // 여기서 'numClusters' 는 각 데이터 포인트의 차원이다. + double[] row = new double[numClusters]; + for (int j = 0; j < numClusters; j++) { + // 'features' 행렬의 i번째 행, j번째 열의 값을 'row' 배열에 저장 + row[j] = features.get(i, j); } + // 'row' 배열을 'DoublePoint' 객체로 변환하여 'clusterInput' 리스트에 추가 + clusterInput.add(new DoublePoint(row)); } - - // 각 그룹은 최대 studentsPerGroup 명을 포함해야 하는 제약 조건을 설정합니다. - // 이를 위해 모든 그룹에 대해 '그룹 제약 조건'을 추가합니다. - for (int j = 0; j < numGroups; j++) { - // 그룹 j가 포함할 수 있는 최대 학생 수를 제한하는 제약식을 생성합니다. - // 이 제약식은 각 그룹에 할당된 학생 수의 합이 studentsPerGroup을 초과하지 않도록 합니다. - Expression groupConstraint = model.addExpression("groupConstraint" + j) - .upper(studentsPerGroup); - for (int i = 0; i < totalStudentCount; i++) { - // 각 학생 i에 대해, 학생이 그룹 j에 속할 경우 변수 x[i][j]의 값을 1로 설정합니다. - groupConstraint.set(x[i][j], 1); + // 'clusterInput' 데이터를 사용하여 KMeans++ 클러스터링을 수행합니다. + // 결과는 클러스터의 리스트 + List> clusters = kMeans.cluster(clusterInput); + + // 클러스터를 원래 학생 ID로 매핑 + // 그룹 리스트를 초기화한다. 각 그룹은 학생 ID의 리스트이다. + List> groups = new ArrayList<>(); + + // 학생이 할당되었는지 추적하는 불리언 배열을 초기화합니다. 배열의 크기는 학생 수임 + boolean[] assigned = new boolean[memberIds.size()]; + + // 학생의 할당 상태를 추적하는 집합을 초기화 + Set assignedMembers = new HashSet<>(); + + // 각 클러스터에 대해 반복 + for (CentroidCluster cluster : clusters) { + // 현재 클러스터에 대한 그룹을 초기화 + List group = new ArrayList<>(); + + // 클러스터에 속한 각 포인트에 대해 반복 + for (DoublePoint point : cluster.getPoints()) { + // 포인트의 인덱스를 clusterInput 리스트에서 찾기 + int index = clusterInput.indexOf(point); + + // 인덱스가 유효하고, 해당 인덱스의 학생이 아직 할당되지 않았으며, + // 해당 학생이 할당된 적이 없는 경우에만 그룹에 추가 + if (index != -1 && !assigned[index] && !assignedMembers.contains( + memberIds.get(index))) { + // 학생 ID를 그룹에 추가 + group.add(memberIds.get(index)); + + // 해당 인덱스와 학생 ID를 할당된 것으로 표시 + assigned[index] = true; + assignedMembers.add(memberIds.get(index)); + } } + // 완성된 그룹을 그룹 리스트에 추가 + groups.add(group); } + // 완성된 그룹 반환 + return groups; } + /** - * 최적화 모델의 목표 함수를 설정합니다. 이 함수는 학생들 간의 친밀도를 최대화하는 방향으로 그룹을 최적화하기 위해 정의됩니다. 각 그룹 내의 학생들 사이에서 친밀도 - * 점수를 기반으로 상호 작용 변수(interaction)를 계산하고, 이 변수를 목표 함수에 추가하여 그룹 내의 친밀도 합을 최대화합니다. + * 주어진 그룹 리스트를 기반으로 학생들을 재배치하여 최소 및 최대 그룹 크기 요구사항을 충족시킵니다. * - * @param model 최적화를 수행할 모델 객체 - * @param x 학생들이 그룹에 할당되는 이진 변수 배열 - * @param relationshipMatrix 학생 간의 친밀도 점수가 저장된 행렬 - * @param numGroups 생성될 그룹의 총 수 - * @param totalStudentCount 전체 학생 수 + * @param groups 학생 ID로 구성된 그룹 리스트 */ - private void setObjectiveFunction(ExpressionsBasedModel model, Variable[][] x, - double[][] relationshipMatrix, int numGroups, int totalStudentCount) { - // 목표 함수를 정의하고 가중치를 1.0으로 설정합니다. - Expression objective = model.addExpression("objective").weight(1.0); - - // 모든 그룹에 대해 각 학생 쌍의 상호작용을 고려하여 친밀도를 계산합니다. - for (int k = 0; k < numGroups; k++) { - for (int i = 0; i < totalStudentCount; i++) { - for (int j = i + 1; j < totalStudentCount; j++) { - // 각 학생 쌍과 그룹에 대한 상호 작용 변수를 생성하고 모델에 추가합니다. - // 이 변수는 두 학생이 동일한 그룹에 할당되었는지 여부를 나타냅니다 - // (1이면 할당됨, 0이면 할당되지 않음). - Variable interaction = Variable.make( - "interaction[" + i + "][" + j + "][" + k + "]").binary(); - model.addVariable(interaction); - - // 두 학생 i와 j가 같은 그룹 k에 있을 때, interaction 변수가 1이 되도록 설정합니다. - // 이를 위해 x[i][k] + x[j][k] - 2 * interaction >= 0 이라는 제약식을 모델에 추가합니다. - // 여기서 x[i][k]와 x[j][k]는 각 학생이 특정 그룹에 할당되면 1의 값을 가집니다. - // 따라서 두 학생 모두 같은 그룹에 할당되었을 때만 (x[i][k] + x[j][k] == 2), - // interaction 은 1이 될 수 있습니다. - model.addExpression("interaction_constraint_" + i + "_" + j + "_" + k) - .set(x[i][k], 1) - .set(x[j][k], 1) - .set(interaction, -2) - .lower(0); - - // interaction 변수가 1이 될 조건을 추가로 정의합니다. interaction 은 두 학생이 같은 그룹에 있지 않을 때 0이어야 합니다. - // interaction - x[i][k] <= 0 이라는 제약식은 interaction 이 1일 때, x[i][k]도 반드시 1이어야 함을 의미합니다. - // 즉, 학생 i가 그룹 k에 할당되지 않았다면, interaction 은 0이 될 수밖에 없습니다. - model.addExpression("interaction_constraint2_" + i + "_" + j + "_" + k) - .set(interaction, 1) - .set(x[i][k], -1) - .upper(0); - - // 마찬가지로, interaction - x[j][k] <= 0 제약식은 - // 학생 j가 그룹 k에 할당되지 않았을 경우 interaction 을 0으로 유지합니다. - // 이 조건은 상호 작용 변수가 두 학생이 실제로 같은 그룹에 할당된 경우에만 1의 값을 가지도록 보장합니다. - model.addExpression("interaction_constraint3_" + i + "_" + j + "_" + k) - .set(interaction, 1) - .set(x[j][k], -1) - .upper(0); - - // 목표 함수에 각 상호 작용의 친밀도 점수를 반영합니다. - objective.set(interaction, relationshipMatrix[i][j]); + private void redistributeMembers(List> groups) { + // 총 클러스터 수를 계산합니다. + int numClusters = groups.size(); + + // 총 학생 수를 계산합니다. + int totalStudents = memberIds.size(); + + // 최소 그룹 크기를 계산합니다. + int minGroupSize = totalStudents / numClusters; + + // 최대 그룹 크기를 계산합니다. + int maxGroupSize = (int) Math.ceil((double) totalStudents / numClusters); + + // 할당된 학생을 추적하기 위한 집합을 초기화합니다. + Set assignedStudents = new HashSet<>(); + + // 할당되지 않은 학생을 추적하기 위한 리스트를 초기화합니다. + List unassignedStudents = new ArrayList<>(); + + // 초기 할당된 학생 집합을 설정하고 할당되지 않은 학생을 수집합니다. + for (List group : groups) { + for (Long student : group) { + if (assignedStudents.contains(student)) { + // 이미 할당된 학생이 그룹에 있으면 unassignedStudents 리스트에 추가합니다. + unassignedStudents.add(student); + } else { + // 처음 할당된 학생은 assignedStudents 집합에 추가합니다. + assignedStudents.add(student); } } } - } - /** - * 최적화 모델의 결과를 추출하는 함수입니다. 각 그룹의 구성과 그룹별 멤버 정보를 반환하여, 어떻게 학생들이 그룹화되었는지 보여줍니다. - * - * @param x 각 학생이 각 그룹에 할당된 여부를 나타내는 변수 배열 - * @param numGroups 총 그룹의 수 - * @param totalStudentCount 조직 내의 총 학생 수 - * @param studentIdToIndex 학생 ID와 이를 배열 인덱스로 매핑하는 맵 - * @return 그룹 구성과 멤버 정보를 담은 AutoGroupMatchingResponse 리스트 - */ - private List extractSolution( - Variable[][] x, int numGroups, int totalStudentCount, - Map studentIdToIndex) { + // 모든 그룹이 최소 크기 요구사항을 충족하도록 보장합니다. + for (List group : groups) { + while (group.size() < minGroupSize && !unassignedStudents.isEmpty()) { + // 그룹 크기가 최소 크기보다 작고 할당되지 않은 학생이 있으면 + // unassignedStudents 리스트에서 학생을 제거하고 그룹에 추가합니다. + Long student = unassignedStudents.removeFirst(); + group.add(student); + assignedStudents.add(student); + } + } - // 최종 그룹 구성과 멤버 정보를 담을 리스트를 초기화 - List groupResponses = new ArrayList<>(); + // 최대 그룹 크기를 초과하는 그룹에서 초과 멤버를 재배치합니다. + for (List group : groups) { + while (group.size() > maxGroupSize) { + // 그룹 크기가 최대 크기보다 크면 그룹의 마지막 학생을 제거하고 + // unassignedStudents 리스트에 추가합니다. + Long student = group.removeLast(); + unassignedStudents.add(student); + assignedStudents.remove(student); + } + } - // 각 그룹에 대해 반복 - for (int j = 0; j < numGroups; j++) { - // 현재 그룹에 속한 멤버들을 저장할 리스트를 초기화 - List members = new ArrayList<>(); - - // 각 학생에 대해 반복 - for (int i = 0; i < totalStudentCount; i++) { - // 학생 i가 그룹 j에 할당된 경우 - if (x[i][j].getValue().intValue() == 1) { - // 배열 인덱스를 사용해 학생 ID를 조회 - Long studentId = getKeyByValue(studentIdToIndex, i); - - // 학생 ID가 존재하는 경우 - if (studentId != null) { - // 학생 ID로 데이터베이스에서 Member 객체를 조회 - Member member = memberRepository.findById(studentId).orElse(null); - - // Member 객체가 존재하는 경우 - if (member != null) { - // Member 객체를 MemberSimpleDTO로 변환 - MemberSimpleDTO memberDto = memberMapper.memberToMemberSimpleDTO( - member); - - // 멤버 리스트에 추가 - members.add(memberDto); - } - } - } + // 남아있는 할당되지 않은 학생들을 공간이 있는 그룹에 배치합니다. + for (List group : groups) { + while (group.size() < maxGroupSize && !unassignedStudents.isEmpty()) { + // 그룹 크기가 최대 크기보다 작고 할당되지 않은 학생이 있으면 + // unassignedStudents 리스트에서 학생을 제거하고 그룹에 추가합니다. + Long student = unassignedStudents.removeFirst(); + group.add(student); + assignedStudents.add(student); } - // 현재 그룹의 멤버 정보를 포함한 응답 객체를 생성하여 리스트에 추가 - groupResponses.add(AutoGroupMatchingResponse.builder() - .members(members) - .headCount(members.size()) - .build()); } - // 최종 그룹 구성과 멤버 정보를 담은 리스트를 반환 - return groupResponses; } /** - * 최적화 모델의 결과를 출력하는 함수입니다. 각 그룹의 구성과 그룹별 친밀도 점수를 출력하여, 어떻게 학생들이 그룹화되었는지 보여줍니다. + * 주어진 그룹 목록을 기반으로 AutoGroupMatchingResponse 객체의 리스트를 빌드합니다. * - * @param x 각 학생이 각 그룹에 할당된 여부를 나타내는 변수 배열 - * @param numGroups 총 그룹의 수 - * @param totalStudentCount 조직 내의 총 학생 수 - * @param studentIdToIndex 학생 ID와 이를 배열 인덱스로 매핑하는 맵 - * @param relationshipMatrix 학생 간의 친밀도 점수를 저장한 행렬 + * @param groups 학생 ID로 구성된 그룹 리스트 + * @return 각 그룹에 해당하는 AutoGroupMatchingResponse 객체의 리스트 */ - private void printSolution(Variable[][] x, int numGroups, int totalStudentCount, - Map studentIdToIndex, double[][] relationshipMatrix) { - log.info("Solution:"); - double totalScore = 0; // 모든 그룹의 총 친밀도 점수를 저장할 변수 + private List buildResponse(List> groups) { + // 결과 응답을 저장할 리스트를 초기화 + List responses = new ArrayList<>(); // 각 그룹에 대해 반복 - for (int j = 0; j < numGroups; j++) { - log.info("Group {} : ", (j + 1)); // 그룹 번호 출력 - double groupScore = 0; // 해당 그룹의 친밀도 점수를 계산할 변수 - - // 해당 그룹에 속한 모든 학생에 대해 반복 - for (int i = 0; i < totalStudentCount; i++) { - if (x[i][j].getValue().intValue() == 1) { // 학생 i가 그룹 j에 할당된 경우 - long studentId = getKeyByValue(studentIdToIndex, i); // 학생 ID 조회 - log.info("Student ID: {} ", studentId); // 학생 ID 출력 - - // 그룹 내 다른 학생들과의 친밀도 점수 합산 - for (int k = 0; k < totalStudentCount; k++) { - // 다른 학생 k도 같은 그룹에 할당된 경우 - if (i != k && x[k][j].getValue().intValue() == 1) { - // i와 k의 친밀도 점수를 groupScore 에 더함 - groupScore += relationshipMatrix[i][k]; - } - } - } - } - totalScore += groupScore; // 그룹 점수를 총 점수에 추가 - log.info(" Group Score: {}", groupScore); // 그룹별 친밀도 점수 출력 + for (List group : groups) { + // 현재 그룹에 속한 멤버들의 정보를 저장할 리스트를 초기화 + List members = group.stream() + // 멤버 ID를 사용하여 데이터베이스에서 멤버 객체를 조회 + .map(id -> memberRepository.findById(id).orElse(null)) + // 조회된 멤버 객체가 null 이 아닌 경우에만 필터링 + .filter(Objects::nonNull) + // 멤버 객체를 MemberSimpleDTO 객체로 변환 + .map(memberMapper::memberToMemberSimpleDTO) + // 변환된 DTO 객체들을 리스트로 수집 + .collect(Collectors.toList()); + + // 현재 그룹의 멤버 리스트와 멤버 수를 포함한 응답 객체를 생성 + responses.add(new AutoGroupMatchingResponse(members, members.size())); } - log.info("Total Score: {}", totalScore); // 모든 그룹의 총 친밀도 점수 출력 + + // 모든 그룹에 대한 응답 리스트를 반환 + return responses; } + /** - * 맵에서 주어진 값에 해당하는 키를 찾아 반환합니다. + * 각 그룹의 구성원과 해당 그룹의 총 친밀도 점수를 로그에 기록합니다. * - * @param map 키와 값을 저장하고 있는 맵 - * @param value 찾고자 하는 값 - * @return 찾은 키, 없으면 null 반환 + * @param groups 각 그룹의 학생 ID 리스트 + * @param relationshipMatrix 학생 간의 친밀도 점수를 저장한 행렬 + * @param studentIdToIndex 학생 ID를 배열 인덱스로 매핑하는 맵 */ - private Long getKeyByValue(Map map, Integer value) { - for (Map.Entry entry : map.entrySet()) { - if (Objects.equals(value, entry.getValue())) { - return entry.getKey(); + private void logGroupResults(List> groups, + double[][] relationshipMatrix, + Map studentIdToIndex) { + + // 모든 그룹에 대해 반복 + for (int i = 0; i < groups.size(); i++) { + // 현재 그룹을 가져온다. + List group = groups.get(i); + + // 현재 그룹의 구성원들을 로그에 기록 + log.info("Group {}: {}", i + 1, group); + + // 그룹의 총 친밀도 점수를 저장할 변수를 초기화 + double groupScore = 0.0; + + // 그룹 내 모든 학생 쌍에 대해 반복 + for (int j = 0; j < group.size(); j++) { + for (int k = j + 1; k < group.size(); k++) { + // 두 학생의 인덱스를 가져온다. + Integer index1 = studentIdToIndex.get(group.get(j)); + Integer index2 = studentIdToIndex.get(group.get(k)); + + // 인덱스가 null이 아닌 경우 친밀도 점수를 추가 + if (index1 != null && index2 != null) { + groupScore += relationshipMatrix[index1][index2]; + } + } } + // 현재 그룹의 총 친밀도 점수를 로그에 출력 + log.info("Group {} Score: {}", i + 1, groupScore); } - return null; } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java index b4611321..b07e406c 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/controller/GroupController.java @@ -57,8 +57,7 @@ public ResponseEntity> inviteMatchingRoom(String key, Lo public ResponseEntity>> getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest) { List autoGroupMatchingResponse = -// groupService.getGroupMatching(autoGroupMatchingRequest); - groupService.testMethod(autoGroupMatchingRequest); + groupService.getGroupMatching(autoGroupMatchingRequest); return ResponseEntity.ok(ResultResponse.success(autoGroupMatchingResponse)); } } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java index 28f22ec8..1de96286 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupService.java @@ -19,6 +19,4 @@ public interface GroupService { List getGroupMatching( AutoGroupMatchingRequest autoGroupMatchingRequest); - - List testMethod(AutoGroupMatchingRequest autoGroupMatchingRequest); } diff --git a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java index 526f7d71..cad074b6 100644 --- a/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java +++ b/backEnd/src/main/java/com/quiz/ourclass/domain/challenge/service/GroupServiceImpl.java @@ -158,7 +158,6 @@ private void updateGroupCount(Set members, long orgId, GroupType groupTy } } - @Transactional @Override public void deleteMatchingMember(String key, Long memberId) { @@ -210,51 +209,6 @@ public List getGroupMatching( return new ArrayList<>(); } - // TODO : 테스트 끝나고 해당 코드 지우기 - // 테스트를 위해서 강제 그룹 형성 - // 차성원(15), 홍유준(10), 정철주(9) - public List testMethod( - AutoGroupMatchingRequest autoGroupMatchingRequest) { - // 하드코딩된 멤버들을 포함하는 그룹을 생성 - List group1 = List.of(15L, 10L, 9L); - - List members = autoGroupMatchingRequest.members().stream() - .map(memberRepository::findById) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(member -> !group1.contains(member.getId())) - .map(memberMapper::memberToMemberSimpleDTO) - .collect(Collectors.toList()); - Collections.shuffle(members); - List> groups = new ArrayList<>(); - int groupSize = autoGroupMatchingRequest.minCount(); - int groupCount = members.size() / groupSize; - int left = members.size() % groupSize; - int addCount = left / groupCount; - int start = 0; - for (int i = 0; i < groupCount; i++) { - int size = groupSize; - if (left > 0) { - size += Math.min(left, addCount); - left -= addCount; - } - groups.add(members.subList(start, start + size)); - start += size; - } - List testGroup = group1.stream() - .map(memberRepository::findById) - .filter(Optional::isPresent) - .map(Optional::get) - .map(memberMapper::memberToMemberSimpleDTO) - .toList(); - groups.add(testGroup); - return groups.stream().map(group -> AutoGroupMatchingResponse.builder() - .members(group) - .headCount(group.size()) - .build()) - .toList(); - } - private List getRandomGroup( AutoGroupMatchingRequest autoGroupMatchingRequest) { List members = autoGroupMatchingRequest.members().stream()