7.3 블로그 글 상세 뷰 구현

SummerToday·2024년 2월 15일
1
post-thumbnail
post-custom-banner

엔티티에 생성, 수정 시간 추가

// domain - Article.java

@Entity // 엔티티로 지정
@Getter
@NoArgsConstructor
public class Article{

      ~ 생략 ~
    
    @CreatedDate // 엔티티가 생성될 때 생성 시간 저장
    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @LastModifiedDate // 엔티티가 수정될 때 수정 시간 저장
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
 
      ~ 생략 ~
    
}
  • @CreatedDate
    엔티티가 생성될 때 생성시간을 created_at 컬럼에 저장한다.

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

BlogApplication 수정

// springbootdeveloper - BlogApplication.java

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

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

}
  • @EnableJpaAuditing
    Application 클래스에 해당 어노테이션을 사용하여 Audit 기능을 활성화 시킨다.
    • Audit 기능
      • Spring Data JPA에서 제공하는 엔티티의 변경 이력을 추적하고 관리하는 기능이다.
      • 데이터베이스 테이블의 각 레코드에 대해 생성일시, 수정일시, 생성자, 수정자 등의 정보를 저장하고자 할 때 사용된다.
      • spring-boot-starter-data-jpa 의존성만 추가해도 Audit을 사용할 수 있다.

컨트롤러 메서드 구현

// dto - ArticleViewResponse.java

@RequiredArgsConstructor
@Controller
public class BlogViewController {

    private final BlogService blogService;

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

        model.addAttribute("article", new ArticleViewResponse(article));

        return "article";
    }
}
  • 뷰에서 사용할 DTO 구현.

// controller - BlogViewController.java

@RequiredArgsConstructor
@Controller
public class BlogViewController {

    private final BlogService blogService;
    
      ~ 생략 ~
    
    @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()
    인자 id에 URL로 넘어온 값을 받아 findById() 메서드로 넘겨 글을 조회하고, 화면에서 사용할 모델에 데이터를 저장한 다음, 보여줄 화면의 템플릿 이름을 반환.


HTML 뷰 구현

// resources - templates - article.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>블로그 글</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/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 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>

  <script src="/js/article.js"></script>
</body>
  • ${#temporals.format(article.createdAt, 'yyyy-MM-dd HH:mm')}
    article.createdAt의 값을 가져와서 'yyyy-MM-dd HH:mm' 형식의 문자열로 포맷팅한다.

  • location.href
    JavaScript에서 현재 창의 URL을 나타내는 속성이다. 해당 속성을 사용하면 현재 페이지의 URL을 읽거나 변경할 수 있다.


블로그 글 목록 뷰 수정

// resources - templates - articleList.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>블로그 글 목록</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/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}">
        <div class="card">
            <div class="card-header" th:text="${item.id}">
            </div> 
            <div class="card-body">
                <h5 class="card-title" th:text="${item.title}"></h5>
                <p class="card-text" th:text="${item.content}"></p>
                <!-- 해당 부분 수정-->
                <a th:href="@{/articles/{id}(id=${item.id})}" class="btn btn-primary">보러가기</a> <!--블로그 글 상세화면 바로가기-->
            </div>
        </div>
        <br>
    </div>
</div>
</body>
  • 블로그 글 상세 화면을 블로그 글 리스트 화면에서 바로 보러갈 수 있도록 보러가기 버튼을 수정한다.

  • th:href="@{/articles/{id}(id=${item.id})}"
    /articles/{id}와 매핑되는 컨트롤러가 실행되어, 결국에는 해당 컨트롤러가 반환하는 뷰가 보여진다. id 값에는 모델의 item 객체의 id 속성 값이 들어간다.






    해당 글은 다음 도서의 내용을 정리하고 참고한 글임을 밝힙니다.

    신선영, ⌜스프링 부트 3 벡엔드 개발자 되기 - 자바 편⌟, 골든래빗(주), 2023, 384쪽

profile
IT, 개발 관련 정보들을 기록하는 장소입니다.
post-custom-banner

0개의 댓글