<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>게시판 글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" />
<!-- Include stylesheet -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div style="width:1500px; margin:0 auto; padding: 50px; border:1px solid #efefef;">
<h3>게시판 글쓰기</h3>
<hr />
<div class="row">
<div class="col-sm">
<div class="form-floating mb-2">
<input type="text" id="title" class="form-control" autofocus required />
<label for="title" class="form-label">제목</label>
</div>
<div style="margin-bottom:5px;">
<!-- Create the editor container -->
<div id="editor" style="height:300px;">
<p>Hello World!</p>
<p>Some initial <strong>bold</strong> text</p>
<p><br></p>
</div>
</div>
<div class="form-floating mb-2">
<input type="text" id="writer" class="form-control" required />
<label for="writer" class="form-label">작성자</label>
</div>
<div>
<input type="submit" value="글쓰기" class="btn btn-primary" onclick="getEditorContent()"/>
</div>
</div>
</div>
</div>
</div>
<!-- Include the Quill library -->
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<!-- Initialize Quill editor -->
<script>
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'script': 'sub'}, { 'script': 'super' }], // superscript/subscript
[{ 'indent': '-1'}, { 'indent': '+1' }], // outdent/indent
[{ 'direction': 'rtl' }], // text direction
[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'font': [] }],
[{ 'align': [] }],
['clean'] // remove formatting button
];
// 위쪽에 있는 태그 중에서 id가 editor인 것을 찾아서 toolbar는 toolbarOptions의 값으로 대체하고 테마를 snow로 해서 변경
var quill = new Quill('#editor', {
modules: {
toolbar: toolbarOptions
},
theme: 'snow'
});
function getEditorContent(){
const title = document.getElementById("title"); // id가 title인 정보를 가져오기
const writer = document.getElementById("writer"); // id가 writer인 정보를 가져오기
const content = quill.root.innerHTML; // 위쪽의 editor객체를 통해서 가져오기
// 유효성 검사
if(title.value.length <= 0 ){
alert('제목을 입력하세요.');
title.focus();
return false; // 아래쪽 소스코드를 수행하지 않음. 함수가 종료됨.
}
if(writer.value.length < 1){
alert('작성자를 입력하세요.');
title.focus();
return false; // 함수 종료
}
// <form action="write.do" method="post">
// <input type="text" name = "title" value = "실제입력값"></input>
// <input type="text" name = "title" value = "실제입력값"></input>
// <input type="text" name = "title" value = "실제입력값"></input>
// </form>
var form = document.createElement("form");
form.action = "write.do";
form.method = "post";
// <input type"text" name = "title" value = "실제입력값"></input>
var input1 = document.createElement("input");
input1.type = "text"
input1.name = "title";
input1.value = title.value;
form.appendChild(input1);
var input2 = document.createElement("input");
input1.type = "text"
input1.name = "content";
input1.value = content;
form.appendChild(input2);
var input3 = document.createElement("input");
input1.type = "text"
input1.name = "writer";
input1.value = writer.value;
form.appendChild(input3);
document.body.appendChild(form);
form.submit();
}
</script>
</body>
</html>
board_write.jsp를 이렇게 수정한다.
제목을 입력하지 않으니 제목을 입력하라는 창이 나온다.
작성자도 마찬가지이다.
public class Board {
private long no;
private String title;
private String content;
private String writer;
private long hit;
private Date regdate;
}
옛날에 사용하던 dto를 가져온다.
public interface BoardMapper {
@Insert({
" Insert Into board (title, content, writer)",
" VALUES(#{obj.title}, #{obj.content}, #{obj.writer}) "
})
public int insertBoardOne(@Param("obj") Board obj);
}
BoardMapper에 insertBoardOne을 추가하고
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String title = request.getParameter("title");
String content = request.getParameter("content");
String writer = request.getParameter("writer");
Board obj = new Board();
obj.setTitle(title);
obj.setContent(content);
obj.setWriter(writer);
int ret = MybatisContext.getSqlSession().getMapper(BoardMapper.class).insertBoardOne(obj);
if(ret == 1) { // 성공하면 목록페이지로
response.sendRedirect("select.do");
}
else { // 실패하면 글쓰기 페이지로
response.sendRedirect("write.do");
}
// 1. DB 추가하기
// 2. 적절한 페이지로 이동
// http://127.0.0.1:8080/web02/board/select.do
response.sendRedirect("select.do");
}
BoardWriteController.java의 dopost를 이렇게 작성한다.
위 내용으로 글쓰기를 눌러보자.
아직 select.do를 만들지 않았으니 당연히 404 에러가 발생한다.
하지만 H2 콘솔에 들어가 확인해보면 데이터가 정상적으로 추가된 것을 볼 수 있다.
@Select({
" SELECT b.* FROM board b ORDER BY no DESC"
})
public List<Board> selectBoardList();
mapper에 select를 생성하고
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.DB에서 게시글 전체 읽기
List<Board> list = MybatisContext.getSqlSession().getMapper(BoardMapper.class).selectBoardList();
// 2. view로 list전달
request.setAttribute("list", list);
// 3. board_select.jsp 화면에 표시
request.getRequestDispatcher("/WEB-INF/board_write.jsp").forward(request, response);
}
BoardSelectController를 만든다.
<%@ 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 lang="ko">
<head>
<meta charset="UTF-8">
<title>게시판 글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" />
</head>
<body>
<div class="container mx-auto p-2" style="width: 800px">
<h2>게시글 목록</h2>
<button type="button" class="btn btn-outline-primary">글쓰기</button>
<form class="row g-2">
<div class=""></div>
</form>
<table class="table">
<thead class="text-center">
<tr>
<th scope="col-1">#</th>
<th scope="col-4">제목</th>
<th scope="col-2">작성자</th>
<th scope="col-1">조회수</th>
<th scope="col-4">작성일자</th>
</tr>
</thead>
<tbody class="text-center">
<c:forEach var="obj" items="${list}">
<tr>
<th scope="row">${obj.no}</th>
<td>${obj.title}</td>
<td>${obj.writer}</td>
<td>${obj.hit}</td>
<td>${obj.regdate}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
board_select.jsp를 생성하면
이렇게 목록이 나온다.
이것을
이라고 한다
// 전체 개수(페이지네이션용)
@Select({
" SELECT COUNT(*) cnt FROM board"
})
public long countBoardList();
mapper를 생성하고
// 게시글 전체 개수
long cnt = MybatisContext.getSqlSession().getMapper(BoardMapper.class).countBoardList();
// 2. view로 list전달
request.setAttribute("pages", (cnt-1)/ 10 + 1);
controller에 추가한다.
위 두 링크에 들어가서
이렇게 js 파일을 저장하고 js 폴더에 넣는다.
</table>
<ul id="pagination-demo" class="pagination-sm"></ul>
</div>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.4.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/js/jquery.twbsPagination.min.js"></script>
<script>
// $(document).ready"(function () {
$(function(){
$('#pagination-demo').twbsPagination({
totalPages: Number('${pages}'),
visiblePages: 10,
first: '≪',
last : '≫',
prev : '<',
next : '>',
initiateStartPageClick:false,
startPage : Number('${param.page}'),
onPageClick: function (event, page) {
window.location.href="select.do?page="+page;
}
});
});
</script>
</body>
board_select.jsp에 추가해준다.
이렇게 전체 로딩이 되면서 아래에 페이지 넘어갈 수 있는 버튼이 생긴다.
이 버튼을
라고 한다.
+startPage : Number('${param.page}')이 있기 때문에 주소창 맨 뒤에 ?page=1이 들어가야 한다.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 주소창에 ?page가 없을 경우 처리
String page = request.getParameter("page");
if( page ==null ) {
response.sendRedirect("select.do?page=1"); // 강제로 page=1
return; // 메소드 종료시키기
}
BoardSelectController.java의 doGet에 위 코드를 추가해주자.
엔터를 누르면
자동으로 page=1로 이동한다.
// 페이지네이션
@Select({
" SELECT b.* FROM ( " ,
" SELECT b.*, ROW_NUMBER() OVER (ORDER BY no DESC) rown FROM board b " ,
" ) b WHERE rown >= #{start} AND rown <=#{end} ORDER BY no DESC "
})
public List<Board> selectBoardListPage(@Param("start") int start, @Param("end") int end);
mapper에 페이지네이션 매퍼를 추가하였다.
// 페이지네이션 시작값
int start = Integer.parseInt(page)*10-9;
// 페이지네이션 종료값
int end = Integer.parseInt(page)*10;
// 1.DB에서 게시글 전체 읽기
List<Board> list = MybatisContext.getSqlSession().getMapper(BoardMapper.class).selectBoardListPage(start,end);
BoardSelectController의 doGet을 수정하였다.
한 페이지에 10개까지만 나오고, 총 글 수가 36이니 4페이지까지만 생성된다.
package mapper;
import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import dto.Board;
@Mapper
public interface BoardMapper {
// 글쓰기
@Insert({
" Insert Into board (title, content, writer)",
" VALUES(#{obj.title}, #{obj.content}, #{obj.writer}) "
})
public int insertBoardOne(@Param("obj") Board obj);
// 전체 목록
@Select({
" SELECT b.* FROM board b ORDER BY no DESC"
})
public List<Board> selectBoardList();
// 전체 개수(페이지네이션용)
@Select({
" SELECT COUNT(*) cnt FROM board "
})
public long countBoardList();
// 페이지네이션
@Select({
" SELECT b.* FROM ( " ,
" SELECT b.*, ROW_NUMBER() OVER (ORDER BY no DESC) rown FROM board b " ,
" ) b WHERE rown >= #{start} AND rown <=#{end} ORDER BY no DESC "
})
public List<Board> selectBoardListPage(@Param("start") int start, @Param("end") int end);
}
package controller;
import java.io.IOException;
import java.util.List;
import config.MybatisContext;
import dto.Board;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import mapper.BoardMapper;
@WebServlet(urlPatterns = {"/board/select.do"})
public class BoardSelectController extends HttpServlet {
private static final long serialVersionUID = 1L;
public BoardSelectController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 주소창에 ?page가 없을 경우 처리
String page = request.getParameter("page");
if( page ==null ) {
response.sendRedirect("select.do?page=1"); // 강제로 page=1
return; // 메소드 종료시키기
}
// 페이지네이션 시작값
int start = Integer.parseInt(page)*10-9;
// 페이지네이션 종료값
int end = Integer.parseInt(page)*10;
// 1.DB에서 게시글 전체 읽기
List<Board> list = MybatisContext.getSqlSession().getMapper(BoardMapper.class).selectBoardListPage(start,end);
// 게시글 전체 개수
long cnt = MybatisContext.getSqlSession().getMapper(BoardMapper.class).countBoardList();
// 2. view로 list전달
request.setAttribute("list", list);
request.setAttribute("pages", (cnt-1)/ 10 + 1);
// 3. board_select.jsp 화면에 표시
request.getRequestDispatcher("/WEB-INF/board_select.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<%@ 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" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>게시판글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/bootstrap.min.css" /><title>Insert title here</title>
</head>
<body>
<div class="container">
<a href="write.do" class="btn btn-primary">글쓰기</a>
<div style="width:500px; margin-top:10px;">
<form class="row g-2">
<div class="col-auto">
<input type="text" name="text" class="form-control" placeholder="검색어" style="width:300px;"/>
</div>
<div class="col-auto">
<input type="submit" class="btn btn-primary" value="검색" />
</div>
</form>
</div>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">글번호</th>
<th scope="col">제목</th>
<th scope="col">작성자</th>
<th scope="col">조회수</th>
<th scope="col">날짜</th>
</tr>
</thead>
<tbody>
<c:forEach var="obj" items="${list}">
<tr>
<td scope="row">${obj.no}</td>
<td>${obj.title}</td>
<td>${obj.writer}</td>
<td>${obj.hit}</td>
<td>${obj.regdate}</td>
</tr>
</c:forEach>
</tbody>
</table>
<ul id="pagination-demo" class="pagination"></ul>
</div>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.4.min.js"></script>
<script src="${pageContext.request.contextPath}/resources/js/jquery.twbsPagination.min.js"></script>
<script>
// $(document).ready(function(){
$(function(){
$('#pagination-demo').twbsPagination({
totalPages : Number('${pages}'),
visiblePages : 10,
first : '≪',
last : '≫',
prev : '<',
next : '>',
initiateStartPageClick : false,
startPage : Number('${param.page}'),
onPageClick : function (event, page) {
window.location.href="select.do?page=" + page;
}
});
});
</script>
</body>
</html>```