4월 18일

SJY0000·2022년 4월 18일
0

Springboot

목록 보기
17/24

오늘 배운 것

  • 게시판만들기(2)

게시판 출력, 조회, 수정, 삭제

  • Mapper
package com.myapp.bbs.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.myapp.bbs.model.BoardVO;

@Mapper
public interface BoardMapper {

	public void enroll(BoardVO board); // 게시판 글 등록
	
	public List<BoardVO> getList(); // 게시판 모든 글 불러오기
	
	public BoardVO getPage(int bno); // 게시글 불러오기
	
	public int modify(BoardVO board); // 게시글 수정
	
	public int delete(int bno); // 게시글 삭제
}
  • Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- com.myapp.bbs.dao 패키지 안의 BoardMapper.java를 여기서 입력하겠다는 설정  -->
<mapper namespace="com.myapp.bbs.dao.BoardMapper">

	<!-- board 테이블에 데이터 넣기 -->
    <insert id="enroll" parameterType="BoardVO"> <!-- application.properties에 설정을 하지 않았다면 resultType="com.myapp.bbs.model.BoardVO" 라고 적었야함 -->
		insert into board(title, content, writer) 
		values (#{title}, #{content}, #{writer});
    </insert>
	
	<!-- board 테이블에 등록된 모든 글 불러오기 -->
    <select id="getList" resultType="BoardVO">
     	select * 
     	from board
    </select>
     
     <!-- board 테이블의 글 불러오기 -->
     <select id="getPage" resultType="BoardVO">
     	select * 
     	from board 
     	where bno=#{bno}
     </select>
     
     <!-- board 테이블의 글 수정하기 -->
     <update id="modify">
     	update board 
     	set title=#{title}, content=#{content}, updatedate=now()
     	where bno=#{bno}
     </update>
     
     <!-- board 테이블의 글 삭제하기 -->
     <delete id="delete">
     	delete from board 
     	where bno=#{bno}
     </delete>
</mapper>
  • Service
package com.myapp.bbs.service;

import java.util.List;

import com.myapp.bbs.model.BoardVO;

public interface BoardService {

	public void enroll(BoardVO board); // 게시판 글 등록
	
	public List<BoardVO> getList(); // 게시판 모든 글 불러오기
	
	public BoardVO getPage(int bno); // 게시글 불러오기
	
	public int modify(BoardVO board); // 게시글 수정하기
	
	public int delete(int bno); // 게시글 삭제
}
  • Service Impl
  • Class에 @Service 붙이는 것 체크
package com.myapp.bbs.service;

import java.util.List;

import org.springframework.stereotype.Service;

import com.myapp.bbs.dao.BoardMapper;
import com.myapp.bbs.model.BoardVO;

@Service
public class BoardServiceImpl implements BoardService {

	private BoardMapper boardMapper;
	
	public BoardServiceImpl(BoardMapper boardMapper) {
		this.boardMapper = boardMapper;
	}
	
	@Override
	public void enroll(BoardVO board) {
		boardMapper.enroll(board);
	}

	@Override
	public List<BoardVO> getList() {
		return boardMapper.getList();
	}

	@Override
	public BoardVO getPage(int bno) {
		return boardMapper.getPage(bno);
	}

	@Override
	public int modify(BoardVO board) {
		return boardMapper.modify(board);
	}

	@Override
	public int delete(int bno) {
		return boardMapper.delete(bno);
	}

}

참고(Service 클래스를 만드는 이유? 의존성주입(Dendency Injection))

https://tecoble.techcourse.co.kr/post/2021-04-27-dependency-injection/

  • Controller에서 처리
package com.myapp.bbs.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.myapp.bbs.model.BoardVO;
import com.myapp.bbs.service.BoardService;

import lombok.extern.java.Log;

@Controller
@RequestMapping("/board")
@Log	// console의 Log 출력 (print out 대신 사용)
public class BoardController {
	
	private BoardService boardService;
	
	public BoardController(BoardService boardService) {
		this.boardService = boardService;
	}

	@GetMapping("/list")
	public String boardListGet(Model model) {
		log.info("게시판 리스트 페이지 진입");
		model.addAttribute("boardList", boardService.getList());
		return "list";
	}
	/**
	 * 게시글 조회하기
	 * @param bno
	 * @param model
	 * @return
	 */
//	@GetMapping("/list/{bno}")
//	public String getBoard(@PathVariable("bno") int bno, Model model) {
//		model.addAttribute("board", boardService.getPage(bno));
//		return "get";
//	}
	
	@GetMapping("/get")
	public String getBoard(@RequestParam("bno") int bno, Model model) {
		model.addAttribute("board", boardService.getPage(bno));
		return "get";
	}
	
	@GetMapping("/enroll")
	public String boardEnrollGet(Model model) {
		log.info("게시판 등록 페이지 진입");
		model.addAttribute("board", new BoardVO());
		return "enroll";
	}
	
	@PostMapping("/enroll")
	public String boardEnrollPost(BoardVO board, RedirectAttributes attr) {
		boardService.enroll(board);
		attr.addFlashAttribute("message", "게시글 등록 완료!");
		
		return "redirect:/board/list"; // Post 다음 Redirect
	}
	
//	@GetMapping("/modify/{bno}")
//	public String boardModify(@PathVariable("bno") int bno, Model model) {
//		model.addAttribute("board", boardService.getPage(bno));
//		return "modify";
//	}
	
	@GetMapping("/modify")
	public String boardModifyGet(@RequestParam("bno") int bno, Model model) {
		model.addAttribute("board", boardService.getPage(bno));
		return "modify";
	}
	
	@PostMapping("/modify")
	public String boardModifyPOST(BoardVO board,  RedirectAttributes attr) {
		boardService.modify(board);
		attr.addFlashAttribute("message", "수정 성공");
		return "redirect:/board/list";		// post에 redirect 하는 이유는 새로 고침 하면 중복전송이 되기 때문에 그것을 방지하기위해서 post - redirect - get 방식
	}
	
	@GetMapping("/delete")
	public String boardDelete(@RequestParam("bno") int bno) {
		boardService.delete(bno);
		return "redirect:/board/list";
	}

페이지

메인게시판 페이지

  • 게시글 제목 클릭 시 게시글 페이지로 이동
  • 날짜타입 입력 시 변환확인 (String -> Date, Date -> Date)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head th:replace="fragments/head :: 헤드"></head>
  <body class="g-sidenav-show bg-gray-200">
    <aside th:replace="fragments/aside :: 어사이드"></aside>
    <!-- 메인 컨텐트 시작 -->
    <main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg">
      <!-- 상단 네브바 -->
      <nav th:replace="fragments/nav :: 네브"></nav>
      <!-- 컨텐츠 시작 -->
      <div class="container-fluid py-4">
        <!-- 빈 컨텐츠 (여기서 시작)-->
        <a th:href="@{/board/enroll}" class="btn btn-primary my-3">게시글 등록</a>
        <div class="card">
          <div class="table-responsive">
            <table class="table align-items-center mb-0">
              <thead>
                <tr>
                  <th class="text-center text-secondary text-xxs font-weight-bolder opacity-7">No</th>
                  <th class="text-center text-secondary text-xxs font-weight-bolder opacity-7">제목</th>
                  <th class="text-center text-secondary text-xxs font-weight-bolder opacity-7">작성자</th>
                  <th class="text-center text-secondary text-xxs font-weight-bolder opacity-7">등록일</th>
                  <th class="text-center text-secondary text-xxs font-weight-bolder opacity-7">수정일</th>
                  <th class="text-secondary opacity-7">기타</th>
                </tr>
              </thead>
              <tbody>
                <tr th:each="board : ${boardList}">
                  <td class="align-middle text-center">
                    <span class="text-secondary text-sx" th:text="${board.bno}"></span>
                  </td>
                  <td class="align-middle text-center">
                    <!-- thymeleaf문법에서는 Parameter로 넘길 때는 ()안에 변수명과 값을 넣어준다 -->
                    <a th:href="@{/board/get(bno=${board.bno})}"><span class="text-secondary text-sx" th:text="${board.title}"></span></a>
                    <!-- <a th:href="@{'/board/list/' + ${board.bno}}"><span class="text-secondary text-sx" th:text="${board.title}"></span></a> -->
                  </td>
                  <td class="align-middle text-center">
                    <span class="text-secondary text-sx" th:text="${board.writer}"></span>
                  </td>
                  <td class="align-middle text-center">
                    <!-- 연-월-일 am,pm 시:분:초, thymeleaf문법에서 String타입에서 Date타입을 나타낼때 이런식으로 사용-->
                    <span class="text-secondary text-sx" th:text="${#temporals.format(board.regdate, 'yyyy-MM-dd a hh:mm:ss')}"></span> 
                  </td>
                  <td class="align-middle text-center">
                    <span class="text-secondary text-sx" th:text="${#temporals.format(board.updateDate, 'yyyy-MM-dd a hh:mm:ss')}"></span>
                  </td>
                </tr>
      </div>
    </main>

    <!-- 오른쪽 숨김창 , JS 링크들 -->
    <hidden th:replace="fragments/hidden :: 숨김창"></hidden>
    <jslink th:replace="fragments/jslink :: 링크"></jslink>
    <script>
      document.getElementById('pageName').textContent = '게시판 목록';
    </script>
  </body>
</html>

참고(Thymeleaf문법에서 날짜타입 변환)

https://ssd0908.tistory.com/32

게시글 조회 페이지

  • 목록버튼 클릭 시 메인게시판 페이지로 이동
  • 수정버튼 클릭 시 수정 페이지로 이동
  • 삭제버튼 클릭 시 삭제확인창으로 이중체크
    <!-- 메인 컨텐트 시작 -->
    <main class="main-content mt-0">
      <section>
        <div class="page-header min-vh-100">
          <div class="container">
            <div class="row">
              <div class="col-md-10 ms-auto me-auto">
                <div class="card card-plain">
                  <div class="card-body bg-white">
                    <table class="table table-condensed">
                      <tr>
                        <th>번호</th>
                        <td th:text="${board.bno}"></td>
                        <th>작성일</th>
                        <td th:text="${#temporals.format(board.regdate, 'yyyy-MM-dd a hh:mm:ss')}"></td>
                      </tr>
                      <tr>
                        <th>작성자</th>
                        <td th:text="${board.writer}"></td>
                        <th>수정일</th>
                        <td th:text="${#temporals.format(board.updateDate, 'yyyy-MM-dd a hh:mm:ss')}"></td>
                      </tr>
                      <tr>
                        <th>제목</th>
                        <td colspan="3" th:text="${board.title}"></td>
                      </tr>
                      <tr>
                        <th>내용</th>
                        <td colspan="3" th:text="${board.content}"></td>
                      </tr>
                    </table>
                  </div>
                  <div class="card-footer bg-white text-center pt-0 px-lg-2 px-1">
                    <a th:href="@{/board/list}" class="btn btn-success">목록</a>
                    <!-- <a th:href="@{'/board/modify/' + ${board.bno}}" class="btn btn-secondary">수정</a> -->
                    <a th:href="@{/board/modify(bno=${board.bno})}" class="btn btn-secondary">수정</a>
                    <button onclick="deleteConfirm()" class="btn btn-danger">삭제</button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
    </main>

    <!-- 오른쪽 숨김창 , JS 링크들 -->
    <hidden th:replace="fragments/hidden :: 숨김창"></hidden>
    <jslink th:replace="fragments/jslink :: 링크"></jslink>
    <script>
      function deleteConfirm() {
        if (confirm('정말로 삭제할까요?')) {
          location.href = '/board/delete?bno=' + '[[${board.bno}]]';
        }
      }
    </script>

게시글 수정 페이지

 <!-- 메인 컨텐트 시작 -->
    <main class="main-content mt-0">
      <section>
        <div class="page-header min-vh-100">
          <div class="container">
            <div class="row">
              <div class="col-md-10 ms-auto me-auto">
                <div class="card card-plain">
                  <div class="card-header">
                    <h4 class="font-weight-bolder">게시글 수정</h4>
                    <p class="mb-0">게시글을 수정해주세요.</p>
                  </div>
                  <div class="card-body bg-white">
                    <form role="form" th:action="@{/board/modify}" method="post" th:object="${board}">
                      <input type="hidden" th:field="*{bno}" />
                      <!-- is-filled 없으면 label의 제목 텍스트와 입력된 값이 겹쳐서 출력됨-->
                      <div class="input-group input-group-outline mb-3 is-filled">
                        <label class="form-label">제목</label>
                        <input type="text" class="form-control" th:field="*{title}" required />
                      </div>
                      <div class="input-group input-group-outline mb-3">
                        <div class="input-group input-group-dynamic">
                          <textarea th:field="*{content}" class="form-control" rows="5" placeholder="내용을 적어주세요." spellcheck="false" required></textarea>
                        </div>
                      </div>
                      <div class="input-group input-group-outline mb-3 is-filled">
                        <label class="form-label">작가</label>
                        <input type="text" class="form-control" th:field="*{writer}" readonly required />
                      </div>
                      <div class="text-center">
                        <a th:href="@{/board/list}" class="btn btn-danger">수정 취소</a>
                        <button type="submit" class="btn btn-success">수정 완료</button>
                      </div>
                    </form>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
    </main>

0개의 댓글