본문 바로가기
프로젝트/게시판 만들기

[Spring boot] 게시판 만들기 (2주차 : DB 테이블 생성, 게시글 작성폼 생성, 글 작성 처리, 게시글 리스트)

by zzingni 2025. 4. 9.

 

※ [한코딩] 게시판 만들기 유튜브를 참고하여 진행하는 프로젝트입니다.

 

 

 

개발 환경


사용언어 : Java

프레임 워크 : Spring boot

통합 개발 환경 : IntelliJ

데이터베이스 : MariaDB

뷰 템플릿(템플릿 엔진) : Thymeleaf

 

 

프로젝트 진행 순서


 

 

[Spring boot] 게시판 만들기 (1주차 : 개발 환경 세팅, 프로젝트 생성)

※ [한코딩] 게시판 만들기 유튜브를 참고하여 진행하는 프로젝트입니다.   개발 환경사용언어 : Java프레임 워크 : Spring boot통합 개발 환경 : IntelliJ데이터베이스 : MariaDB뷰 템플릿(템플릿 엔진)

zprograming.tistory.com

 

 

1. 개발 환경 세팅

 - IntelliJ Community 다운로드

 - MariaDB 다운로드

 - MySQL Workbench 다운로드

 

2. 프로젝트 생성

 - IntelliJ Community에서 Spring Boot 프로젝트 생성 (https://start.spring.io/)

 - MariaDB Database(스키마) 생성 

 

 

3. 게시물 작성

 

- db에 board 테이블 및 필드 생성

※ workbench 접속 전 cmd 창에 net start mariadb로 실행하고 시작할 것.

 

board 테이블에 id, title, content를 생성한다. 각각 타입은 자동지정 되었고, id에는 PK를 체크. id, title, content 에는 NN을 체크해줬다.

 

 

- 게시글 작성 폼 생성

package com.study.board.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class BoardController {

    @GetMapping("/board/write") // localhost:8090/board/write
    public String boardwriteForm() {
        return "boardwrite";
    }
}

 

controller에 @GetMapping 으로 /board/write 주소와 매핑해준 뒤, boardwrite 파일을 return 해주는 코드 작성.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>게시물 작성 폼</title>
</head>
<style>
    .layout {
        width : 500px;
        margin : 0 auto;
        margin-top : 40px;
    }
    .layout input {
        width : 100%;
        box-sizing : boarder-box;
    }

    .layout textarea {
        width : 100%;
        margin-top : 10px;
        min-height : 300px;
    }

</style>
<body>
    <div class = "layout">
        <form action = "/board/writepro" method="post">
            <input name = "title" type = "text">
            <textarea name = "content"></textarea>
            <button type = "submit">작성</button>
        </form>
    </div>
</body>
</html>

 

templates 패키지 안에 위의 @GetMapping("/board/write") 에서 return 해주는 boardwrtie.html 을 작성한다.

 

 

 

실행을 누르면 정상적으로 폼이 나타난다.

 

 

@PostMapping("/board/writepro")
public String boardWritePro(@RequestParam("title") String title,
                            @RequestParam("content") String content) {
    System.out.println("제목 : " + title);
    System.out.println("내용 : " + content);
    return "";
}

 

그 후 System.out.println으로 html 태그에 name으로 지정해줬던 title과 content를 웹페이지에서 받아와 콘솔에 정상적으로 출력되는지 확인해준다. (이 때 발생한 문제는 포스트 아래 Trouble Shooting 부분에 자세히 적었다!)

 

 

localhost:8090/board/write 페이지에서 폼에 제목과 내용을 입력 후 저장하면 localhost:8090/board/wrtiepro 웹페이지로 넘어가고 404에러가 뜨지만,

 

 

데이터는 정상적으로 넘어온 것으로 확인할 수 있다.

 

 

 

코드 실행에 필요한 여러 패키지와 클래스를 생성한다.

 

entity 패키지 생성 > Board 클래스 생성  ☞  데이터베이스 테이블과 매핑되는 클래스 (도메인 모델)
package com.study.board.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;

@Entity // @Entity 는 테이블을 의미함. 이 class 가 db에 있는 table 을 의미한다는 것.
@Data
public class Board { // 테이블이름과 일치시키는 것이 좋음.

    @Id // primary key
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String title;

    private String content;

}
  • 실제 데이터베이스에 저장될 데이터를 담는 객체.
  • 각 필드는 DB 컬럼과 매핑됨.
  • @Entity를 통해 JPA가 관리하는 엔티티로 지정.

 

repository 패키지 생성 > BoardRepository 인터페이스 생성  ☞  데이터베이스 접근을 담당 (DAO 역할)
package com.study.board.repository;

import com.study.board.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BoardRepository extends JpaRepository<Board, Integer> { // extends 상속받음. JpaRepository를 상속받아 타입지정.
}
  • JPA를 통해 DB에 저장하거나 조회하는 작업을 함.
  • save, findById, deleteById 같은 기본 메서드 제공.
  • 복잡한 쿼리는 직접 메서드 이름으로 정의하거나 @Query로 작성 가능.

 

service 패키지 생성 > BoardService 클래스 생성   ☞  비즈니스 로직 처리
package com.study.board.service;

import com.study.board.entity.Board;
import com.study.board.repository.BoardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


@Service
public class BoardService {

    @Autowired
    private BoardRepository boardRepository; // @Autowired가 객체 알아서 생성해줌.


    public void write(Board board) {
        boardRepository.save(board);
    }
}
  • 컨트롤러와 리포지토리 사이의 중간 계층.
  • DB 작업뿐만 아니라 로직 처리, 트랜잭션 처리 등도 여기에 위치.
  • 코드를 깔끔하게 유지하고 재사용성도 높여줌.

 

이 때, entity, repository, service 계층을 나누는 건 역할 분리(Separation of Concerns) 원칙을 따르기 위해서라고 생각하면 될 듯 하다...!

 

 

 

코드 작성 완료 후 /board/write 페이지에서 제목과 내용을 저장하면 database에 정상적으로 들어오는 것을 확인할 수 있다.

 

 

 

4. 게시물 리스팅

 

use board;

DELIMITER $$

CREATE PROCEDURE testDataInsert()
BEGIN
    DECLARE i INT DEFAULT 1;

    WHILE i <= 120 DO
        INSERT INTO board(title, content)
          VALUES(concat('제목',i), concat('내용',i));
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER $$


call testDataInsert;

 

테스트 데이터 생성해준다.

 

 

 

데이터들이 잘 생성되었다.

 

 

 

    @GetMapping("/board/list")
    public String boardList(Model model) { // 데이터를 담아서 페이지로 보낼 때 Model 사용
        model.addAttribute("list", boardService.boardList()); // list라는 이름으로 보낼 건데, boardService에 boardList() >> 반환된 리스트를 list 라는 이름으로 넘기겠다는 뜻.
        return "boardlist";
    }

 

게시글 리스트 페이지를 나타내기 위해 controller에 위의 코드를 작성한다.

 

    public List<Board> boardList() {
        return boardRepository.findAll(); // Board 라는 class가 담긴 LIst 반환
    }

 

BoardService에 list를 반환하는 코드를 작성한다.

 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>게시글 리스트 페이지</title>
</head>
<style>
    .layout {
            width : 500px;
            margin : 0 auto;
            margin-top : 40px;
    }
</style>
<body>
    <div class = "layout">
        <table>
            <thead>
                <tr>
                    <th>글번호</th>
                    <th>제목</th>
                </tr>
            </thead>
            <tbody>
                <tr th:each="board : ${list}"> <!-- >each 는 반복문 >> list에서 board가 없어질 때까지 반복함. -->
                    <td th:text="${board.id}">1</td>
                    <td th:text="${board.title}">제목입니다.</td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

 

boardlist를 나타낼 html 코드를 작성한다.

Thymeleaf 템플릿 엔진을 쓸 때 필요한 네임스페이스 선언을 해주고, th 접두사를 써서 th:text, th:if, th:each 등 Thymeleaf 전용 속성을 사용한다.

 

 

 

 

 

 

게시글 리스트가 정상적으로 화면에 잘 나타난다.

 

 

 

5. 게시물 삭제

6. 게시물 수정

7. 게시물 리스트 페이징 

 

 

 

Trouble Shooting


1. html 코드의 title 과 content 가 콘솔 창에 넘어오지 않는 문제

 

에러원인

IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. 
Ensure that the compiler uses the '-parameters' flag.

 

컨트롤러 메서드에서 String title, String content 이렇게 파라미터 이름만 썼는데, 자바 컴파일 시 -parameters 옵션 없이 컴파일돼서 파라미터 이름을 리플렉션으로 못 가져오는 상황.

 

 

해결방법

import org.springframework.web.bind.annotation.RequestParam;

 

컨트롤러 파일 상단에 import문 추가 후,

 

@PostMapping("/board/writepro")
public String boardWritePro(@RequestParam("title") String title,
                            @RequestParam("content") String content) {
    System.out.println("제목 : " + title);
    System.out.println("내용 : " + content);
    return "";
}

 

@RequestParam 을 명시적으로 붙여준다.

 

 

이제 localhost:8090/board/write 에서 작성한 title과 content가 /board/writepro 로 잘 넘어오는 걸 확인할 수 있다!

 

 

 

2. lombok으로 데이터 받은 후 getTitle() 메서드가 동작하지 않는 문제

에러원인 : lombok 플러그인이 설치되어 있지 않았다.

 

해결방법 : 설정 > 플러그인 > lombok 설치

 

 

 

2주차 소감


 

javascript 강의 시간에 Get과 Post 방식 개념에 대해 배웠는데, 그 때는 이론적인 부분만 배우다 보니 머리에 잘 들어오지 않았다. @GetMapping 과 @PostMapping 어노테이션에 대해 공부하면서 개념을 확실히 짚고 넘어가야겠다고 생각했다.

 

그리고 데이터베이스야... 제발 오류 내지 말아줘......