Closed wongakim-99 closed 3 months ago
웹 페이지에서 게시글을 등록하면 서버를 통해 DB에 저장됨. 이렇게 DB에 저장된 데이터를 웹 페이지에 출력하는 과정은 다양한 요소 간 상호 작용으로 이루어짐.
DB에 저장한 데이터를 웹 페이지에서 보려면 해당 출력 페이지에 접속해야 됨. 그러면 URL 요청이 필요함. 게시글 1번 id를 조회할 때 localhost:8080/articles/1, 2번 id를 조회할 때 localhost:8080/articles/2 ..이런식으로 URL 요청을 받겠다. 먼저 localhost:8080/articles/1000으로 접속해 보면 아무것도 나오지 않을 것이다. 해당 URL 요청을 받아 줄 컨트롤러가 없기 때문. articles/id 로 URL 요청을 했을 때 이를 받아 줄 컨트롤러를 만들겠다.
URL 요청을 받기 위해 맨 아래에 @GetMapping 어노테이션 작성. 괄호 안에 URL은 id에 따라 /articles/1, articles/2, articles/3 등으로 받기로 했으므로 "/articles/{id}"로 입력.
URL요청을 받아 수행할 show() 라는 메서드 만듬. 메서드의 매개변수는 URL에 있는 id를 가져오는데, id 앞에 @PathVariable 어노테이션을 붙임. @PathVariable 은 URL 요청으로 들어온 전달값을 컨트롤러의 매개변수로 가져오는 어노테이션
로깅 기능을 통해 컨트롤러가 id를 잘 받았는지 확인 log.info("id =" + id);
1-1) DB에서 데이터를 가져오는 주체는 리파지터리. 리파지터리의 구현 객체는 다음과 같이 @Autowired 어노테이션으로 주입받음. 이 리파지터리로 DB에 저장된 데이터를 가져올 예정
1-2) articleRepository 까지 입력하고 점(.) 을 찍으면 사용할 수 있는 메서드 목록이 나옴. 목록에서 findById(Long id)를 선택. findById() 는 JPA의 CrudRepository가 제공하는 메서드로, 특정 엔티티의 id 값을 기준으로 데이터를 찾아 Optional 타입으로 반환.
2-1) articleEntity에 담긴 데이터를 모델에 등록. 데이터를 모델에 등록하는 이유는 MVC 패턴에 따라 조회한 데이터를 뷰 페이지에서 사용하기 위함.
2-2) 모델을 사용하기 위해 show() 메서드의 매개변수로 model 객체를 받아옴,
2-3) 모델에 데이터를 등록할 때는 addAttribute() 메서드를 사용.
사용자가 입력한 데이터를 조회하려면 먼저 URL요청을 해야됨. 실습에서는 /articles/id 형식으로 URL요청
컨트롤러는 @GetMapping("/articles/{id}")로 URL 요청을 받는다. 그리고 이 URL에 포함된 id를 show()메서드의 매개변수로 받는데, 이때 매개변수 앞에 @PathVariable 어노테이션을 붙임. 그래야 URL의 id를 가져올 수 있음.
리파지터리에서 DB에 저장된 데이터를 id로 조회할 때 findById() 메서드를 사용. 특별히 조회된 데이터가 없는 경우도 처리해야 하므로 orElse() 메서드로 null이 반환되도록 함.
Article articleEntity = articleRepository.findById(id).orElse(null);
최종적으로 모델에 등록한 데이터를 뷰 페이지에서 사용할 수 있게 설정. 이때 샵(#)과 슬래시(/)를 이용해 열고 닫음으로써 데이터를 사용할 수 있는 영역을 지정.
이렇게 단일 데이터를 조회하는 과정을 통해 MVC, JPA, DB의 상호작용을 확인할 수 있음.
확인췍
단일 데이터가 아닌 여러 데이터, 즉 데이터 목록을 조회해보겠다. 단일 데이터를 조회할 때와 방법은 같지만 다른 점이 하나 있다. 단일 데이터를 조회할 때는 리파지터리가 엔티티를 반환했다면, 데이터 목록을 조회할 때는 엔티티의 묶음인 리스트를 반환한다.
show() 메서드 아래에 index() 라는 메서드를 추가하고 return 문에서는 아직 아무것도 반환X index() 메서드에 @GetMapping("/articles")를 선언해 URL 요청을 받도록 함. 이 요청이 들어오면 index() 메서드가 수행되면서 뷰 페이지를 설정하는 코드들이 실행됨.
1) 모든 데이터 가져오기 - DB에서 데이터를 가져오려면 리파지터리가 필요하다. 따라서 articleRepository 를 입력하고 점(.) 을 찍은 후 이번에는 findAll() 이라는 메서드를 선택함. findAll() 은 해당 리파지터리에 있는 모든 데이터를 가져오는 메서드이다.
List<Article> articleEntityList = articleRepository.findAll();
이렇게 하면 DB에서 조회한 데이터 묶음을 리스트에 담긴 Article 타입으로 가져온다. 그러나 코드에 오류를 나타내는 빨간색 물결이 표시됩니다. 마우스를 findAll() 메서드에 올려 보면 findAll() 메서드가 반환하는 데이터 타입은 Iterable 인데 작성한 타입은 List 라서 서로 불일치한다는 메시지가 뜬다.
이를 해결하는 방법은 3가지가 있다.
첫째, 캐스팅(형변환)하면 된다. Iterable, Collection, List 인터페이스의 상하 관계는 Iterable<- Collection <- List 이다. 캐스팅(casting)이란 데이터 타입을 변환하는 것을 말하며 형변환이라고도 한다.
자바에서 상속 관계가 있는 특정 객체는 상황에 따라 더 넓은 범위로 해석될 수도, 때때로 좁은 범위로 해석될 수도 있다. 이때 넓은 범위로 해석하는 것을 업캐스팅(upcasting), 좁은 범위로 해석하는 것을 다운캐스팅(downcasting)이라 한다.
예를 들어 '고양이'를 '생물'로 해석했다면 업캐스팅한 것이고, '생물'에서 다시 '동물'로 해석했다면 다운캐스팅한 것이다.
따라서 코드를 다음과 같이 수정하면 findAll() 메서드가 반환하는 데이터 타입 Iterable
List<Article> articleEntityList = (List<Article>)articleRepository.findAll();
둘째, articleEntityList의 타입을 findAll() 메서드가 반환하는 타입으로 맞추는 방법. List
Iterable<Article> articleEntityList = articleRepository.findAll();
셋째, Iterable 인터페이스가 익숙하지 않다면 많이 사용하는 ArrayList를 이용할 수도 있다. findAll() 메서드가 Iterable이 아닌 ArrayList를 반환하도록 수정하는 것이다.
ArticleRepository를 들어가면 CrudRepository를 상속받고 있다. 세번째 방법에선 CrudRepository의 메서드를 오버라이딩 해주겠다. 블록 안 공간에서 마우스 오른쪽 버튼을 누르고 Generate -> Override Methods를 클릭한다. 메서드 선택 창이 뜨면 findAll():Iterable
추가한 코드에서 findAll() 메서드의 반환값은 기본적으로
2) 모델에 데이터 등록하기
가져온 데이터를 받은 articleEntityList를 뷰 페이지로 전달할 때는 모델을 사용한다.
index() 메서드의 매개변수로 model객체를 받아 온다. model.addAttribute() 메서드로 전달할 데이터 묶음인 articleEntityList 를 "articleList" 라는 이름으로 등록한다.
확인 췍
데이터 조회 과정
@PathVariable
findById()
findAll()
{{#article}} {{/article}}
반환 데이터 타입 불일치 문제 해결 방법 아래와 같이 특정 메서드가 반환하는 데이터 타입과 사용자가 작성한 반화 데이터 타입이 다를 경우, 아래와 같이 3가지 방법으로 해결가능
앞선 이슈번호 까지는 웹 페이지에서 전송한 폼 데이터를 DB에 저장하는 데이터 생성 과정을 살펴봤다면, 이 장에서는 DB에 저장된 데이터를 조회해 웹 페이지에 출력하는 과정