2025-02-03

















<!-- lombok 라이브러리 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<!-- spring-jdbc 라이브러리 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- mybatis framework 라이브러리 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mybatis-spring 라이브러리 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<hr width="30%" color="maroon">
<h3>BOARD 테이블 게시물 전체 리스트 페이지</h3>
<hr width="30%" color="maroon">
<br> <br>
<table border="1" width="600">
<c:set var="list" value="${List }" />
<c:set var="paging" value="${Paging }" />
<tr>
<td colspan="5" align="right">
전체 게시물 수 : ${paging.totalRecord } 개
</td>
</tr>
<tr>
<th>게시글 No.</th> <th>게시글 제목</th> <th>게시글 작성자</th>
<th>게시글 조회수</th> <th>게시글 작성일자</th>
</tr>
<c:if test="${!empty list }">
<c:forEach items="${list }" var="dto">
<tr>
<td>${dto.board_no }</td>
<td><a href="<%=request.getContextPath() %>
/board_content.go?no=${dto.board_no }&page=${paging.page }">
${dto.board_title }</a></td>
<td>${dto.board_writer }</td>
<td>${dto.board_hit }</td>
<td>${dto.board_date.substring(0, 10) }</td>
</tr>
</c:forEach>
</c:if>
<c:if test="${empty list }">
<tr>
<td colspan="5" align="center">
<h3>게시물 목록이 없습니다...</h3>
</td>
</tr>
</c:if>
</table>
<br> <br>
<input type="button" value="글쓰기"
onclick="location.href='board_write.go'">
<br> <br>
<%-- 페이징 처리 --%>
<c:if test="${paging.page > paging.block }">
<a href="<%=request.getContextPath() %>/board_list.go?page=1">[처음]</a>
<a href="<%=request.getContextPath() %>/board_list.go?page=${paging.startBlock - 1 }">◀</a>
</c:if>
<c:forEach begin="${paging.startBlock }" end="${paging.endBlock }" var="i">
<c:if test="${i == paging.page }">
<b><a href="<%=request.getContextPath() %>/board_list.go?page=${i }">${i }</a></b>
</c:if>
<c:if test="${i != paging.page }">
<a href="<%=request.getContextPath() %>/board_list.go?page=${i }">${i }</a>
</c:if>
</c:forEach>
<c:if test="${paging.allPage > paging.endBlock }">
<a href="<%=request.getContextPath() %>/board_list.go?page=${paging.endBlock + 1 }">▶</a>
<a href="<%=request.getContextPath() %>/board_list.go?page=${paging.allPage }">[마지막]</a>
</c:if>
<br>
<hr width="30%" color="maroon">
<br>
<%-- 검색 폼 영역 --%>
<form method="post" action="<%=request.getContextPath() %>/board_search.go">
<select name="field">
<option value="title">제목</option>
<option value="cont">내용</option>
<option value="writer">작성자</option>
</select>
<input name="keyword">
<input type="submit" value="검색">
</form>
</div>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.spring.model.BoardDAO" alias="boardDao" />
<typeAlias type="com.spring.model.BoardVO" alias="boardVo" />
<typeAlias type="com.spring.model.PageVO" alias="pageVo" />
</typeAliases>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="boardDao"> <!-- mybatis-config에서 설정한 별칭 입력 -->
<select id="cnt" resultType="int">
select count(*) from board
</select>
<select id="list" parameterType="pageVo" resultType="boardVo">
<![CDATA[select * from (select row_number() over(order by board_no desc) rnum, b.* from board b)
where rnum >= #{startNo} and rnum <= #{endNo}]]>
</select>
<!--
일반적으로 DB 작업을 하다 보면 먼저 사전에 어떤 값을 가져와서 해당 값을
증가시킨 후에 DB에 저장하거나, 혹은 입력된 후에 증가값을 가져올 필요가
있는 경우가 많이 발생을 함.
이런 경우에는 MyBatis 에서 제공하는 selectKey 하는 태그를 이용하여
별도의 쿼리 로직을 사용할 필요 없이 일괄 처리 작업을 할 수 있게 해줌.
* KeyProperty 속성 : 해당 결과 값이 들어갈 DTO(VO) 객체의 멤버 변수명을
작성하면 됨.
* order 속성 : 해당 쿼리문의 실행 순서를 의미함.
- BEFORE : 원래 실행할 쿼리문 이전에 selectKey 태그가 실행이 됨.
- AFTER : 원래 실행할 쿼리문 이후에 selectKey 태그가 실행이 됨.
※ 주의사항 : 반드시 멤버변수에 해당하는 setter() 와 getter() 메서드가 존재해야 함.
-->
<insert id="add" parameterType="boardVo">
<selectKey resultType="int" keyProperty="board_no" order="BEFORE">
select max(board_no) from board
</selectKey>
insert into board values(#{board_no} + 1, #{board_writer},
#{board_title}, #{board_cont}, #{board_pwd}, default, sysdate, '')
</insert>
<select id="cont" parameterType="int" resultType="boardVo">
select * from board where board_no = #{no}
</select>
<update id="read" parameterType="int">
update board set board_hit = board_hit + 1 where board_no = #{no}
</update>
<update id="modify" parameterType="boardVo">
update board set board_title = #{board_title}, board_cont = #{board_cont},
board_update = sysdate where board_no = #{board_no}
</update>
<delete id="del" parameterType="int">
delete from board where board_no = #{no}
</delete>
<update id="seq" parameterType="int">
<![CDATA[update board set board_no = board_no - 1 where board_no > #{board_no}]]>
</update>
<select id="count" parameterType="map" resultType="int">
select count(*) from board
<if test="Field == 'title'">
where board_title
</if>
<if test="Field == 'cont'">
where board_cont
</if>
<if test="Field == 'writer'">
where board_writer
</if>
like '%' || #{Keyword} || '%'
</select>
<select id="search" parameterType="pageVo" resultType="boardVo">
select * from (select row_number() over(order by board_no desc) rnum, b.* from board b
<choose>
<when test="field == 'title'">
where board_title
</when>
<when test="field == 'cont'">
where board_cont
</when>
<when test="field == 'writer'">
where board_writer
</when>
</choose>
<![CDATA[
like '%' || #{keyword} || '%') where rnum >= #{startNo} and rnum <= #{endNo}
]]>
</select>
</mapper>
package com.spring.model;
import lombok.Data;
import lombok.NoArgsConstructor;
// 페이징 처리 작업 시 작업할 내용을 설정하는 객체
@Data
@NoArgsConstructor // 기본 생성자
public class PageVO {
// 페이징 처리 관련 멤버 선언
private int page; // 현재 페이지
private int rowsize; // 한 페이지당 보여질 게시물의 수
private int totalRecord; // DB 상의 board 테이블 전체 게시물 수
private int startNo; // 해당 페이지의 시작 글 번호
private int endNo; // 해당 페이지의 끝 글 번호
private int startBlock; // 해당 페이지의 시작 블럭
private int endBlock; // 해당 페이지의 끝 블럭
private int allPage; // 전체 페이지 수
private int block = 3; // 아래의 보여질 최대 페이지 수
// 검색 관련 멤버 선언
private String field;
private String keyword;
// 일반적인 페이징 처리 인자 생성자
public PageVO(int page, int rowsize, int totalRecord) {
this.page = page;
this.rowsize = rowsize;
this.totalRecord = totalRecord;
// 해당 페이지에서 시작 글 번호
this.startNo = (this.page * this.rowsize) - (this.rowsize - 1);
// 해당 페이지에서 끝 글 번호
this.endNo = (this.page * this.rowsize);
// 해당 페이지에서 시작 블럭
this.startBlock = (((this.page - 1) / this.block) * this.block) + 1;
// 해당 페이지에서 끝 블럭
this.endBlock = (((this.page - 1) / this.block) * this.block) + this.block;
// 전체 페이지 수를 얻어오는 과정
this.allPage = (int)Math.ceil(this.totalRecord / (double)this.rowsize);
if (this.endBlock > this.allPage) {
this.endBlock = this.allPage;
}
} // 인자 생성자
// 검색 페이징 처리 인자 생성자
public PageVO(int page, int rowsize, int totalRecord, String field, String keyword) {
// this를 이용하여 위에 인자 생성자를 불러옴
this(page, rowsize, totalRecord);
this.field = field;
this.keyword = keyword;
}
}
package com.spring.board;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.spring.model.BoardDAO;
import com.spring.model.BoardVO;
import com.spring.model.PageVO;
@Controller
public class BoardController {
@Autowired
private BoardDAO dao;
// 한 페이지당 보여질 게시물의 수
private final int rowsize = 3;
// DB 상의 전체 게시물의 수
private int totalRecord = 0;
@RequestMapping("board_list.go")
public String list(HttpServletRequest request, Model model) {
int page; // 현재 페이지 변수
// 페이징 처리 작업
if (request.getParameter("page") != null) {
page = Integer.parseInt(request.getParameter("page"));
} else {
// 처음으로 "게시물 전체 목록" a 링크를 클릭한 경우
page = 1;
}
// DB 상의 전체 게시물의 수를 확인하는 메서드 호출
totalRecord = this.dao.getListCount();
PageVO vo = new PageVO(page, rowsize, totalRecord);
// 현재 페이지에 해당하는 게시물을 가져오는 메서드 호출
List<BoardVO> boardList = this.dao.getBoardList(vo);
model.addAttribute("List", boardList)
.addAttribute("Paging", vo);
return "board_list";
}
@RequestMapping("board_write.go")
public String write() {
return "board_write";
}
@RequestMapping("board_write_ok.go")
public void writerOk(BoardVO vo, HttpServletResponse response) throws IOException {
int chk = this.dao.insertBoard(vo);
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
if (chk > 0) {
out.println("<script>");
out.println("alert('게시글 등록 성공')");
out.println("location.href='board_list.go'");
out.println("</script>");
} else {
out.println("<script>");
out.println("alert('게시글 등록 실패')");
out.println("history.back()");
out.println("</script>");
}
}
@RequestMapping("board_content.go")
public String content(@RequestParam("no") int no,
@RequestParam("page") int nowPage, Model model) {
// 조회수를 증가 시켜주는 메서드 호출
this.dao.readCount(no);
// 게시글 번호에 해당하는 게시글의 상세 내역을 조회하는 메서드 호출
BoardVO cont = this.dao.boardContent(no);
model.addAttribute("Content", cont)
.addAttribute("Paging", nowPage);
return "board_content";
}
@RequestMapping("board_modify.go")
public String modify(@RequestParam("no") int no,
@RequestParam("page") int nowPage, Model model) {
// 게시글 번호에 해당하는 게시글의 상세 내역을 조회하는 메서드 호출
BoardVO vo = this.dao.boardContent(no);
model.addAttribute("Modify", vo)
.addAttribute("Page", nowPage);
return "board_modify";
}
@RequestMapping("board_modify_ok.go")
public void modifyOk(BoardVO vo, @RequestParam("db_pwd") String db_pwd,
@RequestParam("page") int nowPage, HttpServletResponse response) throws IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
if (vo.getBoard_pwd().equals(db_pwd)) {
// 비밀번호가 일치하는 경우
int chk = this.dao.updateBoard(vo);
if (chk > 0) {
out.println("<script>");
out.println("alert('게시글 수정 성공')");
out.println("location.href='board_content.go?no=" + vo.getBoard_no() +
"&page=" + nowPage + "'");
out.println("</script>");
} else {
out.println("<script>");
out.println("alert('게시글 수정 실패')");
out.println("history.back()");
out.println("</script>");
}
} else {
// 비밀번호가 틀린 경우
out.println("<script>");
out.println("alert('비밀번호가 틀립니다.')");
out.println("history.back()");
out.println("</script>");
}
}
@RequestMapping("board_delete.go")
public String delete(@RequestParam("no") int no,
@RequestParam("page") int nowPage, Model model) {
BoardVO vo = this.dao.boardContent(no);
model.addAttribute("Delete", vo)
.addAttribute("Page", nowPage);
return "board_delete";
}
@RequestMapping("board_delete_ok.go")
public void deleteOk(BoardVO vo, @RequestParam("db_pwd") String db_pwd,
@RequestParam("page") int nowPage, HttpServletResponse response) throws IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
if (vo.getBoard_pwd().equals(db_pwd)) {
// 비밀번호가 일치하는 경우
int res = this.dao.deleteBoard(vo.getBoard_no());
if (res > 0) {
this.dao.updateSequence(vo.getBoard_no());
out.println("<script>");
out.println("alert('게시글 삭제 성공')");
out.println("location.href='board_list.go?page=" + nowPage + "'");
out.println("</script>");
} else {
out.println("<script>");
out.println("alert('게시글 삭제 실패')");
out.println("history.back()");
out.println("</script>");
}
} else {
// 비밀번호가 틀린 경우
out.println("<script>");
out.println("alert('비밀번호가 틀립니다.')");
out.println("history.back()");
out.println("</script>");
}
}
@RequestMapping("board_search.go")
public String search(@RequestParam("field") String field, @RequestParam("keyword") String keyword,
HttpServletRequest request, Model model) {
// 검색 결과 페이징 처리 작업
int page; // 현재 페이지 변수
if (request.getParameter("page") != null) {
page = Integer.parseInt(request.getParameter("page"));
} else {
// "검색" 버튼을 클릭한 경우 - 검색 요청
page = 1;
}
// 검색 분류(field)와 검색어(keyword)에 해당하는 게시글의 수를 DB에서 확인하는 작업
Map<String, String> map = new HashMap<String, String>();
map.put("Field", field);
map.put("Keyword", keyword);
totalRecord = this.dao.searchBoardCount(map);
PageVO pVo = new PageVO(page, rowsize, totalRecord, field, keyword);
// 검색 시 한 페이지 당 보여질 게시물의 수 만큼 검색한 게시물을 List로 가져오는 메서드
List<BoardVO> searchList = this.dao.searchBoardList(pVo);
model.addAttribute("SearchPageList", searchList)
.addAttribute("Paging", pVo);
return "board_search_list";
}
@RequestMapping("board_search_cont.go")
public String searchCont(Model model, @RequestParam("no") int no,
@RequestParam("page") int nowPage, @RequestParam("field") String field,
@RequestParam("keyword") String keyword) {
// 조회수 증가 메서드
this.dao.readCount(no);
// 게시글 번호에 해당하는 게시글을 조회하는 메서드 호출
BoardVO searchCont = this.dao.boardContent(no);
model.addAttribute("sCont", searchCont)
.addAttribute("Page", nowPage)
.addAttribute("Field", field)
.addAttribute("Keyword", keyword);
return "board_search_cont";
}
}'Spring, Boot > 기초 내용 정리' 카테고리의 다른 글
| Spring(AOP)_00 (0) | 2025.02.06 |
|---|---|
| Spring(FileUpload)_01 (0) | 2025.02.06 |
| Spring(MyBatis)_03 (0) | 2025.02.05 |
| Spring(MyBatis)_02 (0) | 2025.02.05 |
| Spring(MyBatis)_01 (0) | 2025.02.05 |