테이블 데이터 비우고 다시 넣기
우선 테스트를 하기 위해 기존에 저장된 테이블을 비우자
이렇게 저장된 테이블이 비워진다.
ddl-auto를 create로 설정한 다음 부트를 재실행하자
그러면 기존 테이블들이 drop되고 새로 생성된다.
이제 포스트맨에서 값들을 넣어보자
이렇게 값을 전달하고 MySQL Workbench에서 테이블을 확인해보면
값들이 잘 들어간 것을 확인할 수 있다.
이제 데이터가 지워지지 않게
ddl-auto를 다시 update로 설정한다.
selete 테스트
그럼 이제 DummyControllerTest.java에서 select 코드를 작성해보자
Optional이란?
Optional<T>는 null이 올 수 있는 값을 감싸는 Wrapper 클래스로,
참조하더라도 NPE(NullPointerException)가 발생하지 않도록 도와준다.
그래서 이제 null이 되지 않게 Optinal을 잘 이용해서 코드를 작성해보자
첫 번째 방법(오답)
User user = userRepository.findById(id).get();
// .get()을 붙였다는 건 null이 리턴될리가 없다며
// 유저 객체를 바로 Optional해서 뽑아서 주는 것이다.
이렇게 코드를 작성하면 안된다. 유저 id인 4가 없는 경우에
http://localhost:9090/blog/dummy/user/4 와 같이 요청하면 null이다.
따라서 이 방법은 정답이 아니다.
두 번째 방법
orElseGet은 "null이면 니가 객체 하나 만들어서 user에 넣어줘 그럼 user가 null이 아니잖아?" 하는 것이다.
orElse는 null이던 말던 항상 실행되고 orElseGet은 null일 때만 실행된다.
그럼 orElseGet 안에 넣을 수 있는 파라미터는 무엇일까?
바로 Supplier 타입이다.
그런데 Supplier가 뭐냐고? ㄷㄷ
Supplier<T>는 함수형 인터페이스이다.
Supplier.class를 열어보면
이렇게 작성되어있는 인터페이스이다.
다른 함수형 인터페이스들과 다르게 매개변수를 받지 않고 단순히 무엇인가를 반환하는 *추상메소드가 존재한다.
*추상메소드
추상 메소드란 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드를 의미한다.
자바에서 추상 메소드를 선언하여 사용하는 목적은
추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 하기 위함이다.
예를 들면 모듈처럼 중복되는 부분이나 공통적인 부분은 미리 다 만들어진 것을 사용하고, 이를 받아 사용하는 쪽에서는 자신에게 필요한 부분만을 재정의하여 사용함으로써 생산성이 향상되고 배포 등이 쉬워지기 때문이다.
이러한 추상 메소드는 선언부만이 존재하며, 구현부는 작성되어 있지 않다.
바로 이 작성되어 있지 않은 구현부를 자식 클래스에서 오버라이딩하여 사용하는 것이다.
다시 돌아가서, 그래서 orElseGet를 작성해보면
알다시피 인터페이스는 객체를 생성할 수 없기 때문에 생성자를 가질 수 없다. (new 불가능)
하지만 이렇게 익명 객체(클래스)를 만들면 인터페이스를 new 할 수 있다.
익명 객체는 단독으로 생성할 수 없고 클래스를 상속하거나 구현할 인터페이스가 있어야만 한다.
따라서 이 인터페이스 Supplier가 들고있는 get()을 오버라이딩 해주자
그럼 이와 같이 작성된다.
세 번째 방법
orElseThrow를 사용한다.
여기서 X를 IllegalArgumentException으로 바꿔준다.
이제 테스트해보자
현재 id는 3까지 있으니 유저 정보를 출력해야하고,
4부터는 없으니 해당 유저는 없다는 문구가 떠야한다.
실행결과 :
3을 요청하니 id가 3에 해당하는 유저 정보를 제대로 출력한다.
그럼 없는 유저인 id 4를 요청해보자
IllegalArgumentException 처리가 제대로 되었다.
그런데 유저들한테 이런 페이지를 보여주는 것은 좋지 않다.
스프링에서는 이런 Exception이 발생하면 이를 가로채서 따로 에러 페이지를 만들어 보여주는 것이 좋다.
이러한 Exception 처리는 나중에 또 공부하겠다.
+ 추가
람다식 사용
해당 코드를 람다식 사용으로 훨씬 코드를 줄일 수 있다.
이렇게 람다식을 사용하면 orElseThrow안에 어떤 타입이 들어가야하는지 신경을 쓰지 않고
익명으로 처리할 수 있다.
즉, Supplier 타입으로 리턴해야 한다 이런 것을 몰라도 된다. 리턴 타입을 몰라도 된다는 것이다.
스프링 부트에서의 json 변환
...
스프링 서버가 reponse를 해주는데 reponse 해주는 데이터는 application/json이라고
Content-Type을 http헤더에 명시해서 던져준다.
전체 User 가져오기
여기서 T는 *제네릭이다.
제네릭 :
제네릭은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법이다.
즉, 클래스 내부에서 지정하는 것이 아니라 외부에서 사용자에 의해 지정되는 것을 의미한다.
특정 타입을 미리 지정하는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입이라는 것이다.
타입은 User가 된다.
실행결과 :
성공적으로 모든 User 데이터들을 리턴한 것을 확인할 수 있다.
Paging 테스트
(DESC - 최신순으로 정렬)
스프링 부트에서는 pageable 이라는 강력한 기능을 제공한다.
실행결과 :
우선 다음과 같이 매핑을 변경해주고
실행해주면
이렇게 페이징이 제대로 동작한다.
우선, 아래쪽의 pageable 정보가 리턴될 필요는 없으니까
Page<User>에서 List<User>로 변경한다.
그런데 이렇게 코드를 작성하는 것보다 좋은 방법이 있다.
이렇게 코드를 작성하는 것이다.
저 중간에 if(pagingUsers.isLast()) { } 와 같은 코드를 작성하는 페이지 처리도 가능해진다.
실행결과 :
페이징 처리가 성공적으로 이루어졌다.
참고자료 : https://youtu.be/z_yxfFUX1xI
'자바 스프링 > 부트 블로그 JPA 프로젝트' 카테고리의 다른 글
#14 delete 테스트, Exception 처리하기 (0) | 2022.05.07 |
---|---|
#13 update 테스트 (0) | 2022.05.07 |
#11 insert 테스트와 enum 사용법 (1) | 2022.05.06 |
#10 연관관계에 대한 이해 (0) | 2022.05.05 |
#9 JPA와 DB테이블 생성(User, Board, Reply) (0) | 2022.05.05 |