Burninghering's Blog
article thumbnail
Published 2022. 6. 6. 05:06
Exception 처리 Spring

 

기본적으로 2가지 방식이 있다

 

dto - User.java

package com.example.exception.dto;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class User {

    @NotEmpty
    @Size(min=1,max=10)
    private String name;

    @Min(1)
    @NotNull
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

controller - ApiController.java

package com.example.exception.controller;

import com.example.exception.dto.User;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/user")
public class ApiController {

    @GetMapping("")
    public User get(@RequestParam String name, @RequestParam(required = false) Integer age){
        //(required = false)란 그 변수가 없어도 동작을 하되, 그 변수는 Null이 된다
        //(required = false)는 ?name=1234같이 값이 안들어가있으면 error 터뜨림
        User user = new User();
        user.setName(name);
        user.setAge(age);

        int a= 10+age; //age에 값을 넣어주지 않으면 Null point가 발생하도록 함

        return user;
    }

    @PostMapping("")
    public User post(@Valid @RequestBody User user){
        System.out.println(user);
        return user;
    }
}

 

name과 age에 아무 값을 안넣고 GET 요청을 넣었더니 에러 발생~!

java:18 ->

user.setAge(age);

 

User.java에서

public void setAge(int age) {
    this.age = age;
}

int로 age를 받아야 하는데,

 

ApiController.java에서

@GetMapping("")
public User get(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age){
    //(required = false)란 그 변수가 없어도 동작을 하되, 그 변수는 Null이 된다
    //(required = false)는 ?name=1234같이 값이 안들어가있으면 error 터뜨림
    User user = new User();
    user.setName(name);
    user.setAge(age);

    int a= 10+age; //age에 값을 넣어주지 않으면 Null point가 발생하도록 함

    return user;
}

Integer로 받아버리니 에러가 터져버린다.

 

또 다른 예제로 

Post를 보냈는데,

서버 쪽에서는 친절하게 에러를 알려주지만

클라이언트쪽에서는 단순하게 에러를 터뜨리고 끝낸다


첫 번째 방법!

ExceptionHandler

advice - GlobalControllerAdvice

package com.example.exception.advice;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice //Rest API Controller에 할 예정이니까
public class GlobalControllerAdvice {

    //내가 잡고자 하는 메소드 만들어보자

    @ExceptionHandler(value = Exception.class) //전체적인 예외 다 잡을거임
    public ResponseEntity exception(Exception e){ //Rest API니까 ResponseEntity받자
        //value = Exception.class 여기서 설정한 값을 Exception e에 매개변수로 받을 수 있다

        System.out.println("----------------------");
        System.out.println(e.getLocalizedMessage());
        System.out.println("----------------------");

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");

    }
}

 

내가 지정한 ExceptionHandler를 통해 메시지가 찍히게 됨

 

아까와는 다르게  Body에 아무런 메시지도 없다!

 

 

ExceptionHandler 함수에

System.out.println(e.getClass().getName());

추가해주면

 

어떤 예외가 터졌는지 볼 수 있게 된다 

 

 

그대로 복사해서 따로 잡아보자

특정 메소드의 예외 잡기!

@ExceptionHandler(value= MethodArgumentNotValidException.class)
public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){

    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}

 

결과 : 

 

 

또는,

@RestControllerAdvice(basePackages = "com.example.exception.controller")

basePackages를 붙여서

특정 패키지 하위에 있는 모든 예외들을 다 잡을 것이다

라고 명시 가능

 


두 번째 방법!

특정 컨트롤러에서만 예외 잡기

package com.example.exception.controller;

import com.example.exception.dto.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/user")
public class ApiController {

    @GetMapping("")
    public User get(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age){
        //(required = false)란 그 변수가 없어도 동작을 하되, 그 변수는 Null이 된다
        //(required = false)는 ?name=1234같이 값이 안들어가있으면 error 터뜨림
        User user = new User();
        user.setName(name);
        user.setAge(age);

        int a= 10+age; //age에 값을 넣어주지 않으면 Null point가 발생하도록 함

        return user;
    }

    @PostMapping("")
    public User post(@Valid @RequestBody User user){
        System.out.println(user);
        return user;
    }

    @ExceptionHandler(value= MethodArgumentNotValidException.class)
    public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }
    
}

 

맨 아래에 ExceptionHandler를 그대로 복사해서 해당 controller에 붙여넣어주면,

해당 controller에서 나오는 예외만 잡겠다는 의미가 됨 

 

예외처리 코드 

위 POST 예외는 

무슨 코드를 타고 예외로 잡힐까?

@ExceptionHandler(value= MethodArgumentNotValidException.class)
public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){

    System.out.println("api controller");
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}

 

@RestControllerAdvice()

위와 같이 GlobalControllerAdvice에 예외처리 메소드가 있다고 하더라도,

 

@ExceptionHandler

해당 controller에 있는 예외처리 메소드가 우선순위이다!

'Spring' 카테고리의 다른 글

Spring - DTO를 사용하는 이유  (0) 2022.06.16
Validation 모범 사례  (0) 2022.06.13
Custom Validation  (0) 2022.06.05
Validation  (0) 2022.06.01
Object Mapper 활용 - json 값 바꾸기  (0) 2022.05.30
profile

Burninghering's Blog

@개발자 김혜린

안녕하세요! 반갑습니다.