이전 게시글은 여기
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기(19) - 파일 업로드를 이용해 프로필 사진 넣기
덧글은 무엇으로 이루어져 있을까?
유저의 프로필 사진, 유저의 이름, 내용, 삭제 수정 버튼이 있다.
이 포스트에서는 덧글을 쓰고 유저의 사진, 이름, 내용을 도출하는 코드만 쓴다.
먼저 덧글을 쓰는 jsp는 다음과 같다. 상세보기 페이지, 게시물의 내용을 띄우는 div 박스 아래에 띄운다.
-detail.jsp
<hr />
<!-- 댓글 박스 -->
<div class="row bootstrap snippets">
<div class="col-md-12">
<div class="comment-wrapper">
<div class="panel panel-info">
<div class="panel-heading m-2"><b>Comment</b></div>
<div class="panel-body">
<textarea id="reply__write__form" class="form-control" placeholder="write a comment..." rows="3"></textarea>
<br>
<button onclick="replyWrite(${detailDto.boardDto.board.id}, ${sessionScope.principal.id })" class="btn btn-primary pull-right">댓글쓰기</button>
<div class="clearfix"></div>
<hr />
<!-- 댓글 리스트 시작-->
<ul id="reply__list" class="media-list">
<c:forEach var="replyDto" items="${detailDto.replysDto }">
<!-- 댓글 아이템 -->
<li class="media">
<img onerror="this.src='/blog/image/userProfile.png'" src="${replyDto.userProfile }" class="img-circle">
<div class="media-body">
<strong class="text-primary">${replyDto.username }</strong>
<p>
${replyDto.reply.content }
</p>
</div>
</li>
</c:forEach>
</ul>
<!-- 댓글 리스트 끝-->
</div>
</div>
</div>
</div>
</div>
<!-- 댓글 박스 끝 -->
천천히 봅시다.
textarea에 js를 적용할때 찾을 수 있도록 아이디를 걸어둡니다.
그리고 버튼에는 버튼을 눌렀을 때 작동할 function을 설정합니다. 우리가 덧글을 쓸 땐 뭐가 필요할까요? 이 글을 쓰는 사람과, 그 덧글이 쓰이는 내용이 들어가므로 변수에 아이디와 게시글 아이디를 받아서 자바스크립트 함수에 넘기게 된다.
(함수는 좀 있다 이야기 합시다)
댓글 리스트에는 받아온 값들을 list로 만들어 foreach문으로 출력한다.
이제 함수에 대해서 얘기해봅시다.
function replyWrite(boardId, userId){
console.log(userId);
if(userId===undefined){
alert("로그인이 필요합니다.");
return;
}
var data= {
boardId : boardId,
userId: userId,
content : $("#reply__write__form").val()
};
$.ajax({
type: "post",
url : "/blog/reply?cmd=writeProc",
data : JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json"
}).done(function(result){
//정상응답
if(result==-1 || result==0){
alert("덧글 등록 실패");
}else{
//1.reply__list를 찾아 비우기
alert("덧글 등록 성공");
$("#reply__list").empty();
console.log(result);
//2.ajax 재호출 findAll()
renderReplyList(result);
//3.reply__list를 찾아 내부에 채워주기
$("#reply__write__form").val("");
}
}).fail(function(error){
alert("덧글 등록 실패");
});
}
function renderReplyList(replyDtos){
for (var replyDto of replyDtos) {
$("#reply__list").append(makeReplyItem(replyDto));
//reply-id 추가 시작
var replyItem = `<li id="reply-${replyDto.reply.id }" class="media">`;
//reply-id 추가 끝
}
}
function makeReplyItem(replyDto) {
var replyItem=`<li class = "media">`;
if(replyDto.userProfile ==null){
replyItem+=`<img src="/blog/image/userProfile.png" class="img-circle">`;
}else{
replyItem+=`<img src="${replyDto.userProfile}" class="img-circle">`;
}
replyItem += `<div class ="media-body">`;
replyItem += `<strong class="text-primary">${replyDto.username}</strong>`;
replyItem += `<p>${replyDto.reply.content}</p>`;
replyItem += `</div>`;
//휴지통 추가 시작
replyItem += `<div class="m-3">`;
replyItem += `<i onclick="replydelete(${replyDto.reply.id})" style="cursor : pointer;" class="Tiny material-icons">delete</i>`;
replyItem += `</div>`;
replyItem += `</li>`;
return replyItem;
}
ajax로 받는 이유는 전체 DOM을 받아서 리로드하는 것은 시간이 오래걸리기 때문에 일부 dom(일부 <div>)만 리로드 하는 것이 목적이다. 여기서는 덧글을 담는 <div>만 리로드 한다.
일단 내가 쓸 덧글을 ajax 통신으로 액션으로 보낸다.
여기서 앞에서 매개변수를 지정한 이유와 id를 지정한 이유를 볼 수 있다.
ajax로 내가 데이터를 보낼 url을 지정하고, 데이터를 설정한다.
데이터는 세 가지를 보내야 하니까, 이것을 Json 데이터로 묶어서 보낸다. 그래서 JSON.stringify함수를 통해 string을 json으로 변환한다.
json으로 보내니까, 보내는 컨텐츠 타입과 데이터 타입을 지정한다.
이제 정상응답을 보내줄 액션을 만들자.
-ReplyController.java
reply 역시 다른 controller과 같은 방식을 공유한다.
package com.cos.blog.controller;
import java.io.IOException;
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.cos.blog.action.Action;
import com.cos.blog.action.board.BoardDeleteProcAction;
import com.cos.blog.action.board.BoardDetailAction;
import com.cos.blog.action.board.BoardHomeAction;
import com.cos.blog.action.board.BoardSearchAction;
import com.cos.blog.action.board.BoardUpdateAction;
import com.cos.blog.action.board.BoardUpdateProcAction;
import com.cos.blog.action.board.BoardWriteAction;
import com.cos.blog.action.board.BoardWriteProcAction;
import com.cos.blog.action.reply.ReplyDeleteProcAction;
import com.cos.blog.action.reply.ReplyWriteProcAction;
import com.cos.blog.action.user.UsersLoginAction;
// http://localhost:8000/blog/board
@WebServlet("/reply")
public class ReplyController extends HttpServlet {
private final static String TAG = "ReplyController : ";
private static final long serialVersionUID = 1L;
public ReplyController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doProcess(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doProcess(request, response);
}
protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// http://localhost:8000/blog/user?cmd=join
String cmd = request.getParameter("cmd");
System.out.println(TAG+"router : "+cmd);
Action action = router(cmd);
action.execute(request, response);
}
public Action router(String cmd) {
if(cmd.equals("writeProc")) {
// 홈페이지로 이동
return new ReplyWriteProcAction(); //Board의 목록
}
return null;
}
}
라우터를 통해 해당 액션과 연결하고.
-ReplyWriteProcAction.java
package com.cos.blog.action.reply;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.cos.blog.action.Action;
import com.cos.blog.dto.ReplyResponseDto;
import com.cos.blog.model.Reply;
import com.cos.blog.repository.ReplyRepository;
import com.cos.blog.util.Script;
import com.google.gson.Gson;
public class ReplyWriteProcAction implements Action {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//form 타입이 아니고 json이기 때문에 request.getParameter 못씀
BufferedReader br=request.getReader();
StringBuffer sb= new StringBuffer();
String input=null;
while((input=br.readLine())!=null) {
sb.append(input);
}
System.out.println(sb.toString());
Gson gson=new Gson();
Reply reply=gson.fromJson(sb.toString(), Reply.class);
//ReplyRepository 연결 - save(reply)
//script.outText()응답
ReplyRepository replyRepository=ReplyRepository.getInstance();
int result=replyRepository.save(reply);
//save 성공하면 1 실패하면 0,1
if(result==1) {
List<ReplyResponseDto> replyDtos =replyRepository.findAll(reply.getBoardId());
String replyDtosJson=gson.toJson(replyDtos);
Script.outJson(replyDtosJson, response);
}else {
Script.outText("error", response);
}
}
}
json타입은 key-value형태로 값을 받지 않기 때문에 json은 getParameter형태로 값을 불러 올 수 없다. 그렇기 때문에 getReader()로 불러와서 이것을 Buffer로 받는다.
받아서 append 해서 붙여준 StringBuffer의 형태를 String 형태로 변환하여 Reply 형태 객체에 담고 이 객체로 데이터베이스에 접근한다.
접근해서 받은 값이, update에 성공하여 1을 반환하면 등록된 값을 이용하여 게시판 매개변수를 where절에 넣고 이 값을 다시 json 데이터로 변환시켜 응답한다.
-ReplyResponsitory.java의 덧글 등록 쿼리와 덧글 불러오기 쿼리
public int save(Reply reply) {
final String SQL="insert into reply(id,userId,boardid,content,createdate) values (reply_SEQ.nextval,?,?,?,sysdate)";
try {
conn=DBConn.getConnection();
pstmt = conn.prepareStatement(SQL);
//물음표 완성하기
pstmt.setInt(1, reply.getUserId());
pstmt.setInt(2, reply.getBoardId());
pstmt.setString(3, reply.getContent());
return pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
System.out.println(TAG+"save : "+e.getMessage());
}finally {
DBConn.close(conn, pstmt);
}
return -1;
}
public List<ReplyResponseDto> findAll(int boardId) {
StringBuffer sb= new StringBuffer();
sb.append("select r.id, r.userId, r.boardId, r.content, r.createDate, ");
sb.append(" u.username, u.userprofile ");
sb.append("from reply r inner join users u ");
sb.append("on r.userid=u.id ");
sb.append("where boardid=? ");
sb.append("order by r.id desc");
final String SQL=sb.toString();
List<ReplyResponseDto> replyDtos=null;
try {
conn=DBConn.getConnection();
pstmt = conn.prepareStatement(SQL);
//물음표 완성하기
pstmt.setInt(1, boardId);
rs=pstmt.executeQuery();
replyDtos=new ArrayList<>();
while(rs.next()){
Reply reply=Reply.builder()
.id(rs.getInt(1))
.userId(rs.getInt(2))
.boardId(rs.getInt(3))
.content(rs.getString(4))
.createDate(rs.getTimestamp(5))
.build();
ReplyResponseDto replydto=ReplyResponseDto.builder()
.reply(reply)
.username(rs.getString(6))
.userProfile(rs.getString(7))
.build();
replyDtos.add(replydto);
}
이렇게 불러온 값을 자바스크립트 for in 구문을 통해 받은 배열만큼 값을 순환시키고, 순환 될때마다 받아온 덧글창이 만들어지고(html 함수를 백틱을 통해 추가했다.) 이 만들어진 html 코드가 empty된 공간 안에 랜더링 된다.
다음처럼 굳이 새로고침 하지 않아도 ajax 통신을 통해 덧글창만 새로 쓰였다.
'JSP' 카테고리의 다른 글
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기 20.06.15 완성 깃허브, 영상 (0) | 2020.06.15 |
---|---|
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기(21) - ajax를 이용한 덧글 삭제 구현하기 (0) | 2020.06.15 |
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기(19) - 파일 업로드를 이용해 프로필 사진 넣기 (0) | 2020.06.12 |
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기(18) - 키워드를 이용한 검색 만들기 (0) | 2020.06.12 |
Servlet 과 JSP를 이용한(모델2 형식) 블로그 만들기(17) - 쿠키를 이용한 새로고침 시 조회수 무한 증가 방어 (0) | 2020.06.12 |