Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#106 Exception Handling #107

Merged
merged 11 commits into from
May 4, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.rollthedice.backend.domain.bookmark.entity.Bookmark;
import com.rollthedice.backend.domain.bookmark.repository.BookmarkRepository;
import com.rollthedice.backend.domain.member.entity.Member;
import com.rollthedice.backend.domain.news.exception.NewsNotFoundException;
import com.rollthedice.backend.global.oauth2.service.AuthService;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import com.rollthedice.backend.domain.news.entity.News;
import com.rollthedice.backend.domain.news.mapper.NewsMapper;
import com.rollthedice.backend.domain.news.repository.NewsRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -45,7 +45,7 @@ public void saveBookmark(Long newsId) {
bookmarkRepository.save(Bookmark.builder()
.member(member)
.news(newsRepository.findById(newsId)
.orElseThrow(EntityNotFoundException::new))
.orElseThrow(NewsNotFoundException::new))
.build());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.rollthedice.backend.domain.debate.exception;

import com.rollthedice.backend.global.error.exception.BusinessException;
import com.rollthedice.backend.global.error.ErrorCode;

public class DebateRoomNotFoundException extends BusinessException {
public DebateRoomNotFoundException() {
super(ErrorCode.DEBATE_ROOM_NOT_FOUND_ERROR);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import com.rollthedice.backend.domain.debate.dto.request.DebateMessageRequest;
import com.rollthedice.backend.domain.debate.dto.response.DebateMessageResponse;
import com.rollthedice.backend.domain.debate.entity.DebateRoom;
import com.rollthedice.backend.domain.debate.exception.DebateRoomNotFoundException;
import com.rollthedice.backend.domain.debate.mapper.DebateMessageMapper;
import com.rollthedice.backend.domain.debate.repository.DebateRoomRepository;
import com.rollthedice.backend.domain.news.repository.DebateMessageRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -31,7 +31,7 @@ public void saveAIDebateMessage(Long roomId, DebateMessageRequest request) {
}

private DebateRoom getDebateRoom(final Long roomId) {
return debateRoomRepository.findById(roomId).orElseThrow(EntityNotFoundException::new);
return debateRoomRepository.findById(roomId).orElseThrow(DebateRoomNotFoundException::new);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.rollthedice.backend.domain.member.exception;

import com.rollthedice.backend.global.error.ErrorCode;
import com.rollthedice.backend.global.error.exception.BusinessException;

public class MemberNotFoundException extends BusinessException {
public MemberNotFoundException() {
super(ErrorCode.MEMBER_NOT_FOUND_ERROR);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.rollthedice.backend.domain.member.service;

import com.rollthedice.backend.domain.member.dto.MemberServiceDto;
import com.rollthedice.backend.domain.member.dto.SignUpDto;
import com.rollthedice.backend.domain.member.dto.response.MemberResponse;
import com.rollthedice.backend.domain.member.entity.Member;
import com.rollthedice.backend.domain.member.exception.MemberNotFoundException;
import com.rollthedice.backend.domain.member.repository.MemberRepository;
import com.rollthedice.backend.global.oauth2.service.AuthService;
import com.rollthedice.backend.global.security.jwt.refresh.service.RefreshTokenService;
import com.rollthedice.backend.global.security.jwt.service.JwtService;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -38,7 +37,7 @@ public void update(MemberServiceDto memberServiceDto) {

@Transactional(readOnly = true)
public Member findByEmail(String email) {
return memberRepository.findByEmail(email).orElseThrow(EntityNotFoundException::new);
return memberRepository.findByEmail(email).orElseThrow(MemberNotFoundException::new);
}

public MemberResponse getMemberInfo() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
package com.rollthedice.backend.domain.news.api;

import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.data.domain.Pageable;

import java.util.List;

public interface NewsApi {
@Operation(
summary = "μš”μ•½ λ‰΄μŠ€ 쑰회",
summary = "μš”μ•½ λ‰΄μŠ€ 전체 쑰회",
description = "μš”μ•½ λ‰΄μŠ€λ₯Ό νŽ˜μ΄μ§€λ‘œ λ‚˜λˆ„μ–΄ μ‘°νšŒν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"news"}
)
@ApiResponse(
responseCode = "200",
description = "OK"
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
)
List<NewsResponse> getNews(Pageable pageable);

@Operation(
summary = "μš”μ•½ λ‰΄μŠ€ 상세 쑰회",
description = "ν•˜λ‚˜μ˜ μš”μ•½ λ‰΄μŠ€λ₯Ό 상세 μ‘°νšŒν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"news"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
),
@ApiResponse(
responseCode = "404",
description = "λ‰΄μŠ€λ₯Ό 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€."
)
})
NewsDetailResponse getDetailNews(
@Parameter(in = ParameterIn.PATH, description = "λ‰΄μŠ€ ID", required = true)
Long newsId
);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rollthedice.backend.domain.news.api;

import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import com.rollthedice.backend.domain.news.service.NewsService;
import lombok.RequiredArgsConstructor;
Expand All @@ -21,4 +22,10 @@ public class NewsController implements NewsApi {
public List<NewsResponse> getNews(final Pageable pageable) {
return newsService.getNews(pageable);
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/{newsId}")
public NewsDetailResponse getDetailNews(final @PathVariable Long newsId) {
return newsService.getDetailNews(newsId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.rollthedice.backend.domain.news.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NewsDetailResponse {
private Long id;
private String url;
private String title;
private String content;
private String thumbnailUrl;
private String postDate;
private Boolean isBookmarked;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.rollthedice.backend.domain.news.exception;

import com.rollthedice.backend.global.error.exception.BusinessException;
import com.rollthedice.backend.global.error.ErrorCode;

public class NewsNotFoundException extends BusinessException {

public NewsNotFoundException() {
super(ErrorCode.NEWS_NOT_FOUND_ERROR);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rollthedice.backend.domain.news.mapper;

import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse;
import com.rollthedice.backend.domain.news.dto.response.NewsResponse;
import com.rollthedice.backend.domain.news.entity.News;
import org.mapstruct.Mapper;
Expand All @@ -9,4 +10,6 @@
public interface NewsMapper {

NewsResponse toResponse(final News news, boolean isBookmarked);

NewsDetailResponse toDetailResponse(final News news, boolean isBookmarked);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.rollthedice.backend.domain.bookmark.service.BookmarkService;
import com.rollthedice.backend.domain.member.entity.Member;
import com.rollthedice.backend.domain.news.dto.response.NewsDetailResponse;
import com.rollthedice.backend.domain.news.exception.NewsNotFoundException;
import com.rollthedice.backend.global.oauth2.service.AuthService;
import com.rollthedice.backend.domain.news.contentqueue.ContentProducer;
import com.rollthedice.backend.domain.news.dto.ContentMessageDto;
Expand All @@ -10,7 +12,6 @@
import com.rollthedice.backend.domain.news.entity.News;
import com.rollthedice.backend.domain.news.mapper.NewsMapper;
import com.rollthedice.backend.domain.news.repository.NewsRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -45,7 +46,7 @@ public List<News> getNotCrawled() {
@Transactional
public void updateSummarizedNews(ContentMessageDto messageDto) {
News news = newsRepository.findById(messageDto.getId())
.orElseThrow(EntityNotFoundException::new);
.orElseThrow(NewsNotFoundException::new);
news.updateSummarizedContent(messageDto.getContent());
}

Expand All @@ -66,7 +67,9 @@ public List<NewsResponse> getNews(final Pageable pageable) {
.collect(Collectors.toList());
}

public News getOneNews(Long newsId) {
return newsRepository.findById(newsId).orElseThrow(EntityNotFoundException::new);
public NewsDetailResponse getDetailNews(Long newsId) {
Member member = authService.getMember();
final News news = newsRepository.findById(newsId).orElseThrow(NewsNotFoundException::new);
return newsMapper.toDetailResponse(news, bookmarkService.isBookmarked(member, news));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.rollthedice.backend.global.error;

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

@Getter
@RequiredArgsConstructor
public enum ErrorCode {
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "λ‚΄λΆ€ μ„œλ²„μ— 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."),
CLOVA_API_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "CLOVA API ν˜ΈμΆœμ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€."),

// MEMBER
MEMBER_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "νšŒμ› 정보λ₯Ό 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€." ),

// NEWS
NEWS_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "λ‰΄μŠ€λ₯Ό 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€."),

// DEBATE
DEBATE_ROOM_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "토둠방을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.");


private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.rollthedice.backend.global.error;

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

import java.util.Collections;

@Getter
public class ErrorResponse {
private HttpStatus status;
private String message;

public ErrorResponse(HttpStatus status, String message) {
this.status = status;
this.message = message;
}

public static ErrorResponse create(final ErrorCode errorCode) {
return new ErrorResponse(
errorCode.getStatus(),
errorCode.getMessage()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.rollthedice.backend.global.error;

import com.rollthedice.backend.global.error.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(BusinessException.class)
protected ResponseEntity<ErrorResponse> handleRuntimeException(BusinessException e) {
final ErrorCode errorCode = e.getErrorCode();
log.warn(e.getMessage());

return ResponseEntity
.status(errorCode.getStatus())
.body(new ErrorResponse(errorCode.getStatus(),
errorCode.getMessage()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.rollthedice.backend.global.error.exception;

import com.rollthedice.backend.global.error.ErrorCode;
import lombok.Getter;

@Getter
public class BusinessException extends RuntimeException{
private final ErrorCode errorCode;

public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.rollthedice.backend.global.error.exception;

import com.rollthedice.backend.global.error.ErrorCode;
import lombok.Getter;

import java.io.IOException;

@Getter
public class ExternalApiException extends RuntimeException {

private final ErrorCode errorCode;

public ExternalApiException(ErrorCode errorCode) {
this.errorCode = errorCode;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.rollthedice.backend.domain.member.entity.Member;
import com.rollthedice.backend.domain.member.entity.Role;
import com.rollthedice.backend.domain.member.entity.SocialType;
import com.rollthedice.backend.domain.member.exception.MemberNotFoundException;
import com.rollthedice.backend.domain.member.repository.MemberRepository;
import com.rollthedice.backend.global.oauth2.dto.LoginRequest;
import com.rollthedice.backend.global.oauth2.userInfo.OAuth2UserInfo;
import com.rollthedice.backend.global.security.jwt.service.JwtService;
import com.rollthedice.backend.global.query.QueryService;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -54,7 +54,7 @@ public Member getMember() {

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return memberRepository.findByEmail(userDetails.getUsername()).orElseThrow(EntityNotFoundException::new);
return memberRepository.findByEmail(userDetails.getUsername()).orElseThrow(MemberNotFoundException::new);
}

}
Loading