스프링부트 블로그 만들기 – 예외처리
예외처리(Exception)하는 방법
모든 익셉션에 대한 함수를 만든다.
함수가 세분화 되지만 함수 개수가 많아진다.
RuntimeException 함수로 처리한다.
모든 예외를 처리할 수 있는데 세분화 할 수 없다.
IllegalArgumentException 함수를 사용한다.
어떤 익셉션이 발생하더라도 내가 정의한 익셉션을 던질 수 있다.
커스텀 익셉션으로 처리한다.
예외처리
1.존재하지 않는 게시글을 주소창에서 강제 요청했을 때의 예외처리를 해준다.
@GetMapping("/board/{id}") public String detail(@PathVariable int id, Model model) { //select * from board where id = :id //1.orElse : 값을 찾으면 Board가 리턴, 못찾으면 (괄호안 내용 리턴) // Board boardEntity = boardRepository.findById(id) // .orElse(new Board(100, "글없어요", "글없어요", null)); //2.orElseThrow Board boardEntity = boardRepository.findById(id) .orElseThrow(); model.addAttribute("boardEntity",boardEntity); return "board/detail"; }
Optional
null을 가질 수도 혹은 안 가질 수도 있는 박스
orElse
값을 찾으면 Board가 리턴, 못찾으면 괄호안 내용 리턴한다. 주로 디폴트값으로 지정하고 싶을 때 사용한다.
Board boardEntity = boardRepository.findById(id).orElse(new Board());
orElseThrow
Board boardEntity = boardRepository.findById(id)
.orElseThrow();
2.throw로 던진 예외처리를 받아줄 클래스 GlobalExceptionHandler.java를 만들어준다.
package com.cos.blogapp.handler; import java.util.NoSuchElementException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.cos.blogapp.util.Script; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = NoSuchElementException.class) public @ResponseBody String error1(NoSuchElementException e) { System.out.println("Error:"+e.getMessage()); return Script.href("/","게시글 id를 찾을 수 없습니다."); } }
@ControllerAdvice 가 하는일
1.Exception을 Handling한다.
2.@Controller의 역활을 한다.
익셉션 처리 결과 화면
예외처리 Test
catch/try와 throw 비교
package com.cos.blogapp.web; import org.junit.jupiter.api.Test; import com.cos.blogapp.domain.board.Board; public class BoardControllerTest { @Test public void 익셉션테스트() { try { Board b = null; System.out.println(b.getContent()); } catch (Exception e) { System.out.println("오류가 났어요"); System.out.println(e.getMessage()); } } @Test public void 익셉션테스트2() throws Exception{ throw new Exception(); } }
존재하지 않는 게시글에 대한 Exception 처리 외에도 다른 Exception이 발생한다면 위와 같은 방법은 범용성이 없다. 모든 익셉션에 대한 함수를 각각 만들어 둘 수도 있지만 어떤 익셉션 상황이 발생할 지는 일어나지 않고 우리가 미리 추측하는데는 한계가 있다. RuntimeException을 사용하면 한번에 모든 익셉션에 적용할 수 있지만 각각의 익셉션에 대한 세분화를 할 수 없게된다. 이에 자바에서는 IllegalArgumentException이라는 함수를 제공하여 커스텀화 할 수 있게 만들었다. 여기서 더 나아가 개발자가 직접 함수를 만들어 커스텀할 수도 있다.
커스텀 익셉션 처리
1.handler.ex 패키지 안에 커스텀 익셉션 처리할 MyNotFountException.java 파일을 만들어준다.
package com.cos.blogapp.handler.ex; /** * * @author dahyechoi 2021.09.16 * 1.id를 못찾았을 때 사용 * * */ public class MyNotFountException extends RuntimeException{ public MyNotFountException(String msg) { super(msg); } }
2.GlobalExceptionHandler에서 만들어둔 커스텀 익셉션을 사용하는 코드로 수정한다
package com.cos.blogapp2.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.cos.blogapp2.handler.ex.MyNotFountException; import com.cos.blogapp2.util.Script; //Throw 받아주는 클래스 //@ControllerAdvice 가 하는일 - 1.익셉션을 핸들링, 2.@Controller의 역활까지 한다. @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = MyNotFountException.class) public @ResponseBody String error1(MyNotFountException e) { //@ResponseBody = 자바스크립트 리턴 System.out.println("Error:"+e.getMessage()); return Script.href("/",e.getMessage()); //file return } }
3.BoardController에서 게시글 상세보기 코드를 수정한다.
@GetMapping("/board/{id}") public String detail(@PathVariable int id, Model model) { Board boardEntity = boardRepository.findById(id).orElseThrow(() -> new MyNotFountException(id+"를 못 찾았어요.")); model.addAttribute("boardEntity",boardEntity); return "board/detail"; }
람다식
Java 1.8 버전부터 등장한 람다식은 클래스가 1급 객체인 자바에서 함수를 넘기기 위한 목적으로 만들어졌다. 코드가 매우 간결해지고 따로 타입을 적지 않기 때문에 인터페이스에서 함수를 하나만 사용해야한다.