Skip to content

Commit

Permalink
mission: submit week7 mission
Browse files Browse the repository at this point in the history
  • Loading branch information
ahtop00 committed Nov 16, 2024
1 parent 65a8f89 commit f18abe7
Show file tree
Hide file tree
Showing 22 changed files with 482 additions and 2 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// 에러관련 의존성 주입
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'jakarta.validation:jakarta.validation-api:3.0.2'

// QueryDsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories
// @EnableJpaRepositories -> 보통 springBoot가 알아서 리포지토리 추가시켜줌
@EnableJpaAuditing //생성일 및 업데이트일 자동 입력
public class Umc7thMissionApplication {

public static void main(String[] args) {
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/javalab/umc7th_mission/apiPayload/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package javalab.umc7th_mission.apiPayload;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import javalab.umc7th_mission.apiPayload.code.status.SuccessStatus;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
//공통 응답 클래스
public class ApiResponse<T> {

@JsonProperty("isSuccess")
private final Boolean isSuccess;
private final String code;
private final String message;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T result;


// 성공한 경우 응답 생성

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

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


// 실패한 경우 응답 생성
public static <T> ApiResponse<T> onFailure(String code, String message, T data){
return new ApiResponse<>(false, code, message, data);
}
}
8 changes: 8 additions & 0 deletions src/main/java/javalab/umc7th_mission/apiPayload/BaseCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package javalab.umc7th_mission.apiPayload;

//해당 인터페이스의 역할 -> 구체화 하는 Status에서
// 두개의 메소드를 반드시 오버라이드할 것을 강제하는 역할
public interface BaseCode {
ReasonDTO getReason();
ReasonDTO getReasonHttpStatus();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package javalab.umc7th_mission.apiPayload;

public interface BaseErrorCode {

ErrorReasonDTO getReason();

ErrorReasonDTO getReasonHttpStatus();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package javalab.umc7th_mission.apiPayload;

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

@Getter
@Builder
public class ErrorReasonDTO {

private HttpStatus httpStatus;

private final boolean isSuccess;
private final String code;
private final String message;

public boolean getIsSuccess(){return isSuccess;}
}
18 changes: 18 additions & 0 deletions src/main/java/javalab/umc7th_mission/apiPayload/ReasonDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package javalab.umc7th_mission.apiPayload;

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

@Getter
@Builder
public class ReasonDTO {

private HttpStatus httpStatus;

private final boolean isSuccess;
private final String code;
private final String message;

public boolean getIsSuccess(){return isSuccess;}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package javalab.umc7th_mission.apiPayload.code.status;

import javalab.umc7th_mission.apiPayload.BaseErrorCode;
import javalab.umc7th_mission.apiPayload.ErrorReasonDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorStatus implements BaseErrorCode {

// 가장 일반적인 응답
_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 에러, 관리자에게 문의 바랍니다."),
_BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON400","잘못된 요청입니다."),
_UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON401","인증이 필요합니다."),
_FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."),

//임시
TEMP_EXCEPTION(HttpStatus.BAD_REQUEST, "TEMP4001", "테스트용 에러코드"),

// 멤버 관련 에러
MEMBER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MEMBER4001", "사용자가 없습니다."),
NICKNAME_NOT_EXIST(HttpStatus.BAD_REQUEST, "MEMBER4002", "닉네임은 필수 입니다."),

// 예시,,,
ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "ARTICLE4001", "게시글이 없습니다.");


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()
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build()
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package javalab.umc7th_mission.apiPayload.code.status;

import javalab.umc7th_mission.apiPayload.BaseCode;
import javalab.umc7th_mission.apiPayload.ReasonDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum SuccessStatus implements BaseCode {

// 일반적인 응답
_OK(HttpStatus.OK, "COMMON200", "성공입니다.");

//맴버 관련 응답

// ~~~ 관련 응답

//성공응답 추가시 ENUM 형식으로 계속 밑에 추가하면 된다.
private final HttpStatus httpStatus;
private final String code;
private final String message;

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

@Override
public ReasonDTO getReasonHttpStatus() {
return ReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(true)
.httpStatus(httpStatus)
.build()
;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package javalab.umc7th_mission.apiPayload.exception;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
import javalab.umc7th_mission.apiPayload.ApiResponse;
import javalab.umc7th_mission.apiPayload.ErrorReasonDTO;
import javalab.umc7th_mission.apiPayload.code.status.ErrorStatus;
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.RestController;
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(annotations = {RestController.class})
public class ExceptionAdvice extends ResponseEntityExceptionHandler {


@ExceptionHandler
public ResponseEntity<Object> validation(ConstraintViolationException e, WebRequest request) {
String errorMessage = e.getConstraintViolations().stream()
.map(constraintViolation -> constraintViolation.getMessage())
.findFirst()
.orElseThrow(() -> new RuntimeException("ConstraintViolationException 추출 도중 에러 발생"));

return handleExceptionInternalConstraint(e, ErrorStatus.valueOf(errorMessage), HttpHeaders.EMPTY,request);
}

@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, (existingErrorMessage, newErrorMessage) -> existingErrorMessage + ", " + newErrorMessage);
});

return handleExceptionInternalArgs(e,HttpHeaders.EMPTY,ErrorStatus.valueOf("_BAD_REQUEST"),request,errors);
}

@ExceptionHandler
public ResponseEntity<Object> exception(Exception e, WebRequest request) {
e.printStackTrace();

return handleExceptionInternalFalse(e, ErrorStatus._INTERNAL_SERVER_ERROR, HttpHeaders.EMPTY, ErrorStatus._INTERNAL_SERVER_ERROR.getHttpStatus(),request, e.getMessage());
}

@ExceptionHandler(value = GeneralException.class)
public ResponseEntity onThrowException(GeneralException generalException, HttpServletRequest request) {
ErrorReasonDTO errorReasonHttpStatus = generalException.getErrorReasonHttpStatus();
return handleExceptionInternal(generalException,errorReasonHttpStatus,null,request);
}

private ResponseEntity<Object> handleExceptionInternal(Exception e, ErrorReasonDTO reason,
HttpHeaders headers, HttpServletRequest request) {

ApiResponse<Object> body = ApiResponse.onFailure(reason.getCode(),reason.getMessage(),null);
// e.printStackTrace();

WebRequest webRequest = new ServletWebRequest(request);
return super.handleExceptionInternal(
e,
body,
headers,
reason.getHttpStatus(),
webRequest
);
}

private ResponseEntity<Object> handleExceptionInternalFalse(Exception e, ErrorStatus errorCommonStatus,
HttpHeaders headers, HttpStatus status, WebRequest request, String errorPoint) {
ApiResponse<Object> body = ApiResponse.onFailure(errorCommonStatus.getCode(),errorCommonStatus.getMessage(),errorPoint);
return super.handleExceptionInternal(
e,
body,
headers,
status,
request
);
}

private ResponseEntity<Object> handleExceptionInternalArgs(Exception e, HttpHeaders headers, ErrorStatus errorCommonStatus,
WebRequest request, Map<String, String> errorArgs) {
ApiResponse<Object> body = ApiResponse.onFailure(errorCommonStatus.getCode(),errorCommonStatus.getMessage(),errorArgs);
return super.handleExceptionInternal(
e,
body,
headers,
errorCommonStatus.getHttpStatus(),
request
);
}

private ResponseEntity<Object> handleExceptionInternalConstraint(Exception e, ErrorStatus errorCommonStatus,
HttpHeaders headers, WebRequest request) {
ApiResponse<Object> body = ApiResponse.onFailure(errorCommonStatus.getCode(), errorCommonStatus.getMessage(), null);
return super.handleExceptionInternal(
e,
body,
headers,
errorCommonStatus.getHttpStatus(),
request
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package javalab.umc7th_mission.apiPayload.exception;

import javalab.umc7th_mission.apiPayload.BaseErrorCode;
import javalab.umc7th_mission.apiPayload.ErrorReasonDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class GeneralException extends RuntimeException {

private BaseErrorCode code;

public ErrorReasonDTO getErrorReason() {
return this.code.getReason();
}

public ErrorReasonDTO getErrorReasonHttpStatus(){
return this.code.getReasonHttpStatus();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package javalab.umc7th_mission.apiPayload.exception.handler;

import javalab.umc7th_mission.apiPayload.BaseErrorCode;
import javalab.umc7th_mission.apiPayload.exception.GeneralException;

public class TempHandler extends GeneralException {
public TempHandler(BaseErrorCode errorCode) {
super(errorCode);
}
}
18 changes: 18 additions & 0 deletions src/main/java/javalab/umc7th_mission/converter/TempConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package javalab.umc7th_mission.converter;

import javalab.umc7th_mission.web.dto.TempResponse;

public class TempConverter {

public static TempResponse.TempTestDTO toTempTestDTO(){
return TempResponse.TempTestDTO.builder()
.testString("This is Test!")
.build();
}

public static TempResponse.TempExceptionDTO toTempExceptionDTO(Integer flag){
return TempResponse.TempExceptionDTO.builder()
.flag(flag)
.build();
}
}
Loading

0 comments on commit f18abe7

Please sign in to comment.