spring_2기[본캠프]/과제

[과제] Spring 스탠다드 과제 1

minwoo95 2026. 1. 13. 22:33

controller

-UserController

dto

-ErrorResponse

-UserJoinRequest

exception

-BusinessException

-DuplicateEmailException

-GlobalExceptionHandler

 

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-webmvc'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
    testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

 

main

package com.example.springstandardtask1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SpringStandardTask1Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringStandardTask1Application.class, args);
    }

}

 

GlobalExceptionHandler

package com.example.springstandardtask1.exception;

import com.example.springstandardtask1.dto.ErrorResponse;
import org.springframework.http.HttpStatus;
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 java.util.List;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<ErrorResponse> handleValid(MethodArgumentNotValidException e) {
        List<ErrorResponse.FieldErrorDetail> details = e.getBindingResult().getFieldErrors().stream()
                .map(error -> new ErrorResponse.FieldErrorDetail(
                        error.getField(),
                        String.valueOf(error.getRejectedValue()),
                        error.getDefaultMessage()))
                .collect(Collectors.toList());

        return ResponseEntity.badRequest().body(new ErrorResponse("VALID_FAIL", "입력값 검증 실패", details));
    }

    @ExceptionHandler(BusinessException.class)
    protected ResponseEntity<ErrorResponse> handleBusiness(BusinessException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse(e.getErrorCode(), e.getMessage(), null));
    }
}

 

DuplicateEmailException

package com.example.springstandardtask1.exception;

public class DuplicateEmailException extends BusinessException {
    public DuplicateEmailException() {
        super("이미 가입된 이메일입니다.", "USER_409");
    }
}

 

BusinessException

package com.example.springstandardtask1.exception;

public class BusinessException extends RuntimeException {
    private final String errorCode;
    public BusinessException(String message, String errorCode) {
        super(message);
        this.errorCode = errorCode;
    }
    public String getErrorCode() { return errorCode; }
}

 

UserJoinRequest

package com.example.springstandardtask1.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record UserJoinRequest(
        @NotBlank(message = "이메일은 필수입니다.")
        @Email(message = "이메일 형식이 아닙니다.")
        String email,

        @NotBlank(message = "비밀번호는 필수입니다.")
        @Size(min = 8, message = "8자 이상 입력하세요.")
        String password
) {}

 

ErrorResponse

package com.example.springstandardtask1.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;

public record ErrorResponse(
        String code,
        String message,
        @JsonInclude(JsonInclude.Include.NON_NULL)
        List<FieldErrorDetail> errors
) {
    public record FieldErrorDetail(String field, String value, String reason) {}
}

 

UserController

package com.example.springstandardtask1.controller;

import com.example.springstandardtask1.dto.UserJoinRequest;
import com.example.springstandardtask1.exception.DuplicateEmailException;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @PostMapping("/join")
    public String join(@RequestBody @Valid UserJoinRequest request) {
        if ("duplicate@example.com".equals(request.email())) {
            throw new DuplicateEmailException();
        }
        return "회원가입 성공: " + request.email();
    }
}