Day 79

ChangWoo·2022년 12월 26일
0

중앙 HTA

목록 보기
23/51

  • 재요청 URI 앞에는 redirect가 붙는다.

회원가입

HomeController
RegisterFormController
RegisterController
FrontController

실행과정

  • 요청에 대한 응답은 재요청 URL과 회원가입 성공화면 이다.
  • 최종적으로 받은 응답은 회원가입 폼 화면과 회원가입 성공화면이다.

실행 결과

RegisterSuccessController

RegisterSuccess.jsp

실행결과

로그인 /로그아웃

로그인

LoginFormController

LoginController

loginform.jsp

navbar.jsp

home.jsp


> 실행결과
![](https://velog.velcdn.com/images/hcw0709/post/21a56a33-1c6c-430a-b3fa-ebce02fe25a5/image.png)
![](https://velog.velcdn.com/images/hcw0709/post/9d5217e6-d044-4d54-9e6d-35d3bfac4517/image.png)
![](https://velog.velcdn.com/images/hcw0709/post/8925905c-655f-4bc9-90af-85138cd41537/image.png)

> 로그인 전
![](https://velog.velcdn.com/images/hcw0709/post/c6a0dcc0-5af0-4ea5-921c-88b746cafb36/image.png)

> 로그인 후
![](https://velog.velcdn.com/images/hcw0709/post/5d185014-b73c-400b-b3c5-f2211dc98f53/image.png)


> **로그아웃**

LogoutController


> 실행결과
![](https://velog.velcdn.com/images/hcw0709/post/579ab4ce-665a-4c30-a604-ad9e569a55fa/image.png)


### 새글 등록

> **새글 등록 버튼 활성화 /비활성화**

list.jsp

<c:if test="${not empty loginUserId }">
			<a href="form.hta" class="btn btn-primary btn-sm float-end">새 글쓰기</a>
		</c:if>
> 로그인 전
![](https://velog.velcdn.com/images/hcw0709/post/e6a1a61c-87ef-4977-bcbc-753797ec38eb/image.png)

> 로그인 후
![](https://velog.velcdn.com/images/hcw0709/post/a2c3d2f7-5d37-4146-96f7-309e6e6dd657/image.png)


> **글 등록폼 활성화 / 비활성화**
FormController

package com.sample.app.controller.post;

import com.sample.model2.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

/*
 * 요청 URI

/post/form.hta
요청 파라미터
없음
반환값
post/form.jsp
redirect:/app/user/loginform.hta?error=deny
요청처리 내용
세션에서 로그인된 사용자 정보를 조회한다.
사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL("redirect:/app/user/loginform.hta?error=deny")을 반환한다.
세션에 로그인된 사용자 정보가 존재하면 psot/form.jsp를 반환한다.
*/
public class FormController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 세션에서 로그인된 사용자정보를 조회한다.
		// 로그인된 사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL을 반환한다.
		HttpSession session = request.getSession();
		if (session.getAttribute("loginUserId") == null) {
		return "redirect:/app/user/loginform.hta?error=deny";
		}
	
		// 세션에 로그인된 사용자정보가 존재하면 post/form.jsp를 반환한다.
		return "post/form.jsp";
	}
}

> 실행결과 (로그인 전)
![](https://velog.velcdn.com/images/hcw0709/post/d25ae7f6-5c13-4bf5-8877-23224f251b36/image.png)

> 실행결과 (로그인 후)
![](https://velog.velcdn.com/images/hcw0709/post/3f1269be-3ca5-42b6-9894-0c220c0b4114/image.png)

> **글 등록**

InsertController
package com.sample.app.controller.post;

import com.sample.app.dao.PostDao;
import com.sample.app.vo.Post;
import com.sample.model2.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

/*

  • 요청 URI

  • 	/post/insert.hta
  • 요청 파라미터

  • 	title
  • 	content
  • 반환값

  • 	redirect:/app/user/loginform.hta?error=deny
  • 	redirect:list.hta
  • 요청처리 내용

  • 	세션에서 로그인된 사용자 정보를 조회한다.
  • 	사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL("redirect:/app/user/loginform.hta?error=deny")을 반환한다.
  • 	요청파라미터값을 조회한다.
  • 	Post객체를 생성해서 제목, 로그인한 사용자 아이디, 내용을 저장한다.
  • 	PostDao의 insertPoset(Post post)를 호출해서 게시글 정보를 저장시킨다.
  • 	게시글 목록을 요청하는 재요청 URL을 반환한다.

    */
    public class InsertController implements Controller {

    @Override
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	
    	// 세션에서 로그인된 사용자정보를 조회한다.
    	// 로그인된 사용자정보가 존재하지 않으면 로그인폼을 요청하는 재요청 URL을 반환한다.
    	HttpSession session = request.getSession();
    	if (session.getAttribute("loginUserId") == null) {
    		return "redirect:/app/user/loginform.hta?error=deny";
    	}
    	
    	String loginUserId = (String) session.getAttribute("loginUserId");
    	
    	// 요청 파라미터값을 조회한다.
    	String title = request.getParameter("title");
    	String content = request.getParameter("content");
    	
    	// Post객체를 생성해서 게시글 제목, 내용, 로그인한 사용자 아이디를 대입한다.
    	Post post = new Post();
    	post.setTitle(title);
    	post.setUserId(loginUserId);
    	post.setContent(content);
    	
    	// PostDao객체의 insertPost(Post post) 메소드를 호출해서 게시글 정보를 저장한다.
    	PostDao postDao = PostDao.getInstance();
    	postDao.insertPost(post);
    	
    	// 게시글 목록을 요청하는 재요청 URL을 반환한다.
    	return "redirect:list.hta";
    }

    }


> 실행결과


> **리스트 출력**
ListController

package com.sample.app.controller.post;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sample.app.dao.PostDao;
import com.sample.app.dto.PostListDto;
import com.sample.model2.Controller;
import com.sample.util.Pagination;
import com.sample.util.StringUtils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/*
 * 요청 URI
 * 		/post//list.hta
 * 		/post/list.hta?page=2
 * 요청파라미터
 * 		page
 * 반환값
 * 		post/list.jsp
 * 요청처리 내용
 * 		요청파라미터에서 페이지번호를 조회한다.

총 데이터갯수를 조회한다.
페이징처리 처리를 위한 Pagination객체 생성
게시글 목록 조회범위를 계산해서 Map 객체에 저장한다.
PostDao의 getPosts(Map<String, Object> param) 메소드를 실행해서 게시글을 조회한다.
*
조회된 게시글목록을 요청객체의 속성으로 저장한다.
생성된 Pagination 객첼르 요청객체의 속성으로 저장한다.
*
게시글 목록정보와 페이징정보를 표시하는 jsp 페이지를 반환한다.
/

public class ListController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 요청 파라미터값을 조회한다.
		int currentPage = StringUtils.stringToInt(request.getParameter("page"), 1);

      PostDao postDao = PostDao.getInstance();
		// 총 게시글 갯수를 조회하고, Pagination객체를 생성한다.
		int totalRows = postDao.getTotalRows();
		Pagination pagination = new Pagination(currentPage, totalRows);
	
		// 게시글 목록 조회에 필요한 정보를 저장하는 Map 객체를 생성한다.
		Map<String, Object> param = new HashMap<>();
		param.put("begin", pagination.getBegin());
		param.put("end", pagination.getEnd());
	
		// PostDao의 getPosts(Map<String, Object> param)메소드를 실행시켜서 게시글 목록을 조회한다.
		List<PostListDto> postListDtos = postDao.getPosts(param);
	
		// 요청객체의 속성으로 게시글 목록정보를 저장한다.
		request.setAttribute("posts", postListDtos);
		// 요청객체의 속성으로 페이징처리 정보를 저장한다.
		request.setAttribute("pagination", postListDtos);
	
		// 내부이동할 jsp 페이지를 반환한다.
		return "post/list.jsp";
	}
}
list.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>게시글 목록을 확인하세요. 
		<c:if test="${not empty loginUserId }">
			<a href="form.hta" class="btn btn-primary btn-sm float-end">새 글쓰기</a>
		</c:if>
	  </p>
		<table class="table table-sm">
			<colgroup>
				<col width="10%">
				<col width="*">
				<col width="10%">
				<col width="10%">
				<col width="7%">
				<col width="15%">
			</colgroup>
			<thead>
				<tr>
					<th>번호</th>
					<th>제목</th>
					<th class="text-center">작성자</th>
					<th class="text-center">조회수</th>
					<th class="text-center">댓글수</th>
					<th class="text-center">등록일</th>
				</tr>
			</thead>
			<tbody>
			  <c:choose>
			  	<c:when test="${empty posts }">
					<tr>
						<td colspan="6" class="text-center">게시글이 없습니다.</td>
					</tr>	
			  	</c:when>
			  	<c:otherwise>
			  		<%--
			  			${posts}는 List<PostListDto> 객체가 조회된다.
			  			<c:forEach />는 List<PostListDto> 객체에 저장된 PostListDto의 갯수만큼 컨텐츠를 반복해서 출력한다.
			  			var="dto"는 List<PostListDto>객체에서 순서대로 하나씩 조회한 PostListDto 객체가 대입된다.
			  			${dto.no }는 PostListDto객체의 멤버변수 no에 저장된 값을 출력한다.
			  		--%>
			  		<c:forEach var="dto" items="${posts }">
						<tr>
							<td>${dto.no }</td>
							<td><a href="detail.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>
			  	</c:otherwise>
			  </c:choose>
			</tbody>
		</table>
		
		<nav>
			<ul class="pagination pagination-sm justify-content-center">
				<li class="page-item"><a class="page-link" href="list.hta?page=1">이전</a></li>
				<li class="page-item"><a class="page-link" href="list.hta?page=1">1</a></li>
				<li class="page-item"><a class="page-link active" href="list.hta?page=2">2</a></li>
				<li class="page-item"><a class="page-link" href="list.hta?page=3">3</a></li>
				<li class="page-item"><a class="page-link" href="list.hta?page=4">4</a></li>
				<li class="page-item"><a class="page-link" href="list.hta?page=2">다음</a></li>
			</ul>
		</nav>
	</div>
</div>
```

실행결과

list.hta의 구조

insert.hta의 잘못된 구조

list와 insert의 차이

  • list는 조회이므로 데이터가 많이 필요하지 않기 때문에 redirect가 필요 없다.
  • insert는 추가 /변경 /삭제 작업 중 하나이기 때문에 따로 또 조회를 하는 작업이 더 필요하다. 그렇기 때문에 redirect가 필요하다.

상세정보

DetailController

package com.sample.app.controller.post;

import java.util.List;

import com.sample.app.dao.CommentDao;
import com.sample.app.dao.PostDao;
import com.sample.app.dto.CommentListDto;
import com.sample.app.dto.PostDetailDto;
import com.sample.model2.Controller;
import com.sample.util.StringUtils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/*
 * 요청 URI
 * 		/post/detail.hta
 * 요청 파라미터
 * 		postNo
 * 반환값
 * 		post/detail.jsp
 * 요청처리 내용
 * 		요청파라미터로 전달된 게시글번호를 조회한다.
 * 		PostDao객체의 getPostByNo(int postNo)를 실행해서 게시글 번호에 해당하는 게시글 상세정보를 조회한다.
 * 		CommentDao객체의 getCommentsByPostNo(int postNo)를 실행해서 게시글 번호에 해당하는 댓글목록을 조회한다.
 * 		요청객체의 속성으로 조회된 게시글 정보를 저장한다.
 * 		요청객체의 속성으로 조회된 댓글목록 정보를 저장한다.
 * 		
 * 		게시글 상세정보와 댓글 목록을 표시하는 jsp 페이지를 반환한다.
 */

public class DetailController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 요청파라미터 값을 조회한다.
		int postNo = StringUtils.stringToInt(request.getParameter("postNo"));
		
		PostDao postDao = PostDao.getInstance();
		CommentDao commentDao = CommentDao.getInstance();
		
		// 게시글 번호에 해당하는 게시글 상세정보를 조회한다.
		PostDetailDto dto = postDao.getPostByNo(postNo);
		// 게시글 번호에 해당하는 댓글 목록 정보를 조회한다.
		List<CommentListDto> commentListDtos = commentDao.getCommentsByPostNo(postNo);
		
		// 요청객체의 속성으로 게시글정보의 댓글목록정보를 저장한다.
		request.setAttribute("post", dto);
		request.setAttribute("comments", commentListDtos);
		
		return "post/detail.jsp";
	}
}
detail.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>게시글 상세정보를 확인하세요. <button class="btn btn-primary btn-sm float-end" data-bs-toggle="modal" data-bs-target="#modal-form-comments">댓글 쓰기</button></p>
			<table class="table table-sm">
				<colgroup>
					<col width="15%">
					<col width="35%">
					<col width="15%">
					<col width="35%">
				</colgroup>
				<tbody>
					<tr>
						<th>제목</th>
						<td colspan="3">${post.title }</td>
					</tr>
					<tr>
						<th>번호</th>
						<td>${post.no }</td>
						<th>작성자</th>
						<td>${post.userName }</td>
					</tr>
					<tr>
						<th>등록일</th>
						<td><fmt:formatDate value="${post.createdDate }" /></td>
						<th>최종수정일</th>
						<td><fmt:formatDate value="${post.updatedDate }" /></td>
					</tr>
					<tr>
						<th>조회수</th>
						<td><fmt:formatNumber value="${post.readCount }" /></td>
						<th>댓글수</th>
						<td><fmt:formatNumber value="${post.commentCount }" /></td>
					</tr>
					<%-- 
					그냥 ${post.content}로 했을 때는 혹시나 누군가가 글 등록 시 나쁜 짓을 할 수 있으므로 
					밑의 c:out 방식이나 textarea 방식으로 해야 한다.
					그런데 그냥 c:out만 하면 들여쓰기나 줄 바꿈이 안되므로
					
					<tr>
						<th>내용</th>
						<td colspan="3"><textarea rows="5" class="form-control" readonly="readonly">${post.content }</textarea></td>
					</tr>
					--%>
					<tr>
						<th>내용</th>
						<td colspan="3"><c:out value="${post.content }" /></td>
					</tr>
					<%-- 
					<tr>
						<th>내용</th>
						<td colspan="3">&lt;script&gt;<br>alert('안녕')<br>&lt;/script&gt;</td>
					</tr>
					--%>
				</tbody>
			</table>
		</div>
	</div>
	<div class="row mb-3">
		<div class="col-12">
			<a href="modifyform.hta?postNo=100" class="btn btn-warning btn-sm">수정</a>
			<a href="delete.hta?postNo=100" class="btn btn-danger btn-sm">삭제</a>
		</div>
	</div>
	<div class="row mb-3">
		<div class="col">
			<div class="border p-3">
				<p class="mb-0 small">
					<span>홍길동</span> <span class="text-muted float-end">2022-12-11</span>
				</p>
				<p>
					댓글내용입니다. 댓글 내용입니다.
					<a href="deleteComment.hta?postNo=100&commentNo=1000" class="float-end"><i class="bi bi-trash-fill text-danger"></i></a>
				</p>
			</div>
		</div>
	</div>
</div>
<!-- 댓글 등록폼 -->
<div class="modal" tabindex="-1" id="modal-form-comments">
	<div class="modal-dialog">
		<form id="form-add-depts" class="p-3" method="post" action="insertComment.hta">
		<input type="hidden" name="postNo" value="100">
		<div class="modal-content">
			<div class="modal-header">
				<h5 class="modal-title">댓글 등록폼</h5>
				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
			</div>
			<div class="modal-body">
					<div class="row mb-2">
						<div class="col-sm-12">
							<textarea class="form-control" rows="3" name="content"></textarea>
						</div>
					</div>
			</div>
			<div class="modal-footer">
				<button type="button" class="btn btn-secondary btn-xs" data-bs-dismiss="modal">닫기</button>
				<button type="submit" class="btn btn-primary btn-xs">등록</button>
			</div>
		</div>
		</form>
	</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>

실행결과 (${post.content} 로 실행 시)

실행결과 (<c:out value="${post.content }" /> 로 실행 시)

  • 그냥 ${post.content}로 실행시 혹시나 누군가가 나쁜짓을 하기 위해 위의 결과처럼 실행된다.
  • 그래서 아래처럼 c:out방식을 이용하여 실행 시 나쁜 짓을 했어도 그대로 내용으로 화면에 출력된다.
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글