Skip to content

Commit

Permalink
Merge pull request #23 from hyundai-fruitfruit/HEENDY-79-exception-re…
Browse files Browse the repository at this point in the history
…sponse

[Heendy 79 exception response] 예외 응답 형식 설정 및 예외 처리 추가
  • Loading branch information
sooyoungh authored Mar 1, 2024
2 parents 5d84939 + 75a8119 commit 0620334
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/hyundai/app/event/enumType/EventType.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import java.util.List;
import java.util.Random;

import static com.hyundai.app.exception.ErrorCode.EVENT_TYPE_NOT_EXIST;
import static com.hyundai.app.exception.ErrorCode.EVENT_TYPE_INVALID;

/**
* @author 엄상은
Expand Down Expand Up @@ -50,7 +50,7 @@ public static EventType of(String eventType) {
.filter(e -> e.equals(eventEnum))
.findFirst()
.map(EventType::getRandomEventType)
.orElseThrow(() -> new AdventureOfHeendyException(EVENT_TYPE_NOT_EXIST));
.orElseThrow(() -> new AdventureOfHeendyException(EVENT_TYPE_INVALID));

}
}
20 changes: 7 additions & 13 deletions src/main/java/com/hyundai/app/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,17 @@ public enum ErrorCode {
// 인증 및 인가
UNAUTHORIZED_ACCESS(UNAUTHORIZED, "인증되지 않은 사용자입니다."),
FORBIDDEN_ACCESS(FORBIDDEN, "인가되지 않은 접근입니다."),

// 리뷰
REVIEW_SCORE_INVALID(BAD_REQUEST, "별점은 1~5점까지의 정수이어야 합니다."),
REVIEW_CONTENT_INVALID(BAD_REQUEST, "리뷰 내용은 최소 5자 이상이어야합니다."),

// 아이디값
STORE_ID_INVALID(BAD_REQUEST, "해당하는 매장 id가 없습니다."),
HASHTAG_ID_INVALID(BAD_REQUEST, "해당하는 해시태그 id가 없습니다."),
MEMBER_ID_INVALID(BAD_REQUEST, "해당하는 회원 id가 없습니다."),
MEMBER_NOT_EXIST(BAD_REQUEST, "해당하는 회원 oauth id가 존재하지 않습니다."),
MEMBER_NOT_EXIST(NOT_FOUND, "해당하는 회원 oauth id가 존재하지 않습니다."),

// 이벤트
EVENT_NOT_EXIST(BAD_REQUEST, "해당하는 이벤트가 존재하지 않습니다."),
EVENT_TYPE_NOT_EXIST(BAD_REQUEST, "이벤트 타입은 RESTAURANT, CAFE, SHOPPING, RANDOM 중 하나이어야 합니다."),
EVENT_NOT_EXIST(NOT_FOUND, "해당하는 이벤트가 존재하지 않습니다."),
EVENT_TYPE_INVALID(BAD_REQUEST, "이벤트 타입은 RESTAURANT, CAFE, SHOPPING, RANDOM 중 하나이어야 합니다."),

// 매장
STORE_NOT_EXIST(BAD_REQUEST, "해당하는 매장 id가 존재하지 않습니다."),
STORE_NOT_EXIST(NOT_FOUND, "해당하는 매장 id가 존재하지 않습니다."),
REVIEW_SCORE_INVALID(BAD_REQUEST, "별점은 1~5점까지의 정수이어야 합니다."),
REVIEW_CONTENT_INVALID(BAD_REQUEST, "리뷰 내용은 최소 5자 이상이어야합니다."),
HASHTAG_NOT_EXIST(NOT_FOUND, "해당하는 해시태그 id가 없습니다."),

// 500 에러
SERVER_UNAVAILABLE(SERVICE_UNAVAILABLE, "서버에 오류가 발생하였습니다."),
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/hyundai/app/exception/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.hyundai.app.exception;

import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

/**
* @author 황수영
* @since 2024/02/28
* 예외 응답 형식
*/
@Getter
@Builder
@RequiredArgsConstructor
public class ErrorResponse {
private final String errorMessage;
private final String errorType;
private final HttpStatus httpStatus;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.hyundai.app.exception;

import lombok.extern.log4j.Log4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

/**
* @author 황수영
* @since 2024/02/28
* 예외 응답 반환하는 핸들러
*/
@Log4j
@RestControllerAdvice
public class ExceptionResponseHandler extends ResponseEntityExceptionHandler {

/**
* @author 황수영
* @since 2024/02/28
* 자체 예외 응답 처리
*/
@ExceptionHandler(AdventureOfHeendyException.class)
public ResponseEntity<Object> handleCustomException(AdventureOfHeendyException e) {
return handleExceptionInternal(e);
}

/**
* @author 황수영
* @since 2024/02/28
* 자체 예외 이외의 모든 예외 처리
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllException(Exception e) {
return handleExceptionAll(e);
}

/**
* @author 황수영
* @since 2024/02/28
* 자체 예외 ResponseEntity 생성
*/
private ResponseEntity<Object> handleExceptionInternal(AdventureOfHeendyException e) {
log.error("자체 예외 발생 : " + e);

return ResponseEntity.status(e.getErrorCode().getHttpStatus())
.body(ErrorResponse.builder()
.errorMessage(e.getErrorCode().getMessage())
.errorType(String.valueOf(e.getErrorCode()))
.httpStatus(e.getErrorCode().getHttpStatus())
.build());
}

/**
* @author 황수영
* @since 2024/02/28
* 자체 예외 이외의 모든 ResponseEntity 생성
*/
private ResponseEntity<Object> handleExceptionAll(Exception e) {
log.error("예외 발생 : " + e);

return ResponseEntity.status(ErrorCode.SERVER_UNAVAILABLE.getHttpStatus())
.body(ErrorResponse.builder()
.errorMessage(e.getMessage())
.errorType(e.toString())
.httpStatus(ErrorCode.SERVER_UNAVAILABLE.getHttpStatus())
.build());
}
}
6 changes: 6 additions & 0 deletions src/main/java/com/hyundai/app/guide/GuideController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.hyundai.app.guide;

import com.hyundai.app.exception.AdventureOfHeendyException;
import com.hyundai.app.exception.ErrorCode;
import com.hyundai.app.guide.dto.GuideTypeResDto;
import com.hyundai.app.guide.dto.HashtagListResDto;
import com.hyundai.app.store.dto.StoreResDto;
Expand Down Expand Up @@ -51,6 +53,10 @@ public ResponseEntity<List<HashtagListResDto>> getGuideByCategory(@PathVariable(
public ResponseEntity<List<StoreResDto>> findStoresByHashtags(@RequestParam("hashtagId")int hashtagId) {
log.debug("해시 태그 선택 시, 관련 식당들 조회 => 해시 태그 : " + hashtagId);
List<StoreResDto> stores = hashtagService.findStoresByMostSavedHashtags(hashtagId);
if (stores.isEmpty()) {
log.error("해당 해시 태그의 식당들이 존재하지 않습니다. => 해시 태그 : " + hashtagId);
throw new AdventureOfHeendyException(ErrorCode.STORE_NOT_EXIST);
}
return new ResponseEntity<>(stores, HttpStatus.ACCEPTED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.hyundai.app.member.service.MemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -28,6 +27,11 @@ public class AuthController {
@Qualifier("memberServiceImpl")
private MemberService memberService;

/**
* @author 황수영
* @since 2024/02/12
* 회원가입/로그인(OAuth 로그인) API
*/
@PostMapping("/login")
@ApiOperation("회원가입/로그인 API")
public ResponseEntity<LoginResDto> login(@RequestBody LoginReqDto loginReqDto) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class MemberController {
@Qualifier("memberServiceImpl")
private MemberService memberService;

/**
* @author 황수영
* @since 2024/02/14
* 회원 조회 API
*/
@GetMapping
@ApiOperation("회원 정보 조회 API")
public ResponseEntity<MemberResDto> login(@ApiIgnore @MemberId String memberId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ private KakaoResDto getMemberInfoByLoginToken(String accessToken) {
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(headers);
return getMemberInfoFromOAuth(request);
}


/**
* @author 황수영
* @since 2024/02/12
* Kakao에서 받아온 사용자 정보에서 email 추출
*/
private KakaoResDto getMemberInfoFromOAuth(HttpEntity<MultiValueMap<String, String>> request) {
KakaoResDto kakaoResDto = null;
try {
Expand Down
56 changes: 41 additions & 15 deletions src/main/java/com/hyundai/app/member/service/MemberServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.hyundai.app.member.service;

import com.hyundai.app.exception.AdventureOfHeendyException;
import com.hyundai.app.exception.ErrorCode;
import com.hyundai.app.member.domain.Member;
import com.hyundai.app.member.dto.LoginReqDto;
import com.hyundai.app.member.dto.LoginResDto;
Expand All @@ -22,7 +24,7 @@
/**
* @author 황수영
* @since 2024/02/13
* (설명)
* 회원 관련 서비스단
*/
@Log4j
@Service
Expand All @@ -31,18 +33,17 @@ public class MemberServiceImpl implements MemberService {

@Value("${jwt.access-validity}")
private long accessValidity;

private final MemberMapper memberMapper;
private final KakaoOauthClient oAuthClient;
private final JwtTokenGenerator authTokenGenerator;
private final AwsS3Config awsS3Config;
private final MemberQrService memberQrService;

public MemberResDto getMemberInfo(String id) {
Member member = memberMapper.findById(id);
return MemberResDto.of(member);
}

/**
* @author 황수영
* @since 2024/02/13
* 회원가입/로그인 기능
*/
public LoginResDto login(LoginReqDto loginReqDto) {
String email = oAuthClient.getEmail(loginReqDto);
OauthType oauthType = OauthType.valueOf(loginReqDto.getOauthType().toUpperCase());
Expand All @@ -56,11 +57,21 @@ public LoginResDto login(LoginReqDto loginReqDto) {
return joinByOauthId(email, oauthType);
}

/**
* @author 황수영
* @since 2024/02/13
* access token 재발급
*/
private String updateAccessToken(Member member) {
String memberId = String.valueOf(member.getId());
return authTokenGenerator.createJwtToken(memberId, accessValidity);
}

/**
* @author 황수영
* @since 2024/02/13
* token 갱신
*/
private LoginResDto getUpdatedToken(Member member) {
String newAccessToken = updateAccessToken(member);
String refreshToken = member.getRefreshToken();
Expand All @@ -71,30 +82,45 @@ private LoginResDto getUpdatedToken(Member member) {
.build();
}

/**
* @author 황수영
* @since 2024/02/13
* oauth id값으로 회원가입
*/
public LoginResDto joinByOauthId(String email, OauthType oauthType) {
String oauthId = oauthType.createOauthIdWithEmail(email);
LoginResDto loginResDto = authTokenGenerator.createLoginResDto(oauthId);
String memberId = UUID.randomUUID().toString();
LoginResDto loginResDto = authTokenGenerator.createLoginResDto(memberId);
String qrUrl = generateQrCodeAndUploadToS3(memberId);

Member member = Member.builder()
.id(memberId)
.email(email)
.nickname(Nickname.getRandomNickname())
.role(Role.ROLE_MEMBER)
.oauthId(oauthId)
.oauthId(oauthType.createOauthIdWithEmail(email))
.refreshToken(loginResDto.getRefreshToken())
.qrUrl(qrUrl)
.build();
log.debug("joinByEmail member" + member.toString());
memberMapper.saveMember(member);

Member savedMember = memberMapper.findByOauthId(oauthId);
log.debug("joinByEmail savedMember" + savedMember);

return loginResDto;
}


/**
* @author 황수영
* @since 2024/02/13
* 회원 정보 조회
*/
public MemberResDto getMemberInfo(String id) {
log.debug("회원 정보 조회 : " + id);
Member member = memberMapper.findById(id);
if (member == null) {
log.error("회원 id가 존재하지 않습니다. : " + id);
throw new AdventureOfHeendyException(ErrorCode.MEMBER_NOT_EXIST);
}
return MemberResDto.of(member);
}

/**
* @author 엄상은
* @since 2024/02/26
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/com/hyundai/app/security/AuthDetailsService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.hyundai.app.security;

import com.hyundai.app.exception.AdventureOfHeendyException;
import com.hyundai.app.exception.ErrorCode;
import com.hyundai.app.member.mapper.MemberMapper;
import com.hyundai.app.member.domain.Member;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,8 +24,11 @@ public class AuthDetailsService implements UserDetailsService {

@Override
public AuthUserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
Member member = memberMapper.findById(id);
log.debug("loadUserByUsername() => member : " + member);
return new AuthUserDetails(member);
Member findMember = memberMapper.findById(id);
log.debug("loadUserByUsername() => member : " + id);
if (findMember == null) {
throw new AdventureOfHeendyException(ErrorCode.MEMBER_NOT_EXIST);
}
return new AuthUserDetails(findMember);
}
}
Loading

0 comments on commit 0620334

Please sign in to comment.