실습(동적쿼리_검색)
- [Web_Spring] 14 이어서
1. src/main/java/com.example.board/domain/dao/BoardDAO.java
package com.example.board.domain.dao;
import com.example.board.domain.vo.BoardVO;
import com.example.board.domain.vo.Criteria;
import com.example.board.mapper.BoardMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
// RDB에 가깝던 mapper 인터페이스를
// 객체에 가깝게 변경시켜주는 역할
@RequiredArgsConstructor
public class BoardDAO {
private final BoardMapper boardMapper;
// 게시글 목록
public List<BoardVO> getList(Criteria criteria){
return boardMapper.getList(criteria);
}
// 게시글 추가
public void register(BoardVO boardVO){
boardMapper.insert(boardVO);
}
// 게시글 한 개 가져오기
public BoardVO findByBoardNumber(Long boardNumber){
return boardMapper.select(boardNumber);
}
// 게시글 수정
public boolean modify(BoardVO boardVO){
return boardMapper.update(boardVO) == 1;
}
// 게시글 삭제
public boolean remove(Long boardNumber){
return boardMapper.delete(boardNumber) == 1;
}
// 게시글 전체 개수
public int getTotal(Criteria criteria){
return boardMapper.getTotal(criteria);
}
}
2. src/test/java/com.example.board/domain/dao/BoardDaoTests.java
package com.example.board.domain.dao;
import com.example.board.domain.vo.BoardVO;
import com.example.board.domain.vo.Criteria;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Slf4j
public class BoardDaoTests {
@Autowired
private BoardDAO boardDAO;
// @Test
// public void getListTest(){
// boardDAO.getList().stream().map(BoardVO::toString).forEach(log::info);
// }
// @Test
// public void insertTest(){
// BoardVO boardVO = new BoardVO();
// boardVO.setBoardTitle("새롭게 추가된 게시글 제목1");
// boardVO.setBoardContent("새롭게 추가된 게시글 내용1");
// boardVO.setBoardWriter("new1");
// boardDAO.register(boardVO);
// log.info("추가된 게시글 번호 : " + boardVO.getBoardNumber());
// }
// @Test
// public void selectTest(){
// log.info(boardDAO.findByBoardNumber(2582L).toString());
// }
// @Test
// public void updateTest(){
// BoardVO boardVO = boardDAO.findByBoardNumber(2582L);
// boardVO.setBoardTitle("수정된 게시글 제목");
// boardVO.setBoardContent("수정된 게시글 내용");
//
// log.info("UPDATE : " + boardDAO.modify(boardVO));
// }
// @Test
// public void deleteTest(){
// log.info("DELETE : " + boardDAO.remove(2582L));
// }
@Test
public void getTotalTest(){
log.info("총 게시글 : " + boardDAO.getTotal(new Criteria()));
}
}
3. src/main/java/com.example.board/service/BoardService.java
package com.example.board.service;
import com.example.board.domain.vo.BoardVO;
import com.example.board.domain.vo.Criteria;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface BoardService {
public List<BoardVO> getList(Criteria criteria);
public void register(BoardVO boardVO);
public BoardVO get(Long boardNumber);
public boolean modify(BoardVO boardVO);
public boolean remove(Long boardNumber);
public int getTotal(Criteria criteria);
}
4. src/main/java/com.example.board/service/BoardServiceImpl.java
package com.example.board.service;
import com.example.board.domain.dao.BoardDAO;
import com.example.board.domain.vo.BoardVO;
import com.example.board.domain.vo.Criteria;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import java.util.List;
// Service
// 여러 개의 DML을 하나의 서비스로 묶어준다.
@Service
@RequiredArgsConstructor
@Qualifier("board") @Primary
public class BoardServiceImpl implements BoardService{
private final BoardDAO boardDAO;
@Override
public List<BoardVO> getList(Criteria criteria) {return boardDAO.getList(criteria);}
@Override
public void register(BoardVO boardVO) {boardDAO.register(boardVO);}
@Override
public BoardVO get(Long boardNumber) {
return boardDAO.findByBoardNumber(boardNumber);
}
@Override
public boolean modify(BoardVO boardVO) {
return boardDAO.modify(boardVO);
}
@Override
public boolean remove(Long boardNumber) {
return boardDAO.remove(boardNumber);
}
@Override
public int getTotal(Criteria criteria) {
return boardDAO.getTotal(criteria);
}
}
5. src/main/resource/templates/board/list.html
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Board</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<link rel="stylesheet" href="/css/main.css" type="text/css"/>
<style>
.small-width {display: none;}
.big-width {display: block;}
div#searchWrap {
text-align: center;
display: flex;
}
select{
width:30%;
}
#keyword{
width:60%;
}
form#searchForm {
overflow: hidden;
}
@media(max-width: 918px){
.boardRegisterDate {display: none;}
.boardUpdateDate {display: none;}
.small-width {display: block;}
.big-width {display: none;}
div.small-width {display: block;}
div.big-width {display: none;}
div#searchWrap { display: block;}
select{
width:100%;
}
#keyword{
width:100%;
}
.search{
width:100%;
}
}
</style>
</head>
<body class="is-preload">
<!-- Main -->
<div id="main">
<div class="wrapper">
<div class="inner">
<!-- Elements -->
<header class="major">
<h1>Board</h1>
<p>게시판 목록</p>
</header>
<!-- Table -->
<h3><a href="/board/register" class="button small">글 등록</a></h3>
<div class="table-wrapper">
<table>
<thead>
<tr class="tHead">
<th class="boardNumber">번호</th>
<th class="boardTitle">제목</th>
<th class="boardWriter">작성자</th>
<th class="boardRegisterDate">작성일</th>
<th class="boardUpdateDate">수정일</th>
</tr>
</thead>
<tbody>
<th:block th:each="board:${boardList}">
<tr class="tBody" th:object="${board}">
<td class="boardNumber" th:text="*{boardNumber}"></td>
<td class="boardTitle"><a id="goRead" th:text="*{boardTitle}" th:href="*{boardNumber}"></a></td>
<td class="boardWriter" th:text="*{boardWriter}"></td>
<td class="boardRegisterDate" th:text="*{boardRegisterDate}"></td>
<td class="boardUpdateDate" th:text="*{boardUpdateDate}"></td>
</tr>
</th:block>
</tbody>
</table>
<form method="get" action="/board/list" id="searchForm" th:object="${pageDTO}">
<div class="fields">
<div class="field">
<div id="searchWrap" th:object="${criteria}">
<select name="type">
<option value="">검색 기준</option>
<option value="T" th:selected="*{type == 'T'}">제목</option>
<option value="C" th:selected="*{type == 'C'}">내용</option>
<option value="W" th:selected="*{type == 'W'}">작성자</option>
<option value="TC" th:selected="*{type == 'TC'}">제목 또는 내용</option>
<option value="TW" th:selected="*{type == 'TW'}">제목 또는 작성자</option>
<option value="TCW" th:selected="*{type == 'TCW'}">제목 또는 내용 또는 작성자</option>
</select>
<input id="keyword" type="text" th:field="*{keyword}"/>
<a href="#" class="search button primary icon solid fa-search">검색</a>
</div>
</div>
</div>
</form>
<div class="big-width" style="text-align: center">
<a class="changePage" th:if="${pageDTO.prev}" th:href="${pageDTO.startPage - 1}"><code><</code></a>
<th:block th:each="num:${#numbers.sequence(pageDTO.startPage, pageDTO.endPage)}">
<code th:text="${num}" th:if="${pageDTO.criteria.pageNum == num}"></code>
<a class="changePage" th:unless="${pageDTO.criteria.pageNum == num}" th:href="${num}"><code th:text="${num}"></code></a>
</th:block>
<a class="changePage" th:if="${pageDTO.next}" th:href="${pageDTO.endPage + 1}"><code>></code></a>
</div>
<!--이전버튼 <code>현재페이지</code> 다음버튼-->
<!--이전버튼 : 현재페이지 - 1-->
<!--다음버튼 : 현재페이지 + 1-->
<div class="small-width" style="text-align: center;" th:object="${pageDTO}">
<a class="changePage" th:if="*{criteria.pageNum > 1}" th:href="${criteria.pageNum - 1}"><code><</code></a>
<code th:text="${criteria.pageNum}"></code>
<a class="changePage" th:if="*{criteria.pageNum < realEnd}" th:href="${criteria.pageNum + 1}"><code>></code></a>
</div>
<form action="/board/list" th:object="${criteria}" name="pageForm">
<input type="hidden" th:field="*{pageNum}">
<input type="hidden" th:field="*{amount}">
<input type="hidden" th:field="*{type}">
<input type="hidden" th:field="*{keyword}">
</form>
</div>
</div>
</div>
</div>
</body>
<!-- Scripts -->
<script src="/js/jquery.min.js"></script>
<script src="/js/jquery.dropotron.min.js"></script>
<script src="/js/browser.min.js"></script>
<script src="/js/breakpoints.min.js"></script>
<script src="/js/util.js"></script>
<script src="/js/main.js"></script>
<script th:inline="javascript">;
let boardNumber = [[${boardNumber}]];
let $pageForm = $(pageForm);
let $serachForm = $(searchForm);
let params = [[${pageDTO.criteria.listLink}]];
$("a#goRead").on("click", function(e){
e.preventDefault();
location.href = "/board/read" + params + "&boardNumber=" + $(this).attr("href");
})
$("#searchForm a").on("click", function(e){
e.preventDefault();
if(!$serachForm.find("option:selected").val()){
alert("검색종류를 선택하세요");
return false;
}
if(!$serachForm.find("input[name='keyword']").val()){
alert("키워드를 입력하세요");
return false;
}
$serachForm.submit();
});
if(boardNumber != null){
alert(boardNumber + "번 게시글이 등록되었습니다.");
}
$("a.changePage").on("click", function(e){
e.preventDefault();
$pageForm.find("input[name='pageNum']").val($(this).attr("href"));
$pageForm.submit();
});
</script>
</html>
6. src/main/java/com.example.board/controller/BoardController.java
package com.example.board.controller;
import com.example.board.domain.vo.BoardVO;
import com.example.board.domain.vo.Criteria;
import com.example.board.domain.vo.PageDTO;
import com.example.board.service.BoardService;
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.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import javax.servlet.http.HttpServletRequest;
/*
* TASK URL METHOD PARAMETER FORM URL이동
*
* 전체목록 /board/list GET 없음 없음
* 등록 /board/register POST 모든 항목 필요 /board/list
* 조회 /board/read GET boardNumber 없음
* 삭제 /board/remove POST boardNumber 없음 /board/list
* 수정 /board/modify POST 모든 항목 필요 /board/read
*
* */
@Controller
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/board/*")
public class BoardController {
private final BoardService boardService;
@GetMapping("register")
public void register(){}
@GetMapping("list")
public String getList(Criteria criteria, Model model){
log.info("----------------------------");
log.info("list............. : " + criteria);
log.info("----------------------------");
model.addAttribute("boardList", boardService.getList(criteria));
model.addAttribute("pageDTO", new PageDTO(criteria, boardService.getTotal(criteria)));
return "/board/list";
}
@PostMapping("register")
// 매개변수에 선언된 객체는 자동으로 화면에 전달되므로,
// 이를 막기 위해서는 redirect 방식의 전송이 필요하다.
public RedirectView register(BoardVO boardVO, RedirectAttributes rttr){
log.info("----------------------------");
log.info("register............. : " + boardVO);
log.info("----------------------------");
boardService.register(boardVO);
// 1. Flash 사용
// 세션에 파라미터를 저장하고, request 객체가 초기화된 후 다시 request에 담아준다.
rttr.addFlashAttribute("boardNumber", boardVO.getBoardNumber());
// 2. 쿼리 스트링
// rttr.addAttribute("boardNumber", boardVO.getBoardNumber());
return new RedirectView("/board/list");
}
// 게시글 상세보기
@GetMapping({"read", "modify"})
public void read(Long boardNumber, HttpServletRequest req, Model model){
log.info("----------------------------");
log.info(req.getRequestURI() + "............. : " + boardNumber);
log.info("----------------------------");
model.addAttribute("board", boardService.get(boardNumber));
}
// 수정
@PostMapping("modify")
public RedirectView modify(BoardVO boardVO, RedirectAttributes rttr){
log.info("----------------------------");
log.info("modify............. : " + boardVO);
log.info("----------------------------");
boardService.modify(boardVO);
// 컨트롤러에서 다른 컨트롤러의 매개변수로 파라미터를 전달할 때에는
// addAttribute(), 쿼리스트링 방식으로 전달해야 받을 수 있다.
// Flash방식은 최종 응답 화면에서 사용될 파라미터를 전달할 때에만 사용하도록 한다.
rttr.addAttribute("boardNumber", boardVO.getBoardNumber());
return new RedirectView("/board/read");
}
// 삭제
@PostMapping("remove")
public String remove(Long boardNumber, Criteria criteria, Model model){
log.info("----------------------------");
log.info("remove............. : " + boardNumber);
log.info("----------------------------");
boardService.remove(boardNumber);
return getList(criteria, model);
}
}
'웹 개발 > Spring' 카테고리의 다른 글
[Web_Spring] 17 (0) | 2022.06.29 |
---|---|
[Web_Spring] 16 (0) | 2022.06.28 |
[Web_Spring] 14 (0) | 2022.06.26 |
[Web_Spring] 13 (0) | 2022.06.25 |
[Web_Spring] 12 (0) | 2022.06.24 |