loginform과 login
- loginform.hta에서 FrontController와 LoginFormController를 실행하고 loginform.jsp로 내부이동 하여 로그인 화면으로 전달되어 login.hta를 실행시킨다.
- login.hta에서 FrontController와 LoginController를 실행해서 home.hta를 재요청 한다.
- login.hta의 세션객체에 사용자 id가 담겨져서 재요청을 한다.
home화면
- home.jsp에서 include 한 부분으로 인해 navbar.jsp코드들로 인해 세션객체 안에 loinUserId가 있는가 없는가에 따라 상단 바에 보이는 메뉴가 달라진다.
- loinUserId가 있으면, 로그아웃과 게시판이 표시된다.
- loinUserId가 없으면, 로그인이 표시된다.
- 세션객체에 값을 담는 행위는 LoginController에서 발생한다.
list
- list.hta?page=2에서 요청객체는 page=2가 되고 ListController에서 응답을 받는다.
- 세션객체에 값이 들어있는 주인이 list를 요청하면 "새 게시글 쓰기"가 표시된다.
- 세션객체에 값이 없는 주인이 list를 요청하면 "새 게시글 쓰기"가 표시되지 않는다.
- PageContext : page 안에서만 접근 가능한 객체 / c:set을 사용하여 이 안에 beginPage와 endPage가 속성으로 저장된다.
post
- post/form.hta에서 새글쓰기 폼을 요청하고 FrontController에서 form.jsp로 내부이동하여 게시글 등록 화면을 실행한다.
- 게시글 등록화면에서 "등록"버튼을 클릭하였을 때 insert.hta가 실행되며 요청객체로 title과 content가 전달된다.
- FrontController가 실행되고, InsertController로 넘어가서 먼저, 세션객체를 통해 로그인한 사용자인지 확인한다. (로그인 시 게시글 등록 / 비로그인 시 로그인 화면으로 redirect)
- title과 content를 꺼내고 Post를 만든다.
- post 안에는 title / content / loginUserId가 담긴다.
- list.hta로 redirect 한다.
list.jsp
<c:if test="${pagination.totalRows > 0 }">
<nav>
<ul class="pagination pagination-sm justify-content-center">
<li class="page-item">
<a class="page-link ${pagination.first ? 'disabled' : '' }" href="list.hta?page=${pagination.prevPage }">이전</a>
</li>
<c:forEach var="number" begin="${pagination.beginPage }" end="${pagination.endPage }">
<li class="page-item">
<a class="page-link ${param.page == number ? 'active' : '' }" href="list.hta?page=${number }">${number }</a>
</li>
</c:forEach>
<li class="page-item">
<a class="page-link ${pagination.last ? 'disabled' : '' }" href="list.hta?page=${pagination.nextPage }">다음</a>
</li>
</ul>
</nav>
</c:if>
실행결과
detail.jsp
<c:if test="${post.userId == loginUserId }">
<div class="row mb-3">
<div class="col-12">
<a href="modifyform.hta?postNo=${post.no }" class="btn btn-warning btn-sm">수정</a>
<a href="delete.hta?postNo=${post.no }" class="btn btn-danger btn-sm">삭제</a>
</div>
</div>
</c:if>
실행결과(로그인한 사용자와 글 작성자가 다를 때)
실행결과(로그인한 사용자와 글 작성자가 같을 때)
InsertCommentController
package com.sample.app.controller.post;
import com.sample.app.dao.CommentDao;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Comment;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* 요청 URI
* /post/insertComment.hta
* 요청 파라미터
* postNo
* content
* 반환값
* redirect:/app/user/loginform.hta?error=deny
* redirect:detail.hta?postNo=100
*
* 요청처리 내용
* 세션에서 로그인된 사용자 정보를 조회한다.
* 사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL("redirect:/app/user/loginform.hta?error=deny")을 반환한다.
* 요청파라미터 값(게시글 번호, 댓글내용)을 조회한다.
* Comment 객체를 생성해서 작성자 아이디, 내용, 게시글 번호를 저장한다.
* CommentDao 객체의 insertComment(Comment comment)를 호출해서 댓글정보를 저장시킨다.
* 게시글 번호로 PostDao의 getPostByNo(int postNo)를 실행해서 게시글 정보를 조회한다.
* 게시글 정보의 댓글 갯수를 1 증가시킨다.
* PostDao의 updatePost(Post post)를 실행시켜서 변경된 정보를 반영시킨다.
*
*
* 게시글 상세정보를 재요청하는 URL을 응답으로 보낸다.
*/
public class InsertCommentController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 세션객체에서 로그인된 사용자정보를 조회한다.
HttpSession session = request.getSession();
String loginUserId = (String) session.getAttribute("loginUserId");
if (loginUserId == null) {
return "redirect:/app/user/loginform.hta?error=deny";
}
// 요청 파라이머 값을 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
String content = request.getParameter("content");
// Comment객체를 생성해서 작성자 아이디, 내용, 게시글 번호를 저장한다.
Comment comment = new Comment();
comment.setUserId(loginUserId);
comment.setContent(content);
comment.setPostNo(postNo);
CommentDao commentDao = CommentDao.getInstance();
PostDao postDao = PostDao.getInstance();
// CommentDao의 insertComment(Comment comment) 를 실행해서 댓글 정보를 테이블에 저장시킨다.
commentDao.insertComment(comment);
// 게시글 번호로 게시글 정보를 조회한다.
Post post = postDao.getPostByNo(postNo);
// 게시글 정보의 댓글 수를 증가시킨다.
post.setCommentCount(post.getCommentCount() + 1);
// PostDao 객체의 updatePost(Post post)를 실행해서 변경된 게시글 정보로 갱신시킨다.
postDao.updatePost(post);
return "redirect:detail.hta?postNo=" + postNo;
}
실행결과 (댓글 작성 전)
실행결과 (댓글 작성 후)
- 댓글 수가 count 된다.
detail.jsp
<!-- 댓글 목록 -->
<div class="row mb-3">
<div class="col">
<c:choose>
<c:when test="${empty comments }">
<div class="border p-2 mb-2">
<p class="mb-0">등록된 댓글이 없습니다.</p>
</div>
</c:when>
<c:otherwise>
<%--
items="{comments}"는 요청객체에 "comments"로 저장된 객체를 조회한다.
${comments}로 조회된 객체는 List<CommentListDto> 다.
var="comment"는 반복을 수행할 때마다 List<CommentListDto>에 저장된 CommentListDto객체가
순서대로 comment에 대입된다.
comment에 대입된 객체는 CommentListDto다.
comment -> CommentListDto [no=100, userId="hong", userName="홍길동", content="댓글입니다.", postNo=2]
--%>
<c:forEach var="comment" items="${comments }">
<div class="border p-2 mb-2">
<p class="mb-0 small">
<span class="text-muted">${comment.userName }</span>
<span class="text-muted float-end"><fmt:formatDate value="${comment.createdDate }" /></span>
</p>
<p class="mb-0">
${comment.content }
<a href="deleteComment.hta?postNo=100&commentNo=${comment.postNo }&commentNo=${comment.no }" class="float-end"><i class="bi bi-trash-fill text-danger"></i></a>
</p>
</div>
</c:forEach>
</c:otherwise>
</c:choose>
</div>
</div>
실행결과
detail.jsp
<p class="mb-0">
${comment.content }
<c:if test="${comment.userId == loginUserId }">
<a href="deleteComment.hta?postNo=${comment.postNo }&commentNo=${comment.no }" class="float-end"><i class="bi bi-trash-fill text-danger"></i></a>
</c:if>
</p>
실행결과
DeleteCommentController
package com.sample.app.controller.post;
import com.sample.app.dao.CommentDao;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Comment;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* 요청 URI
* /post/deleteComment.hta
* 요청 파라미터
* postNo
* commentNo
* 반환값
* redirect:/app/user/loginform.hta?error=deny : 로그인 상태가 아닐 때
* redirect:detail.hta?postNo=100&error=comment : 댓글 작성자와 로그인한 사용자가 다를 때
* redirect:detail.hta?postNo=100 : 댓글삭제가 완료되었을 때
* 요청처리 내용
* 사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL("redirect:/app/user/loginform.hta?error=deny")을 반환한다.
* 요청파라미터 값(게시글 번호, 댓글번호)을 조회한다.
* CommentDao객체의 getCommentByNo(int commentNo)을 실행해서 댓글 정보를 조회한다.
* 댓글 작성자 아이디와 로그인한 사용자 아이닥 일치하지 않으면 재요청 URL("redirect:detail.hta?postNo=100&error=comment")을 반환한다.
* CommentDao객체의 deleteComment(int commentNo)을 실행해서 댓글을 삭제한다.
* PostDao객체의 getPostByNo(int postNo)를 실행해서 게시글 정보를 조회한다.
* 게시글 정보의 댓글 갯수를 1감소시킨다.
* PostDao객체의 updatePost(Post post)를 실행해서 변경된 게시글 정보를 테이블에 반영시킨다.
*
* 게시글 상세화면을 요청하는 재요청 URL을 반환한다.
*/
public class DeleteCommentController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 세션에서 로그인 정보를 조회한다.
HttpSession session = request.getSession();
String loginUserId = (String) session.getAttribute("loginUserId");
if (loginUserId == null) {
return "redirect:/app/user/loginform.hta?error=deny";
}
// 요청 파라미터 값(게시글 번호, 댓글 번호)를 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
int commentNo = StringUtils.stringToInt(request.getParameter("commentNo"));
CommentDao commentDao = CommentDao.getInstance();
PostDao postDao = PostDao.getInstance();
// 댓글번호로 댓글정보를 조회한다.
Comment comment = commentDao.getCommentByNo(commentNo);
// 댓글정보의 댓글 작성자 아아디와 로그인한 사용자 아이디가 일치하는지 확인한다.
if (!comment.getUserId().equals(loginUserId)) {
return "redirect:detail.hta?postNo=" + postNo + "error=comment";
}
// 댓글정보 삭제하기
commentDao.deleteComment(commentNo);
// 게시글 번호에 해당하는 게시글 정보 조회하기
Post post = postDao.getPostByNo(postNo);
// 댓글 갯수 1 감소시키키
post.setCommentCount(post.getCommentCount() -1);
// 변경된 게시글 정보를 테이블에 반영시키기
postDao.updatePost(post);
return "redirect:detail.hta?postNo=" + postNo;
}
}
실행 결과
detail.jsp
<div class="col">
<c:choose>
<c:when test="${param.error eq 'comment' }">
<div class="alert alert-danger">
다른 사람의 댓글은 삭제할 수 없습니다.
</div>
</c:when>
<c:when test="${param.error eq 'post' }">
<div class="alert alert-danger">
다른 사람의 게시글은 수정하거나 삭제할 수 없습니다.
</div>
</c:when>
</c:choose>
ReadController
package com.sample.app.controller.post;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/*
* 요청 URI
* /post/read.hta
* 요청 파라미터
* postNo
* 반환값
* redirect:detail.hta?postNo=100
* 요청처리 내용
* 요청파라미터값(게시글 번호)을 조회한다.
* PostDao객체의 getpostByno(int postNo)를 실행해서 게시글 정보를 조회한다.
* 게시글 정보의 조회수를 1증가시킨다.
* PostDao객체의 updatePost(Post post)를 실행해서 변경된 게시글 정보를 테이블에 반영시킨다.
* 게시글 상세정보를 요청하는 재요청 URL을 응답으로 보낸다.
*/
public class ReadController implements Controller{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 요청파라미터값(게시글 번호)를 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
PostDao postDao = PostDao.getInstance();
// 게시글 번호에 해당하는 게시글 정보를 조회한다.
Post post = postDao.getPostByNo(postNo);
// 게시글의 조회수를 1증가시킨다.
post.setReadCount(post.getReadCount() + 1);
// 변경된 게시글 정보를 테이블에 반영시킨다.
postDao.updatePost(post);
return "redirect:detail.hta?postNo=" + postNo;
}
}
list.jsp
<c:forEach var="dto" items="${posts }">
<tr>
<td>${dto.no }</td>
<td><a href="read.hta?postNo=${dto.no }" class="text-decoration-none">${dto.title }</a></td>
<td class="text-center">${dto.userName }</td>
<td class="text-center">${dto.readCount }</td>
<td class="text-center">${dto.commentCount }</td>
<td class="text-center"><fmt:formatDate value="${dto.createdDate }" /></td>
</tr>
</c:forEach>
ModifyFormController
package com.sample.app.controller.post;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* 요청 URI
* /post/modifyform.hta
* 요청 파라미터
* postNo
* 반환값
* redirect:/app/user/loginform.hta?error=deny 로그인 상태가 아닐 때
* redirect:detail.hta?postNo=100&error=post 게시글 작성자와 로그인한 사용자가 서로 다를 때
* post/modifyform.jsp 게시글 정보를 조회해서 수정폼에 표시할 준비가 됐을 때
* 요청처리 내용
* 세션에서 로그인 정보를 조회해서 로그인상태가 아니면 재요청URL을 반환한다.
* 요청파라미터값(게시글번호)를 조회한다.
* PostDao의 getPostByNo(int postNo)를 실행해서 게시글번호에 해당하는 게시글 정보를 조회한다.
* 게시글 작성자와 로그인한 사용자의 아이디를 비교해서 서로 다르면 재요청 URL을 반환한다.
* 요청객체에 조회된 게시글 정보를 저장한다.
* 게시글 수정화면으로 내부이동할 수 있도록 post/modifyform.jsp를 반환한다.
*/
public class ModifyFormController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 세션에서 로그인된 사용자 정보를 조회한다.
HttpSession session = request.getSession();
String loginUserId = (String) session.getAttribute("loginUserId");
if (loginUserId == null) {
return "redirect:/app/user/loginform.hta?error=deny";
}
// 요청파라미터값(게시글 번호)를 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
PostDao postDao = PostDao.getInstance();
// 게시글 번호에 해당하는 게시글 정보를 조회한다.
Post post = postDao.getPostByNo(postNo);
if (post == null) {
return "redirect:list.hta";
}
// 게시글 작성자와 로그인한 사용자가 일치하지 않으면 재요청 URL을 응답으로 보낸다.
if (!post.getUserId().equals(loginUserId)) {
return "redirect:detail.hta?postNo=" + postNo + "&error=post";
}
// 요청객체의 속성으로 조회된 게시글 정보를 저장시킨다.
request.setAttribute("post", post);
return "post/modifyform.jsp";
}
}
modifyform.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<title>application</title>
</head>
<body>
<%@ include file="../common/navbar.jsp" %>
<div class="container my-3">
<div class="row mb-3">
<div class="col">
<h1 class="fs-4 border p-2 bg-light">게시글 수정</h1>
</div>
</div>
<div class="row mb-3">
<div class="col">
<p>제목과 내용을 입력하세요</p>
<form class="border bg-light p-3" method="post" action="modify.hta">
<!-- 실제 수정하는 게시글의 번호가 value에 지정되어야 함 -->
<input type="hidden" name="postNo" value="${post.no }" />
<div class="mb-2">
<label class="form-label">제목</label>
<input type="text" class="form-control" name="title" value="${post.title }"/>
</div>
<div class="mb-2">
<label class="form-label">내용</label>
<textarea rows="4" class="form-control" name="content">${post.content }</textarea>
</div>
<div class="text-end">
<a href="detail.hta?postNo=${post.no }" class="btn btn-secondary btn-sm">취소</a>
<button type="submit" class="btn btn-primary btn-sm">수정</button>
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</body>
</html>
ModifyController
package com.sample.app.controller.post;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* 요청 URI
* /post/modify.hta
* 요청 파라미터
* postNo
* title
* content
* 반환값
* redirect:app/user/loginform.hta?error=deny
* redirect:detail.hta?postNo=100
* redirect:detail.hta?postNo=100
* 요청처리 내용
* 로그인 상태가 아니면 재요청 URL을 반환한다.
* 요청파라미터값(게시글번호, 제목, 내용)을 조회한다.
* PostDao객체의 getPostByNo(int postNo)를 실행해서 게시글 정보를 조회한다.
* 게시글 작성자와 로그인한 사용자가 서로 다르면 재요청 URL을 반환한다.
* 게시글의 제목과 내용을 요청파라미터로 조회한 값으로 변경한다.
* PostDao객체의 updatePost(Post post)를 실행해서 변경된 게시글 정보를 테이블에 반연시킨다.
*
* 게시글 상세정보를 요청하는 재요청 URL을 반환한다.
*
*/
public class ModifyController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 세션에서 로그인정보를 조회한다.
HttpSession session = request.getSession();
String loginUserId = (String) session.getAttribute("loginUserId");
if (loginUserId == null) {
return "redirect:app/user/loginform.hta?error=deny";
}
// 요청파라미터 값을 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
String title =request.getParameter("title");
String content = request.getParameter("content");
// 게시글 번호에 해당하는 게시글 정보를 조회한다.
PostDao postDao = PostDao.getInstance();
Post post = postDao.getPostByNo(postNo);
// 게시글 작성자와 로그인한 사용자가 일치하지 않으면 재요청 URL을 반환한다.
if (!post.getUserId().equals(loginUserId)) {
return "redirect:detail.hta?postNo=" + postNo + "&error=post";
}
// 조회된 게시글 정보의 제목과 내용을 변경한다.
post.setTitle(title);
post.setContent(content);
// 변경된 게시글 정보를 테이블에 반영시킨다.
postDao.updatePost(post);
return "redirect:detail.hta?postNo=" + postNo;
}
}
실행결과 (수정 전)
실행결과 (수정 폼)
실행결과 (수정 후)
- 수정 후에도 조회수는 증가하지 않는다.
DeleteContorller
package com.sample.app.controller.post;
import com.sample.app.dao.PostDao;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
/*
* 요청 URI
* /post/delete.hta
* 요청 파라미터
* postNo
* 반환값
* redirect:app/user/loginform.hta?error=deny
* redirect:detail.hta?postNo=100&error=post
* redirect:list.hta
* 요청처리 내용
* 로그인 상태가 아니면 재요청 URL을 반환한다.
* 요청파라미터값(게시글번호, 제목, 내용)을 조회한다.
* PostDao객체의 getPostByNo(int postNo)를 실행해서 게시글 정보를 조회한다.
* 게시글 작성자와 로그인한 사용자가 서로 다르면 재요청 URL을 반환한다.
* 게시글정보의 삭제여부를 "Y"로 변경한다.
* PostDao객체의 updatePost(Post post)를 실행해서 변경된 게시글 정보를 테이블에 반영시킨다.
*
* 게시글 목록을 요청하는 재요청 URL을 반환한다.
*/
public class DeleteController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 세션에서 사용자 정보를 조회한다.
HttpSession session = request.getSession();
String loginUserId = (String) session.getAttribute("loginUserId");
if(loginUserId == null) {
return "redirect:/app/user/loginform.hta?error=deny";
}
// 요청파라미터값(게시글번호)를 조회한다.
int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
// 게시글번호에 해당하는 게시글 정보를 조회한다.
PostDao postDao = PostDao.getInstance();
Post post = postDao.getPostByNo(postNo);
// 게시글 작성자와 로그인한 사용자가 서로 다르면 재요청 URL을 반환한다.
if (!post.getUserId().equals(loginUserId)) {
return "redirect:detail.hta?postNo=" + postNo + "error=post";
}
// 게시글 정보의 삭제여부를 Y로 변경한다.
post.setDeleted("Y");
// 변경된 게시글 정보를 테이블에 반영시킨다.
postDao.updatePost(post);
return "redirect:list.hta";
}
}
실행결과(실행 전)
실행결과(실행 후)