09009

[Spring Boot] 회원 + 게시판 연습 (3) - 게시글 작성 및 목록 조회 본문

Back-End/Spring
[Spring Boot] 회원 + 게시판 연습 (3) - 게시글 작성 및 목록 조회
09009

게시판 테이블 설계

 

BoardDTO 생성

package com.yeongin.boardTest.dto;

import com.yeongin.boardTest.entity.BoardEntity;
import lombok.*;

import java.time.LocalDateTime;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class BoardDTO {
    private Long id;
    private Long memberId;
    private String title;
    private String content;
    private int readCount;
    private LocalDateTime regDate;

    private String writer;

    public static BoardDTO toBoardDTO(BoardEntity boardEntity) {
        BoardDTO boardDTO = new BoardDTO();
        boardDTO.setId(boardEntity.getId());
        boardDTO.setTitle(boardEntity.getTitle());
        boardDTO.setContent(boardEntity.getContent());
        boardDTO.setReadCount(boardEntity.getReadCount());
        boardDTO.setRegDate(boardEntity.getRegDate());
        boardDTO.setMemberId(boardEntity.getMemberEntity().getId());
        boardDTO.setWriter(boardEntity.getMemberEntity().getName());
        return boardDTO;
    }



}

 

BoardEntity 생성

package com.yeongin.boardTest.entity;

import com.yeongin.boardTest.dto.BoardDTO;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.lang.reflect.Member;

@Entity
@SequenceGenerator(
        name = "board_seq_generator"
        , sequenceName = "board_seq"
        , initialValue = 1,
        allocationSize = 1
)
@Getter
@Setter
@Table(name = "board_table")
public class BoardEntity extends BaseEntity {
    @Id
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE
            , generator = "board_seq_generator"
    )
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    @Column
    private int readCount;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private MemberEntity memberEntity;

    public static BoardEntity toSaveEntity(BoardDTO boardDTO, MemberEntity memberEntity) {
        BoardEntity boardEntity = new BoardEntity();
        boardEntity.setId(boardDTO.getId());
        boardEntity.setTitle(boardDTO.getTitle());
        boardEntity.setContent(boardDTO.getContent());
        boardEntity.setReadCount(0);
        boardEntity.setMemberEntity(memberEntity);
        return boardEntity;
    }


}

 

MemberEntity

코드 추가

@OneToMany(mappedBy = "memberEntity", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
private List<BoardEntity> boardEntityList = new ArrayList<>();
package com.yeongin.boardTest.entity;

import com.yeongin.boardTest.dto.MemberDTO;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@SequenceGenerator(
        name = "member_seq_generator"
        , sequenceName = "member_seq"
        , initialValue = 1
        , allocationSize = 1
)
@Table(name = "member_table")
public class MemberEntity extends BaseEntity {
    @Id
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE
            , generator = "member_seq_generator"
    )
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private String name;

    @OneToMany(mappedBy = "memberEntity", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
    private List<BoardEntity> boardEntityList = new ArrayList<>();


    public static MemberEntity toMemberEntity(MemberDTO memberDTO) {
        MemberEntity memberEntity = new MemberEntity();
        memberEntity.setId(memberDTO.getId());
        memberEntity.setEmail(memberDTO.getEmail());
        memberEntity.setPassword(memberDTO.getPassword());
        memberEntity.setName(memberDTO.getName());
        return memberEntity;
    }

}

 

board/write.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>글쓰기</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css">
    <style>
        .orangeButton {
            background: #ff6f0f;
            font-weight: bold;
            color: white;
        }
        .boardTh {
            width: 25%;
            background-color : #f4f4f4!important;
        }
    </style>
</head>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
<body>
<div class="container">
    <div th:include="common/header :: header"></div>
    <div class="row mt-5">
        <div class="col"></div>
        <div class="col-10">

            <div class="row mt-2">
                <div class="col">

                    <div class="row fs-4 fw-bold text-center">
                        <div class="col">
                            게시글 작성하기
                        </div>
                    </div>

                    <div class="row mt-2">
                        <div class="col">
                            <form action="/board/write" method="post">
                                <input type="hidden" name="memberId" th:value="${session.memberDTO.id}">
                                <div class="row mt-4 justify-content-center">
                                    <div class="col-10">
                                        <table class="table">
                                            <tr>
                                                <th class="boardTh text-center">제목</th>
                                                <td>
                                                    <div class="row">
                                                        <div class="col text-start ms-2">
                                                            <input type="text" class="form-control"
                                                            name="title">
                                                        </div>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <th class="boardTh text-center">내용</th>
                                                <td>
                                                    <div class="row">
                                                        <div class="col text-start ms-2">
                                                            <textarea class="form-control" rows="5"
                                                            name="content"></textarea>
                                                        </div>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    </div>
                                </div>

                                <div class="row justify-content-center">
                                    <div class="col-10 text-end">
                                        <button class="btn orangeButton"> 작성하기
                                            <i class="bi bi-pencil-square"></i>
                                        </button>
                                    </div>
                                </div>


                            </form>

                        </div>
                    </div>


                </div>
            </div>




        </div>
        <div class="col"></div>
    </div>
</div>

<script th:inline="javascript">



</script>
</body>
</html>

 

 

BoardController

    @PostMapping("/write")
    public String write(@ModelAttribute BoardDTO boardDTO, HttpSession session) {
        MemberDTO memberDTO = (MemberDTO) session.getAttribute("memberDTO");
        boardService.save(boardDTO, memberDTO.getId());
        return "redirect:/";
    }

 

 

BoardService

package com.yeongin.boardTest.service;

import com.yeongin.boardTest.dto.BoardDTO;
import com.yeongin.boardTest.entity.BoardEntity;
import com.yeongin.boardTest.entity.MemberEntity;
import com.yeongin.boardTest.repository.BoardRepository;
import com.yeongin.boardTest.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class BoardService {
    private final MemberRepository memberRepository;
    private final BoardRepository boardRepository;

    // 게시글 작성
    public void save(BoardDTO boardDTO, Long id) {
        MemberEntity memberEntity = memberRepository.findById(id).get();
        boardRepository.save(BoardEntity.toSaveEntity(boardDTO, memberEntity));
    }

 

BoardRepository

package com.yeongin.boardTest.repository;

import com.yeongin.boardTest.entity.BoardEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BoardRepository extends JpaRepository<BoardEntity, Long> {
}

게시글 목록 조회

main.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>main</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css">
    <style>
        .orangeButton {
            background: #ff6f0f;
            font-weight: bold;
            color: white;
        }
    </style>
</head>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
<body>
    <div class="container">
        <div th:include="common/header :: header"></div>
        <div class="row mt-5">
            <div class="col"></div>
            <div class="col-10">

                <div class="row mt-2 fs-2 fw-bold">
                    <div class="col text-center">
                        Main Page
                    </div>
                </div>

                <div class="row mt-3">
                    <div class="col">
                        <table class="table">

                            <tr class="table-secondary text-center">
                                <th class="col-md-1">번호</th>
                                <th class="col-md-6">제목</th>
                                <th class="col-md-2">글쓴이</th>
                                <th class="col-md-2">날짜</th>
                                <th class="col-md-1">조회</th>
                            </tr>
                            <tr th:each="board: ${boardList}">
                                <td class="col-md-1 text-center" th:text="${board.id}"></td>
                                <td class="col-md-6 text-left" th:text="${board.title}"></td>
                                <td class="col-md-2 text-center" th:text="${board.writer}"></td>
                                <td class="col-md-2 text-center" th:text="*{#temporals.format(board.regDate, 'yyyy-MM-dd HH:mm:ss')}"></td>
                                <td class="col-md-1 text-center" th:text="${board.readCount}"></td>
                            </tr>
                        </table>

                    </div>
                </div>

                <div class="row mt-2 text-end" th:if="${session.memberDTO != null}">
                    <div class="col">
                        <button class="btn orangeButton"
                        onclick="writeBoard()"> 글쓰기
                            <i class="bi bi-pencil-square"></i>
                        </button>
                    </div>
                </div>


            </div>
            <div class="col"></div>
        </div>
    </div>

<script th:inline="javascript">

    const writeBoard = () => {
        location.href = "/board/write";
    }

</script>
</body>
</html>

 

BoardDTO

	private String writer;
	
    public static BoardDTO toBoardDTO(BoardEntity boardEntity) {
            BoardDTO boardDTO = new BoardDTO();
            boardDTO.setId(boardEntity.getId());
            boardDTO.setTitle(boardEntity.getTitle());
            boardDTO.setContent(boardEntity.getContent());
            boardDTO.setReadCount(boardEntity.getReadCount());
            boardDTO.setRegDate(boardEntity.getRegDate());
            boardDTO.setMemberId(boardEntity.getMemberEntity().getId());
            boardDTO.setWriter(boardEntity.getMemberEntity().getName());
            return boardDTO;
        }

 

 

HomeController

package com.yeongin.boardTest.controller;

import com.yeongin.boardTest.dto.BoardDTO;
import com.yeongin.boardTest.dto.MemberDTO;
import com.yeongin.boardTest.service.BoardService;
import com.yeongin.boardTest.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.ArrayList;
import java.util.List;

@Controller
@RequiredArgsConstructor
public class HomeController {
    private final BoardService boardService;
    private final MemberService memberService;
    @GetMapping("/")
    public String main(Model model) {
        List<BoardDTO> boardDTOList =  boardService.findAll();
        model.addAttribute("boardList", boardDTOList);
        return "main";
    }

 

BoardService

   // 게시글 조회
    @Transactional
    public List<BoardDTO> findAll() {
        List<BoardEntity> boardEntityList = boardRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
        List<BoardDTO> boardDTOList = new ArrayList<>();
        for (BoardEntity boardEntity : boardEntityList) {
            boardDTOList.add(BoardDTO.toBoardDTO(boardEntity));
        }
        return boardDTOList;
    }