본문 바로가기

SpringBoot/Blog프로젝트 with JPA &데어프로그래밍님

21.1.3 TIL - 데이터 select와 JPA paging

※본 포스팅은 데어프로그래밍님 스프링부트 블로그 프로젝트 수강 후 작성한 내용입니다.

 

원래 하루에 강의 4개씩 들으려고 했는데 2개 밖에 안들었다ㅠ TIL도 안쓸뻔했지만 이거라도 쓰자! 싶어서 이시간에 쓴다!ㅎㅎ;;

 

[data select]

 

1) 모든 user data 선택

지난시간에 만들어둔 userRepository를 사용할 것이고 해당 인터페이스는 JpaRepository를 extend하고 있기 때문에 따로 함수정의를 해주지 않아도 select할 때 필요한 함수들을 사용할 수 있다.

이중에서 findAll() 함수를 사용해서 user table에 있는 모든 데이터를 가지고 올 수 있다. 여러개의 데이터를 가져오는 것이므로 List 타입으로 정의한다. 

@GetMapping("dummy/allUser")
public List<User> list(){
	return userRepository.findAll();
}

2) id로 한개의 데이터 선택

여기서는 주소에서 id 파라미터를 전달받아서 해당 아이디를 가지는 데이터를 가져오도록 했다.

이것도 역시 JpaRepository에서 제공하는 함수를 이용한다. 이때 findById() 를 사용하는데 이 함수는 return type이 Optional이다. User 객체로 바로 리턴해주지 않는 이유는 만약 받은 id를 가지는 데이터가 없는 경우 바로 User 객체를 리턴하는 함수라면 null을 리턴하게 될 것이다. null이 리턴되면 프로그램에 문제가 생길 수 있기 때문에 이를 방지하기 위해서 프로그래머가 리턴된것이 null인지 아닌지 확인 후 사용할 수 있도록 하기 위함이다. 이 Optional을 처리하기 위한 방법은 3가지를 알려주셨다.

-get() 사용. User객체가 null이 나올 일이 없는 경우 따로 null에 대한 처리 필요없이 그냥 가져오면 되는 경우에 사용한다.

-orElseGet() 사용. 이 경우 null이 아니면 그냥 가져오고 null이면 빈 User객체를 만들어서 user에 넣어준다. 이 방법을 사용하면 각 column에 null or default값이 들어있는 데이터가 리턴된다. 파라미터로 들어갈 수 있는 타입은 Supplier 타입니다. Supplier는 인터페이스이기 때문에 그냥 new해서 생성할 수 없고 익명 클래스를 만들어야 하기 때문에 @Override를 해주어야 한다. 이 방법을 사용할 경우의 코드는 아래와 같다.

User user = userRepository.findById(id).orElseGet(new Supplier<User>() {
	@Override
	public User get() {
		return new User();
	}
}); 

-orElseThrow() 사용. 최종적으로 사용할 방법이다. findById함수가 정의된 것을 보면 @throws IllegalArgumentException if {@literal id} is {@literal null} 라고 되어있다. 즉 throw를 선호하는 것이기 때문에 이를 따라간다. null인 경우 exception처리를 해주고 에러메세지를 리턴해준다. 코드는 다음과 같다.

	//{id} 주소로 파라미터를 전달 받음
	@GetMapping("dummy/user/{id}")
	public User detail(@PathVariable int id) {
		//잘못된 인수가 id부분에 들어온경우 Supplier부분 실행.
		User user = userRepository.findById(id).orElseThrow(new Supplier<IllegalArgumentException>() {
			@Override
			public IllegalArgumentException get() {
				return new IllegalArgumentException("해당 유저는 없습니다. id:"+id);
			}
		});
		return user;
	}

@PathVariable int id 를 쓸 때 id부분은 GetMapping에 있는 파라미터 이름과 같은 것을 써야한다. int를 썼기 때문에 해당 파라미터를 int형으로 받아온다.

 

[JPA paging]

JPA는 페이징 처리를 위한 기본적인 기능들을 제공해준다. 여기서는 페이지의 사이즈를 정하고(한 페이지에 나오는 데이터의 개수), 데이터 정렬 기능을 사용한다. 강의를 들을때는 해당부분의 설명이 길었어서 조금 복잡하다고 생각했는데 지금 TIL을 쓰려고 코드를 다시보니 이 기능을 코드로 다 짜려면 얼마나 복잡했을까... 진짜 좋은 기능을 제공해주는 구나! 라는 생각이 든다ㅎㅎ 그럼 코드를 먼저 살펴보자!

	@GetMapping("dummy/user")
	public List<User> pageList(@PageableDefault(size = 2, sort="id", direction = Sort.Direction.DESC) Pageable pageable){
		Page<User> pagingUser = userRepository.findAll(pageable);
		List<User> users = pagingUser.getContent();
		return users;
	}

@PageableDefault에서 size는 한 페이지에 나오는 데이터의 개수이다.

direction을 Sort.Direction.ASC로 정하면 첫페이지에 id=1,2를 가지는 데이터, 두번째 페이지에 id=3을 가지는 데이터가 나오고 코드에서 처럼 DESC로 할 경우 id=3,2를 가지는 데이터가 첫페이지에, 두번째 페이지에는 id=1을 가지는 데이터가 나온다. (데이터가 3개 있다는 가정하에)

페이지 번호는 다른 프로그래밍 언어들의 번호들이 그렇듯 0번부터 시작한다. 첫번째 페이지 번호가 0번, 두번째 페이지번호는 1번 인것이다. 

첫번째 페이지의 경우 ~/dummy/user 를 하거나 ~/dummy/user?page=0을 하면 볼 수 있고, 두번째 페이지는 ~/dummy/user?page=1 을 하면 볼 수 있다.

만약 Page객체 자체를 리턴하면 user 데이터에 대한 정보 뿐만 아니라 페이지에 대한 정보들도 같이 나온다. 하지만 우리는 페이지 정보는 지금 필요 없기 때문에 getContent()를 해서 user에 대한 정보만 리턴해준다. findAll().getContent();를 해서 바로 리스트로 받아올 수도 있지만 pagingUser를 따로 만든 이유는 이렇게 하면 나중에 Pageable에서 제공하는 다른 함수가 필요한 경우 사용 가능하기 때문이다. 어쨌든 마지막은 코드처럼 List로 만들어서 리턴하는 것이 좋다.

댓글