Spring MyBatis (7) 댓글 기능

강서진·2024년 2월 6일
0

Spring

목록 보기
18/18
post-custom-banner

2번째 필수강의 pt.4 10, 11강 요약

댓글 기능을 추가하기 위해 다음과 같은 순서로 진행한다.

  1. DB테이블 생성
  2. Mapper.xml 작성
  3. DAO 작성 & 테스트
  4. Service 작성 & 테스트
  5. 컨트롤러 작성 & 테스트
  6. 뷰(UI) 작성 & 테스트

1~5번은 백엔드에서, 6번은 프론트에서 담당한다.
DAO에서는 순수하게 데이터에 접근하는 기능을 작성하고, Setvice에서는 비즈니스 로직과 트랜잭션을 처리하며, 컨트롤러에서는 요청과 응답을 처리하고, 데이터 유효성을 검증하며 실행 흐름을 제어한다.


DB 테이블 생성

CREATE TABLE `springbasic`.`comment` (
  `cno` INT NOT NULL AUTO_INCREMENT,
  `bno` INT NOT NULL,
  `pcno` INT NULL,
  `comment` VARCHAR(3000) NULL,
  `commenter` VARCHAR(30) NULL,
  `reg_date` DATETIME NULL DEFAULT now(),
  `up_date` DATETIME NULL DEFAULT now(),
  PRIMARY KEY (`cno`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;

Mapper.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="com.fastcampus.ch4.dao.CommentMapper">
    <delete id="deleteAll" parameterType="int">
        DELETE FROM comment
        WHERE  bno = #{bno}
    </delete>

    <select id="count" parameterType="int" resultType="int">
        SELECT count(*) FROM comment
        WHERE  bno = #{bno}
    </select>

    <delete id="delete" parameterType="map">
        DELETE FROM comment WHERE cno = #{cno} AND commenter = #{commenter}
    </delete>

    <insert id="insert" parameterType="CommentDto">
        INSERT INTO comment
            (bno, pcno, comment, commenter, reg_date, up_date)
        VALUES
            (#{bno}, #{pcno}, #{comment}, #{commenter}, now(), now())
    </insert>

    <select id="selectAll" parameterType="int" resultType="CommentDto">
        SELECT cno, bno, pcno, comment, commenter, reg_date, up_date
        FROM comment
        WHERE bno = #{bno}
        ORDER BY reg_date ASC, cno ASC
    </select>

    <select id="select" parameterType="int" resultType="CommentDto">
        SELECT cno, bno, pcno, comment, commenter, reg_date, up_date
        FROM comment
        WHERE cno = #{cno}
    </select>

    <update id="update" parameterType="CommentDto">
        UPDATE comment
        SET comment = #{comment}
          , up_date = now()
        WHERE cno = #{cno} and commenter = #{commenter}
    </update>
</mapper>

DAO 작성

Mapper 문서를 참고하여 작성한다. 작성 후 인터페이스를 추출하였다.

  @Repository
  public class CommentDaoImpl implements CommentDao {
    @Autowired
    SqlSession session;
    String namespace = "com.fastcampus.ch4.dao.CommentMapper.";

  @Override
  public int deleteAll(Integer bno) throws Exception{
    return session.delete(namespace+"deleteAll", bno);
  }

  @Override
  public int count(Integer bno) throws Exception{
    return session.selectOne(namespace+"count", bno);
  }

  @Override
  public int delete(Integer cno, String commenter) throws Exception{
    Map map = new HashMap();
    map.put("cno", cno);
    map.put("commenter", commenter);
    return session.delete(namespace+"delete", map);
  }

  @Override
  public int insert(CommentDto dto) throws Exception{
    return session.insert(namespace + "insert", dto);
  }

  @Override
  public List<CommentDto> selectAll(Integer bno) throws Exception{
    return session.selectList(namespace + "selectAll", bno);
  }

  @Override
  public CommentDto select(Integer cno) throws Exception{
    return session.selectOne(namespace+"select", cno);
  }

  @Override
  public int update(Integer cno, String commenter) throws Exception{
    Map map = new HashMap();
    map.put("cno", cno);
    map.put("commenter", commenter);
    return session.update(namespace + "update", map);
  }

DTO 작성

테이블을 생성했던 것과 동일하게 작성해준다. 생성자 메서드는 default 값이 있는 cno, reg_date, up_date를 제외하도록 한다.


Service 작성

댓글이 삭제되면, 게시글에서도 댓글의 개수가 수정되어야 하기 때문에 BoardDao와 CommentDao가 둘 다 필요하다.
다만 service에 하나씩 @Autowired로 주입하기보다는(=인스턴스 변수 주입) 생성자 메서드로 주입받는 것이 낫다. 이 때는 애너테이션을 붙이지 않아도 주입할 수 있다.

    public CommentServiceImpl(CommentDao commentDao, BoardDao boardDao) {
        this.commentDao = commentDao;
        this.boardDao = boardDao;
    }

BoardMapper에 아래와 같은 sql을 추가하고, 이 기능을 DAO와 Service에도 넣어준다.
이 기능은 CommentServiceImpl에서 사용하며, BoardService에서 사용할 필요는 없다.

    <update id="updateCommentCount" parameterType="map">
        UPDATE springbasic.board
        SET comment_count = comment_count + #{count}
        WHERE bno = #{bno}
    </update>

덧글을 삭제하는 기능은 먼저 덧글 수에서 -1 시킨 후, 댓글을 지워야 한다. 이 때 쿼리가 두 번 실행되므로 둘 중에 하나라도 실패해서는 안되기 때문에 @Transactional 애너테이션을 사용하며, 예외가 발생하면 롤백이 실행되도록 작성하였다.

  @Override
  @Transactional(rollbackFor = Exception.class)
  public int remove(Integer cno, Integer bno, String commenter) throws Exception {
    int rowCnt = boardDao.updateCommentCount(bno, -1);
    System.out.println("updateCommentCnt - rowCnt = " + rowCnt);
//        throw new Exception("test");
    rowCnt = commentDao.delete(cno, commenter);
    System.out.println("rowCnt = " + rowCnt);
    return rowCnt;
  }

Controller 작성

post-custom-banner

0개의 댓글