화면까지 구성했고 어떤 식으로 주소매핑을 해야 할지 정했다.
이번에는 주소매핑에서 mapper까지 설정해 보도록 하겠다.
이전글에서 Update로 되어있는 부분은 Insert로 수정하였다.
댓글을 작성하고 작성 버튼을 누르면 /board/replyInsertPro 여기서 댓글을 작성하는 처리과정을 거치게 된다. 이 과정부터 시작해 보도록 하자
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO, Model model) {
System.out.println("BoardController replyInsertPro()");
BoardDTO boardDTO = new BoardDTO();
boardService.replyUpdatePro(replyDTO);
return "redirect:/board/content?no="+boardDTO.getNo();
}
작성하고 나니 굳이 BoardDTO 객체를 안에서 작성할 필요는 없을 것 같다는 생각이 들었다.
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsert()");
boardService.replyInsert(replyDTO);
return "redirect:/board/content?no="+boardDTO.getNo();
}
Controller에서 return 값을 저렇게 써본적은 처음인데 잘 될 거라고 생각한다.
BoardService
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardService replyInsert()");
replyDTO.setNum(boardDAO.getMaxNum()+1); //댓글 번호(PK) 값 설정
replyDTO.setReplyWriteTime(new Timestamp(System.currentTimeMillis())); //댓글 작성 시간
boardDAO.replyInsert(replyDTO);
}
댓글 번호는 PK라 어디 보이지 않아도 반드시 필요한 값, 댓글 작성 시간도 따로 값을 지정해주지 않았기 때문에 Service에서 설정이 필요함. 비밀글 처리를 jsp에서 해줘야 할지 Service에서 해야 할지 잘 모르겠다.
BoardDAO
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardDAO replyInsert()");
sqlSession.insert(namespace+".replyInsert", replyDTO);
}
public int getMaxNum() {
System.out.println("BoardDAO getMaxNum()");
return sqlSession.selectOne(namespace+".getMaxNum");
}
boardMapper
<insert id="replyInsert">
insert into reply(num,id,replyContent,replyHidden,replyWriteTime,re_ref,re_lev,re_sql)
values(#{num},#{id},#{replyContent},#{replyHidden},#{replyWriteTime},#{re_ref},#{re_lev},#{re_sql})
</insert>
<select id="getMaxNum" resultType="java.lang.Integer">
select max(num) from reply
</select>
뭔가 실행하면 오류가 날 것 같다만 일단 실행해보도록 해야겠다.
역시 오류가 뜬다. 어디의 값이 문제인지 toString을 오버라이딩해서 알아보도록 하자
ReplyDTO
@Override
public String toString() {
return "ReplyDTO [id=" + id + ", replyContent=" + replyContent + ", replyHidden=" + replyHidden
+ ", replyWriteTime=" + replyWriteTime + ", re_ref=" + re_ref + ", re_lev=" + re_lev + ", re_seq="
+ re_seq + ", num=" + num + "]";
}
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsert()");
boardService.replyInsert(replyDTO);
replyDTO.toString();
return "redirect:/board/content?no="+boardDTO.getNo();
}
그럼에도 계속해서 똑같은 오류가 난다.
content.jsp에서 댓글form에 num을 hidden으로 넣어보았다. 아마 num값이 넘어오지 않아서 그런가 싶다는 생각이 들었다.
<hr>
댓글<br>
<form action="${pageContext.request.contextPath}/board/replyInsertPro" method="post">
<input type="hidden" name="num">
<input type="text" name="id" value="${sessionScope.id }" readonly="readonly"><br>
<textarea rows="5" cols="30" style="width: 792px; height: 60px" placeholder="내용을 작성해주세요." name="replyContent"></textarea><br>
<span style="float: right;"><input type="checkbox" name="replyHidden">비밀글 <input type="submit" value="작성"></span>
</form>
댓글 목록<br>
이곳에 댓글 목록이 나타남. 작성자 - 댓글 내용 순으로
</div> <%-- content영역 div --%>
이러한 문제를 직면했다. 전에 프로젝트할 때 이러한 상황을 경험했다. 타입이 맞지 않아서 생긴 걸로 기억하는데 자세히 알아보기 위해 검색해 보았다.
HTTP 에러 코드
- 400 : 잘못된 요청으로 문법상 오류가 있어서 서버가 요청을 이해하지 못한 경우 → 잘못입력한 url인 경우가 많음
- 404 : 클라이언트가 요청한 문서를 찾지 못한 경우 → url이나 캐시 삭제
- 405 : request라인에 명시된 메소드를 수행하기 위한 해당 자원의 이용이 허용되지 않았을 경우
- 415 : 지원되지 않는 형식으로 클라이언트가 요청해서 서버가 요청에 대한 승인을 거부한 경우
- 500 : 웹 서버가 요청사항을 수행할 수 없는 경우
참고 : https://donggu1105.tistory.com/145
댓글을 작성했을 때 콘솔창은
replyInsertPro()까지 가지 않을 것을 확인할 수 있다.
이전 글을 확인해 보니 빠진 부분이 있었다. content.jsp 주소매핑과정에서 ReplyDTO도 추가해줘야 한다는 것이다.
@GetMapping("/content")
public String content(BoardDTO boardDTO, ReplyDTO replyDTO, Model model) {
System.out.println("BoardController Content()");
boardDTO = boardService.getBoard(boardDTO); //글에 대한 정보
boardService.readCount(boardDTO); //조회수
model.addAttribute("boardDTO",boardDTO);
model.addAttribute("replyDTO",replyDTO);
return "board/content";
}
이러거나 저러거나 400 오류가 발생함 해당 오류가 발생할 수 있는 이유에 대해서 조금 더 구체적으로 알아보았다.
400 오류가 발생하는 이유
- 필수 입력 누락
- 잘못된 URL 요청
- HTTP 메소드 문제
- 서버 세션 유효성 문제
- 폼 데이터 불일치
- 잘못된 데이터 타입
- Ajax 요청 시 처리 문제
- CORS 정책 문제
이걸 찾아보니 아무래도 비밀글 체크박스와 관련되어 문제가 생긴 것 같다. true 또는 false가 넘어가야 하고, db에는 0 또는 1로 받아져야 하기 때문이다.
이를 체크박스로 해결하려고 하니 어떻게 해야 할지 좀 막막했다. 그래서 알아보니
content.jsp에
<input type="checkbox" name="replyHidden" value="true">비밀글
<input type="hidden" name="replyHidden" value="false">
이렇게 하면 체크박스가 체크되었을 때는 true가 전송되고, 체크되지 않았을 때 false가 전송되게 할 수 있다.
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsertPro()");
//replyHidden을 boolean으로 변환
if("true".equals(replyDTO.isReplyHidden())) {
replyDTO.setReplyHidden(true);
} else {
replyDTO.setReplyHidden(false);
}
boardService.replyInsert(replyDTO);
return "board/content?no="+boardDTO.getNo();
}
replyHidden값을 처리...
이렇게 했음에도 여전히 문제가 생긴다.
원인을 찾지 못했다. 원인이 될 부분만 찾아보았다.
- 폼 데이터 문제
→ num이 비어있으므로 번호를 제대로 설정 - DTO 데이터 처리
→ isReplyHidden() 메소드는 boolean값을 반환해야 함 - 리다이렉션 return
→ "board/content?no=" 는 단순히 URL을 반환 - DAO 및 매퍼 설정
content.jsp
<hr>
댓글<br>
<form action="${pageContext.request.contextPath}/board/replyInsertPro" method="post">
<input type="hidden" name="num" value="${replyDTO.num }">
<input type="text" name="id" value="${sessionScope.id }" readonly="readonly"><br>
<textarea rows="5" cols="30" style="width: 792px; height: 60px" placeholder="내용을 작성해주세요." name="replyContent"></textarea><br>
<span style="float: right;"><input type="checkbox" name="replyHidden" value="true">비밀글 <input type="hidden" name="replyHidden" value="false"><input type="submit" value="작성"></span>
</form>
댓글 목록<br>
이곳에 댓글 목록이 나타남. 작성자 - 댓글 내용 순으로
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsertPro()");
//replyHidden을 boolean으로 변환
if("true".equals(replyDTO.getReplyHidden())) {
replyDTO.setReplyHidden(true);
} else {
replyDTO.setReplyHidden(false);
}
boardService.replyInsert(replyDTO);
return "redirect:/board/content?no="+boardDTO.getNo();
}
BoardService, BoardDAO, boardMapper는 그대로 놔둠.
댓글 작성하니 이번엔
문법오류인가? 일단 검색해 보니 Project - Clean 했을 경우 문제가 해결된다고 한다.
혹시 몰라서 Tomcat까지 Clean을 하고 restart 하고 댓글 작성하니
다시 NullPointerException 발생. 그래도 희망적인 사실은 400 오류 떴을 때보다 콘솔에서 더 많이 진행됨을 확인할 수 있었다.
num값이 넘어오지 못하는 것 같다. 가장 쉬운 방법은 db에서 auto_increment 속성을 추가해 주면 될 것 같은데.. 그렇다면 auto_increment 속성을 추가해 보자. 어차피 reply 테이블의 num 컬럼은 테이블의 기본키를 위한 의미 없는 컬럼이기 때문에 바꿔도 상관없을 것 같다.
추가적으로도 NullPointerException이 발생하였다. 이 과정에서 auto_increment 속성을 걸어뒀는데 getMaxNum()이 필요할까? content.jsp에 num값을 넘겨줘야 할까? BoardController에 replyHidden을 또 boolean으로 변환하는 것이 필요할까?
즉 아래와 같이 변경했다.
content.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>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
</style>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>글 읽기</h1>
<table >
<tr><td>글번호</td><td>${boardDTO.no}</td></tr>
<tr><td>글쓴이</td><td>${boardDTO.id}</td></tr>
<tr><td>조회수</td><td>${boardDTO.readcount}</td></tr>
<tr><td>작성일</td><td>${boardDTO.writetime}</td></tr>
<tr><td>글제목</td><td>${boardDTO.subject}</td></tr>
<tr><td>글내용</td><td>${boardDTO.content}</td></tr>
</table>
<div style="display: center">
<c:if test="${!empty sessionScope.id }">
<c:if test="${sessionScope.id eq boardDTO.id}">
<a href="${pageContext.request.contextPath}/board/update?no=${boardDTO.no}"><input type="button" value="글 수정"></a> <a href="${pageContext.request.contextPath}/board/delete?no=${boardDTO.no}"><input type="button" value="글 삭제"></a>
</c:if>
</c:if>
<a href="${pageContext.request.contextPath}/board/list"><input type="button" value="글 목록"></a>
</div>
<hr>
댓글<br>
<form action="${pageContext.request.contextPath}/board/replyInsertPro" method="post">
<input type="text" name="id" value="${sessionScope.id }" readonly="readonly"><br>
<textarea rows="5" cols="30" style="width: 792px; height: 60px" placeholder="내용을 작성해주세요." name="replyContent"></textarea><br>
<span style="float: right;"><input type="checkbox" name="replyHidden" value="true">비밀글 <input type="hidden" name="replyHidden" value="false"><input type="submit" value="작성"></span>
</form>
댓글 목록<br>
이곳에 댓글 목록이 나타남. 작성자 - 댓글 내용 순으로
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsertPro()");
//replyHidden을 boolean으로 변환
// if("true".equals(replyDTO.getReplyHidden())) {
// replyDTO.setReplyHidden(true);
// } else {
// replyDTO.setReplyHidden(false);
// }
boardService.replyInsert(replyDTO);
return "redirect:/board/content?no="+boardDTO.getNo();
}
BoardSerivce
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardService replyInsert()");
// replyDTO.setNum(boardDAO.getMaxNum()+1); //댓글 번호(PK) 값 설정
replyDTO.setReplyWriteTime(new Timestamp(System.currentTimeMillis())); //댓글 작성 시간
boardDAO.replyInsert(replyDTO);
}
BoardDAO
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardDAO replyInsert()");
sqlSession.insert(namespace+".replyInsert", replyDTO);
}
// public int getMaxNum() {
// System.out.println("BoardDAO getMaxNum()");
// return sqlSession.selectOne(namespace+".getMaxNum");
// }
boardMapper
<insert id="replyInsert">
insert into reply(num,id,replyContent,replyHidden,replyWriteTime)
values(#{num},#{id},#{replyContent},#{replyHidden},#{replyWriteTime})
</insert>
<!-- <select id="getMaxNum" resultType="java.lang.Integer"> -->
<!-- select max(num) from reply -->
<!-- </select> -->
이렇게 하고 댓글을 작성했다.
여전히 오류가 발생하지만 발생하는 이유는 주소줄에서 no=0이라 그런 것 같다. 기존의 no값을 넘겨갈 줄 알았는데 아닌 것 같다. 그래도 값은 들어간 것 같아서 확인해 봤다.
content.jsp에 jstl을 이용해서 나타내기를 하면 될 것 같고, no값이 제대로 받아올 수 있게 수정하면 얼추 될 것 같다.
일단 몇몇 수정
<%@ 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>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
</style>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>글 읽기</h1>
<table >
<tr><td>글번호</td><td>${boardDTO.no}</td></tr>
<tr><td>글쓴이</td><td>${boardDTO.id}</td></tr>
<tr><td>조회수</td><td>${boardDTO.readcount}</td></tr>
<tr><td>작성일</td><td>${boardDTO.writetime}</td></tr>
<tr><td>글제목</td><td>${boardDTO.subject}</td></tr>
<tr><td>글내용</td><td>${boardDTO.content}</td></tr>
</table>
<div style="display: center">
<c:if test="${!empty sessionScope.id }">
<c:if test="${sessionScope.id eq boardDTO.id}">
<a href="${pageContext.request.contextPath}/board/update?no=${boardDTO.no}"><input type="button" value="글 수정"></a> <a href="${pageContext.request.contextPath}/board/delete?no=${boardDTO.no}"><input type="button" value="글 삭제"></a>
</c:if>
</c:if>
<a href="${pageContext.request.contextPath}/board/list"><input type="button" value="글 목록"></a>
</div>
<hr>
댓글<br>
<form action="${pageContext.request.contextPath}/board/replyInsertPro" method="post">
<input type="text" name="id" value="${sessionScope.id }" readonly="readonly"><br>
<textarea rows="5" cols="30" style="width: 792px; height: 60px" placeholder="내용을 작성해주세요." name="replyContent"></textarea><br>
<span style="float: right;"><input type="checkbox" name="replyHidden" value="true">비밀글 <input type="hidden" name="replyHidden" value="false"><input type="submit" value="작성"></span>
</form>
댓글 목록<br>
<c:forEach var="replyDTO" items="${replyList}">
<tr>
<td>${replyDTO.id}</td><td>${replyDTO.replyContent}</td>
</tr>
</c:forEach>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
BoardController
@PostMapping("/replyInsertPro")
public String replyInsertPro(ReplyDTO replyDTO,BoardDTO boardDTO, Model model) {
System.out.println("BoardController replyInsertPro()");
//replyHidden을 boolean으로 변환
// if("true".equals(replyDTO.getReplyHidden())) {
// replyDTO.setReplyHidden(true);
// } else {
// replyDTO.setReplyHidden(false);
// }
boardService.replyInsert(replyDTO);
return "redirect:/board/content?no="+boardDTO.getNo();
}
@GetMapping("/content")
public String content(BoardDTO boardDTO, ReplyDTO replyDTO, Model model) {
System.out.println("BoardController Content()");
boardDTO = boardService.getBoard(boardDTO); //글에 대한 정보
boardService.readCount(boardDTO); //조회수
List<ReplyDTO> replyList = boardService.getReplyList();
model.addAttribute("boardDTO",boardDTO);
model.addAttribute("replyDTO",replyDTO);
return "board/content";
}
BoardSerivce
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardService replyInsert()");
// replyDTO.setNum(boardDAO.getMaxNum()+1); //댓글 번호(PK) 값 설정
replyDTO.setReplyWriteTime(new Timestamp(System.currentTimeMillis())); //댓글 작성 시간
boardDAO.replyInsert(replyDTO);
}
public List<ReplyDTO> getReplyList() {
System.out.println("BoardService getReplyList()");
return boardDAO.getReplyList();
}
BoardDAO
public void replyInsert(ReplyDTO replyDTO) {
System.out.println("BoardDAO replyInsert()");
sqlSession.insert(namespace+".replyInsert", replyDTO);
}
// public int getMaxNum() {
// System.out.println("BoardDAO getMaxNum()");
// return sqlSession.selectOne(namespace+".getMaxNum");
// }
public List<ReplyDTO> getReplyList() {
System.out.println("BoardDAO getReplyList()");
return sqlSession.selectList(namespace+".getReplyList");
}
boardMapper
<insert id="replyInsert">
insert into reply(num,id,replyContent,replyHidden,replyWriteTime)
values(#{num},#{id},#{replyContent},#{replyHidden},#{replyWriteTime})
</insert>
<!-- <select id="getMaxNum" resultType="java.lang.Integer"> -->
<!-- select max(num) from reply -->
<!-- </select> -->
<select id="getReplyList" resultType="com.mystory001.domain.ReplyDTO">
select *
from reply
order by replyWriteTime desc
</select>
문뜩 테이블 설계가 잘 못되었음을 느낀다.
현재 이와같은 ERD인데, 테이블 board와 reply는 no로 연결되어야할 것 같다.
reply 테이블에 no 컬럼을 추가하고 외래키를 지정해주자
다음 ReplyDTO에 no 객체 생성
private int no;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
'organize > 프로젝트' 카테고리의 다른 글
justBoard15 댓글 구현(5) 댓글 페이지 처리 (0) | 2024.10.20 |
---|---|
justBoard14 댓글 구현(4) (0) | 2024.10.15 |
justBoard12 댓글 구현(2) 화면 (1) | 2024.10.12 |
justBoard11 댓글 구현(1) DB (6) | 2024.10.10 |
justBoard10 마무리 (5) | 2024.09.30 |