백엔드/Spring Boot

7. 블로그 화면 구성하기 (3) - 블로그 글 구현하기

두개의 문 2023. 8. 8. 17:36

◎ 블로그 화면 상의 [ 보러 가기 ] 버튼을 누르면, 블로그 글이 보이도록 블로그 글 뷰를 구현해보자.

 

1. 엔티티에 생성, 수정 시간 추가하기 

 

 

1)  글이 언제 생성되고 수정되었는지 뷰에서 확인 가능하게 코드 추가 

 ▪︎ Article.java에 아래의 필드 추가 

    @CreatedDate // 엔티티가 생성될 때 생성 시간 저장 
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    
    @LastModifiedDate 	// 엔티티가 수정될 때 수정 시간 저장 
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

• @CreatedDate : 엔티티가 생성될 때 생성시간을 'created_at' 컬럼에 저장 

 

• @LastModifiedDate : 엔티티가 수정될 때 마지막으로 수정된 시간을 'updated_at' 컬럼에 저장 

 

 

 

2) 엔티티를 생성하면 생성 시간과 수정 시간이 자동으로 저장됨 

     하지만 스프링 부트 서버가 실행될 때마다 SQL문으로 데이터를 넣는 data.sql 파일은 created_at과 updated_at을 바꾸지 않음 

      → 최초 파일 생성에도 이 값을 수정하도록 data.sql 파일을 수정해 실행할 때마다 값이 바뀌도록 해보자 

 

 ▪︎ data.sql

INSERT INTO ARTICLE
	(id, title, content, created_at, updated_at)
    VALUES
    	(article_seq.nextval, '제목1', '내용1', SYSDATE, SYSDATE);

    👉🏻 책에서는 H2 데이터베이스를 쓰지만, 수업시간에 Oracle 데이터베이스로 변경함 

         ∴ Oracle 문법에 맞게 코드 작성 

 

    - 오라클에서 일련번호의 자동 증가 기능이 지원되지 않음 

       → 새로운 일련번호를 가져오려면, sequence 객체를 생성해야 함 

 

    - SQL 명령문 이용 

  CREATE SEQUENCE 시퀀스명;

    - sequence 객체가 만들어지면, '시퀀스명.nextval'로 새로운 일련번호 생성 가능 

   - '시퀀스명.currval' : 현재 번호를 의미함   


 

3) SpringBootDeveloperApplication.java 파일을 열어 엔티티의 created_at, updated_at을 자동으로 업데이트하기 위한 애너테이션 추가 

 

▪︎ HithymeleafApplication.java

 ( 프로젝트명 : Hithymeleaf )

 

package org.choongang.ewha.hithymeleaf;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing	// created_at, updated_at 자동 업데이트 
@SpringBootApplication
public class HiThymeleafApplication {

	public static void main(String[] args) {
		SpringApplication.run(HiThymeleafApplication.class, args);
	}
}

 

 

 


2. 컨트롤러 메서드 작성하기 

 

 

1) 뷰에서 사용할 DTO 생성 

 

 ▪︎ ArticleViewResponse.java ( dto 디렉토리 )

package org.choongang.ewha.hithymeleaf.dto;

import java.time.LocalDateTime;

import org.choongang.ewha.hithymeleaf.domain.Article;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
public class ArticleViewResponse {
  // 변수 선언 
  private Long id;
  private String title;
  private String content;
  private LocalDateTime createdAt;
  
  // 생성자 
  public ArticleViewResponse(Article article) {
    this.id = article.getId();
    this.title = article.getTitle();
    this.content = article.getContent();
    this.createdAt = article.getCreatedAt();
  }
}

 

 

 

2) 블로그 글을 반환할 컨트롤러의 메서드 작성 

 

 ▪︎ BlogViewController.java → getArticle( ) 메서드 추가 

    @GetMapping("/articles/{id}")
    public String getArticle(@PathVariable Long id, Model model) {
        Article article = blogService.findById(id);
        model.addAttribute("article", new ArticleViewResponse(article));

        return "article";
    }

 

• getArticle( ) 메서드는 URL로 넘어온 id값을 findById( ) 메서드로 넘겨 글을 조회 

• 화면에서 사용할 모델인 ArticleViesResponse 객체에 데이터를 저장 → 보여줄 화면의 템플릿 이름으로 반환 

 

• @PathVariable 

  - 이 애너테이션을 사용하여 요청 URI 매핑에서 템플릿 변수를 처리하고, 이를 메서드 매개변수로 설정할 수 있음 

  - {id} 변수로 표시되는 URI의 템플릿 부분을 추출 → getArticle( ) 메서드 호출 

 

 

 


3. HTML 뷰 만들기 

 

1) 화면 작성 

 

 ▪︎ article.html ( resource/template )

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>블로그 글</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
</head>
<body>
<div class="p-5 mb-5 text-center</> bg-light">
	<h1 class="mb-3">My Blog</h1>
	<h4 class="mb-3">블로그에 오신 것을 환영합니다!</h4>
</div>

<div class="container mt-5">
	<div class="row">
		<div class="col-lg-8">
			<article>
				<!-- header 영역  -->
				<header class="mb-4">
					<h1 class="fw-bolder mb-1" th:text="${article.title}"></h1>
					<div class="text-muted fst-italic mb-2" 
							th:text="|Posted on ${ #temporals.format(article.createdAt, 'yyyy-MM-dd HH:mm')}|"></div>
				</header>
				<section class="mb-5">
					<p class="fs-5 mb-4" th:text="${article.content}"></p>
				</section>
				<button type="button" class="btn btn-primary btn-sm">수정</button>
				<button type="button" class="btn btn-secondary btn-sm">삭제</button>
			</article>
		</div>
	</div>
</div>
</body>
</html>

 • 템플릿 함수 중 ${ #temporals.format()} 

   - 날짜 형식을 yyyy-MM-dd HH:mm으로 포매팅함 

   - 포매팅한 날짜 형식을 | | 기호와 함께 Posted on이라는 텍스트와 붙임 

      → 블로그 결과물에 '2099-99-31 23:11 Posted on'과 같이 글을 게시한 시간 알림을 표시할 수 있음 

 

 

 

 

2) 글 리스트 화면에서 글 상세 화면 보러가는 버튼 생성 

 

▪︎ articleList.html 

  : card-body 내에 '보러 가기' 버튼 생성 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>블로그 글 목록</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
</head>
<body>
	<!-- 헤더영역 : 제목표시 -->
	<div class="p-5 mb-5 text-center</> bg-light">
		<h1 class="mb-3">My Blog</h1>
		<h4 class="mb-3">블로그에 오신 것을 환영합니다!</h4>
	</div>
	
	<!--  컨테이너 영역 : 컨텐츠 -->
	<div class="container">
		<div class="row-6" th:each="item : ${articles}"><!-- article 개수만큼 반복 -->
			<!-- 한 개의 블로그 article 내용  -->
			<div class="card">
				<!-- item의 id 출력 -->
				<div class="card-header" th:text="${item.id}">
				</div>
				
				<div class="card-body">
					<!--  item의 title 출력  -->
					<h5 class="card-title" th:text="${item.title}"></h5>
					
					<!--  item의 text 출력  -->
					<p class="card-text" th:text="${item.content}"></p>
					
					<!--  '보러 가기' 버튼 추가  -->
					<a href="@{/articles/{id}(id=${ item.id })}" class="btn btn-primary">보러 가기</a>
				</div>
			</div>
			<br />
		</div>
	</div>
	<!--  푸터 영역(꼬리말) -> 현재 없음  -->
	<div>
	</div>
	
</body>
</html>

• a 태그의 href 속성을 th:href 속성으로 변경, URL 표현식 @{ ... }을 사용해 [보러 가기]를 눌렀을 때, 주소창의 값을 '/articles/{item.id}'으로 변경해 글 상세 화면으로 이동함 

 

 

 

4) 실행 테스트하기 

- 주소창에 'localhost/articles' 입력 후, [보러 가기] 클릭 → 상세 글 보임 

  ⇒ URL : '/articles/1'로 변경되었음을 확인할 수 있음