append
p태그 append 이동
jsp는 board앞에 /있어야 함
servlet으로 갈 때는 /없어도 됨
on delete cascade -> 게시글을 지울 때 댓글도 다 지울 수 있음
package kr.or.ddit.board.service;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import kr.or.ddit.board.dao.BoardDaoImpl;
import kr.or.ddit.board.dao.IBoardDao;
import kr.or.ddit.board.vo.BoardVO;
import kr.or.ddit.board.vo.ReplyVO;
public class BoardServiceImpl implements IBoardService{
private IBoardDao dao;
private static IBoardService service;
private BoardServiceImpl(){
dao = BoardDaoImpl.getInstance();
}
public static IBoardService getInstance(){
if(service == null) service = new BoardServiceImpl();
return service;
}
@Override
public List<BoardVO> selectByPage(Map<String, Integer> map) {
List<BoardVO> list = null;
try {
list = dao.selectByPage(map);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
@Override
public int totalCount() {
int count = 0;
try {
count = dao.totalCount();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return count;
}
@Override
public Map<String, Integer> PageInfo(int page) {
//전체 글 갯수 가져오기
int count = this.totalCount();
//한 페이지당 출력할 글 갯수
int perList = 3;
//한 화면에 출력할 페이지 수
int perPage = 2;
//전체 페이지 수 - 전체 글 갯수 / perList
int totalPage = (int) Math.ceil((double)count / perList); //나누면 실수형 -> 그걸 올림하고 다시 정수형으로 형변환
//list의 시작번호와 끝번호1~5, 6~10, 11~15
int start = (page-1) * perList + 1;
int end = start + perList - 1;
if(end > count) end = count;
//시작페이지와 끝페이지 1~2 3~4 5~6
int startPage = ((page-1) / perPage * perPage) + 1;
int endPage = startPage + perPage - 1;
if(endPage > totalPage) endPage = totalPage;
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("start", start);
map.put("end", end);
map.put("startPage", startPage);
map.put("endPage", endPage);
map.put("totalPage", totalPage);
return map;
}
@Override
public int insertReply(ReplyVO vo) {
int rnum = 0;
try {
rnum = dao.insertReply(vo);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rnum;
}
@Override
public List<ReplyVO> listReply(int bonum) {
List<ReplyVO> list = null;
try {
list = dao.listReply(bonum);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
@Override
public int updateReply(ReplyVO vo) {
int rnum = 0;
try {
rnum = dao.updateReply(vo);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rnum;
}
@Override
public int deleteReply(int renum) {
int rnum = 0;
try {
rnum = dao.deleteReply(renum);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rnum;
}
@Override
public int deleteBoard(int num) {
int res = 0;
try {
res = dao.deleteBoard(num);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
}
package kr.or.ddit.board.dao;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import kr.or.ddit.board.vo.BoardVO;
import kr.or.ddit.board.vo.ReplyVO;
import kr.or.ddit.ibatis.config.SqlMapClientFactory;
import com.ibatis.sqlmap.client.SqlMapClient;
public class BoardDaoImpl implements IBoardDao{
private static IBoardDao dao;
private SqlMapClient smc;
private BoardDaoImpl(){
smc = SqlMapClientFactory.getSqlMapClient();
}
public static IBoardDao getInstance(){
if(dao==null) dao = new BoardDaoImpl();
return dao;
}
@Override
public List<BoardVO> selectByPage(Map<String, Integer> map)
throws SQLException {
List<BoardVO> list = smc.queryForList("board.selectByPage",map);
return list;
}
@Override
public int totalCount() throws SQLException {
int result = (int) smc.queryForObject("board.totalCount");
return result;
}
@Override
public int insertReply(ReplyVO vo) throws SQLException {
return (int)smc.insert("reply.insertReply", vo);
}
@Override
public List<ReplyVO> listReply(int bonum) throws SQLException{
return smc.queryForList("reply.listReply", bonum);
}
@Override
public int updateReply(ReplyVO vo) throws SQLException {
return smc.update("reply.updateReply", vo);
}
@Override
public int deleteReply(int renum) throws SQLException {
return smc.delete("reply.deleteReply", renum);
}
@Override
public int deleteBoard(int num) throws SQLException {
return smc.delete("board.deleteBoard", num);
}
}
package kr.or.ddit.board.controller;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import kr.or.ddit.board.service.BoardServiceImpl;
import kr.or.ddit.board.service.IBoardService;
import kr.or.ddit.board.vo.ReplyVO;
/**
* Servlet implementation class ReplyInsert
*/
@WebServlet("/ReplyInsert.do")
public class ReplyInsert extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//0. 클라이언트 요청 시 전송
ReplyVO vo = new ReplyVO();
try {
BeanUtils.populate(vo, request.getParameterMap());
} catch (IllegalAccessException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vo.setBonum(Integer.parseInt(request.getParameter("bonum")));
vo.setName(request.getParameter("name"));
vo.setCont(request.getParameter("cont"));
//1. service 객체 얻어오기
IBoardService service = BoardServiceImpl.getInstance();
//2.
int rnum = service.insertReply(vo);
//3.
request.setAttribute("res", rnum);
//
request.getRequestDispatcher("board/result.jsp").forward(request, response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//서블릿에서 수행결과 공유
int res = (Integer)request.getAttribute("res");
if(res > 0){
%>
{ "sw" : "성공" }
<% }else{ %>
{ "sw" : "실패" }
<%
}
%>
<%@page import="kr.or.ddit.board.vo.ReplyVO"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//서블릿에서 실행 결과 공유
List<ReplyVO> list = (List<ReplyVO>)request.getAttribute("list");
%>
[
<%
for(int i = 0; i <list.size(); i++){
ReplyVO vo = list.get(i);
if(i > 0) out.print(",");
%>
{
"renum" : "<%= vo.getRenum() %>",
"bonum" : "<%= vo.getBonum() %>",
"name" : "<%= vo.getName() %>",
"cont" : "<%= vo.getCont().replaceAll("\r", "").replaceAll("\n", "<br>") %>",
"date" : "<%= vo.getRedate() %>"
}
<%
}
%>
]
package kr.or.ddit.board.controller;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import kr.or.ddit.board.service.BoardServiceImpl;
import kr.or.ddit.board.service.IBoardService;
import kr.or.ddit.board.vo.ReplyVO;
@WebServlet("/ReplyUpdate.do")
public class ReplyUpdate extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
/*int renum = Integer.parseInt(request.getParameter("renum"));
String cont = request.getParameter("cont");*/
//0. 클라이언트 전송시 값 가져오기- renum, cont - vo에 저장
ReplyVO vo = new ReplyVO();
try {
BeanUtils.populate(vo, request.getParameterMap());
} catch (IllegalAccessException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//1. service객체
IBoardService service = BoardServiceImpl.getInstance();
/*vo.setRenum(renum);
vo.setCont(cont);*/
//2. service 메서드 호출 - 결과값 받기
int result = service.updateReply(vo);
//3. request에 저장
request.setAttribute("res", result);
//4. jsp로 forward
request.getRequestDispatcher("board/result.jsp").forward(request, response);
}
}
package kr.or.ddit.board.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.or.ddit.board.service.BoardServiceImpl;
import kr.or.ddit.board.service.IBoardService;
@WebServlet("/ReplyDelete.do")
public class ReplyDelete extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
//0. 클라이언트 요청시
int idx = Integer.parseInt(request.getParameter("renum"));
//1.service 객체
IBoardService service = BoardServiceImpl.getInstance();
//2. service 메소드 호출 - 결과값
int result = service.deleteBoard(idx);
//3. request에 저장
request.setAttribute("res", result);
//4. jsp로 forward
request.getRequestDispatcher("board/result.jsp").forward(request, response);
}
}
package kr.or.ddit.board.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.or.ddit.board.service.BoardServiceImpl;
import kr.or.ddit.board.service.IBoardService;
@WebServlet("/BoardDelete.do")
public class BoardDelete extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0. 클라이언트 요청시
int idx = Integer.parseInt(request.getParameter("num"));
//1.service 객체
IBoardService service = BoardServiceImpl.getInstance();
//2. service 메소드 호출 - 결과값
int result = service.deleteBoard(idx);
//3. request에 저장
request.setAttribute("res", result);
//4. jsp로 forward
request.getRequestDispatcher("board/result.jsp").forward(request, response);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="board">
<select id="selectByPage" resultClass="boardVO" parameterClass="map">
<![CDATA[
select A.* from (
select rownum as rnum, B.* from (
select * from board1
order by num desc) B
where rownum <= #end#) A
where A.rnum >=#start#
]]>
</select>
<select id="totalCount" resultClass="int">
select count(*) from board1
</select>
<delete id="deleteBoard" parameterClass="int">
delete board1 where num = #num#
</delete>
</sqlMap>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="../js/board.js"></script>
<style>
body{
margin: 10px;
}
.p1{
width: 80%;
padding: 5px;
margin: 3px;
float: left;
}
.p2{
width: 17%;
padding: 5px;
margin: 2px;
float: right;
}
.p3{
clear: both;
}
input[name=reply]{
height: 40px;
vertical-align: top;
}
.pager{
width: 100px;
float: left;
margin: 5px;
margin-left: 5%;
}
.repl{
border: 1px solid gray;
background : #f1f5fa;
margin: 1px;
padding: 5px;
}
#modifyform{
display: none;
}
</style>
<script type="text/javascript">
currentPage = 1;
reply = { } // 객체 선언 - 속성과 메서드를 동적으로 추가해서 사용
$(function(){
listPage(currentPage);
//이벤트
$('#list').on('click', '.action', function(){
//또는 $(document).on('click', '.action', function(){})
idx = $(this).attr('idx');
name = $(this).attr('name');
if(name=="modify"){
alert(idx + "번째 글을 수정합니다");
}else if(name=="delete"){
alert(idx + "번째 글을 삭제합니다");
deleteBoard(this); // db삭제 , 삭제 후 다시 리스트 출력
//list를 출력
//listPage();
}else if(name=="reply"){
alert(idx + "번째 글에 댓글을 답니다");
text = $(this).prev().val();
console.log(text);
// 숫자에 해당하는 대문자가 나옴
name1 = String.fromCharCode(Math.random() * 26 + 65);
name2 = String.fromCharCode(Math.random() * 26 + 97);
name3 = parseInt(Math.random() * 100 + 1);
// name, text
reply.name = name1 + name2 + name3;
reply.bonum = idx;
reply.cont = text;
// 서버로 전송 $.ajax({})
replyInsert(this); // 댓글저장 - 등록버튼 객체
//insert에서는 안쓰고 list에서 씀
//this객체가 insert에서는 필요없고 list에서 사용하기때문에 파라미터로 넘겨줌
//댓글리스트
replyList();
//비동기방식이라서 요청 - 응답의 순서가 아님
}else if(name == "list"){
alert(idx + "번째의 내용과 댓글을 출력합니다.");
replyList(this);
}else if(name == "r_modify"){
alert(idx + "번째 댓글을 수정합니다.");
//alert($(this).parents(".repl").find('.p3').text()); //내용이 들어있는 요소 찾기
//alert($(this).parent().next().text());
//원래 내용 - 수정할 내용 가져오기
oldtext = $(this).parent().next().html(); // - <br>태그를 가져오려면 html()로 가져와야 함
//내용을 줄바꿈(\n) 하여 수정창(modifyform)에 textarea에 출력
newtext = oldtext.replace(/<br>/g, "\n"); // <br>태그를 줄바꿈으로 바꾸고 다시 text변수에 담기
//alert(text);
$('#modifyform textarea').val(newtext);
//댓글 내용이 있는 p3의 내용을 지우기
$(this).parents(".repl").find('.p3').empty();
//댓글 수정폼 p3에 보이기
$(this).parents(".repl").find('.p3').append($('#modifyform'));
//댓글 수정폼 보이기
$('#modifyform').show();
}else if(name == "r_delete"){
alert(idx + "번째 댓글을 삭제합니다.");
// db삭제(idx가 필요) 후 화면에서 제거
deleteReply(this);
//$(this).parents('.repl').remove();
}
});
//페이지번호 리스트 이벤트
$('#pagelist').on('click', '.paging', function(){
currentPage = $(this).text().trim();
listPage(currentPage);
});
//next 이벤트
$('#pagelist').on('click', '.next', function(){
currentPage = parseInt($('.paging').last().text().trim()) + 1;
listPage(currentPage);
});
//previous 이벤트
$('#pagelist').on('click', '.prev', function(){
currentPage = parseInt($('.paging').first().text().trim()) - 1;
listPage(currentPage);
});
//댓글 수정창에서 취소버튼 클릭
$('#btnreset').on('click', function(){
//p3부분을 검색 - 원래 내용이 있었던 자리
p3tag = $('#modifyform').parent();
//-- modifyform을 다시 body로 append
$('body').append($('#modifyform'));
$('#modifyform').hide();
//원래 내용을 원래자리로 출력
//textarea에 줄바꿈
$(p3tag).html(oldtext)
});
//댓글 수정창에서 확인버튼 클릭
$('#btnok').on('click', function(){
//textarea에서 수정한 내용을 가져오기 - \r\n -> <br>로 변경
oldtext = $('#modifyform textarea').val();
newtext = oldtext.replace(/\r/g, "").replace(/\n/g, "<br>");
//p3 부분을 검색 - 원래 내용이 있었던 자리
p3tag = $('#modifyform').parent();
//수정폼 닫기
$('#modifyform').appendTo($('body'));
$('#modifyform').hide();
//수정 내용을 원래자리 p3으로 보내기
$(p3tag).html(newtext);
//db수정을 위해 ajax처리 하기 - oldtext, renum = idx
reply.cont = oldtext;
reply.renum = idx;
updateReply();
});
});//$(function)
</script>
</head>
<body>
<div id="modifyform">
<textarea rows="5" cols="50"></textarea>
<input type="button" value="확인" id="btnok">
<input type="button" value="취소" id="btnreset">
</div>
<h2>게시판</h2>
<br>
<div id="list"></div>
<div id="pagelist"></div>
</body>
</html>
/**
*
*/
function deleteBoard(del){
$.ajax({
url : '/board/BoardDelete.do',
type : 'get',
data : {"num" : idx },
success : function(res){
alert(res.sw);
},
error: function(res){
alert("상태 : " + xhr.status);
},
dataType : 'json'
});
}
function deleteReply(del){
$.ajax({
url: '/board/ReplyDelete.do',
type : 'get',
data : {"renum" : idx},
success : function(res){
alert(res.sw);
$(del).parents(".repl").remove();
} ,
error : function(){
alert("상태 : " + xhr.status);
},
dataType : 'json'
});
}
function updateReply(){
$.ajax({
url : '/board/ReplyUpdate.do',
type : 'post',
data : reply,
success : function(res){
alert(res.sw);
},
error : function(xhr){
alert("상태 : " + xhr.status);
},
dataType : 'json'
});
}
function replyList(brep){ // bref : 댓글등록버튼 또는 제목클릭
//idx에 해당하는 댓글을 가져온다
//리스트를 가져오는 ajax 수행
$.ajax({
url : '/board/ReplyList.do',
type : 'get',
data : {'bonum' : idx }, // reply는 댓글 저장 전에 생긴 것(생성되기 전) - idx대신 reply.bonum은 사용 못함
success : function(res){
//성공
//댓글 리스트 출력
rcode = '';
$(brep).parents('.panel').find('.repl').remove();
$.each(res, function(i,v){
rcode +='<div class="panel-body repl"> ';
rcode +='<p class="p1"> ';
rcode +='<span class="wr">'+ v.name +'</span> ';
rcode +='날짜 :<span class="wd">' + v.date + '</span> ';
rcode +='</p> ';
rcode +=' ';
rcode +='<p class="p2"> ';
rcode +='<input idx="'+ v.renum +'" type="button" name="r_modify" class="action" value="댓글수정"> ';
rcode +='<input idx="'+ v.renum +'" type="button" name="r_delete" class="action" value="댓글삭제"> ';
rcode +='</p> ';
rcode +='<p class="p3">';
rcode += v.cont;
rcode +='</p> ';
rcode += '</div>';
});// $.each
$(brep).parents('.panel').find('.pbody').append(rcode); //find - 밑으로 내려가면서 찾는 것(후손)
},
error : function(xhr){
alert("상태 : " + xhr.status);
},
dataType : 'json'
});
/**/
}
function replyInsert(brep){ // brep - 클릭한 button객체
$.ajax({
url : '/board/ReplyInsert.do',
type : 'post',
data : reply,
success : function(res){
//저장 성공 - res.sw
//댓글 리스트 출력
replyList(brep);
},
error : function(xhr){
alert("상태 : " + xhr.status);
},
dataType : 'json'
});
}
function listPage(cpage){
$.ajax({
url:"/board/List.do",
data: { "page" : cpage},
type: 'get',
success: function(res){
code = '<div class="panel-group" id="accordion">';
$.each(res.datas ,function(i,v){
code +='<div class="panel panel-default">';
code +='<div class="panel-heading">';
code +='<h4 class="panel-title"> ';
code +='<a idx="' + v.num + '" name="list" class="action" data-toggle="collapse" data-parent="#accordion" href="#collapse'+ v.num +'">'+ v.subject +'</a> '; //제목
code +='</h4> ';
code +='</div> ';
code +='<div id="collapse'+ v.num +'" class="panel-collapse collapse"> ';
code +='<div class="panel-body pbody"> ';
code +='<p class="p1"> ';
code +='작성자 :<span class="wr">'+ v.writer +'</span> ';
code +='이메일 :<span class="em">'+ v.mail +'</span> ';
code +='조회수 :<span class="hit">'+ v.hit +'</span> ';
code +='날짜 :<span class="wd">' + v.wdate + '</span> ';
code +='</p> ';
code +=' ';
code +='<p class="p2"> ';
code +='<input idx="'+ v.num +'" type="button" name="modify" class="action" value="수정"> ';
code +='<input idx="'+ v.num +'" type="button" name="delete" class="action" value="삭제"> ';
code +='</p> ';
code +='<p class="p3"> ';
code +='내용출력 내용출력<br> ';
code += v.content;
code +='</p> ';
code +='<p class="p4"> ';
code +=' <textarea rows="" cols="100"></textarea> ';
code +=' <input idx="'+ v.num +'" type="button" value="등록" name="reply" class="action"> ';
code +=' ';
code +=' </p> ';
code +=' </div> ';
code +=' </div> ';
code +='</div> ';
});
code += '</div>';
$('#list').html(code);
$('#pagelist').empty();
//이전버튼만들기
if(res.sp > 1){
pager = '<ul class="pager">';
pager += '<li><a class="prev" href="#">Previous</a></li>';
pager += '</ul>';
$('#pagelist').append(pager);
}
/*<ul class="pager">
<li><a href="#">Previous</a></li>
<li><a href="#">Next</a></li>
</ul>
*/
//페이지번호 만들기
pager = '<ul class="pagination pager">';
for(i=res.sp; i <=res.ep; i++){
if(cpage == i){
pager += '<li class="active"><a class="paging" href="#">' + i + '</a></li>';
}else{
pager += '<li><a class="paging" href="#">' + i + '</a></li>';
}
}
pager += '</ul>';
$('#pagelist').append(pager);
//다음버튼 만들기
if(res.ep < res.tp){
pager = '<ul class="pager">';
pager += '<li><a class="next" href="#">Next</a></li>';
pager += '</ul>';
$('#pagelist').append(pager);
}
},
error: function(xhr){
alert("상태 : " + xhr.status);
},
dataType: 'json'
});
} //listPage