최원종의 개발 블로그

V1(익명블로그)-게시글 목록 보기 본문

Spring boot 입문

V1(익명블로그)-게시글 목록 보기

chl6698 2026. 4. 29. 17:50

 

자바의 기본 패키지(java.lang)를 '강화'해주는 보충용 툴킷 다운

https://mvnrepository.com/artifact/org.apache.commons/commons-lang3/3.18.0

 

 

Maven Repository: org.apache.commons » commons-lang3 » 3.18.0

org.apache.commons commons-lang3 3.18.0 compile Scope:CompileTestProvidedRuntime Format:Groovy LongGroovy ShortKotlin Include backlinks implementation("org.apache.commons:commons-lang3:3.18.0") libraryDependencies += "org.apache.commons" % "commons-lang3"

mvnrepository.com


적용 위치

// Source: https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.18.0'

게시글 목록보기 완성 이미지


BoardController - list() 메서드 추가 코드

package com.tenco.blog.controller;

import com.tenco.blog.model.Board;
import com.tenco.blog.repository.BoardNativeRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Slf4j
@Controller // IoC
@RequiredArgsConstructor // DI
public class BoardController {
    // DI
    private final BoardNativeRepository boardNativeRepository;

    /**
     * 게시글 작성 화면 요청
     * @return 페이지 반환
     * 주소설계 : http://localhost:8080/board/save-form
     */
    @GetMapping("/board/save-form")
    public String saveForm() {

        return "board/save-form";
    }

    /**
     * 게시글 작성 기능 요청
     * @return 페이지 반환
     * 주소설계 : http://localhost:8080/board/save-form
     */
    @PostMapping("/board/save")
    public String saveProc(
            @RequestParam("username") String username,
            @RequestParam("title") String title,
            @RequestParam("content") String content) {
        log.info("username : " + username);
        log.info("title : " + title);
        log.info("content : " + content);
        // insert + 트랜잭션 처리
        boardNativeRepository.save(title, content, username);
        // redirect <-- 다시 URL 요청 해 !
        //return "redirect:/";
        return "redirect:/";
    }


    /**
     * 게시글 목록 화면 요청
     * 주소설계 : http://localhost:8080/
     */
    @GetMapping({"/", "index"})
    public String list(Model model) {
        //
        List<Board> boardList = boardNativeRepository.findAll();
        model.addAttribute("boardList", boardList);
        return "board/list";
    }

}

 

BoardNativeRepository - findAll() 추가 코드

package com.tenco.blog.repository;


import com.tenco.blog.model.Board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository // Ioc + DI
@RequiredArgsConstructor
public class BoardNativeRepository {

    // EntityManager: JPA 핵심 인터페이스
    // 데이터베이스와 모든 작업을 담당
    private final EntityManager em;

    // 트랜잭션 처리
    @Transactional
    public void save(String title, String content, String username) {
        Query query = em.createNativeQuery("insert " +
                "into board_tb(title, content, username, created_at) values (?, ?, ?, now())");

        query.setParameter(1, title);
        query.setParameter(2, content);
        query.setParameter(3, username);

        query.executeUpdate();
    }

    // 게시글 목록 조회 메서드
    public List<Board> findAll() {
        String sql = """
                select * from board_tb order by id desc
                """;
        // while(rs.next)  { Board board = new Board(); board.setTile(rs.getString("title)))}
        Query query = em.createNativeQuery(sql, Board.class);
        return query.getResultList();
    }

}

 

list.mustache - 머스태치 코드 사용

{{> layout/header}}
<div class="container p-5 flex-grow-1">
    {{#boardList}}
        <div class="card mb-3">
            <div class="card-body">
                <h4 class="card-title mb-3">{{title}}</h4>
                <div>{{time}}</div>
                <a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
            </div>
        </div>
    {{/boardList}}


    <ul class="pagination d-flex justify-content-center">
        <li class="page-item"><a href="" class="page-link">Previous</a></li>
        <li class="page-item"><a href="" class="page-link"> Next</a></li>
    </ul>
</div>

{{> layout/footer}}

 

시간 설정 코드


Board 코드

package com.example.blog.board;


import com.exampleyblog.util.MyDateUtil;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

import java.sql.Timestamp;

@Data // get,set, toString ..
// @Entity - JPA가 이 클래스를 데이터베이스 테이블과 매핑하는 객체로 인식하게 설정
// 즉, 이 어노테이션이 있어야 JPA가 관리 함
@Entity
@Table(name = "board_tb")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Board {

    //http://localhost:8080/h2-console
    // @id : 이 필드가 기본키임을 설정 함
    @Id
    // IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String title;
    private String content;
    @CreationTimestamp
    private Timestamp createdAt;
    // createdAt -> 포멧 하는 메서드 만들어 보기
    public String time() {
        return MyDateUtil.timestampFormat(createdAt);
    }

    public void update(BoardRequest.UpdateDTO updateDTO) {
        this.title = updateDTO.getTitle();
        this.content = updateDTO.getContent();
        
    }
}

MyDateUtil 코드 

package com.tenco.blog.util;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.sql.Date;
import java.sql.Timestamp;

//SRP- 단일 책임 원칙
// 날짜/시간 관련된 유틸리티 클래스
public class MyDateUtil {

    // 1. TimeStamp 포메터
    public static String timestampFormat(Timestamp timestamp) {

        //TimeStamp --> Date 형태로 변환
        Date currentDate = new Date(timestamp.getTime());

        return DateFormatUtils.format(currentDate, "yyyy-MM-dd HH:mm");

    }
}

 

파일 위치

 


list.mustache 코드

{{> layout/header}}
<div class="container p-5 flex-grow-1">
    {{#boardList}}
        <div class="card mb-3">
            <div class="card-body">
                <h4 class="card-title mb-3">{{title}}</h4>
                <div>{{time}}</div>
                <a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
            </div>
        </div>
    {{/boardList}}


    <ul class="pagination d-flex justify-content-center">
        <li class="page-item"><a href="" class="page-link">Previous</a></li>
        <li class="page-item"><a href="" class="page-link"> Next</a></li>
    </ul>
</div>

{{> layout/footer}}