GetFavAction
package kr.board.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardFavVO;
import kr.controller.Action;
public class GetFavAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.getParameter("utf-8");
int board_num = Integer.parseInt(request.getParameter("board_num"));
Map<String,Object> mapAjax = new HashMap<String,Object>();
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
BoardDAO dao = BoardDAO.getInstance();
if(user_num==null) { //로그인이 되지 않은 경우
mapAjax.put("status","noFav"); //noFav는 클릭을 하지 않은 것
}else {//로그인이 된 경우
BoardFavVO boardFav = dao.selectFav(new BoardFavVO(board_num,user_num));
if(boardFav !=null) {
//로그인한 회원이 좋아요를 클릭
mapAjax.put("status", "yesFav");
}else {
//로그인한 회원이 좋아요를 미클릭
mapAjax.put("status", "noFav");
}
}
//좋아요 개수
mapAjax.put("count", dao.selectFavCount(board_num));
//JSON 데이터 생성
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData",ajaxData);
return "/Web-INF/views/common/ajax_view.jsp";
}
}
detail.jsp 추가 명시
Js파일 추가
<script type="text/javascript" src="${pageContext.request.contextPath}/js/board.fav.js"></script>
이미지 추가
<%-- 좋아요 --%>
<img id ="output_fav" data-num="${board.board_num}"
src="${pageContext.request.contextPath}/images/fav01.gif" width="50">
좋아요
<span id="output_fcount"></span>
위에 파일 만들고 내용명시 ( board.fav.js")
$(function(){
/*=========================
* 좋아요 선택 여부와 선택한 총 개수 읽기
*==========================*/
function selectFav(){
//서버와 통신
$.ajax({
url:'getFav.do',
type:'post',
data:{board_num:$('#output_fav').attr('data-num')},
dataType:'json',
success:function(param){
displayFav(param);
},
error:function(){
alert('네트워크 오류 발생');
}
});
}
/*=========================
* 좋아요 표시 함수
*==========================*/
function displayFav(param){
let output;
if(param.status == 'yesFav'){//좋아요 선택
output = '../images/fav02/gif';
}else{//좋아요 미선택
output = '../images/fav01.gif';
}
//문서 객체에 설정
$('#output_fav').attr('src',output);
$('#output_fcount').text(param.count);
}
/*=========================
* 초기 데이터 호출
*==========================*/
selectFav();
});
BoardDAO 추가 명시(좋아요 등록) => 좋아요 갯수 위에 명시
(좋아요 삭제) => 좋아요 갯수 아래에 명시
//좋아요 등록
public void insertFav(BoardFavVO favVO) throws Exception{
Connection conn =null;
PreparedStatement pstmt = null;
String sql =null;
try {
//커넥션 풀로부터 커넥션 할당
conn=DBUtil.getConnection();
sql="INSERT INTO zboard_fav (board_num,mem_num) VALUES (?,?)";
//preparedStatement 객체 생성
pstmt=conn.prepareStatement(sql);
//?에 데이터 바인딩
pstmt.setInt(1, favVO.getBoard_num());
pstmt.setInt(2, favVO.getMem_num());
//SQL문 실행
pstmt.executeUpdate();
}catch(Exception e) {
//예외 발생
conn.rollback();
throw new Exception(e);
}finally {
DBUtil.executeClose(null, pstmt, conn);
}
}
//좋아요 개수
public int selectFavCount(int board_num)throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql =null;
int count = 0;
try {
conn = DBUtil.getConnection();
sql = "SELECT COUNT(*) FROM zboard_fav WHERE board_num=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, board_num);
rs = pstmt.executeQuery();
if(rs.next()) {
count = rs.getInt(1);
}
}catch(Exception e) {
throw new Exception(e);
}finally {
DBUtil.executeClose(rs, pstmt, conn);
}
return count;
}
//회원번호와 게시물 번호를 이용한 좋아요 정보
//(회원이 게시물을 호출했을 때 좋아요 선택 여부 표시)
public BoardFavVO selectFav(BoardFavVO favVO)throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
BoardFavVO fav = null;
String sql = null;
try {
conn = DBUtil.getConnection();
sql = "SELECT * FROM zboard_fav WHERE board_num=? AND mem_num=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, favVO.getBoard_num());
pstmt.setInt(2, favVO.getMem_num());
rs = pstmt.executeQuery();
if(rs.next()) {
fav = new BoardFavVO();
fav.setBoard_num(rs.getInt("board_num"));
fav.setMem_num(rs.getInt("mem_num"));
}
}catch(Exception e) {
throw new Exception(e);
}finally{
DBUtil.executeClose(rs, pstmt, conn);
}
return fav;
}
//좋아요 삭제
public void deleteFav(BoardFavVO favVO) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql =null;
try {
conn = DBUtil.getConnection();
sql="DELETE FROM zboard_fav WHERE board_num=? AND mem_num=?";
//preparedStatement 객체 생성
pstmt=conn.prepareStatement(sql);
//?에 데이터 바인딩
pstmt.setInt(1, favVO.getBoard_num());
pstmt.setInt(2, favVO.getMem_num());
//SQL문 실행
pstmt.executeUpdate();
}catch(Exception e) {
throw new Exception(e);
}finally{
DBUtil.executeClose(null, pstmt, conn);
}
}
WriteFavAction
package kr.board.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardFavVO;
import kr.controller.Action;
public class WriteFavAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String,Object> mapAjax =
new HashMap<String,Object>();
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num==null) {//로그인이 되지 않은 경우
mapAjax.put("result", "logout");
}else {//로그인 된 경우
//전송된 데이터 인코딩 타입 지정
request.setCharacterEncoding("utf-8");
//전송된 데이터 반환
int board_num = Integer.parseInt(request.getParameter("board_num"));
BoardFavVO favVO = new BoardFavVO();
favVO.setBoard_num(board_num);
favVO.setMem_num(user_num);
BoardDAO dao = BoardDAO.getInstance();
//좋아요 등록 여부 체크
BoardFavVO db_fav = dao.selectFav(favVO);
if(db_fav!=null) {//좋아요 등록 O
//좋아요 삭제
dao.deleteFav(db_fav);
mapAjax.put("status", "noFav");
}else {//좋아요 등록 X
//좋아요 등록
dao.insertFav(favVO);
mapAjax.put("status", "yesFav");
}
mapAjax.put("result", "success");
mapAjax.put("count", dao.selectFavCount(board_num));
}
//JSON 데이터 생성
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData", ajaxData);
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
board.fav.js 내용추가
좋아요 등록 (및 삭제) 이벤트 연결
/*=========================
* 좋아요 등록 (및 삭제) 이벤트 연결
*==========================*/
$('#output_fav').onclick(function(){
//서버와 통신
$.ajax({
url:'writeFav.do',
type:'post',
data:{board_num:$(this).attr('data-num')},
dataType:'json',
success:function(param){
if(param.result == 'logout'){
alert('로그인 후 좋아요를 눌러주세요');
}else if(param.result == 'success'){
displayFav(param);
}else{
alert('좋아요 등록/삭제 오류 발생');
}
},
error:function(){
alert('네트워크 오류 발생');
}
});
});
BoardDAO 추가 명시 ( 내가 선택한 좋아요 목록) => 좋아요 삭제 밑
이걸 이제 DAO에 명시하기.
//내가 선택한 좋아요 목록
public List<BoardVO> getListBoardFav(int start, int end , int mem_num) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<BoardVO> list = null;
String sql =null;
try {
//커넥션풀로부터 커넥션 할당
conn = DBUtil.getConnection();
//SQL문 작성
//(주의) zboard_fav의 회원번호(좋아요 클릭한 회원번호)로 검색되어야 하기 때문에 f.mem_num으로 표기해야 함
sql="SELECT * FROM (SELECT a.*, rownum rnum FROM "
+ "(SELECT * FROM zboard b JOIN "
+ "zmember m USING(mem_num) JOIN zboard_fav f "
+ "USING(board_num) WHERE f.mem_num=? ORDER BY "
+ "board_num DESC)a) WHERE rnum >=? AND rnum <=?";
//PreparedStatement 객체 생성
pstmt = conn.prepareStatement(sql);
//?에 데이터 바인딩
pstmt.setInt(1,mem_num);
pstmt.setInt(2, start);
pstmt.setInt(3, end);
//SQL문 실행
rs=pstmt.executeQuery();
list = new ArrayList<BoardVO>();
while(rs.next()) {
BoardVO board = new BoardVO();
board.setBoard_num(rs.getInt("board_num"));
board.setTitle(StringUtil.useBrNoHTML(rs.getString("title")));
board.setReg_date(rs.getDate("reg_date"));
board.setId(rs.getString("id")); //조인을 했기 떄문에 id를 가져오기가 가능하다.
list.add(board);
}
}catch(Exception e) {
throw new Exception(e);
}finally{
DBUtil.executeClose(rs, pstmt, conn);
}
return list;
}
kr.member.action => MypageAction에 있는 파일 수정
package kr.member.action;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
import kr.member.dao.MemberDAO;
import kr.member.vo.MemberVO;
public class MyPageAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num == null) {//로그인이 되지 않은 경우
return "redirect:/member/loginForm.do";
}
//로그인이 된 경우
//회원정보
MemberDAO dao = MemberDAO.getInstance();
MemberVO member = dao.getMember(user_num);
//관심 게시물 정보
BoardDAO boardDAO = BoardDAO.getInstance();
List<BoardVO> boardList = boardDAO.getListBoardFav(1, 5, user_num);
request.setAttribute("member", member);
request.setAttribute("boardList", boardList);
//JSP 경로 반환
return "/WEB-INF/views/member/myPage.jsp";
}
}
추가내용
//관심 게시물 정보
BoardDAO boardDAO = BoardDAO.getInstance();
List<BoardVO> boardList = boardDAO.getListBoardFav(1, 5, user_num);
추가한 내용을 저장하기
request.setAttribute("boardList", boardList);
member/myPage.jsp 수정
관심게시물 목록 h3 태그부터 수정 시작 (141라인)
<h3>관심 게시물 목록</h3>
<table>
<tr>
<th>제목</th>
<th>작성자</th>
<th>등록일</th>
</tr>
<c:forEach var="board" items="${boardList}">
<tr>
<td><a href="${pageContext.request.contextPath}/board/detail.do?board_num=${board.board_num}" target="_blank">${fn:substring(board.title,0,12)}</a></td>
<td>${board.id}</td>
<td>${board.reg_date}</td>
</tr>
</c:forEach>
</table>
상단에 추가 명시
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
table.sql 추가 명시
--댓글
create table zboard_reply(
re_num number not null,
re_content varchar2(900) not null,
re_date date default sysdate not null,
re_modifydate date,
re_ip varchar2(40) not null,
board_num number not null,
mem_num number not null,
constraint zreply_pk primary key (re_num),
constraint zreply_fk1 foreign key (board_num) references zboard (board_num),
constraint zreply_fk2 foreign key (mem_num) references zmember (mem_num)
);
create sequence zreply_seq;
kr.board.vo=>BoardReplyVO
package kr.board.vo;
public class BoardReplyVO {
private int re_num; //댓글번호
private String re_content; //내용
private String re_date; //등록일 (1초전 1분전 이러한 방식으로 사용하고자 String 으로 사용)
private String re_modifydate; //수정일
private String re_ip; //아이피주소
private int board_num; //부모글번호
private int mem_num; //작성자 회원번호
private String id; //작성자 id (조인해서 가져오려고 만듬)
public int getRe_num() {
return re_num;
}
public void setRe_num(int re_num) {
this.re_num = re_num;
}
public String getRe_content() {
return re_content;
}
public void setRe_content(String re_content) {
this.re_content = re_content;
}
public String getRe_date() {
return re_date;
}
public void setRe_date(String re_date) {
this.re_date = re_date;
}
public String getRe_modifydate() {
return re_modifydate;
}
public void setRe_modifydate(String re_modifydate) {
this.re_modifydate = re_modifydate;
}
public String getRe_ip() {
return re_ip;
}
public void setRe_ip(String re_ip) {
this.re_ip = re_ip;
}
public int getBoard_num() {
return board_num;
}
public void setBoard_num(int board_num) {
this.board_num = board_num;
}
public int getMem_num() {
return mem_num;
}
public void setMem_num(int mem_num) {
this.mem_num = mem_num;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
views/board/detail.jsp (UI추가) => 맨아래에 명시 73라인 다음
<!-- 댓글 시작 -->
<div id = "reply_div">
<span class="re-title">댓글 달기</span>
<form id="re_form">
<input type="hidden" name="board_num" value="${board.board_num}" id="board_num">
<!-- disabled는 댓글을 달지 못하도록 비활설화 시키는 역할 -->
<textarea rows="3" cols="50" name="re_content"
<c:if test="${empty user_num}">disabled="disabled"</c:if>
id="re_content" class="rep-content"><c:if test="${empty user_num}">로그인해야 작성할 수 있습니다</c:if>
</textarea>
<c:if test="${!empty user_num}">
<div id="re_first">
<span class="letter-count">300/300</span><!-- 글자수 제한 -->
</div>
<div id="re_second" class="align-right">
<input type="submit" value="전송">
</div>
</c:if>
</form>
</div>
<!-- 댓글 목록 출력 시작 -->
<div id="output"></div>
<div class="paging-button" style="display:none;">
<input type="button" value="다음글 보기">
</div>
<div id="loading" style="display:none">
<img src="${pageContext.request.contextPath}/images/loading.gif" width="50" height="50">
</div>
<!-- 댓글 목록 출력 끝 -->
</div>
<!-- 댓글 끝 -->
style.css 추가
/* 게시판 글상세
---------------------*/
ul.detail-info li{
display:inline-block;
}
.detail-img{
max-width:500px;
}
ul.detail-sub{
margin:0;
padding:0;
}
ul.detail-sub li{
display:inline-block;
width:49%;
height:50px;
vertical-align:middle;
}
ul.detail-sub li:first-child img{
vertical-align:middle;
}
ul.detail-sub li:last-child{
text-align:right;
line-height:250%;
}
#output_fav{
cursor:pointer;
}
div#reply_div{
padding:5px 10px 40px 10px;
margin-top:10px;
background-color:#EEEEEE;
}
form #re_form{
width:650px;
border:none;
}
span.re-title{
color:#000;
font-size:12pt;
line-height:200%;
}
span.letter-count{
font-size:10pt;
color:#999;
}
textarea.rep-content{
width:90%;
height:50px;
margin:10px;
}
div#re_first, div#mre_first{
float:left;
width:70%;
padding-left:15px;
margin-bottom:10px;
}
div#re_second, div#mre_second{
float:left;
width:19%;
margin-bottom:10px;
}
div#loading{
text-align:center;
}
div.paging-button{
text-align:right;
}
div#output{
clear:both;
}
form#mre_form{
border:none;
margin:5px;
}
BoardDAO 추가 명시(64일차 시작)
//댓글 등록
public void insertReplyBoard(BoardReplyVO boardReply) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql =null;
try {
//커넥션풀로부터 커넥션 할당
conn = DBUtil.getConnection();
sql = "INSERT INTO zboard_reply (re_num,re_content,"
+ "re_ip,mem_num,board_num) VALUES (zreply_seq.nextval,?,?,?,?)";
pstmt =conn.prepareStatement(sql);
pstmt.setString(1,boardReply.getRe_content());
pstmt.setString(2,boardReply.getRe_ip());
pstmt.setInt(3,boardReply.getMem_num());
pstmt.setInt(4,boardReply.getBoard_num());
pstmt.executeUpdate();
}catch(Exception e) {
throw new Exception(e);
}finally {
DBUtil.executeClose(null, pstmt, conn);
}
}
WriteReplyAction
package kr.board.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardReplyVO;
import kr.controller.Action;
public class WriteReplyAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
//Map은 SON 응답으로 보낼 데이터를 포함한다. 그러므로 아래에 ObjectMapper 를 사용해야됨
Map<String,String> mapAjax =
new HashMap<String,String>();
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num == null) { //로그인이 안된경우
mapAjax.put("result", "logout");
}else {
//전송된 데이터 인코딩 타입 지정
request.setCharacterEncoding("utf-8");
//자바빈을(VO)를 생성해서 전송된 데이터 저장
BoardReplyVO reply = new BoardReplyVO();
reply.setMem_num(user_num);//댓글 작성자 회원번호
reply.setRe_content(request.getParameter("re_content"));
reply.setRe_ip(request.getRemoteAddr());
reply.setBoard_num(Integer.parseInt(request.getParameter("board_num"))); //댓글의 부모 글번호
//위에 받은 4개의 데이터를 전달
BoardDAO dao = BoardDAO.getInstance();
dao.insertReplyBoard(reply);
//전달이 성공했다는 것을 result에 저장해서 Ajax로 보낸다.
mapAjax.put("result", "success");
}
//JSON 데이터로 변환
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax); //문자열이 만들어짐
//만든 문자열을 저장
request.setAttribute("ajaxData", ajaxData);
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
views/board/detail.jsp 수정
<script type="text/javascript" src="${pageContext.request.contextPath}/js/board.reply.js"></script>
스크립트 추가 후 파일 생성
js/board.reply.js
$(function(){
let rowCount = 10;
let currentPage;
let count;
/*====================================
*댓글 목록
* ====================================*/
function selectList(pageNum){
}
/*====================================
*댓글 등록
* ====================================*/
//댓글 등록
$('#re_form').submit(function(event){
if($('#re_content').val().trim()==''){
alert('내용을 입력하세요');
$('#re_content').val('').focus();
return false;
}
//form 이하의 태그에 입혁한 데이터를 모두 읽어서 쿼리 스트링으로 반환
let form_data = $(this).serialize(); //serialize: jQuery 메서드로 폼 데이터를 URL 인코딩된 문자열로 직렬화
//서버와 통신
$.ajax({
url:'writeReply.do',
type:'post',
data:form_data,
dataType:'json',
success:function(param){
if(param.result == 'logout'){
alert('로그인을 해야 작성할 수 있습니다.');
}else if(param.result == 'success'){
//로그인 성공시 폼 초기화를 해야됨.
initForm(); //아래에 만들어둔 initForm을 호출 (초기화 하는 역할)
//댓글 작성이 성공하면 새로 삽입한 글을 포함해서 첫번째 페이지에 게시글 목록을 다시 호출함.
selectList(1);
}else{
alert('댓글 등록 오류');
}
},
error:function(){
alert('네트워크 오류 발생');
}
});
//기본 이벤트 제거
event.preventDefault();
});
//댓글 작성 폼 초기화
function initForm(){
$('textarea').val('');
$('#re_first .letter-count').text('300/300'); //#re_first .letter-count 사이에 공백이 있는 경우는 후손선택자로 들어가기 때문에
}
/*====================================
*댓글 수정
* ====================================*/
/*====================================
*댓글 등록 및 수정 공통
* ====================================*/
//textarea에 내용 입력시 글자 수 체크
$(document).on('keyup','textarea',function(){
//입력한 글자수 구함
let inputLength = $(this).val().length;
if(inputLength > 300){ //300자를 넘어선 경우
$(this).val($(this).val().substring(0,300)); //substring: JavaScript 문자열 메서드로, 문자열의 일부를 추출. 두 인덱스를 사용하여 시작 위치와 끝 위치를 지정
}else{//300자 이하인 경우
let remain = 300 - inputLength;
remain +='/300';
if($(this).attr('id') == 're_content'){
//등록폼 글자수
$('#re_first .letter-count').text(remain);
}else{
//수정폼 글자수
$('#mre_first .letter-count').text(remain);
}
}
});
/*====================================
*댓글 삭제
* ====================================*/
/*====================================
*초기 데이터(목록) 호출
* ====================================*/
selectList(1); //댓글 목록의 function이름
});
이후 댓글을 입력하면 sqldeveloper에 값이 들어간다. (아직 HTML에는 안올라옴)
BoardDAO 추가 명시
//댓글 개수
public int getReplyBoardCount(int board_num)throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql =null;
ResultSet rs = null;
int count = 0;
try {
//커넥션풀로부터 커넥션 할당
conn = DBUtil.getConnection();
//SQL문 작성
sql="SELECT COUNT(*) FROM zboard_reply WHERE board_num=?";
pstmt =conn.prepareStatement(sql);
pstmt.setInt(1, board_num);
//SQL문 실행
rs = pstmt.executeQuery();
if(rs.next()) {
count = rs.getInt(1); //첫 번째 열의 값을 가져온다.
}
}catch(Exception e) {
throw new Exception(e);
}finally {
DBUtil.executeClose(rs, pstmt, conn);
}
return count;
}
//댓글 목록
public List<BoardReplyVO> getListReplyBoard(int start, int end, int board_num) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql =null;
ResultSet rs = null;
List<BoardReplyVO> list = null;
try {
//커넥션풀로부터 커넥션 할당
conn = DBUtil.getConnection();
//SQL문 작성
sql="SELECT * FROM (SELECT a.* rownum rnum FROM "
+ "(SELECT * FROM zboard_reply JOIN zmember USING(mem_num) "
+ "WHERE board_num=? ORDER BY re_num DESC)a) "
+ "WHERE rnum >=? AND rnum <=?";
//PreparedStatment 객체 생성
pstmt = conn.prepareStatement(sql);
//?에 데이터 바인딩
pstmt.setInt(1, board_num);
pstmt.setInt(2, start);
pstmt.setInt(3, end);
//SQL문 실행
rs = pstmt.executeQuery();
list = new ArrayList<BoardReplyVO>();
while(rs.next()) {
BoardReplyVO reply = new BoardReplyVO();
reply.setRe_num(rs.getInt("re_num"));
reply.setRe_date(rs.getString("re_date"));
reply.setRe_modifydate(rs.getString("re_modifydate"));
reply.setRe_content(StringUtil.useBrNoHTML(rs.getString("re_content")));
reply.setBoard_num(rs.getInt("board_num"));
reply.setMem_num(rs.getInt("mem_num"));//작성자 회원번호
reply.setId(rs.getString("id"));//작성자 아이디 (조인했기 때문에 가져올 수 있음)
list.add(reply);
}
}catch(Exception e) {
throw new Exception(e);
}finally {
DBUtil.executeClose(rs, pstmt, conn);
}
return list;
}
ListReplyAction
package kr.board.action;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardReplyVO;
import kr.controller.Action;
import kr.util.PagingUtil;
public class ListReplyAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
//전송된 데이터 인코딩 타입 지정
request.setCharacterEncoding("utf-8"); //숫자만 날라오긴 하지만 명시하는게 좋음
String pageNum = request.getParameter("pageNum");
if(pageNum == null) {
pageNum = "1";
}
String rowCount = request.getParameter("rowCount");
if(rowCount == null) {
rowCount = "10";
}
int board_num = Integer.parseInt(request.getParameter("board_num"));
BoardDAO dao = BoardDAO.getInstance();
int count = dao.getReplyBoardCount(board_num);
/*
* ajax 방식으로 목록을 표시하기 때문에 PagingUtil은 페이지수 표시가
* 목적이 아니라 목록 데이터의 페이지 처리를 위해 rownum 번호를 구하는 것이 목적
*/
PagingUtil page = new PagingUtil(Integer.parseInt(pageNum),count,Integer.parseInt(rowCount));
List<BoardReplyVO> list = null;
if(count > 0) {
list = dao.getListReplyBoard(page.getStartRow(),page.getEndRow(), board_num);
}else {
list = Collections.emptyList(); //비어있는 리스트를 만들어서 반환 (Collections가 기존에 있는 잭슨어쩌구 라고한다)
}
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
Map<String,Object> mapAjax = new HashMap<String,Object>();
mapAjax.put("count", count);
mapAjax.put("list", list);
//로그인한 사람이 작성자인지 체크하기 위해서 로그인한 회원번호 전송
mapAjax.put("user_num", user_num);
//JSON 문자열로 반환
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData", ajaxData);
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
PagingUtil.java(다시명시)
rownum번호를 알아내기 위함인데 코드가 부족해서 다시 업로드(44번라인)
package kr.util;
public class PagingUtil {
private int startRow; // 한 페이지에서 보여줄 게시글의 시작 번호
private int endRow; // 한 페이지에서 보여줄 게시글의 끝 번호
private StringBuffer page;// 페이지 표시 문자열
/**
* currentPage : 현재페이지
* count : 전체 게시물 수
* rowCount : 한 페이지의 게시물의 수
* pageCount : 한 화면에 보여줄 페이지 수
* pageUrl : 호출 페이지 url
* addKey : 부가적인 key 없을 때는 null 처리 (&num=23형식으로 전달할 것)
* */
public PagingUtil(int currentPage,int count, int rowCount) {
//ajax 작업을 할 때 페이지 번호가 보여지는 것이 아니라 다음글 보기 버튼을 누르면 다음 페이지가 보여지는 형식의 작업을
//할 때 목록 데이터를 호출하기 위해 사용(startRow,endRow 를 구하기 위한 용도로만 사용)
this(null,null,currentPage,count,rowCount,0,null,null);
}
public PagingUtil(int currentPage, int count, int rowCount,
int pageCount, String pageUrl) {
this(null,null,currentPage,count,rowCount,pageCount,pageUrl,null);
}
public PagingUtil(int currentPage, int count, int rowCount,
int pageCount, String pageUrl, String addKey) {
this(null,null,currentPage,count,rowCount,pageCount,pageUrl,addKey);
}
public PagingUtil(String keyfield, String keyword, int currentPage, int count, int rowCount,
int pageCount,String pageUrl) {
this(keyfield,keyword,currentPage,count,rowCount,pageCount,pageUrl,null);
}
public PagingUtil(String keyfield, String keyword, int currentPage, int count, int rowCount,
int pageCount,String pageUrl,String addKey) {
if(count >= 0) {
String sub_url = "";
if(keyword != null) sub_url = "&keyfield="+keyfield+"&keyword="+keyword;
if(addKey != null) sub_url += addKey;
// 전체 페이지 수
int totalPage = (int) Math.ceil((double) count / rowCount);
if (totalPage == 0) {
totalPage = 1;
}
// 현재 페이지가 전체 페이지 수보다 크면 전체 페이지 수로 설정
if (currentPage > totalPage) {
currentPage = totalPage;
}
// 현재 페이지의 처음과 마지막 글의 번호 가져오기.
startRow = (currentPage - 1) * rowCount + 1;
endRow = currentPage * rowCount;
// 이전 block 페이지
page = new StringBuffer();
if(pageCount > 0) {
// 시작 페이지와 마지막 페이지 값 구하기.
int startPage = (int) ((currentPage - 1) / pageCount) * pageCount + 1;
int endPage = startPage + pageCount - 1;
// 마지막 페이지가 전체 페이지 수보다 크면 전체 페이지 수로 설정
if (endPage > totalPage) {
endPage = totalPage;
}
if (currentPage > pageCount) {
page.append("<a href="+pageUrl+"?pageNum="+ (startPage - 1) + sub_url +">");
page.append("[이전]");
page.append("</a>");
}
//페이지 번호.현재 페이지는 빨간색으로 강조하고 링크를 제거.
for (int i = startPage; i <= endPage; i++) {
if (i > totalPage) {
break;
}
if (i == currentPage) {
page.append(" <b><span style='color:red;'>");
page.append(i);
page.append("</span></b>");
} else {
page.append(" <a href='"+pageUrl+"?pageNum=");
page.append(i);
page.append(sub_url+"'>");
page.append(i);
page.append("</a>");
}
page.append(" ");
}
// 다음 block 페이지
if (totalPage - startPage >= pageCount) {
page.append("<a href="+pageUrl+"?pageNum="+ (endPage + 1) + sub_url +">");
page.append("[다음]");
page.append("</a>");
}
}else {
page.append("<b>[warning]</b>pageCount는 1이상 지정해야 페이지수가 표시됩니다.");
}
}
}
public StringBuffer getPage() {
return page;
}
public int getStartRow() {
return startRow;
}
public int getEndRow() {
return endRow;
}
}
js/board.reply.js(추가)
$(function(){
let rowCount = 10;
let currentPage;
let count;
/*====================================
*댓글 목록
* ====================================*/
//댓글 목록
function selectList(pageNum){
currentPage = pageNum;
//로딩 이미지 노출
$('#loading').show();
//서버와 통신
$.ajax({
url:'listReply.do',
type:'post',
// 식별자 :숫자로바뀐변수
data:{pageNum:pageNum,rowCount:rowCount,board_num:$('#board_num').val()},
dataType:'json',
success:function(param){
//로딩 이미지 감추기
$('#loading').hide(); // jQuery를 사용하여 HTML 요소를 숨기는 역할
count = param.count;
if(pageNum==1){
//처음 호출시는 해당 ID의 div의 내부 내용물을 제거
$('#output').empty();
}
$(param.list).each(function(index,item){ //item은 댓글의 하나의 레코드라고 보면된다.
let output = '<div class="item">';
output +='<h4>' + item.id + '</h4>';
output += '<div class="sub-item">';
output += '<p>' + item.re_content + '</p>';
if(item.re_modifydate){
output += '<span class="modify-date">최근 수정일 : ' + item.re_modifydate + '</span>';
}else{
output += '<span class="modify-date">최근 등록일 : ' + item.re_date + '</span>';
}
//로그인한 회원번호와 작성자의 회원번호 일치 여부 체크
if(param.user_num == item.mem_num){
output +=' <input type="button" data-renum="'+ item.re_num +'" value="수정" class="modify-btn">';
output +=' <input type="button" data-renum="'+ item.re_num +'" value="삭제" class="delete-btn">';
}
output +='<hr size="1" noshade width="100%">'
output += '</div>';
output += '</div>';
//문서 객체에 추가
$('#output').append(output);
});
//page button 처리
//currentPage: 현재 페이지를 나타내는 변수
//count: 전체 댓글의 개수
//rowCount: 한 페이지에 보여질 댓글의 개수
if(currentPage>=Math.ceil(count/rowCount)){ //Math.ceil() 함수는 주어진 숫자를 올림하여 반환
//다음페이지가 없음
$('.paging-button').hide();
}else{
//다음페이지가 존재
$('.paging-button').show();
}
},
error:function(){
$('#loading').hide();
alert('네트워크 오류 발생');
}
});
}
/*====================================
*댓글 등록
* ====================================*/
//댓글 등록
$('#re_form').submit(function(event){
if($('#re_content').val().trim()==''){
alert('내용을 입력하세요');
$('#re_content').val('').focus();
return false;
}
//form 이하의 태그에 입혁한 데이터를 모두 읽어서 쿼리 스트링으로 반환
let form_data = $(this).serialize(); //serialize: jQuery 메서드로 폼 데이터를 URL 인코딩된 문자열로 직렬화
//서버와 통신
$.ajax({
url:'writeReply.do',
type:'post',
data:form_data,
dataType:'json',
success:function(param){
if(param.result == 'logout'){
alert('로그인을 해야 작성할 수 있습니다.');
}else if(param.result == 'success'){
//로그인 성공시 폼 초기화를 해야됨.
initForm(); //아래에 만들어둔 initForm을 호출 (초기화 하는 역할)
//댓글 작성이 성공하면 새로 삽입한 글을 포함해서 첫번째 페이지에 게시글 목록을 다시 호출함.
selectList(1);
}else{
alert('댓글 등록 오류');
}
},
error:function(){
alert('네트워크 오류 발생');
}
});
//기본 이벤트 제거
event.preventDefault();
});
//댓글 작성 폼 초기화
function initForm(){
$('textarea').val('');
$('#re_first .letter-count').text('300/300'); //#re_first .letter-count 사이에 공백이 있는 경우는 후손선택자로 들어가기 때문에
}
/*====================================
*댓글 수정
* ====================================*/
/*====================================
*댓글 등록 및 수정 공통
* ====================================*/
//textarea에 내용 입력시 글자 수 체크
$(document).on('keyup','textarea',function(){
//입력한 글자수 구함
let inputLength = $(this).val().length;
if(inputLength > 300){ //300자를 넘어선 경우
$(this).val($(this).val().substring(0,300)); //substring: JavaScript 문자열 메서드로, 문자열의 일부를 추출. 두 인덱스를 사용하여 시작 위치와 끝 위치를 지정
}else{//300자 이하인 경우
let remain = 300 - inputLength;
remain +='/300';
if($(this).attr('id') == 're_content'){
//등록폼 글자수
$('#re_first .letter-count').text(remain);
}else{
//수정폼 글자수
$('#mre_first .letter-count').text(remain);
}
}
});
/*====================================
*댓글 삭제
* ====================================*/
/*====================================
*초기 데이터(목록) 호출
* ====================================*/
selectList(1); //댓글 목록의 function이름
});
detail.jsp에 오타가 있어서 댓글 배경이 회색이 이어져 있던 부분을 수정
js/board.reply.js(추가)
댓글등록 위에 명시
//페이지 처리 이벤트 연결(다음 댓글 보기 버튼 클릭시 데이터 추가)
$('.paging-button input').click(function(){
selectList(currentPage + 1); //다음페이지를 보이게 하는법: 현재페이지에서 1페이지를 증가시킴
});
'쌍용교육(JAVA) > MVC' 카테고리의 다른 글
쌍용교육 -JSP수업 66일차 - ch06_mvcPageMVC(11) (0) | 2024.05.24 |
---|---|
쌍용교육 -JSP수업 65일차 - ch06_mvcPageMVC(10) (0) | 2024.05.23 |
쌍용교육 -JSP수업 62일차 - ch06_mvcPageMVC(8) (0) | 2024.05.20 |
쌍용교육 -JSP수업 60~61일차 - ch06_mvcPageMVC(7) (0) | 2024.05.16 |
쌍용교육 -JSP수업 59일차 - ch06_mvcPageMVC(6) (0) | 2024.05.14 |