백엔드/코딩 자율학습 스프링 부트 3 자바 백엔드 개발 입문 1~2장

5장. 게시글 읽기: Read

dlng23 2024. 12. 21. 16:13

5.1 데이터 조회 과정

DB에 저장된 데이터를 웹 페이지에 출력하는 과정

  1. 사용자가 데이터를 조회해 달라고 웹 페이지에서 URL 요청을 보냄
  2. 서버의 컨트롤러가 요청을 받아 해당 URL에서 찾으려는 데이터 정보를 리파지터리에 전달
  3. 리파지터리는 정보를 가지고 DB에 데이터 조회를 요청
  4. DB는 해당 데이터를 찾아 엔티티로 반환
  5. 반환된 엔티티는 모델을 통해 뷰 템플릿으로 전달됨
  6. 최종적으로 결과 뷰 페이지가 완성되어 사용자의 화면에 출력됨

 

5.2 단일 데이터 조회하기

URL 요청받기

DB에 저장한 데이터를 웹 페이지에서 보려면 해당 출력 페이지에 접속해야 함

URL 요청이 필요

 

게시글 n번 id를 조회할 때 localhost:8080/articles/n 에 접속하는 식으로 URL 요청을 받을 예정

 

아직 요청을 받아 줄 컨트롤러가 없기때문에 localhost:8080/articles/1000으로 접속하여도 아무것도 나오지 않음

 

컨트롤러 만들기

1. 조회할 데이터가 Article이므로 ArticleController에 코드를 추가하는 방식으로 작성

ArticleController 코드 열기

 

2. URL 요청을 받기 위해 기존 코드 맨 아래에 @GetMapping() 어노테이션 작성

괄호 안에 URL은 "/articles/{id}"로 입력

중괄호 안에 id를 써 주면 id는 변수로 사용됨

 

3. URL 요청을 받아 수행할 show()라는 메서드 생성

메서드의 매개변수는 URL에 있는 id를 가져옴 → id 앞에 @PathVariable 어노테이션 붙임

@PathVariable: URL 요청으로 들어온 전달값을 컨트롤러의 매개변수로 가져오는 어노테이션

@GetMapping("/articles/{id}")
public String show(@PathVariable Long id){
    return "";
}

 

4. 로깅 기능을 이용하여 컨트롤러가 id를 잘 받았는지 확인

@GetMapping("/articles/{id}")
public String show(@PathVariable Long id){
    log.info("id = " + id);
    return "";
}

 

 

5. 서버 재시작 후 localhost:8080/articles/1000 에 접속

 아직 결과 페이지는 나오지는 않지만 로그를 보면 id = 1000이 잘 전달된 것을 확인할 수 있음

 

데이터 조회해 출력하기

다음으로 해야 할 일 3단계

  1. id를 조회해 DB에서 해당 데이터 가져오기
  2. 가져온 데이터를 모델에 등록하기
  3. 조회한 데이터를 사용자에게 보여 주기 위한 뷰 페이지 만들고 반환하기

id를 조회해 데이터 가져오기

DB에서 데이터를 가져오는 주체는 리파지터리

@Autowired
private ArticleRepository articleRepository;

 

1. findById(Long id) 선택 → 특정 엔티티의 id 값을 지준으로 데이터를 찾아 Optional 타입으로 반환

일단 반환형을 무시하고 찾은 데이터를 Article 타입의 articleEntity 변수에 저장

// 1. id를 조회해 DB에서 해당 데이터 가져오기
Article articleEntity = articleRepository.findById(id);

 

2. 빨간색 물결로 에러표시가 뜸 → findBy(id) 로 찾은 값을 반환할 때 반환형이 Article이 아니기 때문.

반환형은 Optional<Article> 타입임

Optional<Article> 로 수정하면 에러가 사라지지만 다른 방법을 사용

코드 맨 뒤에 .orElse()메서드 추가 → id 값을 데이터를 찾을 때 해당 id가 없으면 null을 반환하라는 뜻

값이 존재하는 경우 articleEntity 변수에 값을 넣고 없으면 null을 저장

 

모델에 데이터 등록하기

articleEntity에 담긴 데이터를 모델에 등록

(MVC 패턴에 따라 조회한 데이터를 뷰 페이지에서 사용하기 위함)

 

1. 모델을 사용하기 위해 show() 메서드의 매개변수로 model 객체를 받아 옴 

public String show(@PathVariable Long id, Model model){
	(중략)
}

 

2. 모델에 데이터를 등록할 때 addAttribute() 메서드 사용

// 2. 가져온 데이터를 모델에 등록하기
model.addAttribute("article", articleEntity);

 

 

뷰 페이지 반환하기

1. 뷰 페이지는 articles라는 디렉터리 안에 show라는 파일이 있다고 가정하고 다음과 같이 반환

// 3. 조회한 데이터를 사용자에게 보여 주기 위한 뷰 페이지 만들고 반환하기
return "articles/show";

 

2. resources > templates > articles에 show.mustache 파일 생성

 

3. 헤더와 푸터 작성

{{>layouts/header}}

{{>layouts/footer}}

 

4. 헤더와 푸터 사이의 데이터를 부트스트랩을 활용하여 작성

 gebootstrap.com 에 접속한 후 table 검색하여 Tables 클릭, 기본 형식의 테이블 [Copy]

 

5. show.mustache에서 헤더와 푸터 사이에 붙여 넣기

 

6. localhost:8080/articles/1000 페이지에 접속하여 확인

 

7. 표를 원하는 형태로 수정

  1. 제목 행의 이름 수정
  2. 필요 없는 코드 삭제
  3. 3번째 내용 행의 속성들은(scope="row", colspan="2") 모두 지우고 가짜 데이터를 임시로 넣음
{{>layouts/header}}
<table class="table">
    <thead>
    <tr>
        <th scope="col">Id</th>
        <th scope="col">Title</th>
        <th scope="col">Content</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th>1</th>
        <td>제목1111</td>
        <td>내용1111</td>
    </tr>
    </tbody>
</table>
{{>layouts/footer}}

 

8. localhost:8080/articles/1000 페이지에서 출력 내용 확인

 

9. 모델에 등록한 article을 뷰 페이지에서 머스테치 문법에 따라 출력

{{#article}} {{/article}}로 사용 범위 지정

 

10. article에 담긴 id, title, content를 이중괄호를 이용해 가져옴

{{>layouts/header}}
<table class="table">
    <thead>
    <tr>
        <th scope="col">Id</th>
        <th scope="col">Title</th>
        <th scope="col">Content</th>
    </tr>
    </thead>
    <tbody>
    {{#article}}
    <tr>
        <th>{{id}}</th>
        <td>{{title}}</td>
        <td>{{content}}</td>
    </tr>
    {{/article}}
    </tbody>
</table>
{{>layouts/footer}}

 

11. 서버 재시작 후 localhost:8080/articles/3에 접속 → 아무런 데이터가 조회되지 않음

휘발성 DB인 메모리 DB를 사용하고 있기때문에 서버를 재시작할 때마다 데이터가 날아가 결과가 출력되지 않음 

 

12. 데이터 추가 위해 localhost:8080/articles/new 페이지에서 제목과 내용 입력하고 [Submit] 클릭

1번 id를 가진 데이터가 만들어졌다고 나옴

 

13. localhost:8080/articles/1에 접속하면 에러 발생

엔티티에 기본 생성자 없어서 에러 발생

 

기본 생성자 추가하기

1. entity > Article 파일 열기

기본 생성자: 매개 변수가 아무것도 없는 생성자

 

2. 롬복 이용 → @NoArgsConstructor 를 추가하면 기본 생성자 코드를 작성하지 않아도 됨

 

3. 서버 재시작 후 localhost:8080/articles/new에 접속하여 제목과 데이터 입력 후 전송

 

4. localhost:8080/articles/1에 접속

 

 

5.3 데이터 목록 조회하기

단일 데이터를 조회할 땐 리파지터리가 엔티티를 반환했지만, 데이터 목록을 조회할 때는 엔티티의 묶음인 리스트를 반환

 

URL 요청받기

데이터 목록 조회는 localhost:8080/articles 라는 URL 요청이 들어왔을 때 처리하는 것으로 함

 

1. ArticleController 열고 show() 메서드 아래에 index() 메서드 추가, return 문에는 아직 아무것도 반환하지 X

public String index(){
    return "";
}

 

2. index() 메서드에 @GetMapping("/articles") 선언하여 URL 요청을 받도록 함

@GetMapping("/articles")
public String index(){
    return "";
}

 

데이터 조회해 출력하기

3단계로 나누어 코드 작성

  1. DB에서 모든 Article 데이터 가져오기
  2. 가져온 Article 묶음을 모델에 등록하기
  3. 사용자에게 보여 줄 뷰 페이지 설정하기

모든 데이터 가져오기

1. articleRepository 입력한 뒤 .을 찍은 후 findAll() 메서드 선택

findAll(): 해당 리파지터리에 있는 모든 데이터를 가져오는 메서드

 

메서드 수행 결과는 articleEntityList라는 이름으로 받음

타입은 데이터의 묶음을 받아오므로 List<Article> 로 설정

 

빨간 물결로 나옴

findAll() 메서드의 반환 데이터 타입: Iterable / 작성한 타입: List 로 불일치

 

해결하는 방법 3가지

  1. 캐스팅(형변환)
    Iterable - Collection - List 

    캐스팅(형변환): 데이터 타입을 변환하는 것
    업캐스팅: 넓은 범위로 해석하는 것
    다운캐스팅: 좁은 범위로 해석하는 것

  2. List<Articㅅle> 을 Iterable<Article>로 업캐스팅
  3. findAll() 메서드가 Iterable이 아닌 ArrayList를 반환하도록 수정

세 번째 방법으로 코드 작성

 

2. com.example.firstproject > repository > ArticleRepository 열기

ArticleRepository가 CrudRepository 상속받음

 

CrudRepository의 메서드를 오버라이딩 해줌

블록 안 공간에서 우클릭 후 Generate → Override Methods 클릭한 후 findAll():Iterable<T> 선택

public interface ArticleRepository extends CrudRepository<Article, Long> {
    @Override
    Iterable<Article> findAll();
}

 

3. findAll() 메서드의 반환 값 타입을 Iterable에서 ArrayList로 바꿈

public interface ArticleRepository extends CrudRepository<Article, Long> {
    @Override
    ArrayList<Article> findAll();
}

 

4. ArticleController로 돌아오면 타입 불일치 문제가 해결된 것을 확인할 수 있음

 

모델에 데이터 등록하기

모델 사용

1. index() 메서드의 매개변수로 model 객체를 받아옴

2. model.addAttribute() 메서드로 articleEntityList를 "articleList" 라는 이름으로 등록

@GetMapping("/articles")
public String index(Model model){
    // 1. 모든 데이터 가져오기
    List<Article> articleEntityList = articleRepository.findAll();

    // 2. 모델에 데이터 등록하기
    model.addAttribute("articleList", articleEntityList);
   
    // 3. 뷰 페이지 설정하기
    return "";
}

 

뷰 페이지 설정하기

1. articles 디렉터리 안에 index.mustache 파일이 뷰 페이지로 설정될 수 있도록 return 문 작성

 

2. resources > templates > articles 에 index.mustache 파일 생성

 

3. 헤더, 푸터 작성

 

4. show.mustache 에서 헤더, 푸터 사이의 내용 복사하여 붙여 넣음

 

5. {{#article}} → {{#articleList}} 로 수정 (닫는 코드도 수정)

{{>layouts/header}}

<table class="table">
    <thead>
    <tr>
        <th scope="col">Id</th>
        <th scope="col">Title</th>
        <th scope="col">Content</th>
    </tr>
    </thead>
    <tbody>
    {{#articleList}}
        <tr>
            <th>{{id}}</th>
            <td>{{title}}</td>
            <td>{{content}}</td>
        </tr>
    {{/articleList}}
    </tbody>
</table>

{{>layouts/footer}}

 

6. 서버 재시작 한 후, localhost:8080/articles/new에 접속하여 제목과 내용 여러 개 추가

(재시작한 후 localhost:8080/articles에 들어가면 DB의 데이터가 날아간 상태이므로 먼저 데이터를 추가해주어야 함)

 

7. 인텔리제이 실행창에서 로그를 통해 데이터가 잘 들어갔는지 확인

8. localhost:8080/articles 에 접속하여 확인

 

mustache 문법

머스테치 문법에 쓴 변수(articleList)가 데이터 묶음인 경우 내부 코드가 반복됨