Skip to content

Commit

Permalink
Null 391 exception refactor (#36)
Browse files Browse the repository at this point in the history
* feat: 에러 핸들러 개편

* refactor: 커스텀 예외로 변경

* refactor: jwt 예외 수정

* refactor: resttemplate 예외 수정

* NULL-393 fix: 403 에러 해결

* refactor: 에러 코드 수정

* fix: 오버라이딩 문제 해결

* fix: errorcode to string
  • Loading branch information
BaeJinho4028 authored Sep 29, 2024
1 parent dba635d commit b7c1d41
Show file tree
Hide file tree
Showing 24 changed files with 273 additions and 142 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/example/oatnote/memotag/MemoTagService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.oatnote.memotag;

import static com.example.oatnote.memotag.service.client.dto.innerDto.ProcessedMemoTags.TagsRelations.*;
import static com.example.oatnote.memotag.service.client.dto.innerDto.ProcessedMemoTags.TagsRelations.Relation;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -33,12 +33,12 @@
import com.example.oatnote.memotag.service.client.dto.AISearchMemoResponse;
import com.example.oatnote.memotag.service.client.dto.innerDto.ProcessedMemoTags;
import com.example.oatnote.memotag.service.memo.MemoService;
import com.example.oatnote.memotag.service.memo.exception.MemoNotFoundException;
import com.example.oatnote.memotag.service.memo.model.Memo;
import com.example.oatnote.memotag.service.memoTagRelation.MemoTagRelationService;
import com.example.oatnote.memotag.service.tag.TagService;
import com.example.oatnote.memotag.service.tag.edge.model.TagEdge;
import com.example.oatnote.memotag.service.tag.model.Tag;
import com.example.oatnote.web.exception.OatIllegalArgumentException;
import com.example.oatnote.web.model.Criteria;

import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -89,8 +89,8 @@ public PagedMemosResponse getMemos(
SortOrderTypeEnum sortOrder,
String userId
) {
if(Objects.equals(sortOrder, SortOrderTypeEnum.NAME)) {
throw new MemoNotFoundException("메모는 이름순으로 정렬할 수 없습니다.");
if (Objects.equals(sortOrder, SortOrderTypeEnum.NAME)) {
throw OatIllegalArgumentException.withDetail("메모는 이름 순으로 정렬할 수 없습니다.");
}

tagId = Objects.requireNonNullElse(tagId, userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseErrorHandler;

import com.example.oatnote.web.exception.OatExternalServiceException;

@Component
public class AIResponseErrorHandler implements ResponseErrorHandler {

Expand All @@ -21,9 +23,9 @@ public boolean hasError(ClientHttpResponse response) throws IOException {
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatusCode statusCode = response.getStatusCode();
if (statusCode.is4xxClientError()) {
throw new HttpClientErrorException(statusCode, "BE Client 오류");
throw OatExternalServiceException.withDetail(String.format("BE Client 오류 : %s", statusCode));
} else if (statusCode.is5xxServerError()) {
throw new HttpServerErrorException(statusCode, "AI Server 오류");
throw OatExternalServiceException.withDetail(String.format("AI Server 오류 : %s", statusCode));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import com.example.oatnote.memotag.service.memo.exception.MemoNotFoundException;
import com.example.oatnote.memotag.service.memo.model.Memo;
import com.example.oatnote.web.exception.OatDataNotFoundException;

import lombok.RequiredArgsConstructor;

Expand All @@ -23,7 +23,7 @@ public Memo saveMemo(Memo memo) {

public Memo getMemo(String memoId, String userId) {
return memoRepository.findByIdAndUserId(memoId, userId)
.orElseThrow(() -> new MemoNotFoundException("메모를 찾지 못했습니다: " + memoId));
.orElseThrow(() -> OatDataNotFoundException.withDetail(String.format("메모를 찾지 못했습니다: %s", memoId)));
}

public List<Memo> getMemos(List<String> memoIds, String userId) {
Expand All @@ -37,7 +37,7 @@ public Page<Memo> getPagedMemos(List<String> memoIds, PageRequest pageRequest, S
public List<Memo> getMemosContainingRegex(String regex, String userId) {
List<Memo> memos = memoRepository.findByContentRegexAndUserId(regex, userId);
if (memos.isEmpty()) {
throw new MemoNotFoundException("존재하지 않는 메모 regex 입니다.");
throw OatDataNotFoundException.withDetail(String.format("해당 regex 의 메모를 찾지 못했습니다: %s", regex));
}
return memos;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package com.example.oatnote.memotag.service.tag;

import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import com.example.oatnote.memotag.service.tag.edge.TagEdgeService;
import com.example.oatnote.memotag.service.tag.edge.model.TagEdge;
import com.example.oatnote.memotag.service.tag.exception.TagNotFoundException;
import com.example.oatnote.memotag.service.tag.model.Tag;
import com.example.oatnote.memotag.service.tag.relation.TagsRelationService;
import com.example.oatnote.web.exception.OatDataNotFoundException;

import lombok.RequiredArgsConstructor;

Expand All @@ -38,7 +36,7 @@ public Page<Tag> getPagedTags(List<String> tagsIds, PageRequest pageRequest, Str

public Tag getTag(String tagId, String userId) {
return tagRepository.findByIdAndUserId(tagId, userId)
.orElseThrow(() -> new TagNotFoundException("태그를 찾지 못했습니다: " + tagId));
.orElseThrow(() -> OatDataNotFoundException.withDetail(String.format("태그를 찾지 못했습니다: %s", tagId)));
}

public void deleteTag(Tag tag) {
Expand Down

This file was deleted.

This file was deleted.

34 changes: 15 additions & 19 deletions src/main/java/com/example/oatnote/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

import java.util.Objects;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.example.oatnote.event.UserRegisteredEvent;
import com.example.oatnote.event.UserWithdrawEvent;
import com.example.oatnote.user.dto.CheckEmailRequest;
import com.example.oatnote.user.dto.SendCodeRequest;
import com.example.oatnote.user.dto.FindPasswordRequest;
import com.example.oatnote.user.dto.LoginUserRequest;
import com.example.oatnote.user.dto.LoginUserResponse;
import com.example.oatnote.user.dto.RefreshUserRequest;
import com.example.oatnote.user.dto.RefreshUserResponse;
import com.example.oatnote.user.dto.RegisterUserRequest;
import com.example.oatnote.user.dto.SendCodeRequest;
import com.example.oatnote.user.dto.VerifyCodeRequest;
import com.example.oatnote.user.service.email.EmailVerificationService;
import com.example.oatnote.user.service.exception.UserAuthException;
import com.example.oatnote.user.service.exception.UserNotFoundException;
import com.example.oatnote.user.service.model.User;
import com.example.oatnote.util.JwtUtil;
import com.example.oatnote.web.exception.OatAuthException;
import com.example.oatnote.web.exception.OatDataNotFoundException;
import com.example.oatnote.web.exception.OatIllegalArgumentException;

import io.jsonwebtoken.JwtException;
import lombok.RequiredArgsConstructor;
Expand All @@ -44,14 +44,14 @@ public void register(RegisterUserRequest registerUserRequest) {
String password = registerUserRequest.password();
String confirmPassword = registerUserRequest.confirmPassword();
if (!Objects.equals(password, confirmPassword)) {
throw new UserAuthException("비밀번호가 일치하지 않습니다.");
throw OatIllegalArgumentException.withDetail("비밀번호가 일치하지 않습니다.");
}

String email = registerUserRequest.email();
String code = registerUserRequest.code();
String name = registerUserRequest.name();
if (userRepository.findByEmail(email).isPresent()) {
throw new UserAuthException("이미 존재하는 이메일입니다: " + registerUserRequest.email());
throw OatIllegalArgumentException.withDetail(String.format("이미 존재하는 이메일입니다: %s", email));
}

emailVerificationService.verifyCode(email, code);
Expand All @@ -68,11 +68,11 @@ public void register(RegisterUserRequest registerUserRequest) {
public LoginUserResponse login(LoginUserRequest loginUserRequest) {
String email = loginUserRequest.email();
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UserNotFoundException("유저를 찾지 못했습니다: " + email));
.orElseThrow(() -> OatDataNotFoundException.withDetail("유저를 찾지 못했습니다: " + email));

String password = loginUserRequest.password();
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new UserAuthException("비밀번호가 일치하지 않습니다");
throw OatIllegalArgumentException.withDetail("비밀번호가 일치하지 않습니다.");
}
String accessToken = jwtUtil.generateAccessToken(user.getId());
String refreshToken = jwtUtil.generateRefreshToken(user.getId());
Expand All @@ -81,20 +81,16 @@ public LoginUserResponse login(LoginUserRequest loginUserRequest) {

public RefreshUserResponse refreshAccessToken(RefreshUserRequest refreshUserRequest) {
String refreshToken = refreshUserRequest.refreshToken();
try {
jwtUtil.validateToken(refreshToken);
String email = jwtUtil.extractUserId(refreshToken);
String newAccessToken = jwtUtil.generateAccessToken(email);
return RefreshUserResponse.of(newAccessToken, refreshToken);
} catch (JwtException e) {
throw new UserAuthException("refresh token 이 일치하지 않습니다." + e);
}
jwtUtil.validateToken(refreshToken);
String email = jwtUtil.extractUserId(refreshToken);
String newAccessToken = jwtUtil.generateAccessToken(email);
return RefreshUserResponse.of(newAccessToken, refreshToken);
}

public void checkEmailDuplication(CheckEmailRequest checkEmailRequest) {
String email = checkEmailRequest.email();
userRepository.findByEmail(email).ifPresent(user -> {
throw new UserAuthException("이미 존재하는 이메일입니다: " + email);
throw OatIllegalArgumentException.withDetail(String.format("이미 존재하는 이메일입니다: %s", email));
});
}

Expand All @@ -114,15 +110,15 @@ public void findPassword(FindPasswordRequest findPasswordRequest) {
String newPassword = findPasswordRequest.newPassword();
String confirmPassword = findPasswordRequest.confirmPassword();
if (!Objects.equals(newPassword, confirmPassword)) {
throw new UserAuthException("비밀번호가 일치하지 않습니다.");
throw OatIllegalArgumentException.withDetail("비밀번호가 일치하지 않습니다.");
}

String email = findPasswordRequest.email();
String code = findPasswordRequest.code();
emailVerificationService.verifyCode(email, code);

User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UserNotFoundException("유저를 찾지 못했습니다: " + email));
.orElseThrow(() -> OatDataNotFoundException.withDetail("유저를 찾지 못했습니다: " + email));

user.updatePassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.example.oatnote.user.service.email.exception.EmailDispatchException;
import com.example.oatnote.user.service.email.exception.EmailVerificationException;
import com.example.oatnote.user.service.email.model.EmailVerification;
import com.example.oatnote.web.exception.OatDataNotFoundException;
import com.example.oatnote.web.exception.OatExternalServiceException;
import com.example.oatnote.web.exception.OatIllegalArgumentException;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
Expand All @@ -30,20 +31,20 @@ public void sendCode(String email, int expiryMinutes) {
sendEmail(email, code);
saveEmailVerification(email, code, expiryMinutes);
} catch (MessagingException e) {
throw new EmailDispatchException("이메일 전송에 실패했습니다.");
throw OatExternalServiceException.withDetail(String.format("이메일 전송에 실패했습니다 : %s", email));
}
}

public void saveEmailVerification(String email, String code, int expiryMinutes) {
emailVerificationRepository.findByEmail(email).ifPresent(emailVerificationRepository::delete);
emailVerificationRepository.save(new EmailVerification(email, code));
emailVerificationRepository.save(new EmailVerification(email, code, expiryMinutes));
}

public void verifyCode(String email, String code) {
EmailVerification emailVerification = emailVerificationRepository.findByEmail(email)
.orElseThrow(() -> new EmailVerificationException("인증 코드가 만료되었거나 존재하지 않습니다."));
.orElseThrow(() -> OatDataNotFoundException.withDetail(String.format("인증 코드가 발급되지 않았습니다 : %s", email)));
if (!Objects.equals(code, emailVerification.getCode())) {
throw new EmailVerificationException("인증 코드가 일치하지 않습니다.");
throw OatIllegalArgumentException.withDetail("인증 코드가 일치하지 않습니다.");
}
emailVerificationRepository.delete(emailVerification);
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public class EmailVerification {
@Field("eTime")
private LocalDateTime expiryTime;

public EmailVerification(String email, String code) {
public EmailVerification(String email, String code, int expiryTime) {
this.email = email;
this.code = code;
this.expiryTime = LocalDateTime.now().plusMinutes(10);
this.expiryTime = LocalDateTime.now().plusMinutes(expiryTime);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected void doFilterInternal(
response.getWriter().write(TOKEN_INVALID_MESSAGE);
return;
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(ERROR_PROCESSING_TOKEN_MESSAGE);
return;
}
Expand Down
14 changes: 4 additions & 10 deletions src/main/java/com/example/oatnote/util/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.example.oatnote.web.exception.OatAuthException;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
Expand Down Expand Up @@ -80,16 +82,8 @@ private Date extractExpiration(String token) {
public void validateToken(String token) throws JwtException {
try {
Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token);
} catch (ExpiredJwtException e) {
throw new JwtException("JWT token has expired", e);
} catch (UnsupportedJwtException e) {
throw new JwtException("Unsupported JWT token", e);
} catch (MalformedJwtException e) {
throw new JwtException("Invalid JWT token", e);
} catch (SecurityException e) {
throw new JwtException("Invalid JWT signature", e);
} catch (IllegalArgumentException e) {
throw new JwtException("JWT claims string is empty", e);
} catch (Exception e) {
throw OatAuthException.withDetail("유효하지 않은 토큰입니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@JsonNaming(SnakeCaseStrategy.class)
public record ErrorResponse(
int errorCode,
String errorCode,
String message
) {

Expand Down
Loading

0 comments on commit b7c1d41

Please sign in to comment.