기존 예외처리 코드를 바꿔보았다.
회원가입 or 로그인 같은 회원 서비스에서 발생할 수 있는 예외들을
MemberException으로 모아 공통 예외 처리를 할 것이다.
먼저 BaseException을 생성한다.
[BaseException]
public abstract class BaseException extends RuntimeException {
public abstract BaseExceptionType getExceptionType();
}
- BaseException은 앞으로 정의할 모든 Custom 예외의 부모 클래스이다.
- 앞으로 BaseException 타입으로 처리할 수 있다.
- RuntimeException을 상속받았다.
- BaseException은 BaseExceptionType을 반환하는 getExceptionType()을 가지고 있다.
- 이후 Enum 설정
다음은 BaseExceptionType을 생성한다.
[BaseExceptionType]
public interface BaseExceptionType {
// 에러 코드
int getErrorCode();
// Http 상태
HttpStatus getHttpStatus();
// 에러 메세지
String getErrorMessage();
}
다음은 Member에 대한 예외처리를 생성한다.
[MemberException]
public class MemberException extends BaseException {
private BaseExceptionType exceptionType;
public MemberException(BaseExceptionType exceptionType) {
this.exceptionType = exceptionType;
}
@Override
public BaseExceptionType getExceptionType() {
return exceptionType;
}
}
- BaseExceptionType을 멤버변수로 가지고 있다.
- 생성자를 통해 생성하는 순간 BaseExceptionType을 설정한다.
다음은 MemberExceptionType을 생성한다.
[MemberExceptionType]
public enum MemberExceptionType implements BaseExceptionType {
// 회원가입, 로그인시
ALREADY_EXIST_USERNAME(600, HttpStatus.CONFLICT, "이미 존재하는 아이디입니다."),
NOT_FOUND_MEMBER(602, HttpStatus.NOT_FOUND, "회원 정보가 없습니다.");
private int errorCode;
private HttpStatus httpStatus;
private String errorMessage;
MemberExceptionType(int errorCode, HttpStatus httpStatus, String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}
@Override
public int getErrorCode() {
return this.errorCode;
}
@Override
public HttpStatus getHttpStatus() {
return this.httpStatus;
}
@Override
public String getErrorMessage() {
return this.errorMessage;
}
}
- enum으로 생성한다.
- 에러코드, Http 상태코드, 에러 메세지가 존재한다.
이제 예외처리를 수정해보자.
먼저, 기존의 중복회원 처리 코드이다.
[기존 Service]
/**
* 회원가입 중복 검사
* 이메일 중복 불가능
* */
private void validateDuplicateMember(Member member) {
Member findMember = memberRepository.findByEmail(member.getEmail());
if(findMember != null) {
// 예외처리
throw new AppException(ErrorCode.MEMBERNAME_DUPLICATED, findMember.getName() + "은 이미 있습니다.");
}
}
[수정 후 Service]
private void validateDuplicateMember(Member member) {
Member findMember = memberRepository.findByEmail(member.getEmail());
if(findMember != null) {
throw new MemberException(MemberExceptionType.ALREADY_EXIST_USERNAME);
}
}
- 만약 먼저 가입한 회원이 있으면, MemberException의 ALREADY_EXIST_USERNAME을 발생시킨다.
그 다음은 Controller를 수정한다.
[기존 Controller]
@PostMapping("/new")
public String newMember(@Valid MemberFormDto memberFormDto, BindingResult bindingResult, Model model){
...
try {
Member member = Member.createMember(memberFormDto, passwordEncoder);
memberService.saveMember(member);
} catch (AppException e){
model.addAttribute("errorMessage", e.getMessage());
return "member/memberForm";
}
return "redirect:/";
}
- 내가 전에 만들어 놓았던 AppException인데, 이것도 Custom한 것이다.
- 다만 다른 방식으로 바꿨을 뿐...
[수정 후 Controller]
@PostMapping("/new")
public String newMember(@Valid MemberFormDto memberFormDto, BindingResult bindingResult, Model model){
...
try {
Member member = Member.createMember(memberFormDto, passwordEncoder);
memberService.saveMember(member);
} catch (MemberException e){
model.addAttribute("errorMessage", e.getExceptionType().getErrorMessage());
return "member/memberForm";
}
return "redirect:/";
}
- MemberException의 ErrorMessage를 viewPage에 보내는 코드이다.
- 뷰페이지가 없고 API 호출만 하는 것이라면, 이 과정은 생략해도 된다.
코드는 다 변경했으니, 테스트코드를 변경해보자.
[기존 TestCode]
@Test
@DisplayName("중복 회원 가입 테스트")
public void saveDuplicateMemberTest(){
Member member1 = createMember();
Member member2 = createMember();
memberService.saveMember(member1);
Throwable e = assertThrows(AppException.class, () -> {
memberService.saveMember(member2);});
assertEquals("김길동은 이미 있습니다.", e.getMessage());
}
- 기존에 Custom한 AppException이다.
[수정 후 TestCode]
@Test
@DisplayName("중복 회원 가입 테스트")
public void saveDuplicateMemberTest(){
Member member1 = createMember();
Member member2 = createMember();
memberService.saveMember(member1);
assertThat(assertThrows(MemberException.class,
() -> memberService.saveMember(member2)).getExceptionType()).isEqualTo(MemberExceptionType.ALREADY_EXIST_USERNAME);
}
- 같은 정보의 회원을 가입시켰을 때, MemberExceptionType.ALREADY_EXIST_USERNAME 즉, "이미 존재하는 아이디입니다."와 일치하는지 테스트한다.
통과한다.
에러를 처리하는 방법은 정말 다양하게 있구나.
역시 끝이 없는 코딩의 세계이다.
- 다른 방식으로 해본 Custom Exception 끝 -
'프로젝트' 카테고리의 다른 글
스프링 시큐리티를 분석해보자 (0) | 2023.02.25 |
---|---|
Session 기반 인증과 Token 기반 인증의 차이가 뭘까? (2) | 2023.02.20 |
[JPA/Thymeleaf] 게시글 작성자만 수정 권한 가지기 (0) | 2023.02.18 |
게시물 조회수 구현, @Query (0) | 2023.02.17 |
CRUD를 분석해보자 (2) - 게시글 수정/삭제/조회 API (0) | 2023.02.11 |