최원종의 개발 블로그

V1(익명블로그)-게시글 작성 하기 본문

Spring boot 입문

V1(익명블로그)-게시글 작성 하기

chl6698 2026. 4. 29. 17:24

 

application-dev.yml 확인

더보기
server:
  servlet:
    encoding:
      charset: utf-8
      force: true
  port: 8080

logging:
  level:
    root: INFO #모든 라이브러리는 INFO 이상만 출력
    com.tenco: DEBUG # 내 프로젝트는 DEBUG 이상 모두 출력

spring:
  #데이터베이스 연결 설정 (MySQL)
  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://localhost:3306/myblog?serverTimezone=Asia/Seoul
#    username: root
#    password: root
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test
    username: sa
    password:
  h2:
    console:
      enabled: true

#      초기 데이터 설정
  sql:
    init:
      data-locations:
        - classpath:db/data.sql

  jpa:
    hibernate:
      # create 애플리케이션 시작시 테이블 새로 생성
      # 기존 데이터는 모드 삭제됨 (개발용)
      ddl-auto: create
    #SQL 쿼리를 콘솔에 출력 (개발용)
    show-sql: true
    properties:
      hibernate:
        # SQL 쿼리를 보기 좋게 포맷팅
        format_sql: true
    # data.sql 파일을 하이버네티트 초기화 이후에 실행
    defer-datasource-initialization: true

 

Board 코드

package com.tenco.blog.model;


import jakarta.persistence.*;
import lombok.Data;

import java.sql.Timestamp;

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

    // @id : 이 필드가 기본키임을 설정 함
    @Id
    // IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String title;
    private String content;
    private Timestamp createdAt;
}

 

save-form.mustache 코드

파일 위치

{{> layout/header}}
<div class="container p-5 flex-grow-1">
    <div class="card">
        <div class="card-header"><b>글쓰기 화면입니다</b></div>
        <div class="card-body">
            <!--  익명 게시글 작성    -->
            <form action="/board/save" method="post">
                <div class="mb-3">
                    <input type="text" name="username"  class="form-control" placeholder="enter username">
                </div>
                <div class="mb-3">
                    <input type="text" name="title" class="form-control" placeholder="enter title">
                </div>
                <div class="mb-3">
                    <textarea type="text" name="content" rows="5" class="form-control" placeholder="enter title">
                    </textarea>
                </div>
                <button class="btn btn-primary">글쓰기 완료</button>
            </form>
        </div>
    </div>
</div>

{{> layout/footer}}

 

BoardController 코드 (진행 중)

package com.tenco.blog.controller;

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

@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 "/";
    }


    /**
     * 게시글 목록 화면 요청
     * @return
     */
    @GetMapping({"/", "index"})
    public String list() {

        return "index";
    }

}

 

BoardNativeRepository 코드

package com.tenco.blog.repository;


import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

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

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

    // DI - 생성자 의존 주입
//    public BoardNativeRepository(EntityManager em) {
//        this.em = 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();
    }

}