게시글 좋아요 기능을 구현하기 위해서는
DB에 boardlike 테이블을 생성(num:좋아요 번호(auo increment), id:좋아요를 누른 사람, bno:게시글 번호)하고 board 테이블에 좋아요 수 속성을 추가하고 board 테이블의 bno와 boardlike의 bno를 외래키관계로 추가 & member 테이블의 id와 boardlike의 id를 외래키관계로 추가해야하며,
이에 따라 boardDto 및 BoardDao 수정, LikeDao를 생성해준다.
Dto의 경우 좋아요 테이블에서 필요한 값은 id와, 게시글번호 뿐이므로(num은 auto_increment 속성이라 필요없음) 별도의 Dto 생성없이 LikeDao에서 매개변수를 직접 입력하여 사용한다.
* boardlike 테이블



* board 테이블

* BoardDto.java
package dto;
import java.text.SimpleDateFormat;
import java.util.Date;
public class BoardDto {
private int num;
private String title;
private String content;
private String id;
private Date postDate;
private int viewCnt;
private String name;
private int commentCnt; //댓글수
private int likeCnt; //좋아요수
public int getLikeCnt() {
return likeCnt;
}
public void setLikeCnt(int likeCnt) {
this.likeCnt = likeCnt;
}
public int getCommentCnt() {
return commentCnt;
}
public void setCommentCnt(int commentCnt) {
this.commentCnt = commentCnt;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getPostDate() {
return postDate;
}
public void setPostDate(Date postDate) {
this.postDate = postDate;
}
public int getViewCnt() {
return viewCnt;
}
public void setViewCnt(int viewCnt) {
this.viewCnt = viewCnt;
}
public BoardDto() {
super();
// TODO Auto-generated constructor stub
}
public BoardDto(String title, String content, String id) {
super();
this.title = title;
this.content = content;
this.id = id;
}
public BoardDto(int num, String title, String content, String id) {
super();
this.num = num;
this.title = title;
this.content = content;
this.id = id;
}
@Override
public String toString() {
return "BoardDto [num=" + num + ", title=" + title + ", content=" + content + ", id=" + id + ", postDate="
+ postDate + ", viewCnt=" + viewCnt + ", name=" + name + ", commentCnt=" + commentCnt + ", likeCnt="
+ likeCnt + ", sdf=" + sdf + "]";
}
}
* BoardDao.java
package dao;
import java.sql.Date;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import javax.servlet.ServletContext;
import dto.BoardDto;
import util.JDBConnect;
public class BoardDao extends JDBConnect{
public BoardDao(ServletContext application) {
super(application);
}
//selectCount - 게시물 개수(int 반환)
public int selectCount(Map<String, String> map) {
//1) 반환값 저장할 변수 선언
int totalCnt = 0;
try {
//2) 쿼리문 작성
String sql = "select count(*) from board ";
if(map.get("searchWord")!=null) {
sql+="where " + map.get("searchField") + " like '%" + map.get("searchWord") + "%' ";
}
//3) stmt 객체 생성
stmt = con.createStatement();
//4) 쿼리문 실행(psmt : 객체 생성시에 sql문을 매개값으로 넣어주고 실행시에 매개값을 주지 않았으나 stmt는 매개값없이 생성 후
// 실행시에 sql문을 매개값으로 넣어줌
rs = stmt.executeQuery(sql);
if(rs.next()) {
totalCnt = rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return totalCnt;
}
public ArrayList<BoardDto> selectList(Map<String, String> map){
//1) 반환값 저장할 변수 선언
ArrayList<BoardDto> blist = new ArrayList<BoardDto>();
try {
String sql = "select * from board ";
if(map.get("searchWord")!=null) {
sql += "where " + map.get("searchField") + " like '%" + map.get("searchWord") + "%' ";
}
sql += "order by num desc ";
sql += "limit "+map.get("offset")+" , "+map.get("pageSize");
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
BoardDto dto = new BoardDto();
dto.setNum(rs.getInt(1));
dto.setTitle(rs.getString(2));
dto.setContent(rs.getString(3));
dto.setId(rs.getString(4));
dto.setPostDate(rs.getTimestamp(5));
dto.setViewCnt(rs.getInt(6));
dto.setCommentCnt(rs.getInt(7));
dto.setLikeCnt(rs.getInt(8));
blist.add(dto);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return blist;
}
public int post(BoardDto b) {
int res = 0;
try {
String sql = "insert into board (title, content, id) values (?, ?, ?)";
psmt = con.prepareStatement(sql);
psmt.setString(1, b.getTitle());
psmt.setString(2, b.getContent());
psmt.setString(3, b.getId());
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
public BoardDto selectNum(int num) {
BoardDto dto = null;
try {
String sql = "select B.*, M.name from board B inner join member M "
+"on B.id = M.id where num = ?";
psmt = con.prepareStatement(sql);
psmt.setInt(1, num);
rs = psmt.executeQuery();
if(rs.next()) {
dto = new BoardDto();
dto.setNum(rs.getInt(1));
dto.setTitle(rs.getString(2));
dto.setContent(rs.getString(3));
dto.setId(rs.getString(4));
dto.setPostDate(rs.getTimestamp(5));
dto.setViewCnt(rs.getInt(6));
dto.setCommentCnt(rs.getInt(7));
dto.setLikeCnt(rs.getInt(8));
dto.setName(rs.getString(9));
};
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}
public int updateViewCnt(int num) {
int res = 0;
try {
String sql = "update board set viewCnt = viewCnt+1 where num=?";
psmt = con.prepareStatement(sql);
psmt.setInt(1, num);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
public int edit(BoardDto b) {
int res = 0;
try {
String sql = "update board set title=?, content=? where num=?";
psmt=con.prepareStatement(sql);
psmt.setString(1, b.getTitle());
psmt.setString(2, b.getContent());
psmt.setInt(3, b.getNum());
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
public int delete(int num, String id) {
int res = 0;
try {
String sql = "delete from board where id=? and num=?";
psmt = con.prepareStatement(sql);
psmt.setString(1, id);
psmt.setInt(2, num);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
//게시물 번호에 해당하는 댓글 수를 1 증가 or 감소
public int updateCommentCnt(String num, int commentCnt) {
int res=0;
try {
String sql = "update board set commentCnt = commentCnt+? where num=?";
psmt=con.prepareStatement(sql);
psmt.setInt(1, commentCnt);
psmt.setString(2, num);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
//게시물 번호에 해당하는 좋아요 수를 1 증가 or 감소
public int updateLikeCnt(String num, int likeCnt) {
int res=0;
try {
String sql = "update board set likeCnt = likeCnt+? where num=?";
psmt=con.prepareStatement(sql);
psmt.setInt(1, likeCnt);
psmt.setString(2, num);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
}
* LikeDao.java
package dao;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import util.JDBConnect;
public class LikeDao extends JDBConnect{
public LikeDao(ServletContext application) {
super(application);
}
//좋아요 누르기
public int insert(String id, String bno) {
int res = 0;
try {
String sql = "insert into boardlike (id, bno) values(?,?)";
psmt=con.prepareStatement(sql);
psmt.setString(1, id);
psmt.setString(2, bno);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
//좋아요 해제
public int delete(String id, String bno) {
int res = 0;
try {
String sql = "delete from boardlike where id=? and bno=?";
psmt=con.prepareStatement(sql);
psmt.setString(1, id);
psmt.setString(2, bno);
res = psmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
//해당 게시물을 사용자(로그인 id)가 좋아요를 눌렀는지 안눌렀는지 확인(게시글 view에 사용)
public int selectLike(String id, String bno) {
int res =0;
try {
String sql = "select count(*) from boardlike where id=? and bno=?";
psmt=con.prepareStatement(sql);
psmt.setString(1, id);
psmt.setString(2, bno);
rs = psmt.executeQuery();
if(rs.next()) {
res = rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
//해당 게시물의 전체 좋아요 수 확인(글 목록에 사용)
public int selectAll(String bno) {
int res =0;
try {
String sql = "select count(*) from boardlike where bno=?";
psmt=con.prepareStatement(sql);
psmt.setString(1, bno);
rs = psmt.executeQuery();
if(rs.next()) {
res = rs.getInt(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
}
* BoardView.jsp
<%@page import="util.JSFunction"%>
<%@page import="dto.BoardDto"%>
<%@page import="dao.BoardDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판</title>
<style>
*{box-sizing: border-box;
margin : 0;
}
form {
width : 700px;
height: 600px;
margin : 0 auto;
}
#container{
border : 1px solid grey;
padding : 10px;
}
button{
margin : 3px;
background-color : white;
border : 1px solid green;
}
h2{text-align : center;
margin : 20px;
}
#viewInfo{
font-size : 12px;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<link rel="stylesheet" href="css/HeaderAndNav.css">
<body>
<%@ include file = "HeaderAndNav.jsp" %>
<h2>상세보기(View)</h2>
<form action="./edit">
<div id="container">
<input type="hidden" name = "num" value="${dto.num }">
<input type="hidden" name = "pageNum" value="${pageNum }">
<div id="like">
<c:choose>
<c:when test="${like ==1}"><button type="button" name = "likeBtn" value="unlike">💚</button>
</c:when>
<c:otherwise><button type="button" name = "likeBtn" value="like">🤍</button>
</c:otherwise>
</c:choose>
</div>
<div><h3>${dto.title }</h3></div>
<div id="viewInfo">
<span>작성자 : ${dto.name } </span>
<span> / 작성일 : ${dto.postDate } </span>
<span> / 조회수 : ${dto.viewCnt } </span>
<span id="cmt"> / 댓글 수 : ${dto.commentCnt }</span>
<span id="likeNum"> / 좋아요 수 : ${dto.likeCnt }</span>
</div>
<br>
<div><h4>내용</h4>${dto.content }</div>
</div>
<c:if test="${dto.id eq sessionScope.id}">
<button>수정</button> <button type="button" onclick="deleteBoard()">삭제</button>
</c:if>
<button type="button" onclick="location.href='list?pageNum=${pageNum }'">목록</button>
</form>
<script>
bno = "${param.bno}";
function deleteBoard(){
let check = confirm("정말로 삭제하시겠습니까?");
if(check){
location.href="delete?num=${dto.num }";
}
}
$(document).ready(function(){
let bno= "${param.num}";
$("#like>button").click(function(){
let mode =$("#like>button").val();
console.log(mode);
let btn = $(this);
$.ajax({
type:'post', // 요청 메서드 (post 방식)
url: './like?', // 요청 URI
/* type:'get', // 요청 메서드 (get 방식)
url: './like?mode='+mode+'&num='+bno, // 요청 URI */
data : { mode:mode , num:bno } ,// 전달 데이터(post 방식에서만 필요)
success : function(result){ // 요청이 성공일 때 실행되는 이벤트
console.log(result.res);
console.log("mode : " + result.mode);
if(result.mode == "unlike"){
btn.val("unlike");
btn.text("💚");
}else{
btn.val("like");
btn.text("🤍");
}
$("#likeNum").text(" / 좋아요 수 : "+result.res)
},
error: function(request, status, error){ alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
}); // $.ajax()
});
})
</script>
<%@include file = "Comment.jsp" %>
</body>
</html>
* LikeController.java
package controller;
import java.io.IOException;
import java.io.PrintWriter;
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.json.simple.JSONObject;
import dao.BoardDao;
import dao.LikeDao;
@WebServlet("/like")
public class LikeController extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num = req.getParameter("num");
String mode = req.getParameter("mode");
LikeDao dao = new LikeDao(getServletContext());
BoardDao bdao = new BoardDao(req.getServletContext());
JSONObject object = new JSONObject();
int res = 0;
resp.setContentType("application/json; charset=UTF-8");
PrintWriter out = resp.getWriter();
if("unlike".equals(mode)) {
res = dao.delete(req.getSession().getAttribute("id")+"", num);
if(res ==1 ) {
res = bdao.updateLikeCnt(num, -1);
object.put("mode", "like");
}
}else {
res = dao.insert(req.getSession().getAttribute("id")+"", num);
if(res ==1 ) {
res = bdao.updateLikeCnt(num, 1);
object.put("mode", "unlike");
}
}
int cnt = dao.selectAll(num);
object.put("res", cnt+"");
dao.close();
out.println(object.toJSONString());
//resp.sendRedirect("view?num="+num);
}
}