yahayaha

20. 댓글 처리하기 (CRUD) 본문

spring/프로젝트

20. 댓글 처리하기 (CRUD)

yaha 2024. 2. 5. 22:58

댓글을 추가하기 위해서 구조에 맞는 테이블을 설계.

 

create table tbl_reply(
    rno number(10,0),
    bno number(10,0) not null,
    reply varchar2(1000) not null,
    replyer varchar2(50) not null,
    replyDate date default sysdate,
    updateDate date default sysdate
); 

create sequence seq_reply;

alter table tbl_reply add constraint pk_reply primary key(rno);

alter table tbl_reply add constraint fk_reply_board
foreign key (bno) references tbl_board(bno);

 

 

tbl_reply 테이블은 bno라는 칼럼을 이용해서 해당 댓글이 어떤 게시물의 댓글인지를 명시.

댓글 자체는 단독으로 CRUD가 가능하므로, 별도의 PK를 부여하고, 외래키(FK) 설정을 통해서 tbl_board 테이블을 참조하도록 설정.

 

ReplyVo 클래스 추가.

 

import java.util.Date;

import lombok.Data;

@Data
public class ReplyVO {

	private Long rno; 
	private Long bno;
	
	private String reply;
	private String replyer;
	private Date repltDate;
	private Date updateDate;
}

 

 

ReplyMapper 클래스 XML 처리

댓글 처리도 화면상에서 페이지 처리가 필요할 수 있으므로 Criteria를 이용해서 처리.

 

mapper패키지에 ReplyMapper 인터페이스, resources에 ReplyMapper.xml을 생성.

 

 

작업을 진행하기 전에 tbl_reply 테이블이 tbl_board 테이블과 FK(외래키)의 관계로 처리되어 있다는걸 알아야함.

 

tbl_reply가 tbl_board 테이블의 bno 값과 정확히 일치 해야함. 테스트를 진행하기 전에 최신 bno 번호 몇 개를 확인.

 

ReplyMapper가 사용 가능 한지에 대한 테스트 코드를 실행. ReplyMapperTest 클래스 생성.

 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class ReplyMapperTests {
	
	@Setter(onMethod_ = @Autowired)
	private ReplyMapper mapper;
	
	@Test
	public void testMapper() {
		log.info(mapper);
	}

}

객체가 정상적으로 사용이 가능한지 확인

 

댓글 등록

외래키를 사용하는 등록 작업 우선 진행.

 

public interface ReplyMapper {

	public int insert(ReplyVO reply);
}

 

ReplyMapper의 SQL처리.

 

<mapper namespace="org.zerock.mapper.ReplyMapper">

    //등록
	<insert id="insert">
		insert into tbl_reply (rno, bno, reply, replyer)
		values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
	</insert>

</mapper>

 

 

SQL도 작성이 되었으면 테스트를 진행.

 

@RunWith(SpringRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class ReplyMapperTests {
	
	// 해달 번호가 게시물이 존재하는지 확인해야함.
	private Long[] bnoArr = { 2461L, 2460L , 2459L, 2458L, 2457L};
	
	@Setter(onMethod_ = @Autowired)
	private ReplyMapper mapper;
	
	@Test
	public void testCreate() {
		IntStream.rangeClosed(1, 10).forEach(i ->{
			ReplyVO reply = new ReplyVO();
			
			//게시물 번호			
			reply.setBno(bnoArr[i % 5]);
			reply.setReply("댓글 테스트" + i);
			reply.setReplyer("댓글 작성자" + i);
			mapper.insert(reply);
		});
	}
}

 

bnoArr은 게시물 번호의 일부로 실제 데이터베이스에 있는 번호여야함. 

(PK와 FK의 관계로 묶여 있기 때문)

 

테스트 결과를 확인.

 

select * from tbl_reply order by rno desc;

 

등록 작업이 처리된 것을 확인 후 조회 작업을 처리.

 

 

댓글 조회

public interface ReplyMapper {

	public int insert(ReplyVO reply);
	
	public ReplyVO read(Long rno); //특정 댓글 읽기
}

 

<mapper namespace="org.zerock.mapper.ReplyMapper">

    //등록
	<insert id="insert">
		insert into tbl_reply (rno, bno, reply, replyer)
		values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
	</insert>
    
    //조회
    <select id="read" resultType="org.zerock.domain.ReplyVO">
	select * from tbl_reply where rno = #{rno}
	</select>

</mapper>

 

@Test
public void testRead() {
    Long targetRno = 5L;

    ReplyVO reply = mapper.read(targetRno);

    log.info(reply);
}

 

정상적으로 5번 댓글이 조회되는지 확인.

 

 

댓글 삭제 

public interface ReplyMapper {

	public int insert(ReplyVO reply);
	
	public ReplyVO read(Long rno); //특정 댓글 읽기
	
	public int delete(Long rno);
}
<mapper namespace="org.zerock.mapper.ReplyMapper">

    //등록
    <insert id="insert">
        insert into tbl_reply (rno, bno, reply, replyer)
        values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
    </insert>

    //조회
    <select id="read" resultType="org.zerock.domain.ReplyVO">
        select * from tbl_reply where rno = #{rno}
    </select>

    //삭제
    <delete id="delete">
        delete from tbl_reply where rno = #{rno}
    </delete>

</mapper>
@Test
public void testDelete() {
    Long targetRno = 1L;

    mapper.delete(targetRno);
}

 

삭제가 된걸 확인.

 

댓글 수정

댓글의 수정은 현재 tbl_reply 테이블의 구조에서는 댓글의 내용과 최종 수정시간을 수정.

 

public interface ReplyMapper {

	public int insert(ReplyVO reply);
	
	public ReplyVO read(Long rno); //특정 댓글 읽기
	
	public int delete(Long rno);
	
	public int update(ReplyVO reply);
}
<mapper namespace="org.zerock.mapper.ReplyMapper">

    //등록
    <insert id="insert">
        insert into tbl_reply (rno, bno, reply, replyer)
        values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
    </insert>

    //조회
    <select id="read" resultType="org.zerock.domain.ReplyVO">
        select * from tbl_reply where rno = #{rno}
    </select>

    //삭제
    <delete id="delete">
        delete from tbl_reply where rno = #{rno}
    </delete>
    
    //수정
    <update id="update">
    	update tbl_reply set reply = #{reply}, updatedate = sysdate where rno = #{rno}
    </update>

</mapper>
@Test
public void testUpdate() {
    Long targetRno = 10L;

    ReplyVO reply = mapper.read(targetRno);

    reply.setReply("수정 댓글");

    int count = mapper.update(reply);

    log.info("업데이트 카운트 " + count);
}

 

 

@Param어노테이션과 댓글 목록

댓글의 목록과 페이징 처리는 기존의 게시물 페이징 처리와 유사하지만, 추가적으로

특정한 게시물의 댓글들만을 대상으로 하기 때문에 추가로 게시물의 번호가 필요.

 

MyBatis는 두 개 이상의 데이터를 파라미터로 전달하기 위해서는 

1. 별도의 객체로 구성

2. Map 사용

3. @Param 사용 

 

여러 방식 중에 가장 간단한 @Param을 이용하는 방식을 사용.

 

@Param의 송성값은 MyBatis에서 SQL을 이용할 때 '#{}'의 이름으로 사용 가능.

 

페이징 처리는 Criteria를 사용하는데 추가적으로 해당 게시물의 번호는 파라미터를 전달하도록 ReplyMapper를 수정.

public interface ReplyMapper {

	public int insert(ReplyVO reply);
	
	public ReplyVO read(Long rno); //특정 댓글 읽기
	
	public int delete(Long rno);
	
	public int update(ReplyVO reply);
	
	public List<ReplyVO> getListWithPaging(
			@Param("cri") Criteria cri,
			@Param("bno") Long bno);
}
<mapper namespace="org.zerock.mapper.ReplyMapper">

    //등록
    <insert id="insert">
        insert into tbl_reply (rno, bno, reply, replyer)
        values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
    </insert>

    //조회
    <select id="read" resultType="org.zerock.domain.ReplyVO">
        select * from tbl_reply where rno = #{rno}
    </select>

    //삭제
    <delete id="delete">
        delete from tbl_reply where rno = #{rno}
    </delete>
    
    //수정
    <update id="update">
    	update tbl_reply set reply = #{reply}, updatedate = sysdate where rno = #{rno}
    </update>

	//#{bno}가 @Param("bno")와 매칭
    <select id="getListWithPaging" resultType="org.zerock.domain.ReplyVO">
        select rno, bno, reply, replyer, replyDate, updatedate
        from tbl_reply
        where bno = #{bno}
        order by rno asc
    </select>

</mapper>
@Test
public void testList() {
    Criteria cri = new Criteria();

    //2461L
    List<ReplyVO> replies = mapper.getListWithPaging(cri, bnoArr[0]);

    replies.forEach(reply -> log.info(reply));
}