다가오는 다음을 향해

[Spring MVC] 댓글 구현(게시판 구현 후 ) 본문

국비학원 공부노트/Spring MVC

[Spring MVC] 댓글 구현(게시판 구현 후 )

hyeseo 2022. 4. 14. 00:23

[ 개발환경 ]
MacBook Air M1 2020년형 
eclipse [2021-3 var]
Java [zulu-8]
JSP
Tomcat [Apache Tomcat/9.0.58]

[ version ]
- springframework - 4.3.14
- aspectj - 1.8.9
- Test - 4.12

Maven repository
- mysql-connector-java  8.0.27
- spring-jdbc - 4.3.14
- spring-test - 4.3.14

mybatis - 3.4.4
mybatis-spring - 1.3.1


 

 

댓글 설계 및 구현

 

댓글 구현 Work


 

  1. table 설계
  2. BoardReplyDTO 작성
  3. boardMapper.xml
  4. BoardDAO.java  / BoardDAOImpl.java
  5. BoardService.java  /BoardServiceImpl.java
  6. BoardController.java

 

테이블 설계


Table: board_reply
댓글 번호 bno int(11) PK AI
댓글 작성자 content varchar(45) not null
댓글 내용 id varchar(45) not null
댓글 작성일 regdate datetime
게시판 번호 readcnt int(11)

 

 

BoardReplyDTO


BoardReplyDTO.java

package kr.co.dong.board;

public class BoardReplyDTO {
	
	private int reno; // 댓글번호
	private String rewriter; // 댓글작성자
	private String rememo; // 댓글내용
	private String redate; // 댓글작성일
	private int bno; // 게시판번호

	public int getReno() {
		return reno;
	}

	public void setReno(int reno) {
		this.reno = reno;
	}

	public String getRewriter() {
		return rewriter;
	}

	public void setRewriter(String rewriter) {
		this.rewriter = rewriter;
	}

	public String getRememo() {
		return rememo;
	}

	public void setRememo(String rememo) {
		this.rememo = rememo;
	}

	public String getRedate() {
		return redate;
	}

	public void setRedate(String redate) {
		this.redate = redate;
	}

	public int getBno() {
		return bno;
	}

	public void setBno(int bno) {
		this.bno = bno;
	}

}



 

boardMapper.xml


boardMapper를 작성하기 전

mybatis-config.xml에 BoardReply Type의 별칭을 설정한다.

 

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<typeAliases>
		<typeAlias alias="Board" type="kr.co.dong.board.BoardDTO"/>
		<typeAlias alias="reply" type="kr.co.dong.board.BoardReplyDTO"/>
	</typeAliases>
</configuration>

 

Mybatis의 SqlSession을 호출하는 XML 매핑구문을 작성한다. (SqlSessionFactory)

boardMapper.xml
게시글 번호에 해당하는
댓글 전체목록
<select id="replyList"  parameterType="java.lang.Integer" resultType="reply">
select * from board_reply where bno=#{bno}
</select>
댓글 상세보기 <select id="getReply" parameterType="java.lang.Integer" resultType="reply">
select * from board_reply where reno=#{reno}
</select>
댓글 등록하기 <insert id="registerReply" parameterType="reply">
insert into board_reply (reno, rewriter, rememo, redate, bno)
values (#{reno}, #{rewriter}, #{rememo}, now(), #{bno})
</insert>
댓글 수정하기 <update id="modifyReply" parameterType="reply">
update board_reply
<set>
<if test="rewriter != null">rewriter=#{rewriter},</if>
<if test="rememo !=null">rememo=#{rememo}</if>
</set>
where reno=#{reno}
</update>
댓글 삭제하기 <delete id="deleteReply" parameterType="java.lang.Integer">
delete from board_reply where reno=#{reno}
</delete>

 

boardMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.co.dong.boardMapper">

	<!-- 글 전체목록-->
	<select id="boardList" resultType="Board">
		select * from board		
	</select>	
	
	<!-- 글 상세보기-->
	<select id="getBoard"  parameterType="java.lang.Integer" resultType="Board">
		select * from board where bno=#{bno}
	</select>
	
	<!--글 등록하기-->
	<insert id="registerBoard" parameterType="Board">
		insert into board (bno, title, content, id, regdate, readcnt, etc)
		values ( #{bno}, #{title},  #{content}, #{id}, now(), #{readcnt}, #{etc})
	</insert>	
	
	<!--글 수정하기-->
	<update id="modifyBoard" parameterType="Board" >
		update board
		<set>
		<if test="title != null">title=#{title},</if>
		<if test="content != null">content=#{content}</if>
		</set>
		where bno=#{bno}
	</update>
	
	<!--글 삭제하기-->
	<delete id="deleteBoard" parameterType="java.lang.Integer">
		delete from board where bno=#{bno}
	</delete>
	
	<!-- 조회수 업데이트 -->
	<update id="readcount" parameterType="java.lang.Integer">
		update board set readcnt = readcnt + 1 where bno = #{bno}
	</update>
	
	<!--게시글번호에 해당하는 댓글 전체조회-->
	<select id="replyList"  parameterType="java.lang.Integer" resultType="reply">
		select * from board_reply where bno=#{bno}
	</select>
	
	<!--댓글 상세조회-->
	<select id="getReply" parameterType="java.lang.Integer" resultType="reply">
		select * from board_reply where reno=#{reno}
	</select>
	
	<!--댓글 등록하기 -->
	<insert id="registerReply" parameterType="reply">
		insert into board_reply (reno, rewriter, rememo, redate, bno)
		values (#{reno}, #{rewriter}, #{rememo}, now(), #{bno})
	</insert>
	
	<!--댓글 수정하기-->
	<update id="modifyReply" parameterType="reply">
		update board_reply
		<set>
			<if test="rewriter != null">rewriter=#{rewriter},</if>
			<if test="rememo !=null">rememo=#{rememo}</if>
		</set>
		where reno=#{reno}
	</update>
	
	<!--댓글 삭제하기-->
	<delete id="deleteReply" parameterType="java.lang.Integer">
		delete from board_reply where reno=#{reno}
	</delete>
</mapper>

 

 

BoardDAO.java/BoardDAOImpl.java


Mybatis로 작성한 SqlSessionFactory에서 인터페이스를 호출하기 때문에

boardDAO interface와 boardDAO를 implements한 boardDAOImpl 를 작성한다.

 

BoardDAO.java

package kr.co.dong.board;

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

public interface BoardDAO {
	
	// 글 전체목록
	public List<BoardDTO> boardList();
	
	// 글 상세보기	
	public BoardDTO getBoard(int bno);
	
	// 글 등록하기
	public int registerBoard(BoardDTO boardDTO);
	
	// 글 수정하기
	public int modifyBoard(BoardDTO boardDTO);
	
	// 글 삭제하기
	public int deleteBoard(int bno);
	
	// 글 조회수증가
	public int updateReadcnt(int bno);
	
	// 글 번호의 댓글 전체목록
	public List<BoardReplyDTO> replyList(int bno);
	
	// 댓글 상세조회
	public BoardReplyDTO getReply(int reno);
	
	// 댓글 등록
	public int registerReply(BoardReplyDTO reply);
	
	// 댓글 수정
	public int modifyReply(BoardReplyDTO reply);
	
	// 댓글 삭제
	public int deleteReply(int reno);
}

 

 

BoardDAOImpl.java

package kr.co.dong.board;

import java.util.List;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

@Repository //DB나 파일같은 외부 I/O 작업을 처리
public class BoardDAOImpl implements BoardDAO {
	
	@Inject // 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.
	private SqlSession sqlSession;
	
	private static final String nameSpace="kr.co.dong.boardMapper";

	@Override
	public List<BoardDTO> boardList() {
		return sqlSession.selectList(nameSpace+".boardList");
	}

	@Override
	public BoardDTO getBoard(int bno) {
		return sqlSession.selectOne(nameSpace+".getBoard", bno);
	}

	@Override
	public int registerBoard(BoardDTO boardDTO) {
		return sqlSession.insert(nameSpace+".registerBoard", boardDTO);
	}

	@Override
	public int modifyBoard(BoardDTO boardDTO) {
		return sqlSession.update(nameSpace+".modifyBoard", boardDTO);
	}

	@Override
	public int deleteBoard(int bno) {
		return sqlSession.delete(nameSpace+".deleteBoard", bno);
	}

	@Override
	public int updateReadcnt(int bno) {
		return sqlSession.update(nameSpace+".readcount", bno);
	}

	@Override
	public List<BoardReplyDTO> replyList(int bno) {
		return sqlSession.selectList(nameSpace+".replyList", bno);
	}

	@Override
	public BoardReplyDTO getReply(int reno) {
		return sqlSession.selectOne(nameSpace + ".getReply", reno);
	}
	
	@Override
	public int registerReply(BoardReplyDTO reply) {
		return sqlSession.insert(nameSpace+".registerReply", reply);
	}

	@Override
	public int modifyReply(BoardReplyDTO reply) {
		return sqlSession.update(nameSpace+".modifyReply", reply);
	}

	@Override
	public int deleteReply(int reno) {
		return sqlSession.delete(nameSpace+".deleteReply", reno);
	}

}

 

BoardService.java/BoardServiceImpl.java


BoardDAO에서 리턴된 result를 controller로 보낸다.

 

BoardService.java

package kr.co.dong.board;

import java.util.List;

public interface BoardService {
	
	// 글 전체목록
	public List<BoardDTO> boardList();
	
	// 글 상세보기	
	public BoardDTO getBoard(int bno);
	
	// 글 등록하기
	public int registerBoard(BoardDTO boardDTO);
	
	// 글 수정하기
	public int modifyBoard(BoardDTO boardDTO);
	
	// 글 삭제하기
	public int deleteBoard(int bno);
	
	// 글 번호의 댓글 전체목록
	public List<BoardReplyDTO> replyList(int bno);
	
	// 댓글 상세조회
	public BoardReplyDTO getReply(int reno);

	// 댓글 등록하기
	public int registerReply(BoardReplyDTO reply);
	
	// 댓글 수정하기
	public int modifyReply(BoardReplyDTO reply);
	
	// 댓글 삭제하기
	public int deleteReply(int reno);

}

 

 

BoardServiceImpl.java

package kr.co.dong.board;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

@Service //서비스 레이어, 내부에서 자바 로직을 처리함
public class BoardServiceImpl implements BoardService {
	
	@Inject //주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.
	private BoardDAO boardDAO;

	@Override
	public List<BoardDTO> boardList() {
		return boardDAO.boardList();
	}

	@Transactional(isolation = Isolation.READ_COMMITTED)	
	@Override
	public BoardDTO getBoard(int bno) {
		boardDAO.updateReadcnt(bno);
		return boardDAO.getBoard(bno);
	}

	@Override
	public int registerBoard(BoardDTO boardDTO) {
		return boardDAO.registerBoard(boardDTO);
	}

	@Override
	public int modifyBoard(BoardDTO boardDTO) {
		return boardDAO.modifyBoard(boardDTO);
	}

	@Override
	public int deleteBoard(int bno) {
		return boardDAO.deleteBoard(bno);
	}

	@Override
	public List<BoardReplyDTO> replyList(int bno) {
		return boardDAO.replyList(bno);
	}
	
	@Override
	public BoardReplyDTO getReply(int reno) {
		return boardDAO.getReply(reno);
	}
	
	@Override
	public int registerReply(BoardReplyDTO reply) {
		return boardDAO.registerReply(reply);
	}

	@Override
	public int modifyReply(BoardReplyDTO reply) {
		return boardDAO.modifyReply(reply);
	}

	@Override
	public int deleteReply(int reno) {
		return boardDAO.deleteReply(reno);
	}

}

 

 

BoardController.java


 

BoardController.java

package kr.co.dong.board;

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

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller // 웹 요청과 응답을 처리함
public class BoardController {
	
	private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
	
	@Inject // 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.
	private BoardService boardService;	
	
	@RequestMapping(value="board/logout", method=RequestMethod.GET)	
	public String logout(HttpSession session) {
		logger.info("로그아웃");
		session.invalidate();
		return "redirect:/";
	}
	
	@RequestMapping(value="board/list")
	public ModelAndView list (HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		logger.info("글 전체목록");
		
		List<BoardDTO> list=boardService.boardList();
		
		ModelAndView mav = new ModelAndView ();
		mav.addObject("list", list);
		mav.setViewName("list");
		return mav;
		
	}
	
	@RequestMapping(value="board/detail",method=RequestMethod.GET)
	public ModelAndView datail(@RequestParam("bno") int bno, HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		logger.info("글 상세보기");
		
		BoardDTO board= boardService.getBoard(bno);
		
		ModelAndView mav = new ModelAndView();
		List<BoardReplyDTO> list = boardService.replyList(bno);
		
		mav.addObject("list",list);
		mav.addObject("board",board);
		mav.setViewName("detail");
		return mav;
	}
	
	@RequestMapping(value="board/register", method=RequestMethod.GET)
	public String registerMove( HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
		logger.info("글 등록하기 View로 이동");
		return "register";
	}
	
	@RequestMapping(value="board/register", method=RequestMethod.POST)
	public String register(BoardDTO board, HttpServletRequest request, HttpSession session) throws Exception {
		logger.info("글 등록하기");

		int result=boardService.registerBoard(board);
		
		if (result==0) {
			logger.info("글 등록실패");
			return "redirect:register";
		}
		return "redirect:list";
	}
	
	@RequestMapping(value="board/update", method=RequestMethod.GET)
	public String modifyMove(@RequestParam("bno") int bno, Model model) throws Exception{ 
		logger.info("글 수정하기 View로 이동");
		
		BoardDTO board= boardService.getBoard(bno);
		
		model.addAttribute("board", board);
		return "update";
	}
	
	@RequestMapping(value="board/update", method=RequestMethod.POST)
	public String modify(BoardDTO board, HttpServletRequest request) throws Exception {
		
		logger.info("글 수정하기");
		int result=boardService.modifyBoard(board);
		
		if (result==0) {
			logger.info("글 수정실패");
			return "redirect:update";
		} else {
			logger.info("글 수정성공");
			return "redirect:list";
		}
	}
	
	@RequestMapping(value="board/delete", method=RequestMethod.GET)
	public String delete(@RequestParam("bno") int bno, HttpServletRequest request) throws Exception {
		logger.info("글 삭제하기");
		
		int result=boardService.deleteBoard(bno);
		
		if (result==0) {
			logger.info("글 삭제실패");
			return "redirect:detail?bno="+ bno;
		} else {
			logger.info("글 삭제성공");
			return "redirect:list";
		}
	}
	
	
	@RequestMapping(value="board/reply", method=RequestMethod.GET)
	public String reply(@RequestParam("bno") int bno, Model model) throws Exception {
		logger.info("댓글등록 View로 이동");
		
		model.addAttribute("bno",bno);
		return "reply";
	}
	
	@RequestMapping(value="board/reply", method=RequestMethod.POST)	
	public String reply(BoardReplyDTO reply, HttpServletRequest request) throws Exception {
		
		logger.info("댓글 등록하기");
		
		int result = boardService.registerReply(reply);
		
		if (result==0) {
			logger.info("댓글등록 실패");
			return "reply";			
		} else {
			logger.info("댓글등록 성공");
			return "redirect:detail?bno="+ reply.getBno();
		}
	}
	
	@RequestMapping(value="board/replyupdate", method=RequestMethod.GET)
	public String modifyReplyMove(@RequestParam("reno") int reno, Model model) throws Exception {
		logger.info("댓글수정 View로 이동");
		
		BoardReplyDTO reply = boardService.getReply(reno);
		
		model.addAttribute("boardreply",reply);
		return "replyupdate";
	}
	

	@RequestMapping(value="board/replyupdate", method=RequestMethod.POST)
	public String modifyReply(BoardReplyDTO reply, RedirectAttributes rttr) throws Exception {
		logger.info("댓글 수정하기");
		
		int result = boardService.modifyReply(reply);
		
		if (result==0) {
			logger.info("댓글 수정실패");
			return "redirect:reply?reno="+reply.getReno();	
		} else {
			logger.info("댓글 수정성공" + reply.getBno());
			return "redirect:detail?bno="+reply.getBno();
		}
	}
	
	@RequestMapping(value="board/deleteReply", method=RequestMethod.GET)
	public String deleteReply(@RequestParam("reno") int reno, HttpServletRequest request) throws Exception {
		logger.info("댓글 삭제하기");
		
		int result=boardService.deleteReply(reno);
		
		if (result==0) {
			logger.info("댓글 삭제실패");
			return "redirect:detail?bno="+ reno;
		} else {
			logger.info("댓글 삭제성공");
			return "redirect:list";
		}
	}

}

 

 

ReplyView


 

❶ 글번호에 해당하는 댓글 목록 조회

 

❷ 댓글 수정

 

댓글 수정하기 화면
댓글 수정성공 화면

❸ 댓글 삭제하기

 

댓글 삭제 전
새로운 댓글 등록하여 댓글 삭제 성공확인