★ Board : 게시글을 올리고, 해당 게시글에 댓글을 다는 곳
★ 소스코드 분석 - com.test.toy.board
■ Add.java
package com.test.toy.board;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
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 javax.servlet.http.HttpSession;
import com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.BoardDTO;
@WebServlet("/board/add.do")
public class Add extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Add.java
String mode = req.getParameter("mode");
String thread = req.getParameter("thread");
String depth = req.getParameter("depth");
req.setAttribute("mode", mode);
req.setAttribute("thread", thread);
req.setAttribute("depth", depth);
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/add.jsp");
dispatcher.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//AddOk.java
//1. 데이터 가져오기
//2. DB 작업 > insert
//3. 결과
HttpSession session = req.getSession();
String subject = req.getParameter("subject");
String content = req.getParameter("content");
String mode = req.getParameter("mode");
BoardDTO dto = new BoardDTO();
dto.setSubject(subject);
dto.setContent(content);
dto.setId((String)session.getAttribute("id"));
BoardDAO dao = new BoardDAO();
int thread = -1;
int depth = -1;
//계산
if (mode.equals("new")) {
//새글 쓰기
//1. 현존하는 모든 게시물 중에서 가장 큰 thread값을 찾아서, 그 값에 +1000을 한 값을 새글의 thread값으로 넣는다.
thread = dao.getMaxThread() + 1000;
//2. 새글의 depth는 항상 0 을 넣는다.
depth = 0;
} else {
int parentThread = Integer.parseInt(req.getParameter("thread"));
int parentDepth = Integer.parseInt(req.getParameter("depth"));
//답변글 쓰기
//1. 현존하는 모든 게시물의 thread값을 대상으로, 현재 작성중인 답변글의 부모글 thread 값보다 작고, 이전 새글의 thread값보다 큰 thread를 모두 찾아서 -1을 한다.
int previousThread = (int)Math.floor((parentThread - 1) / 1000) * 1000;
HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("praentThread", parentThread);
map.put("previousThread", previousThread);
dao.updateThread(map);
//2. 답변글의 thread값은 부모글의 thread-0을 넣는다.
thread = parentThread - 1;
//3. 답변글의 depth값을 부모글의 depth+1을 넣는다.
depth = parentDepth + 1;
}
dto.setThread(thread);
dto.setDepth(depth);
int result = dao.add(dto);
if(result == 1) {
resp.sendRedirect("/toy/board/board.do");
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed');history.back();</script>");
writer.close();
}
}
}
- 코드 분석
- 주어진 요청에 따라 게시판에 새로운 글을 추가하거나 답변글을 작성하는 기능을 수행합니다
- doGet() 메서드:
- mode, thread, depth를 요청 매개변수에서 가져옵니다.
- mode, thread, depth를 요청의 속성으로 설정합니다.
- /WEB-INF/views/board/add.jsp로 포워딩하여 JSP 파일을 렌더링합니다.
- doPost() 메서드:
- 세션을 가져옵니다.
- 요청 매개변수에서 subject, content, mode를 가져옵니다.
- BoardDTO 객체를 생성하고, 가져온 데이터를 설정합니다.
- BoardDAO 객체를 생성합니다.
- mode에 따라 새 글 작성 또는 답변글 작성을 수행합니다.
- 새 글 작성 모드:
- 현재 게시판에서 가장 큰 thread 값을 찾고, 그 값에 1000을 더한 값을 새 글의 thread 값으로 설정합니다.
- 새 글의 depth는 0으로 설정합니다.
- 답변글 작성 모드:
- 부모 글의 thread 값보다 작고, 이전 글의 thread 값보다 큰 모든 thread 값을 찾아서 1을 빼줍니다.
- 답변글의 thread 값은 부모 글의 thread 값에서 1을 뺀 값으로 설정합니다.
- 답변글의 depth 값은 부모 글의 depth 값에 1을 더한 값으로 설정합니다.
- 새 글 작성 모드:
- BoardDTO에 설정한 값으로 게시글을 추가합니다.
- 결과에 따라 리다이렉션하거나 실패 메시지를 출력합니다.
■ Auth.java
package com.test.toy.board;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.BoardDTO;
public class Auth {
public static boolean check(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String seq = req.getParameter("seq");
//글쓴이 본인? or 관리자?
BoardDAO dao = new BoardDAO();
BoardDTO dto = dao.get(seq);
if (!session.getAttribute("id").equals(dto.getId())
&& !session.getAttribute("lv").toString().equals("3")) {
PrintWriter writer = resp.getWriter();
writer.write("<script>alert('failed'); location.href='/toy/index.do';</script>");
writer.close();
return true;
}
return false;
}
}
- 코드 분석
게시판의 권한을 확인하는 Auth 클래스입니다. 주어진 요청에 대해 글쓴이 본인 또는 관리자인지 확인하여 권한이 없는 경우 알림을 표시하고 리다이렉션합니다.
- check() 메서드:
- 요청 매개변수에서 seq 값을 가져옵니다.
- 세션을 가져옵니다.
- BoardDAO 객체를 생성합니다.
- seq 값을 사용하여 해당 글의 정보인 BoardDTO를 가져옵니다.
- 세션에 저장된 id와 lv를 사용하여 권한을 확인합니다.
- 세션의 id와 BoardDTO의 id가 다르고, 세션의 lv가 3이 아닌 경우:
- 알림을 표시하고 홈페이지로 리다이렉션합니다.
- PrintWriter를 사용하여 알림을 출력합니다.
- return true를 반환합니다.
- 세션의 id와 BoardDTO의 id가 다르고, 세션의 lv가 3이 아닌 경우:
- return false를 반환하여 권한 확인이 성공적으로 이루어졌음을 나타냅니다.
이 코드는 주어진 요청에 대해 글쓴이 본인 또는 관리자인지 확인하여 권한이 없는 경우 알림을 표시하고 리다이렉션하는 기능을 제공합니다.
■ Board.java
package com.test.toy.board;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import javax.servlet.RequestDispatcher;
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 javax.servlet.http.HttpSession;
import com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.BoardDTO;
@WebServlet("/board/board.do")
public class Board extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
test(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
test(req, resp);
}
private void test(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Board.java
//1. DB 작업 > select
//2. 결과 반환
HttpSession session = req.getSession();
//읽음 제어
session.setAttribute("read", "n");
//board.do == page=1
//board.do?page=1
//board.do?page=2
//?page=5
//?page=5&column=&word= > ""
//?page=5&column=subject&word=자바 > "subject"
String page = req.getParameter("page");
//페이징
int nowPage = 0; //현재 페이지 번호
int totalCount = 0; //총 게시물 수
int pageSize = 10; //한페이지에서 출력할 게시물 수
int totalPage = 0; //총 페이지 수
int begin = 0; //
int end = 0; //
int n = 0; //
int loop = 0; //
int blockSize = 10; //한번에 보여질 페이지 개수
if (page == null || page == "") nowPage = 1;
else nowPage = Integer.parseInt(page);
//nowPage > 현재 보려는 페이지 번호
//board.do?page=1 > where rnum between 1 and 10
//board.do?page=1 > where rnum between 11 and 20
//board.do?page=1 > where rnum between 21 and 30
begin = ((nowPage - 1) * pageSize) + 1;
end = begin + pageSize - 1;
//2가지 용도로 호출
//1. 일반 목록 보기
//2. 검색 결과 보기
//1.
String column = req.getParameter("column");
String word = req.getParameter("word");
String search = "n"; //검색중(O,X)
HashMap<String, String> map = new HashMap<String, String>();
if ((column == null && word == null)
|| (column.endsWith("") && word.equals(""))) {
search = "n";
} else {
search = "y";
}
// System.out.println("search" + search);
map.put("column", column);
map.put("word", word);
map.put("search", search);
map.put("begin", begin + "");
map.put("end", end + "");
BoardDAO dao = new BoardDAO();
List<BoardDTO> list = dao.list(map);
//데이터 조작
for (BoardDTO dto : list) {
//날짜 출력(기준: 당일)
//- 년월일
//- 시분초
// System.out.println(dto.getRegdate());
//dto.setRegdate(dto.getRegdate().substring(0, 10));
String subject = dto.getSubject();
//태그 이스케이프
subject = subject.replace("<", "<")
.replace(">", ">");
//제목에서 검색 중.. 검색어를 강조
if(search.equals("y") && column.equals("subject")) {
//새글입니다.
//<span style="background-color:yellow; color:red;">새글</span>입니다.
subject = subject.replace(word, "<span style=\"background-color:yellow; color:red;\">" + word + "</span>");
}
dto.setSubject(subject);
}
//페이징 작업
//총 게시물
totalCount = dao.getTotalCount(map);
totalPage = (int)Math.ceil((double)totalCount / pageSize);
/*
<a href="/toy/board/board.do?page=1">[이전 10페이지]</a>
<a href="/toy/board/board.do?page=1">1</a>
<a href="/toy/board/board.do?page=2">2</a>
<a href="/toy/board/board.do?page=3">3</a>
<a href="/toy/board/board.do?page=4">4</a>
<a href="/toy/board/board.do?page=5">5</a>
<a href="/toy/board/board.do?page=6">6</a>
<a href="/toy/board/board.do?page=7">7</a>
<a href="/toy/board/board.do?page=8">8</a>
<a href="/toy/board/board.do?page=9">9</a>
<a href="/toy/board/board.do?page=10">10</a>
<a href="/toy/board/board.do?page=1">[다음 10페이지]</a>
*/
StringBuilder sb = new StringBuilder();
// for (int i=1; i<=totalPage; i++) {
// if (i == nowPage) {
// sb.append(String.format(" <a href=\"#!\" style='color:tomato;'>%d</a> ", i));
// } else {
// sb.append(String.format(" <a href=\"/toy/board/board.do?page=%d\">%d</a> ", i, i));
// }
// }
//board.do?page=1
//[] 1 2 3 4 5 6 7 8 9 10 []
//board.do?page=5
//[] 1 2 3 4 5 6 7 8 9 10 []
//board.do?page=10
//[] 1 2 3 4 5 6 7 8 9 10 []
//board.do?page=11
//[] 11 12 13 14 15 16 17 18 19 20 []
loop = 1; //루프 변수
n = ((nowPage -1) / blockSize) * blockSize + 1; //페이지 번호
//이전 10페이지
if(n == 1) {
sb.append(String.format("<a href=\"#!\">[이전 %d페이지]</a>",blockSize ));
}else {
sb.append(String.format("<a href=\"/toy/board/board.do?page=%d\">[이전 %d페이지]</a>", n-1 ,blockSize ));
}
while (!(loop > blockSize || n > totalPage)) {
if (n == nowPage) {
sb.append(String.format(" <a href=\"#!\" style='color:tomato;'>%d</a> ", n));
} else {
sb.append(String.format(" <a href=\"/toy/board/board.do?page=%d\">%d</a> ", n, n));
}
loop++;
n++;
}
//다음 10페이지
if(n > totalPage) {
sb.append(String.format("<a href=\"#!\">[다음 %d페이지]</a>", blockSize));
}else {
sb.append(String.format("<a href=\"/toy/board/board.do?page=%d\">[다음 %d페이지]</a>", n, blockSize));
}
req.setAttribute("list", list);
req.setAttribute("map", map);
req.setAttribute("totalCount", totalCount);
req.setAttribute("totalPage", totalPage);
req.setAttribute("nowPage", nowPage);
req.setAttribute("pagination", sb);
//JSP 페이지 알 수 있는 정보
//1. req를 통해서 전달된 정보
//2. session/cookie
//3. application
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/board.jsp");
dispatcher.forward(req, resp);
}
}
- 코드 분석
게시판 기능을 담당하는 Board 클래스입니다. 클라이언트로부터의 GET 또는 POST 요청에 대해 처리합니다.
- doGet() 메서드와 doPost() 메서드:
- test() 메서드를 호출하여 요청 처리를 수행합니다.
- test() 메서드:
- 세션을 가져옵니다.
- 세션에 read 속성을 설정하여 읽음 제어를 처리합니다.
- 요청 매개변수에서 page 값을 가져옵니다.
- 페이징 관련 변수들을 초기화합니다.
- page 값이 없는 경우 nowPage를 1로 설정하고, 그렇지 않은 경우 정수로 변환하여 nowPage에 저장합니다.
- 현재 페이지에 따라 begin과 end 값을 계산합니다.
- 검색 관련 변수들을 초기화합니다.
- column과 word 매개변수를 확인하여 검색 상태인지 여부를 결정합니다. map에 관련 정보를 저장합니다.
- BoardDAO 객체를 생성합니다.
- list() 메서드를 호출하여 게시물 목록을 가져옵니다.
- 가져온 게시물 목록을 조작하여 데이터를 가공합니다.
- 날짜 출력 형식을 변경합니다.
- 태그 이스케이프를 처리합니다.
- 검색 중인 경우 제목에서 검색어를 강조합니다.
- getTotalCount() 메서드를 호출하여 총 게시물 수를 가져옵니다.
- 페이징 작업을 수행합니다.
- 이전/다음 페이지 링크 및 페이지 번호 링크를 생성합니다.
- 생성한 링크를 StringBuilder에 추가합니다.
- JSP 페이지에 필요한 정보들을 속성으로 설정합니다.
- RequestDispatcher를 사용하여 JSP 페이지로 포워딩합니다.
이 코드는 게시판의 목록 조회, 페이징 처리, 검색 기능을 구현하고, JSP 페이지로 데이터를 전달하여 출력합니다.
■ Comment.java
package com.test.toy.board;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
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 javax.servlet.http.HttpSession;
import com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.CommentDTO;
@WebServlet("/board/comment.do")
public class Comment extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Comment.java
HttpSession session = req.getSession();
String content = req.getParameter("content");
String bseq = req.getParameter("bseq");
String column = req.getParameter("column");
String word = req.getParameter("word");
String search = req.getParameter("search");
BoardDAO dao = new BoardDAO();
CommentDTO cdto = new CommentDTO();
cdto.setContent(content);
cdto.setBseq(bseq);
cdto.setId((String)session.getAttribute("id"));
int result = dao.addContent(cdto);
if (result == 1) {
resp.sendRedirect("/toy/board/view.do?seq=" + bseq + "&column=" + column + "&word=" + URLEncoder.encode(word, "UTF-8") + "&search=" + search);
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed');history.back();</script>");
writer.close();
}
}
}
- 코드 분석
댓글 기능을 처리하는 Comment 클래스입니다. 클라이언트로부터의 POST 요청에 대해 처리합니다.
- doPost() 메서드:
- 세션을 가져옵니다.
- 요청 매개변수에서 content, bseq, column, word, search 값을 가져옵니다.
- BoardDAO 객체를 생성합니다.
- CommentDTO 객체를 생성하고 매개변수로 전달받은 값을 설정합니다.
- addContent() 메서드를 호출하여 댓글을 추가합니다.
- 결과에 따라 처리합니다.
- 성공한 경우: resp.sendRedirect()를 사용하여 해당 게시물의 상세 페이지로 리다이렉트합니다. 게시물 번호와 검색 관련 매개변수를 함께 전달합니다.
- 실패한 경우: PrintWriter를 사용하여 실패 메시지를 출력하고 이전 페이지로 되돌아갑니다.
■ Del.java
package com.test.toy.board;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
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 com.test.toy.board.repository.BoardDAO;
@WebServlet("/board/del.do")
public class Del extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Del.java
//del.do?seq=10
if (Auth.check(req, resp)) {
return;
};
String seq = req.getParameter("seq");
req.setAttribute("seq", seq);
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/del.jsp");
dispatcher.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String seq = req.getParameter("seq");
BoardDAO dao = new BoardDAO();
//삭제될 글에 달린 댓글이 달렸는지 확인 > 있으면 삭제
int result = 0;
result = dao.delComment(seq); //댓글 삭제
result *= dao.del(seq); //글 삭제
if (result >= 1) {
resp.sendRedirect("/toy/board/board.do");
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed');history.back();</script>");
writer.close();
}
}
}
- 코드 분석
게시물 삭제 기능을 처리하는 Del 클래스입니다. 클라이언트로부터의 GET 및 POST 요청에 대해 처리합니다.
- doGet() 메서드:
- Auth.check() 메서드를 호출하여 권한을 확인합니다.
- seq 매개변수를 가져와서 요청 속성으로 설정합니다.
- RequestDispatcher를 사용하여 삭제 페이지(del.jsp)로 포워딩합니다.
- doPost() 메서드:
- seq 매개변수를 가져옵니다.
- BoardDAO 객체를 생성합니다.
- 댓글을 삭제하기 위해 delComment() 메서드를 호출합니다.
- 게시물을 삭제하기 위해 del() 메서드를 호출합니다.
- 결과에 따라 처리합니다.
- 성공한 경우: resp.sendRedirect()를 사용하여 게시판 페이지로 리다이렉트합니다.
- 실패한 경우: PrintWriter를 사용하여 실패 메시지를 출력하고 이전 페이지로 되돌아갑니다.
■ DelComment.java
package com.test.toy.board;
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 com.test.toy.board.repository.BoardDAO;
@WebServlet("/board/delcomment.do")
public class DelComment extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//DelComment.java
String seq = req.getParameter("seq");
String cseq = req.getParameter("cseq");
BoardDAO dao = new BoardDAO();
int result = dao.delComment2(cseq);
if (result == 1) {
resp.sendRedirect("/toy/board/view.do?seq=" + seq);
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed'); history.back();</script>");
writer.close();
}
}
}
- 코드 분석
댓글 삭제 기능을 처리하는 DelComment 클래스입니다. 클라이언트로부터의 GET 요청에 대해 처리합니다.
- doGet() 메서드:
- seq와 cseq 매개변수를 가져옵니다.
- BoardDAO 객체를 생성합니다.
- delComment2() 메서드를 호출하여 댓글을 삭제합니다.
- 결과에 따라 처리합니다.
- 성공한 경우: resp.sendRedirect()를 사용하여 게시물 페이지로 리다이렉트합니다.
- 실패한 경우: PrintWriter를 사용하여 실패 메시지를 출력하고 이전 페이지로 되돌아갑니다.
■ Dummy.java
package com.test.toy.board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.test.my.DBUtil;
public class Dummy {
public static void main(String[] args) throws Exception{
Connection conn = null;
PreparedStatement stat = null;
conn = DBUtil.open();
String sql = "insert into tblBoard values (seqBoard.nextVal, ?, '내용', 'admin', default, default)";
stat = conn.prepareStatement(sql);
for (int i=0; i<250; i++) {
stat.setString(1, "게시판 페이징 처리 테스트중입니다.." + i);
stat.executeUpdate();
System.out.println(i);
}
stat.close();
conn.close();
}
}
- 코드 분석
주어진 SQL 문을 사용하여 데이터베이스에 더미 게시물을 추가합니다. 주로 게시판 페이징 처리 테스트를 위해 사용될 수 있습니다.
- main() 메서드:
- 데이터베이스 연결을 위해 DBUtil.open() 메서드를 호출하여 Connection 객체를 가져옵니다.
- SQL 문을 준비하기 위해 PreparedStatement 객체를 생성합니다.
- 반복문을 사용하여 250개의 더미 게시물을 생성합니다.
- stat.setString()을 사용하여 게시물 제목을 설정합니다.
- stat.executeUpdate()를 호출하여 SQL 문을 실행하여 게시물을 데이터베이스에 추가합니다.
- 반복 횟수를 출력합니다.
- 사용한 자원을 정리합니다. (stat와 conn을 닫습니다.)
■ Edit.java
package com.test.toy.board;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
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 com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.BoardDTO;
@WebServlet("/board/edit.do")
public class Edit extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Edit.java
//1. 데이터 가져오기(글번호)
//2. DB 작업 > select
//3. 결과 > JSP 호출하기
//1.
String seq = req.getParameter("seq");
BoardDAO dao = new BoardDAO();
BoardDTO dto = dao.get(seq);
req.setAttribute("dto", dto);
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/edit.jsp");
dispatcher.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//EditOk.java
//1. 데이터 가져오기(수정할 값)
//2. DB작업 > update
//3. 결과
//권한 체크 -> 링크로 들어오는 것을 막음.
if (Auth.check(req, resp)) {
return;
};
//1.
String seq = req.getParameter("seq");
String subject = req.getParameter("subject");
String content = req.getParameter("content");
//2.
BoardDAO dao = new BoardDAO();
BoardDTO dto = new BoardDTO();
dto.setSeq(seq);
dto.setSubject(subject);
dto.setContent(content);
int result = dao.edit(dto);
if (result == 1) {
resp.sendRedirect("/toy/board/view.do?seq=" + seq);
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed');history.back();</script>");
writer.close();
}
}
}
- 코드 분석
게시물을 수정하는 기능을 제공하는 Edit 클래스입니다.
- doGet() 메서드:
- 클라이언트로부터 요청된 게시물 번호(seq)를 가져옵니다.
- BoardDAO를 사용하여 해당 게시물을 조회합니다.
- 조회된 게시물(BoardDTO)을 요청 속성에 설정합니다.
- RequestDispatcher를 사용하여 수정 페이지(edit.jsp)로 포워딩합니다.
- doPost() 메서드:
- 권한 체크를 위해 Auth.check() 메서드를 호출하여 인증 상태를 확인합니다.
- 요청 파라미터에서 수정할 게시물 번호(seq), 제목(subject), 내용(content)을 가져옵니다.
- BoardDAO를 사용하여 게시물 객체(BoardDTO)를 생성하고 수정할 값들을 설정합니다.
- dao.edit()를 호출하여 게시물을 수정하고, 결과 값을 반환받습니다.
- 수정이 성공적으로 이루어지면 해당 게시물의 상세 페이지로 리다이렉트합니다.
- 수정이 실패하면 실패 메시지를 출력하고 이전 페이지로 돌아갑니다.
■ EditComment.java
package com.test.toy.board;
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 com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.CommentDTO;
@WebServlet("/board/editcomment.do")
public class EditComment extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//EditComment.java
String bseq = req.getParameter("bseq");
String cseq = req.getParameter("cseq");
String content = req.getParameter("content");
BoardDAO dao = new BoardDAO();
CommentDTO cdto = new CommentDTO();
cdto.setSeq(cseq);
//cdto.setBseq(bseq);
cdto.setContent(content);
int result = dao.editComment(cdto);
if (result == 1) {
resp.sendRedirect("/toy/board/view.do?seq=" + bseq);
} else {
PrintWriter writer = resp.getWriter();
writer.print("<script>alert('failed'); history.back();</script>");
writer.close();
}
}
}
- 코드 분석
댓글을 수정하는 기능을 제공하는 EditComment 클래스입니다.
- doPost() 메서드:
- 요청 파라미터에서 수정할 댓글의 게시물 번호(bseq), 댓글 번호(cseq), 내용(content)을 가져옵니다.
- BoardDAO를 사용하여 댓글 객체(CommentDTO)를 생성하고 수정할 값들을 설정합니다.
- dao.editComment()를 호출하여 댓글을 수정하고, 결과 값을 반환받습니다.
- 수정이 성공적으로 이루어지면 해당 게시물의 상세 페이지로 리다이렉트합니다.
- 수정이 실패하면 실패 메시지를 출력하고 이전 페이지로 돌아갑니다.
■ View.java
package com.test.toy.board;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
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 javax.servlet.http.HttpSession;
import com.test.toy.board.repository.BoardDAO;
import com.test.toy.board.repository.BoardDTO;
import com.test.toy.board.repository.CommentDTO;
@WebServlet("/board/view.do")
public class View extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//View.java
//1. 데이터 가져오기(seq)
//2. DB 작업 > select
//3. 결과 > JSP 호출하기
HttpSession session = req.getSession();
//무분별한 조회 막기
//- 무분별 새로 고침 > 조회수 증가X
//- 다른 경로를 통해서 유입
// - list.do > view.do > 조회수 증가O
// - view.do 즐겨찾기 > 조회수 증가O
// - 링크 > 조회수 증가 O
//요철 헤더 > referer
//현재 페이지릴 보기전에 어디서 왔는지? 이전 페이지 주소반환
//String referer = req.getHeader("referer");
//System.out.println(referer);
//1.
String seq = req.getParameter("seq");
String column = req.getParameter("column");
String word = req.getParameter("word");
String search = req.getParameter("search");
//2.
BoardDAO dao = new BoardDAO();
//무분별한 조회수 막기 ( 새로고침 막기 )
if (session.getAttribute("read") == null
|| session.getAttribute("read").toString().equals("n")) {
//조회수 증가
dao.updateReadCount(seq);
session.setAttribute("read", "y");
}
BoardDTO dto = dao.get(seq);
String content = dto.getContent();
//HTML 태그 이스케이프
content = content.replace("<", "<")
.replace(">", ">");
//글 내용 개행 문자 처리
content = content.replace("\r\n", "<br>");
//내용으로 검색중.. 검색어 강조!!
if(search.equals("y") && column.equals("content")) {
//새글입니다.
//<span style="background-color:yellow; color:red;">새글</span>입니다.
content = content.replace(word, "<span style=\"background-color:yellow; color:red;\">" + word + "</span>");
}
dto.setContent(content);
String subject = dto.getSubject();
//태그 이스케이프
subject = subject.replace("<", "<")
.replace(">", ">");
dto.setSubject(subject);
//댓글 목록 가져오기
List<CommentDTO> clist = dao.clist(seq);
//3
req.setAttribute("dto", dto);
req.setAttribute("clist", clist);
req.setAttribute("column", column);
req.setAttribute("word", word);
req.setAttribute("search", search);
RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/view.jsp");
dispatcher.forward(req, resp);
}
}
- 코드 분석
게시물 상세 페이지를 보여주는 View 클래스입니다.
- doGet() 메서드:
- 요청 파라미터에서 게시물 번호(seq), 검색 관련 파라미터(column, word, search)를 가져옵니다.
- 세션을 사용하여 조회수 증가 여부를 체크합니다.
- BoardDAO를 사용하여 게시물 정보(BoardDTO)와 댓글 목록(CommentDTO)을 가져옵니다.
- 게시물의 내용을 HTML 태그 이스케이프 처리하고 개행 문자를 <br> 태그로 변환합니다.
- 만약 검색 관련 파라미터가 있고, 검색 대상이 "content"인 경우 검색어를 강조하여 표시합니다.
- 게시물 제목도 HTML 태그 이스케이프 처리합니다.
- 게시물 정보(dto), 댓글 목록(clist), 검색 관련 파라미터를 설정한 후, view.jsp로 포워딩합니다.
★ 소스코드 분석 - com.test.toy.board.repository
■ BoardDAO
package com.test.toy.board.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.fasterxml.jackson.databind.ser.std.MapProperty;
import com.test.my.DBUtil;
import com.test.toy.board.Comment;
public class BoardDAO {
private Connection conn;
private Statement stat;
private PreparedStatement pstat;
private ResultSet rs;
public BoardDAO() {
this.conn = DBUtil.open();
}
public int add(BoardDTO dto) {
try {
String sql = "insert into tblBoard (seq, subject, content, id, regdate, readcount, thread, depth) values (seqBoard.nextval, ?, ?, ?, default, default, ?, ?)";
pstat = conn.prepareStatement(sql);
pstat.setString(1, dto.getSubject());
pstat.setString(2, dto.getContent());
pstat.setString(3, dto.getId());
pstat.setInt(4, dto.getThread());
pstat.setInt(5, dto.getDepth());
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
//Board 서블릿이 게시판 목록 출력 요청
public List<BoardDTO> list(HashMap<String, String> map) {
List<BoardDTO> list = new ArrayList<BoardDTO>();
try {
String where ="";
if (map.get("search").equals("y")) {
where = String.format("where %s like '%%%s%%'"
, map.get("column")
, map.get("word"));
}
String sql = String.format("select * from (select a.*, rownum as rnum from vwBoard a %s) where rnum between %s and %s "
, where
, map.get("begin")
, map.get("end")
);
stat = conn.createStatement();
rs = stat.executeQuery(sql);
while (rs.next()) {
BoardDTO dto = new BoardDTO();
dto.setSeq(rs.getString("seq"));
dto.setSubject(rs.getString("subject"));
dto.setId(rs.getString("id"));
dto.setRegdate(rs.getString("regdate"));
dto.setReadcount(rs.getString("readcount"));
dto.setName(rs.getString("name"));
dto.setIsnew(rs.getDouble("isnew"));
dto.setCcnt(rs.getString("ccnt"));
dto.setDepth(rs.getInt("depth"));
list.add(dto);
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
//View 서블릿이 번호를 줄테니 레코드 1줄(DTO)를 주세요~
public BoardDTO get(String seq) {
try {
String sql = "select \r\n"
+ " tblBoard.*,\r\n"
+ " (select name from tblUser where id = tblBoard.id) as name\r\n"
+ "from tblBoard\r\n"
+ " where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, seq);
rs = pstat.executeQuery();
if (rs.next()) {
BoardDTO dto = new BoardDTO();
dto.setSeq(rs.getString("seq"));
dto.setSubject(rs.getString("subject"));
dto.setContent(rs.getString("content"));
dto.setId(rs.getString("id"));
dto.setRegdate(rs.getString("regdate"));
dto.setReadcount(rs.getString("readCount"));
dto.setName(rs.getString("name"));
dto.setThread(rs.getInt("thread"));
dto.setDepth(rs.getInt("depth"));
return dto;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//View 서블릿이 글번호를 건내주면, 조회수 +1 증가
public void updateReadCount(String seq) {
try {
String sql = "update tblBoard set readcount = readcount + 1 where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, seq);
pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
//Edit 서블릿이 DTO를 건내주면, 수정
public int edit(BoardDTO dto) {
try {
String sql = "update tblBoard set subject = ?, content = ? where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, dto.getSubject());
pstat.setString(2, dto.getContent());
pstat.setString(3, dto.getSeq());
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public int del(String seq) {
try {
String sql = "delete from tblBoard where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, seq);
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public int addContent(CommentDTO cdto) {
try {
String sql = "insert into tblComment (seq, content, id, regdate, bseq) values (seqComment.nextVal, ?, ?, default, ?)";
pstat = conn.prepareStatement(sql);
pstat.setString(1, cdto.getContent());
pstat.setString(2, cdto.getId());
pstat.setString(3, cdto.getBseq());
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
//View 서블릿이 현재 보고 있는 글의 딸려있는 댓글 목록을 출력.
public List<CommentDTO> clist(String bseq) {
try {
String sql = "select tblComment.*, (select name from tblUser where id = tblComment.id) as name from tblComment where bseq = ? order by seq desc";
pstat = conn.prepareStatement(sql);
pstat.setString(1, bseq);
rs = pstat.executeQuery();
List<CommentDTO> list = new ArrayList<CommentDTO>();
while (rs.next()) {
CommentDTO dto = new CommentDTO();
dto.setSeq(rs.getString("seq"));
dto.setContent(rs.getString("content"));
dto.setId(rs.getString("id"));
dto.setRegdate(rs.getString("regdate"));
dto.setBseq(rs.getString("bseq"));
dto.setName(rs.getString("name"));
list.add(dto);
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//Del 서블릿이 글번호를 줄테니, 글에 달려있는 댓글도 다 삭제해주세요.
public int delComment(String bseq) {
try {
String sql = "delete from tblComment where bseq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, bseq);
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public int editComment(CommentDTO cdto) {
try {
String sql = "update tblComment set content = ? where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, cdto.getContent());
pstat.setString(2, cdto.getSeq());
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public int delComment2(String cseq) {
try {
String sql = "delete from tblComment where seq = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1, cseq);
return pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
//Board 서블릿이 게시물 총개수를 달라고 요청
public int getTotalCount(HashMap<String, String> map) {
try {
String where ="";
if (map.get("search").equals("y")) {
where = String.format("where %s like '%%%s%%'", map.get("column"), map.get("word") );
}
String sql = String.format("select count(*) as cnt from vwBoard %s", where);
pstat = conn.prepareStatement(sql);
rs = pstat.executeQuery();
if (rs.next()) {
return rs.getInt("cnt");
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public int getMaxThread() {
try {
String sql = "select nvl(max(thread), 0) as thread from tblBoard";
stat = conn.createStatement();
rs = stat.executeQuery(sql);
if (rs.next()) {
return rs.getInt("thread");
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
public void updateThread(HashMap<String, Integer> map) {
try {
String sql = "update tblBoard set thread = thread -1 where thread > ? and thread < ?";
pstat = conn.prepareStatement(sql);
pstat.setInt(1, map.get("previousThread"));
pstat.setInt(2, map.get("parentThread"));
pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 코드 분석
웹 애플리케이션의 게시판 기능과 관련된 데이터베이스 작업을 수행하는 역할을 합니다.
아래는 코드의 구성 요소에 대한 설명입니다:
- 코드는 필요한 자바 클래스와 패키지를 import 문으로 가져옵니다.
- BoardDAO 클래스는 데이터베이스에 대한 연결을 수립하는 생성자를 가지고 있습니다. 생성자에서는 DBUtil 클래스의 open 메서드를 호출하여 데이터베이스 연결을 설정합니다.
- add 메서드는 게시글을 추가하는 기능을 수행합니다. SQL 쿼리를 사용하여 데이터를 입력하고, PreparedStatement를 통해 SQL 문의 매개변수를 설정합니다.
- list 메서드는 게시판 목록을 가져오는 기능을 수행합니다. HashMap을 매개변수로 받아와서 검색 조건에 따라 SQL 쿼리를 동적으로 생성하고, 결과를 List<BoardDTO>로 반환합니다.
- get 메서드는 게시글의 상세 내용을 가져오는 기능을 수행합니다. 게시글 번호를 매개변수로 받아와서 해당하는 게시글 정보를 조회하여 BoardDTO 객체에 저장하여 반환합니다.
- updateReadCount 메서드는 게시글의 조회수를 증가시키는 기능을 수행합니다. 게시글 번호를 매개변수로 받아와서 해당하는 게시글의 조회수를 1 증가시킵니다.
- edit 메서드는 게시글을 수정하는 기능을 수행합니다. BoardDTO 객체를 매개변수로 받아와서 해당하는 게시글의 제목과 내용을 수정합니다.
- del 메서드는 게시글을 삭제하는 기능을 수행합니다. 게시글 번호를 매개변수로 받아와서 해당하는 게시글을 삭제합니다.
- addContent 메서드는 댓글을 추가하는 기능을 수행합니다. CommentDTO 객체를 매개변수로 받아와서 해당하는 게시글에 댓글을 등록합니다.
- clist 메서드는 게시글에 달린 댓글 목록을 가져오는 기능을 수행합니다. 게시글 번호를 매개변수로 받아와서 해당하는 게시글에 달린 댓글 목록을 조회하여 List<CommentDTO>로 반환합니다.
- 다른 메서드들은 댓글 삭제, 수정 등과 관련된 기능을 수행합니다.
- 마지막으로 getTotalCount와 getMaxThread 메서드는 게시글의 총 개수와 가장 큰 스레드 값을 가져오는 기능을 수행합니다.
■ BoardDTO.java
package com.test.toy.board.repository;
import lombok.Data;
@Data
public class BoardDTO {
private String seq;
private String subject;
private String content;
private String id;
private String regdate;
private String readcount;
private String name; //작성자
private double isnew; //최신글
private String ccnt; //현재글에 달린 댓글 개수
private int thread;
private int depth;
}
■ CommentDTO.java
package com.test.toy.board.repository;
import lombok.Data;
@Data
public class CommentDTO {
private String seq;
private String content;
private String id;
private String regdate;
private String bseq;
private String name;
}
★ JSP 파일
■ add.jsp
<%@ 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>Toy Project</title>
<%@ include file="/WEB-INF/views/inc/asset.jsp" %>
<style>
</style>
</head>
<body>
<%@ include file="/WEB-INF/views/inc/header.jsp" %>
<main id="main">
<h1 class="page">게시판
<c:if test="${mode == 'new'}">
<small>글쓰기</small>
</c:if>
<c:if test="${mode == 'reply'}">
<small>답변쓰기</small>
</c:if>
</h1>
<form method="POST" action="/toy/board/add.do">
<table class="vertical">
<tr>
<th>제목</th>
<td><input type="text" name="subject" id="subject" required class="full"></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="content" id="content" required class="full"></textarea></td>
</tr>
</table>
<div>
<button type="button" class=back"
onclick="location.href='/toy/board/board.do';">돌아가기</button>
<button type="submit" class="add primary">글쓰기</button>
</div>
<input type="hidden" name="mode" value="${mode}">
<input type="hidden" name="thread" value="${thread}">
<input type="hidden" name="depth" value="${depth}">
</form>
</main>
<script>
</script>
</body>
</html>
- 코드 분석
JSP(JavaServer Pages)를 사용하여 구현된 게시판의 글쓰기 기능을 담당하는 페이지입니다. 아래는 코드의 구성과 기능에 대한 설명입니다.
- 첫 번째 줄에서는 페이지의 언어를 지정하고, 문자 인코딩을 UTF-8로 설정하고 있습니다.
- JSTL(Core 태그 라이브러리)을 사용하기 위해 태그 라이브러리를 import하고 있습니다.
- <head> 태그 내부에서는 페이지의 제목과 필요한 CSS 파일을 포함시키는 등의 작업을 수행합니다. 현재는 스타일이 지정되어 있지 않은 상태입니다.
- <body> 태그 내부에서는 게시판 페이지의 레이아웃을 구성합니다.
- <%@ include file="/WEB-INF/views/inc/header.jsp" %>를 사용하여 게시판 페이지의 상단에 헤더 부분을 포함시키고 있습니다.
- <main> 태그 내부에서는 게시판의 제목과 글 작성 폼을 표시합니다. 제목은 "게시판"이며, 글 작성 모드(mode)에 따라 "글쓰기" 또는 "답변쓰기"로 표시됩니다.
- <form> 태그를 사용하여 글 작성 폼을 구성하고 있습니다. 폼은 POST 메서드로 전송되며, /toy/board/add.do 주소로 전송됩니다.
- 테이블을 사용하여 제목과 내용을 입력하는 필드를 구성하고 있습니다. 각 필드는 <input> 및 <textarea> 태그를 사용하여 표시되며, 필수 입력 사항(required)으로 지정되어 있습니다.
- <button> 요소를 사용하여 "돌아가기" 및 "글쓰기" 버튼을 표시하고 있습니다. "돌아가기" 버튼은 이전 페이지로 돌아가는 역할을 하며, "글쓰기" 버튼은 폼을 제출하는 역할을 합니다.
- <input> 요소를 사용하여 mode, thread, depth와 같은 숨겨진(hidden) 필드를 생성하여 폼 데이터와 함께 전송됩니다. 이러한 필드는 폼 데이터와 관련된 정보를 서버로 전달하는 데 사용됩니다.
- <script> 태그 내부에서는 JavaScript 코드를 작성할 수 있으며, 현재는 비어있는 상태입니다.
■ board.jsp
<%@ 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>Toy Project</title>
<%@ include file="/WEB-INF/views/inc/asset.jsp" %>
<style>
#list th:nth-child(1) {width : 50px;}
#list th:nth-child(2) {width : auto;}
#list th:nth-child(3) {width : 70px;}
#list th:nth-child(4) {width : 120px;}
#list th:nth-child(5) {width : 50px;}
#list td { text-align: center; }
#list td:nth-child(2) { text-align: left; }
.isnew {
font-size: 14px;
color: red;
}
.comment-count {
font-size: 12px;
color: #777;
}
#searchForm {
margin-bottom: 15px;
text-align: center;
}
#searchForm > * {
box-sizing: border-box;
height: 34px;
}
</style>
</head>
<body>
<%@ include file="/WEB-INF/views/inc/header.jsp" %>
<main id="main">
<h1 class="sub">
게시판
<c:if test="${map.search == 'n'}">
<small>목록</small>
</c:if>
<c:if test="${map.search == 'y'}">
<small>검색</small>
</c:if>
<%--
<span id="pagebar" style="float: right; margin-top: -5px;">
<input type="number" id="page" class="short" min="1" max="${totalPage}" value="${nowPage}">
<input type="button" value="이동" onclick="location.href='/toy/board/board.do?page=' + $('#page').val() + '&column=${map.column}&word=${map.word}';">
</span>
--%>
<span id="pagebar" style="float: right;">
<select onchange="location.href='/toy/board/board.do?page=' + $(this).val() + '&column=${map.column}&word=${map.word}';">
<c:forEach var="i" begin="1" end="${totalPage}">
<option value="${i}" <c:if test="${i == nowPage}">selected</c:if>>${i}페이지</option>
</c:forEach>
</select>
</span>
</h1>
<c:if test="${map.search == 'y'}">
<div style="text-align: center;">
'${map.word}'(으)로 검색한 결과 ${totalCount}건이 있습네다.
</div>
</c:if>
<table id="list">
<tr>
<th>번호</th>
<th>제목</th>
<th>이름</th>
<th>날짜</th>
<th>읽음</th>
</tr>
<c:if test="${list.size() == 0}">
<tr>
<td colspan="5">게시물이 없습니다.</td>
</tr>
</c:if>
<c:forEach items="${list}" var="dto">
<tr>
<td>
<c:if test="${dto.depth == 0}">
${dto.seq}
</c:if>
<c:if test="${dto.depth > 0}">
답변
</c:if>
</td>
<td>
<c:if test="${dto.depth > 0}">
<span class="material-symbols-outlined" style="font-size:15px; margin-left: ${dto.depth * 20}px;">
subdirectory_arrow_right
</span>
</c:if>
<!-- 제목(링크) -->
<a href="/toy/board/view.do?seq=${dto.seq}&column=${map.column}&word=${map.word}&search=${map.search}">${dto.subject}</a>
<!-- 댓글 개수 -->
<c:if test="${dto.ccnt > 0}">
<span class="comment-count">(${dto.ccnt})</span>
</c:if>
<!-- 새글 표시 -->
<c:if test="${dto.isnew < 30 / 24 / 60}">
<span class="isnew">new</span>
</c:if>
</td>
<td>${dto.name}</td>
<td>${dto.regdate}</td>
<td>${dto.readcount}</td>
</tr>
</c:forEach>
</table>
<!-- <form method="GET"> 사용 사례 -->
<form id="searchForm" action="/toy/board/board.do" method="GET">
<select name="column">
<option value="subject">제목</option>
<option value="content">내용</option>
<option value="name">이름</option>
</select>
<input type="text" name="word" class="long" required>
<input type="submit" value="검색하기">
</form>
<div id="pagination" style="text-align : center; margin-bottom: 10px;">${pagination}</div>
<div>
<c:if test="${not empty id}">
<button type="button" class="add Primary" onclick="location.href='/toy/board/add.do?mode=new';">글쓰기</button>
</c:if>
<button type="button" class="list Primary" onclick="location.href='/toy/board/board.do';">목록보기</button>
</div>
</main>
<script>
<c:if test="${map.search == 'y'}">
$('select[name=column]').val('${map.column}');
$('input[name=word]').val('${map.word}');
</c:if>
</script>
</body>
</html>
- 코드 분석
JSP(JavaServer Pages)를 사용하여 구현된 게시판의 목록 페이지입니다. 아래는 코드의 구성과 기능에 대한 설명입니다.
- 첫 번째 줄에서는 페이지의 언어를 지정하고, 문자 인코딩을 UTF-8로 설정하고 있습니다.
- JSTL(Core 태그 라이브러리)을 사용하기 위해 태그 라이브러리를 import하고 있습니다.
- <head> 태그 내부에서는 페이지의 제목과 필요한 CSS 파일을 포함시키는 등의 작업을 수행합니다. 현재는 스타일이 지정되어 있으며, 게시판 목록 테이블의 각 열의 너비(width) 등을 설정하고 있습니다.
- <body> 태그 내부에서는 게시판 페이지의 레이아웃을 구성합니다.
- <%@ include file="/WEB-INF/views/inc/header.jsp" %>를 사용하여 게시판 페이지의 상단에 헤더 부분을 포함시키고 있습니다.
- <main> 태그 내부에서는 게시판의 목록을 표시합니다. 게시판의 제목과 현재 목록인지 검색 결과인지에 따라 다른 내용이 표시됩니다.
- 검색 결과를 표시하는 경우, 검색된 결과 개수와 검색어를 표시하는 부분이 추가됩니다.
- <table> 태그를 사용하여 게시판 목록을 표시하는 테이블을 구성하고 있습니다. 테이블의 각 열은 번호, 제목, 이름, 날짜, 읽음 수로 구성되어 있습니다.
- ${list} 객체를 사용하여 게시판의 글 목록을 반복적으로 표시합니다. 각 글의 번호, 제목, 작성자, 작성일, 읽음 수를 표시합니다.
- 검색 폼을 구성하여 사용자가 원하는 조건으로 게시판을 검색할 수 있도록 합니다. 검색어와 검색 대상을 선택하는 필드와 검색 버튼이 표시됩니다.
- 페이지네이션을 표시하는 부분이 추가됩니다. 사용자는 페이지를 선택하여 다른 페이지로 이동할 수 있습니다.
- 글쓰기 버튼과 목록보기 버튼이 표시되며, 사용자가 해당 버튼을 클릭하면 글쓰기 페이지로 이동하거나 목록 페이지로 돌아갈 수 있습니다.
- <script> 태그 내부에서는 JavaScript 코드를 작성할 수 있으며, 현재는 ${map.search} 값에 따라 검색 폼의 값을 설정하는 부분이 추가되어 있습니다.
■ del.jsp
<%@ 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>Toy Project</title>
<%@ include file="/WEB-INF/views/inc/asset.jsp" %>
<style>
</style>
</head>
<body>
<%@ include file="/WEB-INF/views/inc/header.jsp" %>
<main id="main">
<h1>게시판 <small>삭제하기</small></h1>
<form method="POST" action="/toy/board/del.do">
<div>
<button type="button" class=back"
onclick="history.back();">돌아가기</button>
<button type="submit" class="del primary">삭제하기</button>
</div>
<input type="hidden" name="seq" value="${seq}">
</form>
</main>
<script>
</script>
</body>
</html>
- 코드 분석
JSP(JavaServer Pages)를 사용하여 구현된 게시물 삭제 페이지입니다. 아래는 코드의 구성과 기능에 대한 설명입니다.
- 첫 번째 줄에서는 페이지의 언어를 지정하고, 문자 인코딩을 UTF-8로 설정하고 있습니다.
- JSTL(Core 태그 라이브러리)을 사용하기 위해 태그 라이브러리를 import하고 있습니다.
- <head> 태그 내부에서는 페이지의 제목과 필요한 CSS 파일을 포함시키는 등의 작업을 수행합니다.
- <body> 태그 내부에서는 게시물 삭제 페이지의 레이아웃을 구성합니다.
- <%@ include file="/WEB-INF/views/inc/header.jsp" %>를 사용하여 게시물 삭제 페이지의 상단에 헤더 부분을 포함시키고 있습니다.
- <main> 태그 내부에서는 게시물 삭제를 위한 폼을 표시합니다. 게시물 삭제 페이지의 제목과 함께 "삭제하기"라는 작은 문구가 표시됩니다.
- <form> 태그를 사용하여 게시물 삭제를 위한 폼을 구성하고 있습니다. 폼은 POST 방식으로 데이터를 서버로 전송하며, /toy/board/del.do URL로 데이터를 전송합니다.
- <button> 태그를 사용하여 "돌아가기"와 "삭제하기" 버튼을 표시하고 있습니다. "돌아가기" 버튼은 이전 페이지로 돌아가는 기능을 수행하며, "삭제하기" 버튼은 게시물을 삭제하는 기능을 수행합니다.
- <input> 태그를 사용하여 삭제할 게시물의 식별자인 seq 값을 서버로 전송하고 있습니다. seq 값은 ${seq} 표현식을 통해 동적으로 설정됩니다.
- <script> 태그 내부에서는 JavaScript 코드를 작성할 수 있으며, 현재는 비어있는 상태입니다.
■ edit.jsp
<%@ 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>Toy Project</title>
<%@ include file="/WEB-INF/views/inc/asset.jsp" %>
<style>
</style>
</head>
<body>
<%@ include file="/WEB-INF/views/inc/header.jsp" %>
<main id="main">
<h1>게시판 <small>수정하기</small></h1>
<form method="POST" action="/toy/board/edit.do">
<table class="vertical">
<tr>
<th>제목</th>
<td><input type="text" name="subject" id="subject" required class="full" value="${dto.subject}"></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="content" id="content" required class="full">${dto.content}</textarea></td>
</tr>
</table>
<div>
<button type="button" class=back"
onclick="history.back();">돌아가기</button>
<button type="submit" class="edit primary">수정하기</button>
</div>
<input type="hidden" name="seq" value="${dto.seq}">
</form>
</main>
<script>
</script>
</body>
</html>
- 코드 분석
JSP(JavaServer Pages)를 사용하여 구현된 게시물 수정 페이지입니다. 아래는 코드의 구성과 기능에 대한 설명입니다.
- 첫 번째 줄에서는 페이지의 언어를 지정하고, 문자 인코딩을 UTF-8로 설정하고 있습니다.
- JSTL(Core 태그 라이브러리)을 사용하기 위해 태그 라이브러리를 import하고 있습니다.
- <head> 태그 내부에서는 페이지의 제목과 필요한 CSS 파일을 포함시키는 등의 작업을 수행합니다.
- <body> 태그 내부에서는 게시물 수정 페이지의 레이아웃을 구성합니다.
- <%@ include file="/WEB-INF/views/inc/header.jsp" %>를 사용하여 게시물 수정 페이지의 상단에 헤더 부분을 포함시키고 있습니다.
- <main> 태그 내부에서는 게시물 수정을 위한 폼을 표시합니다. 게시물 수정 페이지의 제목과 함께 "수정하기"라는 작은 문구가 표시됩니다.
- <form> 태그를 사용하여 게시물 수정을 위한 폼을 구성하고 있습니다. 폼은 POST 방식으로 데이터를 서버로 전송하며, /toy/board/edit.do URL로 데이터를 전송합니다.
- <table> 태그를 사용하여 제목과 내용을 입력할 수 있는 입력 필드를 구성하고 있습니다. 제목은 <input> 태그를 사용하고, 내용은 <textarea> 태그를 사용합니다. 값이 기존 게시물의 값으로 미리 설정되도록 ${dto.subject}와 ${dto.content} 표현식을 사용합니다.
- <button> 태그를 사용하여 "돌아가기"와 "수정하기" 버튼을 표시하고 있습니다. "돌아가기" 버튼은 이전 페이지로 돌아가는 기능을 수행하며, "수정하기" 버튼은 게시물을 수정하는 기능을 수행합니다.
- <input> 태그를 사용하여 수정할 게시물의 식별자인 seq 값을 서버로 전송하고 있습니다. seq 값은 ${dto.seq} 표현식을 통해 동적으로 설정됩니다.
- <script> 태그 내부에서는 JavaScript 코드를 작성할 수 있으며, 현재는 비어있는 상태입니다.
■ view.jsp
<%@ 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>Toy Project</title>
<%@ include file="/WEB-INF/views/inc/asset.jsp" %>
<style>
#content {
height:215px;
}
#comment td:nth-child(1) {width: auto;}
#comment td:nth-child(2) {
width: 170px;
test-align: center;
}
#addcomment td:nth-child(1) {width: auto;}
#addcomment td:nth-child(2) {
width: 150px;
text-align: center;
}
.comment-content {
display: flex;
display: table-cell;
justify-content: space-between;
}
.comment-regdate {
font-size: 12px;
color: #777;
}
</style>
</head>
<body>
<!-- template.jsp > add.jsp > view.jsp -->
<%@ include file="/WEB-INF/views/inc/header.jsp" %>
<main id="main">
<h1>게시판 <small>글보기</small></h1>
<table class="vertical">
<tr>
<th>번호</th>
<td>${dto.seq}</td>
</tr>
<tr>
<th>이름</th>
<td>${dto.name}(${dto.id})</td>
</tr>
<tr>
<th>제목</th>
<td>${dto.subject}</td>
</tr>
<tr>
<th>내용</th>
<td id="content">${dto.content}</td>
</tr>
<tr>
<th>날짜</th>
<td>${dto.regdate}</td>
</tr>
<tr>
<th>조회수</th>
<td>${dto.readcount}</td>
</tr>
</table>
<table id="comment">
<c:forEach items="${clist}" var="cdto">
<tr>
<td>
<div class="comment-content">
<div><c:out value="${cdto.content}" /></div>
<div class="comment-regdate">${cdto.regdate}</div>
</div>
</td>
<td>
<div>
<div>${cdto.name}(${cdto.id})</div>
<c:if test="${not empty id && (id == cdto.id || lv == '3')}">
<div>
<button type="button" class="edit" onclick="editComment(${cdto.seq});">수정</button>
<button type="button" class="del" onclick="delComment(${cdto.seq});" >삭제</button>
</div>
</c:if>
</div>
</td>
</tr>
</c:forEach>
</table>
<!-- 로그인 안하면 댓글 못보도록 -->
<c:if test="${not empty id}">
<form method="POST" action="/toy/board/comment.do">
<table id="addcomment">
<tr>
<td><input type="text" name="content" class="full" required></td>
<td>
<button type="submit" class="comment">댓글쓰기</button>
</td>
</tr>
</table>
<input type="hidden" name="bseq" value="${dto.seq}">
<input type="hidden" name="column" value="${column}">
<input type="hidden" name="word" value="${word}">
<input type="hidden" name="search" value="${search}">
</form>
</c:if>
<div>
<!-- 페이지를 다시 불러오기함, db에서 다시 select 해옴 -->
<button type="button" class="back"
onclick="location.href='/toy/board/board.do?column=${column}&word=${word}';">돌아가기</button>
<!-- 세션 아이디 == 글쓴 사람 아이디 || -->
<c:if test="${not empty id && (id == dto.id || lv == '3')}">
<button type="button" class="edit"
onclick="location.href='/toy/board/edit.do?seq=${dto.seq}';">수정하기</button>
<button type="button" class="del"
onclick="location.href='/toy/board/del.do?seq=${dto.seq}';">삭제하기</button>
</c:if>
<button type="button" class="reply"
onclick="location.href='/toy/board/add.do?mode=reply&thread=${dto.thread}&depth=${dto.depth}';">답변하기</button>
<!-- 브라우저가 읽었던 이전 상태를 복구 -->
<!-- <button type="button" class="back"
onclick="history.back();">돌아가기</button> -->
</div>
</main>
<form id="editCommentForm" method="POST" action="/toy/board/editcomment.do">
<input type="hidden" name="bseq">
<input type="hidden" name="cseq">
<input type="hidden" name="content">
</form>
<script>
function editComment(cseq) {
//이전 수정중인 댓글 폼 > 전부 삭제
$('.edit-comment').remove();
const content = $(event.target).closest('tr').find('.comment-content').children().eq(0).text();
$(event.target).closest('tr').after(
`
<tr style="background-color: #EFEFEF;" class="edit-comment">
<td><input type="text" class="full" value="\${content}" id="editcomment"></td>
<td>
<input type="button" value="확인" onclick="editOkComment(\${cseq});">
<input type="button" value="취소" onclick="cancelComment();">
</td>
</tr>
`
);
}
function cancelComment() {
$(event.target).closest('tr').remove();
}
function editOkComment(cseq) {
//부모 글번호
//댓글 번호
//댓글 내용
//console.log(${dto.seq}); //부모글번호
//console.log(cseq); //현재댓글번호
//console.log($('#editcomment').val()); //수정내용
$('#editCommentForm input[name=bseq]').val(${dto.seq});
$('#editCommentForm input[name=cseq]').val(cseq);//수정할 댓글번호
$('#editCommentForm input[name=content]').val($('#editcomment').val());//수정할 텍스트내용
$('#editCommentForm').submit();
}
function delComment(cseq) {
location.href = '/toy/board/delcomment.do?seq=${dto.seq}&cseq=' + cseq;
}
</script>
</body>
</html>
- 코드 분석
JSP(JavaServer Pages)를 사용하여 게시물 상세보기 페이지를 구현한 것입니다. 아래는 코드의 구성과 주요 기능에 대한 설명입니다.
- 첫 번째 줄에서는 페이지의 언어를 지정하고, 문자 인코딩을 UTF-8로 설정하고 있습니다.
- JSTL(Core 태그 라이브러리)을 사용하기 위해 태그 라이브러리를 import하고 있습니다.
- <head> 태그 내부에서는 페이지의 제목과 필요한 CSS 파일을 포함시키는 등의 작업을 수행합니다.
- <body> 태그 내부에서는 게시물 상세보기 페이지의 레이아웃을 구성합니다.
- <%@ include file="/WEB-INF/views/inc/header.jsp" %>를 사용하여 게시물 상세보기 페이지의 상단에 헤더 부분을 포함시키고 있습니다.
- <main> 태그 내부에서는 게시물의 제목, 내용, 작성자 정보 등을 표시합니다.
- <table> 태그를 사용하여 게시물의 정보를 테이블 형태로 표시하고 있습니다. ${dto} 표현식을 사용하여 게시물의 속성값을 동적으로 설정합니다.
- 댓글 목록을 표시하기 위해 <table> 태그 내부에 <c:forEach> 태그를 사용하여 ${clist}(댓글 목록)의 각 댓글을 반복하여 표시합니다. ${cdto} 표현식을 사용하여 각 댓글의 속성값을 동적으로 설정합니다.
- 댓글을 수정하거나 삭제하기 위한 버튼을 표시하고 있습니다. <button> 태그를 사용하며, JavaScript 함수를 호출하여 댓글 수정 및 삭제 동작을 처리합니다.
- 댓글 작성을 위한 폼을 표시하고 있습니다. <form> 태그를 사용하며, 댓글 내용을 입력하는 <input> 태그와 "댓글쓰기" 버튼을 포함하고 있습니다.
- 게시물 수정, 삭제, 답변하기 버튼을 표시하고 있습니다. 사용자의 권한과 현재 로그인한 사용자의 정보에 따라 버튼의 표시 여부를 동적으로 결정합니다.
- <script> 태그 내부에서는 JavaScript 함수를 정의하고 있습니다. 이 함수들은 댓글 수정, 삭제 등의 동작을 처리하는 역할을 수행합니다.
★ 실행 결과
- 글 작성
- 글 리스트 Board
- 글 상세보기
- 댓글 작성
- 수정하기
- 삭제하기
'Server' 카테고리의 다른 글
게시판 개발 STEP 1 - Ajax, Json, Oracle, JDBC etc.. (0) | 2023.05.31 |
---|---|
AJAX STEP 11 - Map (0) | 2023.05.18 |
AJAX STEP 10 - 게시판 목록 보기 (0) | 2023.05.18 |
AJAX STEP 9 - 상품 목록 페이지 (0) | 2023.05.17 |
AJAX STEP 8 - 일기장 AJAX (0) | 2023.05.17 |