Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BEConfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.umc.domain.review.dto.ReviewResponseDto;
import com.example.umc.domain.review.service.ReviewService;
import com.example.umc.global.apiPayload.ApiResponse;
import com.example.umc.global.apiPayload.code.status.SuccessStatus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down Expand Up @@ -32,6 +33,8 @@ public ApiResponse<List<ReviewResponseDto>> getMyReviews(
.stream()
.map(ReviewResponseDto::from)
.collect(Collectors.toList());
return ApiResponse.onSuccess(reviews);

SuccessStatus code = SuccessStatus._OK;
return ApiResponse.onSuccess(code, reviews);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.umc.domain.test.controller;

import com.example.umc.domain.test.converter.TestConverter;
import com.example.umc.domain.test.dto.TestResDTO;
import com.example.umc.domain.test.service.TestQueryService;
import com.example.umc.global.apiPayload.ApiResponse;
import com.example.umc.global.apiPayload.code.status.SuccessStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/temp")
public class TestController {

private final TestQueryService testQueryService;

@GetMapping("/test")
public ApiResponse<TestResDTO.Testing> test() {
// 응답 코드 정의
SuccessStatus code = SuccessStatus._OK;

return ApiResponse.onSuccess(
code,
TestConverter.toTestingDTO("This is Test!"));
}

// 예외 상황
@GetMapping("/exception")
public ApiResponse<TestResDTO.Exception> exception(@RequestParam Long flag) {
testQueryService.checkFlag(flag);

// 응답 코드 정의
SuccessStatus code = SuccessStatus._OK;
return ApiResponse.onSuccess(code, TestConverter.toExceptionDTO("This is Test!"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.umc.domain.test.converter;

import com.example.umc.domain.test.dto.TestResDTO;

public class TestConverter {

// 객체 -> DTO
public static TestResDTO.Testing toTestingDTO(String testing) {
return TestResDTO.Testing.builder()
.testString(testing)
.build();
}

// 객체 -> DTO
public static TestResDTO.Exception toExceptionDTO(String testing) {
return TestResDTO.Exception.builder()
.testString(testing)
.build();
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/example/umc/domain/test/dto/TestResDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.umc.domain.test.dto;

import lombok.Builder;
import lombok.Getter;

public class TestResDTO {

@Builder
@Getter
public static class Testing {
private String testString;
}

@Builder
@Getter
public static class Exception {
private String testString;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.umc.domain.test.exception;

import com.example.umc.global.exception.GeneralException;

public class TestException extends GeneralException {

public TestException(com.example.umc.domain.test.exception.code.TestErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.example.umc.domain.test.exception.code;

import com.example.umc.global.apiPayload.code.BaseErrorCode;
import com.example.umc.global.apiPayload.code.ErrorReasonDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum TestErrorCode implements BaseErrorCode {

// For test
TEST_EXCEPTION(HttpStatus.BAD_REQUEST, "TEST400_1", "이거는 테스트"),
;

private final HttpStatus httpStatus;
private final String code;
private final String message;

@Override
public ErrorReasonDto getReason() {
return ErrorReasonDto.builder()
.message(message)
.code(code)
.isSuccess(false)
.build();
}

@Override
public ErrorReasonDto getReasonHttpStatus() {
return ErrorReasonDto.builder()
.httpStatus(httpStatus)
.message(message)
.code(code)
.isSuccess(false)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.umc.domain.test.service;

public interface TestQueryService {
void checkFlag(Long flag);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.umc.domain.test.service;

import com.example.umc.domain.test.exception.TestException;
import com.example.umc.domain.test.exception.code.TestErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class TestQueryServiceImpl implements TestQueryService {

@Override
public void checkFlag(Long flag) {
if (flag == 1) {
throw new TestException(TestErrorCode.TEST_EXCEPTION);
}
}
}
16 changes: 11 additions & 5 deletions src/main/java/com/example/umc/global/apiPayload/ApiResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@Getter
@AllArgsConstructor
@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
@JsonPropertyOrder({ "isSuccess", "code", "message", "result" })
public class ApiResponse<T> {
@JsonProperty("isSuccess")
private final boolean isSuccess;
Expand All @@ -25,17 +25,23 @@ public static <T> ApiResponse<T> onSuccess(T result) {
true,
SuccessStatus._OK.getCode(),
SuccessStatus._OK.getMessage(),
result
);
result);
}

public static <T> ApiResponse<T> onSuccess(BaseCode code, T result) {
return new ApiResponse<>(
true,
code.getReasonHttpStatus().getCode(),
code.getReasonHttpStatus().getMessage(),
result);
}

public static <T> ApiResponse<T> of(BaseCode code, String message, T result) {
return new ApiResponse<>(
true,
code.getReasonHttpStatus().getCode(),
code.getReasonHttpStatus().getMessage(),
result
);
result);
}

public static <T> ApiResponse<T> onFailure(String code, String message, T result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
@Getter
@AllArgsConstructor
public enum SuccessStatus implements BaseCode {
_OK(HttpStatus.OK, "COMMON2000", "성공입니다."),
_OK(HttpStatus.OK, "COMMON200", "성공적으로 요청을 처리했습니다."),
;

private final HttpStatus httpStatus;
private final String code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests(authz -> authz
// API 경로 허용
.requestMatchers("/api/v1/reviews/**").permitAll()
.requestMatchers("/temp/**").permitAll()
.requestMatchers("/swagger-ui/**").permitAll()
.requestMatchers("/v3/api-docs/**").permitAll()
.requestMatchers("/swagger-ui.html").permitAll()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.umc.global.exception;

import com.example.umc.global.apiPayload.code.BaseErrorCode;
import lombok.Getter;

@Getter
public class GeneralException extends RuntimeException {

private BaseErrorCode codeBase;

public GeneralException(BaseErrorCode codeBase) {
super(codeBase.getReason().getMessage());
this.codeBase = codeBase;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.example.umc.global.exception;

import com.example.umc.global.apiPayload.ApiResponse;
import com.example.umc.global.apiPayload.code.ErrorReasonDto;
import com.example.umc.global.apiPayload.code.status.ErrorStatus;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler
public ResponseEntity<Object> general(GeneralException e, WebRequest request) {
ErrorReasonDto reasonHttpStatus = e.getCodeBase().getReasonHttpStatus();
return handleExceptionInternal(e, reasonHttpStatus, HttpHeaders.EMPTY, reasonHttpStatus.getHttpStatus(), request);
}

@ExceptionHandler
public ResponseEntity<Object> exception(Exception e, WebRequest request) {
return handleExceptionInternalFalse(e,
ApiResponse.onFailure(
ErrorStatus._INTERNAL_SERVER_ERROR.getReasonHttpStatus().getCode(),
ErrorStatus._INTERNAL_SERVER_ERROR.getReasonHttpStatus().getMessage(),
null),
HttpHeaders.EMPTY, HttpStatus.INTERNAL_SERVER_ERROR, request, e.getMessage());
}

@Override
public ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException e, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
Map<String, String> errors = new LinkedHashMap<>();

e.getBindingResult().getFieldErrors().stream()
.forEach(fieldError -> {
String fieldName = fieldError.getField();
String errorMessage = Optional.ofNullable(fieldError.getDefaultMessage()).orElse("");
errors.merge(fieldName, errorMessage, (existingMessage, newMessage) -> existingMessage + ", " + newMessage);
});

return handleExceptionInternalArgs(e, HttpHeaders.EMPTY, errors, HttpStatus.BAD_REQUEST, request);
}

@ExceptionHandler
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException e, WebRequest request) {
String errorMessage = e.getConstraintViolations().stream()
.map(constraintViolation -> constraintViolation.getMessage())
.findFirst()
.orElseThrow(() -> new RuntimeException("ConstraintViolationException translating unexpected"));

return handleExceptionInternalFalse(e, null, HttpHeaders.EMPTY, HttpStatus.BAD_REQUEST, request, errorMessage);
}

protected ResponseEntity<Object> handleExceptionInternal(Exception e, Object body,
HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) {

return handleExceptionInternalFalse(e, ApiResponse.onFailure(
((ErrorReasonDto) body).getCode(),
((ErrorReasonDto) body).getMessage(),
null), headers, statusCode, request, ((ErrorReasonDto) body).getMessage());
}

private ResponseEntity<Object> handleExceptionInternalArgs(Exception e, HttpHeaders headers,
Map<String, String> errors,
HttpStatusCode statusCode, WebRequest request) {
return handleExceptionInternalFalse(e, ApiResponse.onFailure("COMMON400", "잘못된 요청입니다.", errors), headers,
statusCode, request, errors.toString());
}

private ResponseEntity<Object> handleExceptionInternalFalse(Exception e, Object body,
HttpHeaders headers, HttpStatusCode statusCode, WebRequest request, String errorPoint) {
ServletWebRequest servletWebRequest = (ServletWebRequest) request;
String url = servletWebRequest.getRequest().getRequestURI();
log.error("Rest API Exception: {}, url: {}, message: {}", statusCode, url, errorPoint, e);

return super.handleExceptionInternal(e, body, headers, statusCode, request);
}
}
2 changes: 1 addition & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
spring.application.name=umc
spring.profiles.active=dev
spring.config.import=optional:file:./BEConfig/application.properties,optional:file:./BEConfig/application-dev.properties,optional:file:./BEConfig/application-test.properties,optional:file:./BEConfig/application-prod.properties
spring.config.import=optional:file:./BEConfig/application.properties,optional:file:./BEConfig/application-dev.properties