From 95eb70c98c68d9715c943a62b9e6e9ddfdb12e12 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 2 Aug 2024 14:58:23 +0900 Subject: [PATCH 1/5] =?UTF-8?q?:recycle:=20[refact]=20/**=20=EB=B6=99?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gamegoo/dto/member/MemberRequest.java | 6 +- .../service/matching/MatchingService.java | 12 ++++ .../gamegoo/service/member/AuthService.java | 52 ++++++++++++++--- .../service/member/PasswordService.java | 13 +++++ .../service/member/ProfileService.java | 38 ++++++++++++- .../gamegoo/service/member/RiotService.java | 56 ++++++++++++++++--- .../com/gamegoo/util/CodeGeneratorUtil.java | 5 ++ src/main/java/com/gamegoo/util/JWTUtil.java | 5 ++ 8 files changed, 167 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gamegoo/dto/member/MemberRequest.java b/src/main/java/com/gamegoo/dto/member/MemberRequest.java index e348e112..e1761ca1 100644 --- a/src/main/java/com/gamegoo/dto/member/MemberRequest.java +++ b/src/main/java/com/gamegoo/dto/member/MemberRequest.java @@ -60,11 +60,11 @@ public static class PasswordRequestDTO { @Getter public static class PositionRequestDTO { - @Min(value = 1, message = "메인 포지션의 값은 1이상이어야 합니다.") + @Min(value = 0, message = "메인 포지션의 값은 0이상이어야 합니다.") @Max(value = 5, message = "메인 포지션의 값은 5이하이어야 합니다.") int mainP; - @Min(value = 1, message = "서브 포지션의 값은 1이상이어야 합니다.") - @Max(value = 5, message = "서브 포지션의 값은 1이상이어야합니다.") + @Min(value = 0, message = "서브 포지션의 값은 0이상이어야 합니다.") + @Max(value = 5, message = "서브 포지션의 값은 5이하이어야합니다.") int subP; } diff --git a/src/main/java/com/gamegoo/service/matching/MatchingService.java b/src/main/java/com/gamegoo/service/matching/MatchingService.java index 61f2c858..50106d87 100644 --- a/src/main/java/com/gamegoo/service/matching/MatchingService.java +++ b/src/main/java/com/gamegoo/service/matching/MatchingService.java @@ -19,6 +19,12 @@ public class MatchingService { private final MemberRepository memberRepository; private final MatchingRecordRepository matchingRecordRepository; + /** + * 매칭 정보 저장 + * + * @param request + * @param id + */ @Transactional public void save(MatchingRequest.SaveMatchingRequestDTO request, Long id) { // 회원 정보 불러오기 @@ -43,6 +49,12 @@ public void save(MatchingRequest.SaveMatchingRequestDTO request, Long id) { } + /** + * 매칭 상태(status) 수정 : 회원의 가장 최신 매칭만 상태 변경 가능 + * + * @param request + * @param id + */ @Transactional public void modify(MatchingRequest.ModifyMatchingRequestDTO request, Long id) { // 회원 정보 불러오기 diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index a7b20204..be2002ec 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -19,6 +19,7 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import javax.transaction.Transactional; import java.time.Duration; import java.time.LocalDateTime; @@ -31,7 +32,13 @@ public class AuthService { private final JavaMailSender javaMailSender; private final JWTUtil jwtUtil; - // 회원가입 로직 + /** + * RIOT 제외한 회원 정보 저장 (회원가입) + * + * @param email + * @param password + */ + @Transactional public void joinMember(String email, String password) { // 중복 확인하기 @@ -53,7 +60,12 @@ public void joinMember(String email, String password) { memberRepository.save(member); } - //이메일 인증코드 전송 + /** + * 이메일 인증코드 발송 & 이메일 전송 기록 저장 + * + * @param email + */ + @Transactional public void sendEmail(String email) { // 중복 확인하기 boolean isPresent = memberRepository.findByEmail(email).isPresent(); @@ -76,7 +88,13 @@ public void sendEmail(String email) { emailVerifyRecordRepository.save(emailVerifyRecord); } - // jwt refresh 토큰 검증 + /** + * jwt refresh 토큰 검증 + * + * @param refresh_token + * @return + */ + @Transactional public MemberResponse.RefreshTokenResponseDTO verifyRefreshToken(String refresh_token) { // refresh Token 검증하기 Member member = memberRepository.findByRefreshToken(refresh_token) @@ -96,7 +114,12 @@ public MemberResponse.RefreshTokenResponseDTO verifyRefreshToken(String refresh_ return new MemberResponse.RefreshTokenResponseDTO(access_token, new_refresh_token); } - // 이메일 인증코드 검증 + /** + * 이메일 인증코드 검증 + * + * @param email + * @param code + */ public void verifyEmail(String email, String code) { // 이메일로 보낸 인증 코드 중 가장 최근의 데이터를 불러옴 EmailVerifyRecord emailVerifyRecord = emailVerifyRecordRepository.findByEmailOrderByUpdatedAtDesc(email, PageRequest.of(0, 1)) @@ -123,7 +146,12 @@ public void verifyEmail(String email, String code) { } } - // 메일 전송하는 메소드 + /** + * Gmail 발송 + * + * @param email + * @param certificationNumber + */ private void sendEmailInternal(String email, String certificationNumber) { try { MimeMessage message = javaMailSender.createMimeMessage(); @@ -142,7 +170,12 @@ private void sendEmailInternal(String email, String certificationNumber) { } } - // 메일 내용 + /** + * 메일 내용 편집 + * + * @param certificationNumber + * @return + */ private String getCertificationMessage(String certificationNumber) { String certificationMessage = ""; certificationMessage += "

[GAMEGOO 인증메일]

"; @@ -151,7 +184,12 @@ private String getCertificationMessage(String certificationNumber) { return certificationMessage; } - // 로그아웃 + /** + * refresh 토큰 DB에서 삭제 (로그아웃) + * + * @param id + */ + @Transactional public void logoutMember(Long id) { Member member = memberRepository.findById(id).orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); diff --git a/src/main/java/com/gamegoo/service/member/PasswordService.java b/src/main/java/com/gamegoo/service/member/PasswordService.java index 028fe536..afe26163 100644 --- a/src/main/java/com/gamegoo/service/member/PasswordService.java +++ b/src/main/java/com/gamegoo/service/member/PasswordService.java @@ -15,12 +15,25 @@ public class PasswordService { private final MemberRepository memberRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; + /** + * 비밀번호가 맞는지 확인 + * + * @param userId + * @param password + * @return + */ public boolean checkPasswordById(Long userId, String password) { return memberRepository.findById(userId) .map(member -> bCryptPasswordEncoder.matches(password, member.getPassword())) .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); } + /** + * 비밀번호 수정 + * + * @param userId + * @param newPassword + */ public void updatePassword(Long userId, String newPassword) { // jwt 토큰으로 멤버 찾기 Member member = memberRepository.findById(userId) diff --git a/src/main/java/com/gamegoo/service/member/ProfileService.java b/src/main/java/com/gamegoo/service/member/ProfileService.java index f7b30cb0..1a2519a8 100644 --- a/src/main/java/com/gamegoo/service/member/ProfileService.java +++ b/src/main/java/com/gamegoo/service/member/ProfileService.java @@ -23,6 +23,13 @@ public class ProfileService { private final GameStyleRepository gameStyleRepository; private final MemberGameStyleRepository memberGameStyleRepository; + /** + * MemberGameStyle 데이터 추가 : 회원에 따른 게임 스타일 정보 저장하기 + * + * @param request + * @param memberId + * @return + */ @Transactional public List addMemberGameStyles(MemberRequest.GameStyleRequestDTO request, Long memberId) { // 회원 엔티티 조회 @@ -66,6 +73,12 @@ public List addMemberGameStyles(MemberRequest.GameStyleRequestD return member.getMemberGameStyleList(); } + /** + * 회원 탈퇴 처리 + * + * @param userId + */ + @Transactional public void deleteMember(Long userId) { Member member = memberRepository.findById(userId) .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); @@ -75,8 +88,16 @@ public void deleteMember(Long userId) { memberRepository.save(member); } + /** + * 메인 포지션, 서브 포지션 수정 + * + * @param userId + * @param mainP + * @param subP + */ + @Transactional public void modifyPosition(Long userId, int mainP, int subP) { - if (mainP <= 0 || subP <= 0 || mainP > 5 || subP > 5) { + if (mainP < 0 || subP < 0 || mainP > 5 || subP > 5) { throw new MemberHandler(ErrorStatus.POSITION_NOT_FOUND); } @@ -88,6 +109,13 @@ public void modifyPosition(Long userId, int mainP, int subP) { memberRepository.save(member); } + /** + * 프로필 이미지 수정 + * + * @param userId + * @param profileImage + */ + @Transactional public void modifyProfileImage(Long userId, String profileImage) { if (profileImage.length() > 30) { throw new MemberHandler(ErrorStatus.PROFILE_IMAGE_BAD_REQUEST); @@ -100,7 +128,13 @@ public void modifyProfileImage(Long userId, String profileImage) { memberRepository.save(member); } - @Transactional + /** + * 회원 정보 조회 + * + * @param memberId + * @return + */ + @Transactional(readOnly = true) public Member findMember(Long memberId) { return memberRepository.findById(memberId) .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); diff --git a/src/main/java/com/gamegoo/service/member/RiotService.java b/src/main/java/com/gamegoo/service/member/RiotService.java index a0231f23..c2a2c3b4 100644 --- a/src/main/java/com/gamegoo/service/member/RiotService.java +++ b/src/main/java/com/gamegoo/service/member/RiotService.java @@ -15,6 +15,7 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +import javax.transaction.Transactional; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -39,6 +40,15 @@ public class RiotService { // Riot GameName으로 DB에 데이터 저장하기 + + /** + * RIOT 연동 정보 DB에 저장 : GameName, Tag로 Tier, Rank, 승률, 선호 챔피언 3개 조회하기 & DB에 저장 + * + * @param gameName + * @param tag + * @param email + */ + @Transactional public void updateMemberRiotInfo(String gameName, String tag, String email) { // emaiL 로 DB에서 member 가져오기 Member member = memberRepository.findByEmail(email).orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); @@ -118,14 +128,19 @@ public void updateMemberRiotInfo(String gameName, String tag, String email) { memberChampionRepository.save(memberChampion); }); } catch (Exception e) { - System.out.println(e.getMessage()); throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); } } - // RiotAPI - request:game_name, tag / response : puuid - private String getRiotPuuid(String game_name, String tag) { - String url = String.format(RIOT_ACCOUNT_API_URL_TEMPLATE, game_name, tag, riotAPIKey); + /** + * RiotAPI 1 gameName, tag으로 puuid 조회 + * + * @param gameName + * @param tag + * @return + */ + private String getRiotPuuid(String gameName, String tag) { + String url = String.format(RIOT_ACCOUNT_API_URL_TEMPLATE, gameName, tag, riotAPIKey); RiotResponse.RiotAccountDTO accountResponse = null; try { accountResponse = restTemplate.getForObject(url, RiotResponse.RiotAccountDTO.class); @@ -144,7 +159,12 @@ private String getRiotPuuid(String game_name, String tag) { } - // RiotAPI - request:puuid / response : encryptedSummonerId + /** + * RiotAPI 2 - puuid로 encryptedSummonerId 조회 + * + * @param puuid + * @return + */ private String getSummonerId(String puuid) { String summonerUrl = String.format(RIOT_SUMMONER_API_URL_TEMPLATE, puuid, riotAPIKey); @@ -162,7 +182,14 @@ private String getSummonerId(String puuid) { return summonerResponse.getId(); } - // RiotAPI - request: encryptedSummonerId / response : tier, rank + /** + * RiotAPI 3 - encryptedSummonerId로 tier, rank, winrate 조회 + * + * @param member + * @param gameName + * @param encryptedSummonerId + * @param tag + */ private void updateMemberWithLeagueInfo(Member member, String gameName, String encryptedSummonerId, String tag) { // 3. account id로 티어, 랭크, 불러오기 String leagueUrl = String.format(RIOT_LEAGUE_API_URL_TEMPLATE, encryptedSummonerId, riotAPIKey); @@ -193,7 +220,13 @@ private void updateMemberWithLeagueInfo(Member member, String gameName, String e member.setTag(tag); } - // RiotAPI - request: puuid / response : matchId + /** + * RiotAPI 4 - puuid로 최근 매칭 20개의 matchId 가져오기 + * + * @param puuid + * @param count + * @return + */ private List getRecentMatchIds(String puuid, int count) { // 최근 매칭 ID 20개 가져오기 String matchUrl = String.format(RIOT_MATCH_API_URL_TEMPLATE, puuid, count, riotAPIKey); @@ -206,7 +239,14 @@ private List getRecentMatchIds(String puuid, int count) { return Arrays.asList(matchIds); } - // RiotAPI - request: matchId / response : championId + + /** + * RiotAPI 5 - matchId로 선호 챔피언 데이터 조회 + * + * @param matchId + * @param gameName + * @return + */ private Integer getChampionIdFromMatch(String matchId, String gameName) { // 매치 정보 가져오기 String matchInfoUrl = String.format(RIOT_MATCH_INFO_API_URL_TEMPLATE, matchId, riotAPIKey); diff --git a/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java b/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java index d145fff0..c92a3bd0 100644 --- a/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java +++ b/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java @@ -8,6 +8,11 @@ public class CodeGeneratorUtil { private static final SecureRandom random = new SecureRandom(); private static final int CODE_LENGTH = 5; + /** + * 이메일 인증에 사용하는 메소드 : 랜덤 코드 만들기 + * + * @return + */ public static String generateRandomCode() { StringBuilder code = new StringBuilder(CODE_LENGTH); for (int i = 0; i < CODE_LENGTH; i++) { diff --git a/src/main/java/com/gamegoo/util/JWTUtil.java b/src/main/java/com/gamegoo/util/JWTUtil.java index 3a70bde2..12d276f4 100644 --- a/src/main/java/com/gamegoo/util/JWTUtil.java +++ b/src/main/java/com/gamegoo/util/JWTUtil.java @@ -48,6 +48,11 @@ public String createJwt(Long expiredMs) { .compact(); } + /** + * jwt 토큰에 담겨있는 사용자 Id 조회 + * + * @return + */ public static Long getCurrentUserId() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); From 6a204dc0ac69168dd02d8af3e58b46d1600f0121 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 2 Aug 2024 20:04:18 +0900 Subject: [PATCH 2/5] =?UTF-8?q?:bug:=20[fix]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gamegoo/domain/QMatchingRecord.java | 12 +- .../apiPayload/code/status/ErrorStatus.java | 4 +- .../controller/member/AuthController.java | 8 +- .../controller/member/RiotController.java | 13 +- .../domain/champion/MemberChampion.java | 5 +- .../com/gamegoo/dto/member/MemberRequest.java | 6 +- .../gamegoo/service/member/AuthService.java | 67 ++++- .../gamegoo/service/member/RiotService.java | 252 +----------------- src/main/java/com/gamegoo/util/RiotUtil.java | 220 +++++++++++++++ 9 files changed, 322 insertions(+), 265 deletions(-) create mode 100644 src/main/java/com/gamegoo/util/RiotUtil.java diff --git a/src/main/generated/com/gamegoo/domain/QMatchingRecord.java b/src/main/generated/com/gamegoo/domain/QMatchingRecord.java index 27dda445..4d889e5c 100644 --- a/src/main/generated/com/gamegoo/domain/QMatchingRecord.java +++ b/src/main/generated/com/gamegoo/domain/QMatchingRecord.java @@ -31,23 +31,29 @@ public class QMatchingRecord extends EntityPathBase { public final NumberPath id = createNumber("id", Long.class); - public final BooleanPath isComplete = createBoolean("isComplete"); - public final NumberPath mainPosition = createNumber("mainPosition", Integer.class); + public final StringPath matchingType = createString("matchingType"); + public final QMember member; public final BooleanPath mike = createBoolean("mike"); + public final StringPath rank = createString("rank"); + + public final StringPath status = createString("status"); + public final NumberPath subPosition = createNumber("subPosition", Integer.class); - public final NumberPath tier = createNumber("tier", Integer.class); + public final StringPath tier = createString("tier"); //inherited public final DateTimePath updatedAt = _super.updatedAt; public final NumberPath wantPosition = createNumber("wantPosition", Integer.class); + public final NumberPath winRate = createNumber("winRate", Double.class); + public QMatchingRecord(String variable) { this(MatchingRecord.class, forVariable(variable), INITS); } diff --git a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java index d2b43f0f..96718460 100644 --- a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java @@ -53,9 +53,11 @@ public enum ErrorStatus implements BaseErrorCode { MATCHING_STATUS_BAD_REQUEST(HttpStatus.BAD_REQUEST, "MATCH400", "status는 SUCCESS, QUIT 둘 중 하나로만 변경이 가능합니다."), MATCHING_NOT_FOUND(HttpStatus.NOT_FOUND, "MATCH404", "해당 사용자의 매칭 정보가 없습니다."), + // Riot 관련 에러 RIOT_NOT_FOUND(HttpStatus.NOT_FOUND, "RIOT404", "해당 Riot 계정이 존재하지 않습니다."), - RIOT_MATCH_NOT_FOUND(HttpStatus.NOT_FOUND, "RIOTMATCH404", "해당 Riot 계정의 매칭을 불러오는 도중 에러가 발생했습니다."), + RIOT_MATCH_NOT_FOUND(HttpStatus.NOT_FOUND, "RIOTMATCH404", "해당 Riot 계정의 매칭을 불러오는 도중 에러가 발생했습니다. 최근 100판 이내 이벤트 매칭 제외, 일반 매칭(일반게임,랭크게임,칼바람)을 많이 한 계정으로 다시 시도하세요."), + RIOT_PREFER_CHAMPION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "RIOTCHAMPION500", "선호 챔피언을 연동하는 도중 에러가 발생했습니다"), CHAMPION_NOT_FOUND(HttpStatus.NOT_FOUND, "CHAMPION404", "해당 챔피언이 존재하지 않습니다."), RIOT_MEMBER_CONFLICT(HttpStatus.CONFLICT, "RIOT409", "해당 이메일 계정은 이미 다른 RIOT 계정과 연동되었습니다."), RIOT_ACCOUNT_CONFLICT(HttpStatus.CONFLICT, "RIOT409", "해당 RIOT 계정은 이미 다른 이메일과 연동되어있습니다."), diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index 54fd29d7..64ce5808 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -29,7 +29,11 @@ public ApiResponse joinMember( @RequestBody @Valid MemberRequest.JoinRequestDTO joinRequestDTO) { String email = joinRequestDTO.getEmail(); String password = joinRequestDTO.getPassword(); - authService.joinMember(email, password); + String gameName = joinRequestDTO.getGameName(); + String tag = joinRequestDTO.getTag(); + + authService.joinMember(email, password, gameName, tag); + return ApiResponse.onSuccess("회원가입에 성공했습니다."); } @@ -70,7 +74,7 @@ public ApiResponse refreshTokens( public ApiResponse logoutMember() { Long memberId = JWTUtil.getCurrentUserId(); authService.logoutMember(memberId); - + return ApiResponse.onSuccess("로그아웃에 성공했습니다"); } } diff --git a/src/main/java/com/gamegoo/controller/member/RiotController.java b/src/main/java/com/gamegoo/controller/member/RiotController.java index 7114a756..2ff399f6 100644 --- a/src/main/java/com/gamegoo/controller/member/RiotController.java +++ b/src/main/java/com/gamegoo/controller/member/RiotController.java @@ -4,7 +4,6 @@ import com.gamegoo.dto.member.MemberRequest; import com.gamegoo.service.member.RiotService; import io.swagger.v3.oas.annotations.Operation; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; @@ -12,6 +11,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; + @RestController @RequiredArgsConstructor @RequestMapping("/v1/member") @@ -21,16 +22,16 @@ public class RiotController { private final RiotService riotService; @PostMapping("/riot") - @Operation(summary = "회원가입 시 riot API를 통해 소환사명을 인증하는 API", description = "API for verifying by riot API") + @Operation(summary = "실제 존재하는 Riot 계정인지 검증하는 API", description = "API for verifying account by riot API") public ApiResponse VerifyRiot( - @RequestBody @Valid MemberRequest.verifyRiotRequestDTO verifyRiotRequestDTO) { + @RequestBody @Valid MemberRequest.verifyRiotRequestDTO verifyRiotRequestDTO) { String gameName = verifyRiotRequestDTO.getGameName(); String tag = verifyRiotRequestDTO.getTag(); - String email = verifyRiotRequestDTO.getEmail(); - riotService.updateMemberRiotInfo(gameName, tag, email); + riotService.verifyRiot(gameName, tag); - return ApiResponse.onSuccess("Riot 계정이 연동되었습니다."); + return ApiResponse.onSuccess("해당 Riot 계정은 존재합니다."); } + } diff --git a/src/main/java/com/gamegoo/domain/champion/MemberChampion.java b/src/main/java/com/gamegoo/domain/champion/MemberChampion.java index 8715ad6f..7ef4ecd0 100644 --- a/src/main/java/com/gamegoo/domain/champion/MemberChampion.java +++ b/src/main/java/com/gamegoo/domain/champion/MemberChampion.java @@ -5,6 +5,7 @@ import lombok.*; import javax.persistence.*; +import java.util.ArrayList; @Getter @Entity @@ -32,8 +33,10 @@ public void setMember(Member member) { this.member.getMemberChampionList().remove(this); } this.member = member; + if (this.member.getMemberChampionList() == null) { + this.member.setMemberChampionList(new ArrayList<>()); + } this.member.getMemberChampionList().add(this); - } public void removeMember(Member member) { diff --git a/src/main/java/com/gamegoo/dto/member/MemberRequest.java b/src/main/java/com/gamegoo/dto/member/MemberRequest.java index e1761ca1..8934ce91 100644 --- a/src/main/java/com/gamegoo/dto/member/MemberRequest.java +++ b/src/main/java/com/gamegoo/dto/member/MemberRequest.java @@ -47,6 +47,10 @@ public static class JoinRequestDTO { String email; @NotBlank(message = "password는 비워둘 수 없습니다.") String password; + @NotBlank(message = "gameName 값은 비워둘 수 없습니다.") + String gameName; + @NotBlank(message = "tag 값은 비워둘 수 없습니다.") + String tag; } @@ -82,8 +86,6 @@ public static class RefreshTokenRequestDTO { @Getter public static class verifyRiotRequestDTO { - @NotBlank(message = "email 값은 비워둘 수 없습니다.") - String email; @NotBlank(message = "gameName 값은 비워둘 수 없습니다.") String gameName; @NotBlank(message = "tag 값은 비워둘 수 없습니다.") diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index be2002ec..18edbdd9 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -4,12 +4,17 @@ import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.EmailVerifyRecord; import com.gamegoo.domain.Member; +import com.gamegoo.domain.champion.Champion; +import com.gamegoo.domain.champion.MemberChampion; import com.gamegoo.domain.enums.LoginType; import com.gamegoo.dto.member.MemberResponse; +import com.gamegoo.repository.member.ChampionRepository; import com.gamegoo.repository.member.EmailVerifyRecordRepository; +import com.gamegoo.repository.member.MemberChampionRepository; import com.gamegoo.repository.member.MemberRepository; import com.gamegoo.util.CodeGeneratorUtil; import com.gamegoo.util.JWTUtil; +import com.gamegoo.util.RiotUtil; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.mail.javamail.JavaMailSender; @@ -22,32 +27,51 @@ import javax.transaction.Transactional; import java.time.Duration; import java.time.LocalDateTime; +import java.util.List; @Service @RequiredArgsConstructor public class AuthService { private final MemberRepository memberRepository; + private final ChampionRepository championRepository; + private final MemberChampionRepository memberChampionRepository; private final EmailVerifyRecordRepository emailVerifyRecordRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; private final JavaMailSender javaMailSender; private final JWTUtil jwtUtil; + private final RiotUtil riotUtil; /** - * RIOT 제외한 회원 정보 저장 (회원가입) + * 회원가입 : Riot 연동 포함 * * @param email * @param password + * @param gameName + * @param tag + * @return */ @Transactional - public void joinMember(String email, String password) { + public Member joinMember(String email, String password, String gameName, String tag) { - // 중복 확인하기 // 중복 확인하기 if (memberRepository.existsByEmail(email)) { throw new MemberHandler(ErrorStatus.MEMBER_CONFLICT); } - // DB에 넣을 정보 설정 + // puuid 조회 + String puuid = riotUtil.getRiotPuuid(gameName, tag); + + // 최근 선호 챔피언 3개 리스트 조회 + List top3Champions = null; + try { + top3Champions = riotUtil.getPreferChampionfromMatch(gameName, puuid); + } catch (Exception e) { + throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); + } + + // tier, rank, winrate + // DB 저장 + // 1. Riot 정보 제외 저장 Member member = Member.builder() .email(email) .password(bCryptPasswordEncoder.encode(password)) @@ -56,8 +80,43 @@ public void joinMember(String email, String password) { .blind(false) .build(); + + // 2. tier, rank, winrate 저장 + String encryptedSummonerId = riotUtil.getSummonerId(puuid); + riotUtil.addTierRankWinRate(member, gameName, encryptedSummonerId, tag); + + + // 3. 캐릭터와 유저 데이터 매핑해서 DB에 저장하기 + // (1) 해당 email을 가진 사용자의 정보가 MemberChampion 테이블에 있을 경우 제거 + if (member.getMemberChampionList() != null) { + member.getMemberChampionList() + .forEach(memberChampion -> { + memberChampion.removeMember(member); // 양방향 연관관계 제거 + memberChampionRepository.delete(memberChampion); + }); + + } + // DB에 저장 memberRepository.save(member); + + // (2) Champion id, Member id 엮어서 MemberChampion 테이블에 넣기 + top3Champions + .forEach(championId -> { + System.out.println(championId); + Champion champion = championRepository.findById(Long.valueOf(championId)) + .orElseThrow(() -> new MemberHandler(ErrorStatus.CHAMPION_NOT_FOUND)); + + MemberChampion memberChampion = MemberChampion.builder() + .champion(champion) + .build(); + + memberChampion.setMember(member); + memberChampionRepository.save(memberChampion); + }); + + + return member; } /** diff --git a/src/main/java/com/gamegoo/service/member/RiotService.java b/src/main/java/com/gamegoo/service/member/RiotService.java index c2a2c3b4..473d99a1 100644 --- a/src/main/java/com/gamegoo/service/member/RiotService.java +++ b/src/main/java/com/gamegoo/service/member/RiotService.java @@ -2,267 +2,27 @@ import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.apiPayload.exception.handler.MemberHandler; -import com.gamegoo.domain.Member; -import com.gamegoo.domain.champion.Champion; -import com.gamegoo.domain.champion.MemberChampion; -import com.gamegoo.dto.member.RiotResponse; -import com.gamegoo.repository.member.ChampionRepository; -import com.gamegoo.repository.member.MemberChampionRepository; -import com.gamegoo.repository.member.MemberRepository; +import com.gamegoo.util.RiotUtil; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import javax.transaction.Transactional; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class RiotService { - private final MemberRepository memberRepository; - private final ChampionRepository championRepository; - private final MemberChampionRepository memberChampionRepository; - private final RestTemplate restTemplate; - @Value("${spring.riot.api.key}") - private String riotAPIKey; + private final RiotUtil riotUtil; - private static final String RIOT_ACCOUNT_API_URL_TEMPLATE = "https://asia.api.riotgames.com/riot/account/v1/accounts/by-riot-id/%s/%s?api_key=%s"; - private static final String RIOT_SUMMONER_API_URL_TEMPLATE = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/%s?api_key=%s"; - private static final String RIOT_LEAGUE_API_URL_TEMPLATE = "https://kr.api.riotgames.com/lol/league/v4/entries/by-summoner/%s?api_key=%s"; - private static final String RIOT_MATCH_API_URL_TEMPLATE = "https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/%s/ids?start=0&count=%s&api_key=%s"; - private static final String RIOT_MATCH_INFO_API_URL_TEMPLATE = "https://asia.api.riotgames.com/lol/match/v5/matches/%s?api_key=%s"; - - - // Riot GameName으로 DB에 데이터 저장하기 - - /** - * RIOT 연동 정보 DB에 저장 : GameName, Tag로 Tier, Rank, 승률, 선호 챔피언 3개 조회하기 & DB에 저장 - * - * @param gameName - * @param tag - * @param email - */ @Transactional - public void updateMemberRiotInfo(String gameName, String tag, String email) { - // emaiL 로 DB에서 member 가져오기 - Member member = memberRepository.findByEmail(email).orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); - - // 해당 Request에 있는 Email이 이미 DB의 다른 계정과 연동되었을 경우 - if (member.getGameName() != null) { - throw new MemberHandler(ErrorStatus.RIOT_MEMBER_CONFLICT); - } - - // 해당 Request에 있는 GameName이 이미 DB의 다른 email과 연동되었을 경우 - if (memberRepository.findByGameName(gameName).isPresent()) { - throw new MemberHandler(ErrorStatus.RIOT_ACCOUNT_CONFLICT); - } - - /* 티어, 랭킹 정보 불러오기 */ - // 1. game_name, tag로 사용자 puuid 얻기 - String puuid = getRiotPuuid(gameName, tag); - // 2. puuid를 통해 encryptedsummonerid 얻기 - String encryptedSummonerId = getSummonerId(puuid); - // 3. tier, rank 정보 DB에 저장하기 - updateMemberWithLeagueInfo(member, gameName, encryptedSummonerId, tag); - memberRepository.save(member); - - /* 최근 사용한 챔피언 3개 찾기 */ - List recentChampionIds = null; - int count = 20; - - try { - while ((recentChampionIds == null || recentChampionIds.size() < 3) && count <= 100) { - List recentMatchIds = getRecentMatchIds(puuid, count); - - recentChampionIds = recentMatchIds.stream() - .map(matchId -> getChampionIdFromMatch(matchId, gameName)) - .filter(championId -> championId < 1000) - .toList(); - - if (recentChampionIds.size() < 3) { - count += 10; // count를 10 증가시켜서 다시 시도 - } - } - - if (recentChampionIds.size() < 3) { - throw new MemberHandler(ErrorStatus.RIOT_INSUFFICIENT_MATCHES); - } - - // 3. 해당 캐릭터 중 많이 사용한 캐릭터 세 개 저장하기 - // (1) 챔피언 사용 빈도 계산 - Map championFrequency = recentChampionIds.stream() - .collect(Collectors.groupingBy(championId -> championId, Collectors.counting())); - - // (2) 빈도를 기준으로 정렬하여 상위 3개의 챔피언 추출 - List top3Champions = championFrequency.entrySet().stream() - .sorted(Map.Entry.comparingByValue().reversed()) - .limit(3) - .map(Map.Entry::getKey) - .toList(); - - // 3. 캐릭터와 유저 데이터 매핑해서 DB에 저장하기 - // (1) 해당 email을 가진 사용자의 정보가 MemberChampion 테이블에 있을 경우 제거 - member.getMemberChampionList() - .forEach(memberChampion -> { - memberChampion.removeMember(member); // 양방향 연관관계 제거 - memberChampionRepository.delete(memberChampion); - }); - - // (2) Champion id, Member id 엮어서 MemberChampion 테이블에 넣기 - top3Champions - .forEach(championId -> { - Champion champion = championRepository.findById(Long.valueOf(championId)) - .orElseThrow(() -> new MemberHandler(ErrorStatus.CHAMPION_NOT_FOUND)); - - MemberChampion memberChampion = MemberChampion.builder() - .champion(champion) - .build(); - - memberChampion.setMember(member); - memberChampionRepository.save(memberChampion); - }); - } catch (Exception e) { - throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); - } - } - - /** - * RiotAPI 1 gameName, tag으로 puuid 조회 - * - * @param gameName - * @param tag - * @return - */ - private String getRiotPuuid(String gameName, String tag) { - String url = String.format(RIOT_ACCOUNT_API_URL_TEMPLATE, gameName, tag, riotAPIKey); - RiotResponse.RiotAccountDTO accountResponse = null; - try { - accountResponse = restTemplate.getForObject(url, RiotResponse.RiotAccountDTO.class); - } catch (HttpClientErrorException e) { - if (e.getStatusCode().value() == 404) { - throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); - } - throw new MemberHandler(ErrorStatus.RIOT_ERROR); - } - - if (accountResponse == null) { - throw new MemberHandler(ErrorStatus.RIOT_ERROR); - } - - return accountResponse.getPuuid(); + public String verifyRiot(String gameName, String tag) { + String riotPuuid = riotUtil.getRiotPuuid(gameName, tag); - } - - /** - * RiotAPI 2 - puuid로 encryptedSummonerId 조회 - * - * @param puuid - * @return - */ - private String getSummonerId(String puuid) { - - String summonerUrl = String.format(RIOT_SUMMONER_API_URL_TEMPLATE, puuid, riotAPIKey); - RiotResponse.RiotSummonerDTO summonerResponse = null; - try { - summonerResponse = restTemplate.getForObject(summonerUrl, RiotResponse.RiotSummonerDTO.class); - - if (summonerResponse == null) { - throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); - } - } catch (Exception e) { - throw new MemberHandler(ErrorStatus.RIOT_ERROR); - } - - return summonerResponse.getId(); - } - - /** - * RiotAPI 3 - encryptedSummonerId로 tier, rank, winrate 조회 - * - * @param member - * @param gameName - * @param encryptedSummonerId - * @param tag - */ - private void updateMemberWithLeagueInfo(Member member, String gameName, String encryptedSummonerId, String tag) { - // 3. account id로 티어, 랭크, 불러오기 - String leagueUrl = String.format(RIOT_LEAGUE_API_URL_TEMPLATE, encryptedSummonerId, riotAPIKey); - RiotResponse.RiotLeagueEntryDTO[] leagueEntries = restTemplate.getForObject(leagueUrl, RiotResponse.RiotLeagueEntryDTO[].class); - - if (leagueEntries == null) { + if (riotPuuid == null) { throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); } - for (RiotResponse.RiotLeagueEntryDTO entry : leagueEntries) { - // 솔랭일 경우에만 저장 - if ("RANKED_SOLO_5x5".equals(entry.getQueueType())) { - int wins = entry.getWins(); - int losses = entry.getLosses(); - double winrate = (double) wins / (wins + losses); - winrate = Math.round(winrate * 1000) / 10.0; - - // DB에 저장 - member.setTier(entry.getTier()); - member.setRank(entry.getRank()); - member.setWinRate(winrate); - break; - } - } - - // 솔랭을 하지 않는 유저는 gameName만 저장 - member.setGameName(gameName); - member.setTag(tag); + return riotPuuid; } - /** - * RiotAPI 4 - puuid로 최근 매칭 20개의 matchId 가져오기 - * - * @param puuid - * @param count - * @return - */ - private List getRecentMatchIds(String puuid, int count) { - // 최근 매칭 ID 20개 가져오기 - String matchUrl = String.format(RIOT_MATCH_API_URL_TEMPLATE, puuid, count, riotAPIKey); - String[] matchIds = restTemplate.getForObject(matchUrl, String[].class); - - if (matchIds == null || matchIds.length == 0) { - throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); - } - - return Arrays.asList(matchIds); - } - - - /** - * RiotAPI 5 - matchId로 선호 챔피언 데이터 조회 - * - * @param matchId - * @param gameName - * @return - */ - private Integer getChampionIdFromMatch(String matchId, String gameName) { - // 매치 정보 가져오기 - String matchInfoUrl = String.format(RIOT_MATCH_INFO_API_URL_TEMPLATE, matchId, riotAPIKey); - RiotResponse.MatchDTO matchResponse = restTemplate.getForObject(matchInfoUrl, RiotResponse.MatchDTO.class); - - if (matchResponse == null || matchResponse.getInfo() == null || matchResponse.getInfo().getParticipants() == null) { - throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); - } - - // 참가자 정보에서 gameName과 일치하는 사용자의 champion ID 찾기 - return matchResponse.getInfo().getParticipants().stream() - .filter(participant -> gameName.equals(participant.getRiotIdGameName())) - .map(RiotResponse.ParticipantDTO::getChampionId) - .findFirst() - .orElseThrow(() -> new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND)); - } - - } diff --git a/src/main/java/com/gamegoo/util/RiotUtil.java b/src/main/java/com/gamegoo/util/RiotUtil.java new file mode 100644 index 00000000..3dc56a0f --- /dev/null +++ b/src/main/java/com/gamegoo/util/RiotUtil.java @@ -0,0 +1,220 @@ +package com.gamegoo.util; + +import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; +import com.gamegoo.domain.Member; +import com.gamegoo.dto.member.RiotResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import javax.transaction.Transactional; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class RiotUtil { + private final RestTemplate restTemplate; + @Value("${spring.riot.api.key}") + private String riotAPIKey; + + private static final String RIOT_ACCOUNT_API_URL_TEMPLATE = "https://asia.api.riotgames.com/riot/account/v1/accounts/by-riot-id/%s/%s?api_key=%s"; + private static final String RIOT_SUMMONER_API_URL_TEMPLATE = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/%s?api_key=%s"; + private static final String RIOT_LEAGUE_API_URL_TEMPLATE = "https://kr.api.riotgames.com/lol/league/v4/entries/by-summoner/%s?api_key=%s"; + private static final String RIOT_MATCH_API_URL_TEMPLATE = "https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/%s/ids?start=0&count=%s&api_key=%s"; + private static final String RIOT_MATCH_INFO_API_URL_TEMPLATE = "https://asia.api.riotgames.com/lol/match/v5/matches/%s?api_key=%s"; + + @Autowired + public RiotUtil(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + /** + * Riot API : 최근 선호 챔피언 3개 리스트 조회 + * + * @param gameName + * @param puuid + * @return + */ + @Transactional + public List getPreferChampionfromMatch(String gameName, String puuid) { + // 최근 플레이한 챔피언 리스트 조회 + List recentChampionIds = null; + int count = 20; + + try { + while ((recentChampionIds == null || recentChampionIds.size() < 3) && count <= 100) { + List recentMatchIds = getRecentMatchIds(puuid, count); + + recentChampionIds = recentMatchIds.stream() + .map(matchId -> getChampionIdFromMatch(matchId, gameName)) + .filter(championId -> championId < 1000) + .toList(); + + if (recentChampionIds.size() < 3) { + count += 10; // count를 10 증가시켜서 다시 시도 + } + } + } catch (Exception e) { + throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); + } + + if (recentChampionIds.size() < 3) { + throw new MemberHandler(ErrorStatus.RIOT_INSUFFICIENT_MATCHES); + } + + // 2. 해당 캐릭터 중 많이 사용한 캐릭터 세 개 저장하기 + // (1) 챔피언 사용 빈도 계산 + Map championFrequency = recentChampionIds.stream() + .collect(Collectors.groupingBy(championId -> championId, Collectors.counting())); + + // (2) 빈도를 기준으로 정렬하여 상위 3개의 챔피언 추출 + List top3Champions = championFrequency.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .limit(3) + .map(Map.Entry::getKey) + .toList(); + + if (top3Champions.isEmpty()) { + throw new MemberHandler(ErrorStatus.RIOT_INSUFFICIENT_MATCHES); + } + + return top3Champions; + } + + /** + * RiotAPI : gameName, tag으로 puuid 조회 + * + * @param gameName + * @param tag + * @return + */ + public String getRiotPuuid(String gameName, String tag) { + String url = String.format(RIOT_ACCOUNT_API_URL_TEMPLATE, gameName, tag, riotAPIKey); + RiotResponse.RiotAccountDTO accountResponse = null; + try { + accountResponse = restTemplate.getForObject(url, RiotResponse.RiotAccountDTO.class); + } catch (HttpClientErrorException e) { + if (e.getStatusCode().value() == 404) { + throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); + } + throw new MemberHandler(ErrorStatus.RIOT_ERROR); + } + + if (accountResponse == null) { + throw new MemberHandler(ErrorStatus.RIOT_ERROR); + } + + return accountResponse.getPuuid(); + } + + /** + * RiotAPI : puuid로 encryptedSummonerId 조회 + * + * @param puuid + * @return + */ + public String getSummonerId(String puuid) { + + String summonerUrl = String.format(RIOT_SUMMONER_API_URL_TEMPLATE, puuid, riotAPIKey); + RiotResponse.RiotSummonerDTO summonerResponse = null; + try { + summonerResponse = restTemplate.getForObject(summonerUrl, RiotResponse.RiotSummonerDTO.class); + + if (summonerResponse == null) { + throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); + } + } catch (Exception e) { + throw new MemberHandler(ErrorStatus.RIOT_ERROR); + } + + return summonerResponse.getId(); + } + + /** + * RiotAPI : encryptedSummonerId로 tier, rank, winrate 조회 + * + * @param member + * @param gameName + * @param encryptedSummonerId + * @param tag + */ + public void addTierRankWinRate(Member member, String gameName, String encryptedSummonerId, String tag) { + // account id로 티어, 랭크, 불러오기 + String leagueUrl = String.format(RIOT_LEAGUE_API_URL_TEMPLATE, encryptedSummonerId, riotAPIKey); + RiotResponse.RiotLeagueEntryDTO[] leagueEntries = restTemplate.getForObject(leagueUrl, RiotResponse.RiotLeagueEntryDTO[].class); + + if (leagueEntries == null) { + throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); + } + + for (RiotResponse.RiotLeagueEntryDTO entry : leagueEntries) { + // 솔랭일 경우에만 저장 + if ("RANKED_SOLO_5x5".equals(entry.getQueueType())) { + int wins = entry.getWins(); + int losses = entry.getLosses(); + double winrate = (double) wins / (wins + losses); + winrate = Math.round(winrate * 1000) / 10.0; + + // DB에 저장 + member.setTier(entry.getTier()); + member.setRank(entry.getRank()); + member.setWinRate(winrate); + break; + } + } + + // 솔랭을 하지 않는 유저는 gameName만 저장 + member.setGameName(gameName); + member.setTag(tag); + } + + /** + * RiotAPI : puuid로 최근 매칭 20개의 matchId 가져오기 + * + * @param puuid + * @param count + * @return + */ + private List getRecentMatchIds(String puuid, int count) { + // 최근 매칭 ID 20개 가져오기 + String matchUrl = String.format(RIOT_MATCH_API_URL_TEMPLATE, puuid, count, riotAPIKey); + String[] matchIds = restTemplate.getForObject(matchUrl, String[].class); + + if (matchIds == null || matchIds.length == 0) { + throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); + } + + return Arrays.asList(matchIds); + } + + + /** + * RiotAPI : matchId로 선호 챔피언 데이터 조회 + * + * @param matchId + * @param gameName + * @return + */ + public Integer getChampionIdFromMatch(String matchId, String gameName) { + // 매치 정보 가져오기 + String matchInfoUrl = String.format(RIOT_MATCH_INFO_API_URL_TEMPLATE, matchId, riotAPIKey); + RiotResponse.MatchDTO matchResponse = restTemplate.getForObject(matchInfoUrl, RiotResponse.MatchDTO.class); + + if (matchResponse == null || matchResponse.getInfo() == null || matchResponse.getInfo().getParticipants() == null) { + throw new MemberHandler(ErrorStatus.RIOT_NOT_FOUND); + } + + // 참가자 정보에서 gameName과 일치하는 사용자의 champion ID 찾기 + return matchResponse.getInfo().getParticipants().stream() + .filter(participant -> gameName.equals(participant.getRiotIdGameName())) + .map(RiotResponse.ParticipantDTO::getChampionId) + .findFirst() + .orElseThrow(() -> new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND)); + } + +} From 59db537680b9783802bdcf3dfb0297b9d5a04122 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 2 Aug 2024 20:36:08 +0900 Subject: [PATCH 3/5] =?UTF-8?q?:bug:=20[fix]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20return=20=EA=B0=92=EC=97=90=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/member/AuthController.java | 8 ++- .../controller/member/ProfileController.java | 34 +++++------ .../gamegoo/converter/MemberConverter.java | 59 ++++++++++++------- .../gamegoo/dto/member/MemberResponse.java | 18 ++++-- .../gamegoo/service/member/AuthService.java | 3 +- .../gamegoo/service/member/RiotService.java | 7 +++ 6 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index 64ce5808..f778d50d 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -1,6 +1,8 @@ package com.gamegoo.controller.member; import com.gamegoo.apiPayload.ApiResponse; +import com.gamegoo.converter.MemberConverter; +import com.gamegoo.domain.Member; import com.gamegoo.dto.member.MemberRequest; import com.gamegoo.dto.member.MemberResponse; import com.gamegoo.service.member.AuthService; @@ -25,16 +27,16 @@ public class AuthController { @PostMapping("/join") @Operation(summary = "회원가입 API 입니다.", description = "API for join") - public ApiResponse joinMember( + public ApiResponse joinMember( @RequestBody @Valid MemberRequest.JoinRequestDTO joinRequestDTO) { String email = joinRequestDTO.getEmail(); String password = joinRequestDTO.getPassword(); String gameName = joinRequestDTO.getGameName(); String tag = joinRequestDTO.getTag(); - authService.joinMember(email, password, gameName, tag); + Member member = authService.joinMember(email, password, gameName, tag); - return ApiResponse.onSuccess("회원가입에 성공했습니다."); + return ApiResponse.onSuccess(MemberConverter.toMyProfileDTO(member)); } @PostMapping("/email/send") diff --git a/src/main/java/com/gamegoo/controller/member/ProfileController.java b/src/main/java/com/gamegoo/controller/member/ProfileController.java index ca649a78..8cb381c8 100644 --- a/src/main/java/com/gamegoo/controller/member/ProfileController.java +++ b/src/main/java/com/gamegoo/controller/member/ProfileController.java @@ -9,17 +9,13 @@ import com.gamegoo.service.member.ProfileService; import com.gamegoo.util.JWTUtil; import io.swagger.v3.oas.annotations.Operation; -import java.util.List; -import java.util.stream.Collectors; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.stream.Collectors; @RestController @RequiredArgsConstructor @@ -32,16 +28,16 @@ public class ProfileController { @PutMapping("/gamestyle") @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") public ApiResponse> addGameStyle( - @RequestBody MemberRequest.GameStyleRequestDTO gameStyleRequestDTO) { + @RequestBody MemberRequest.GameStyleRequestDTO gameStyleRequestDTO) { Long memberId = JWTUtil.getCurrentUserId(); List memberGameStyles = profileService.addMemberGameStyles( - gameStyleRequestDTO, memberId); + gameStyleRequestDTO, memberId); List dtoList = memberGameStyles.stream() - .map(memberGameStyle -> MemberResponse.GameStyleResponseDTO.builder() - .gameStyleId(memberGameStyle.getGameStyle().getId()) - .gameStyleName(memberGameStyle.getGameStyle().getStyleName()) - .build()).collect(Collectors.toList()); + .map(memberGameStyle -> MemberResponse.GameStyleResponseDTO.builder() + .gameStyleId(memberGameStyle.getGameStyle().getId()) + .gameStyleName(memberGameStyle.getGameStyle().getStyleName()) + .build()).collect(Collectors.toList()); return ApiResponse.onSuccess(dtoList); } @@ -49,7 +45,7 @@ public ApiResponse> addGameStyle( @PutMapping("/position") @Operation(summary = "주/부 포지션 수정 API 입니다.", description = "API for Main/Sub Position Modification") public ApiResponse modifyPosition( - @RequestBody @Valid MemberRequest.PositionRequestDTO positionRequestDTO) { + @RequestBody @Valid MemberRequest.PositionRequestDTO positionRequestDTO) { Long userId = JWTUtil.getCurrentUserId(); int mainP = positionRequestDTO.getMainP(); int subP = positionRequestDTO.getSubP(); @@ -62,7 +58,7 @@ public ApiResponse modifyPosition( @PutMapping("/profile_image") @Operation(summary = "프로필 이미지 수정 API 입니다.", description = "API for Profile Image Modification") public ApiResponse modifyPosition( - @RequestBody MemberRequest.ProfileImageRequestDTO profileImageDTO) { + @RequestBody MemberRequest.ProfileImageRequestDTO profileImageDTO) { Long userId = JWTUtil.getCurrentUserId(); String profileImage = profileImageDTO.getProfileImage(); @@ -72,7 +68,7 @@ public ApiResponse modifyPosition( } @DeleteMapping("") - @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Member") + @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Blinding Member") public ApiResponse blindMember() { Long userId = JWTUtil.getCurrentUserId(); @@ -81,7 +77,7 @@ public ApiResponse blindMember() { } - @Operation(summary = "마이페이지 조회 API", description = "나 -> 나 조회하는 마이페이지 API 입니다.") + @Operation(summary = "회원 조회하는 API 입니다.", description = "API for looking up member") @GetMapping("/profile") public ApiResponse getBlockList() { Long memberId = JWTUtil.getCurrentUserId(); diff --git a/src/main/java/com/gamegoo/converter/MemberConverter.java b/src/main/java/com/gamegoo/converter/MemberConverter.java index 8f7dedc6..c374130d 100644 --- a/src/main/java/com/gamegoo/converter/MemberConverter.java +++ b/src/main/java/com/gamegoo/converter/MemberConverter.java @@ -3,16 +3,17 @@ import com.gamegoo.domain.Friend; import com.gamegoo.domain.Member; import com.gamegoo.dto.member.MemberResponse; +import org.springframework.data.domain.Page; + import java.util.List; import java.util.stream.Collectors; -import org.springframework.data.domain.Page; public class MemberConverter { public static MemberResponse.blockListDTO toBlockListDTO(Page blockList) { List blockedMemberDtoList = blockList.stream() - .map(MemberConverter::toBlockedMemberDTO) - .collect(Collectors.toList()); + .map(MemberConverter::toBlockedMemberDTO) + .collect(Collectors.toList()); return MemberResponse.blockListDTO.builder() .blockedMemberDTOList(blockedMemberDtoList) @@ -36,31 +37,45 @@ public static MemberResponse.blockedMemberDTO toBlockedMemberDTO(Member membr) { } public static MemberResponse.myProfileMemberDTO toMyProfileDTO(Member member) { - List dtoList = member.getMemberGameStyleList().stream() - .map(memberGameStyle -> MemberResponse.GameStyleResponseDTO.builder() - .gameStyleId(memberGameStyle.getGameStyle().getId()) - .gameStyleName(memberGameStyle.getGameStyle().getStyleName()) - .build()).collect(Collectors.toList()); + List gameStyleResponseDTOList = null; + if (member.getMemberGameStyleList() != null) { + gameStyleResponseDTOList = member.getMemberGameStyleList().stream() + .map(memberGameStyle -> MemberResponse.GameStyleResponseDTO.builder() + .gameStyleId(memberGameStyle.getGameStyle().getId()) + .gameStyleName(memberGameStyle.getGameStyle().getStyleName()) + .build()).collect(Collectors.toList()); + } + + List championResponseDTOList = null; + if (member.getMemberChampionList() != null) { + championResponseDTOList = member.getMemberChampionList().stream() + .map(memberChampion -> MemberResponse.ChampionResponseDTO.builder() + .championId(memberChampion.getMember().getId()) + .championName(memberChampion.getChampion().getName()) + .build()).collect(Collectors.toList()); + } + return MemberResponse.myProfileMemberDTO.builder() - .email(member.getEmail()) - .gameName(member.getGameName()) - .tag(member.getTag()) - .tier(member.getTier()) - .rank(member.getRank()) - .profileImg(member.getProfileImage()) - .updatedAt(String.valueOf(member.getUpdatedAt())) - .gameStyleResponseDTOList(dtoList) - .build(); + .email(member.getEmail()) + .gameName(member.getGameName()) + .tag(member.getTag()) + .tier(member.getTier()) + .rank(member.getRank()) + .profileImg(member.getProfileImage()) + .updatedAt(String.valueOf(member.getUpdatedAt())) + .gameStyleResponseDTOList(gameStyleResponseDTOList) + .championResponseDTOList(championResponseDTOList) + .build(); } public static MemberResponse.friendInfoDTO toFriendInfoDto(Friend friend) { return MemberResponse.friendInfoDTO.builder() - .memberId(friend.getToMember().getId()) - .name(friend.getToMember().getGameName()) - .memberProfileImg(friend.getToMember().getProfileImage()) - .isLiked(friend.getIsLiked()) - .build(); + .memberId(friend.getToMember().getId()) + .name(friend.getToMember().getGameName()) + .memberProfileImg(friend.getToMember().getProfileImage()) + .isLiked(friend.getIsLiked()) + .build(); } } diff --git a/src/main/java/com/gamegoo/dto/member/MemberResponse.java b/src/main/java/com/gamegoo/dto/member/MemberResponse.java index 9a29b3d9..df994ce9 100644 --- a/src/main/java/com/gamegoo/dto/member/MemberResponse.java +++ b/src/main/java/com/gamegoo/dto/member/MemberResponse.java @@ -1,11 +1,8 @@ package com.gamegoo.dto.member; +import lombok.*; + import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; public class MemberResponse { @@ -55,6 +52,16 @@ public static class GameStyleResponseDTO { String gameStyleName; } + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ChampionResponseDTO { + + Long championId; + String championName; + } + @Getter @Setter @AllArgsConstructor @@ -78,6 +85,7 @@ public static class myProfileMemberDTO { String rank; String updatedAt; List gameStyleResponseDTOList; + List championResponseDTOList; } @Builder diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index 18edbdd9..b4b221c2 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -97,7 +97,6 @@ public Member joinMember(String email, String password, String gameName, String } - // DB에 저장 memberRepository.save(member); // (2) Champion id, Member id 엮어서 MemberChampion 테이블에 넣기 @@ -115,6 +114,8 @@ public Member joinMember(String email, String password, String gameName, String memberChampionRepository.save(memberChampion); }); + // DB에 저장 + memberRepository.save(member); return member; } diff --git a/src/main/java/com/gamegoo/service/member/RiotService.java b/src/main/java/com/gamegoo/service/member/RiotService.java index 473d99a1..20dc2dd7 100644 --- a/src/main/java/com/gamegoo/service/member/RiotService.java +++ b/src/main/java/com/gamegoo/service/member/RiotService.java @@ -14,6 +14,13 @@ public class RiotService { private final RiotUtil riotUtil; + /** + * Riot 계정 유무 확인 + * + * @param gameName + * @param tag + * @return + */ @Transactional public String verifyRiot(String gameName, String tag) { String riotPuuid = riotUtil.getRiotPuuid(gameName, tag); From 0abf678d220be688d1d75a2898445bc90263400f Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 2 Aug 2024 20:36:57 +0900 Subject: [PATCH 4/5] =?UTF-8?q?:bug:=20[fix]=20=EC=98=A4=ED=83=80=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gamegoo/converter/MemberConverter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gamegoo/converter/MemberConverter.java b/src/main/java/com/gamegoo/converter/MemberConverter.java index c374130d..4f99948c 100644 --- a/src/main/java/com/gamegoo/converter/MemberConverter.java +++ b/src/main/java/com/gamegoo/converter/MemberConverter.java @@ -26,12 +26,12 @@ public static MemberResponse.blockListDTO toBlockListDTO(Page blockList) } - public static MemberResponse.blockedMemberDTO toBlockedMemberDTO(Member membr) { + public static MemberResponse.blockedMemberDTO toBlockedMemberDTO(Member member) { return MemberResponse.blockedMemberDTO.builder() - .memberId(membr.getId()) - .profileImg(membr.getProfileImage()) - .email(membr.getEmail()) - .name(membr.getGameName()) + .memberId(member.getId()) + .profileImg(member.getProfileImage()) + .email(member.getEmail()) + .name(member.getGameName()) .build(); } From cb8d5badb21fd1a1d4819ac164418ca932be9a52 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 2 Aug 2024 20:47:07 +0900 Subject: [PATCH 5/5] =?UTF-8?q?:bug:=20[fix]=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/gamegoo/service/member/AuthService.java | 2 -- src/main/java/com/gamegoo/util/RiotUtil.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index b4b221c2..247b538e 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -114,8 +114,6 @@ public Member joinMember(String email, String password, String gameName, String memberChampionRepository.save(memberChampion); }); - // DB에 저장 - memberRepository.save(member); return member; } diff --git a/src/main/java/com/gamegoo/util/RiotUtil.java b/src/main/java/com/gamegoo/util/RiotUtil.java index 3dc56a0f..96169a20 100644 --- a/src/main/java/com/gamegoo/util/RiotUtil.java +++ b/src/main/java/com/gamegoo/util/RiotUtil.java @@ -42,7 +42,7 @@ public RiotUtil(RestTemplate restTemplate) { */ @Transactional public List getPreferChampionfromMatch(String gameName, String puuid) { - // 최근 플레이한 챔피언 리스트 조회 + // 1. 최근 플레이한 챔피언 리스트 조회 List recentChampionIds = null; int count = 20; @@ -63,6 +63,7 @@ public List getPreferChampionfromMatch(String gameName, String puuid) { throw new MemberHandler(ErrorStatus.RIOT_MATCH_NOT_FOUND); } + // 최근 선호 챔피언 수가 충분하지 않을 경우 에러 발생 if (recentChampionIds.size() < 3) { throw new MemberHandler(ErrorStatus.RIOT_INSUFFICIENT_MATCHES); }