Spring

스프링 - Part 3 - 기본적인 웹 게시물 관리 02 (영속/비즈니스 계층의 CRUD 구현)

록's 2023. 3. 22. 12:06
728x90
반응형

영속/비즈니스 계층의 CRUD 구현

 

영속 계층의 작업

  • 테이블의 칼럼 구조를 반영하는 VO(Value Object) 클래스의 생성
  • MyBatis의 Mapper 인터페이스 작성/XML 처리
  • 작성한 Mapper 인터페이스의 테스트

 

영속 계층의 구현 준비

 

VO 클래스의 작성

VO 클래스를 생성하는 작업은 테이블 설계를 기준으로 작성

 

확인 > select * from tbl_board where bno > 0

 

 

 

 

프로젝트에 org.codehows.domain 패키지 생성, BoardVO 클래스 정의

 

// BoardVO.java

package org.codehows.domain;

import java.util.Date;

import lombok.Data;

@Data
public class BoardVO {

	private Long bno;
	private String title;
	private String content;
	private String writer;
	private Date regdate;
	private Date updateDate;
}

 

 

Mapper 인터페이스와 Mapper XML

 

// root-context.xml

	<mybatis-spring:scan base-package="org.codehows.mapper"/>

 

 

// BoardMapper.java

package org.codehows.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.codehows.domain.BoardVO;

public interface BoardMapper {
   
   @Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();

}

 

// BoardMapperTests.java

package org.codehows.mapper;

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.SpringJUnit4ClassRunner;

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

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardMapperTests {
	
	@Setter(onMethod_ = @Autowired)
	private BoardMapper mapper;
	
	@Test
	public void testGetList() {
		mapper.getList().forEach(board -> log.info(board));
	}
}

실행을 하면 오류가 뜰수도 있다. (권한문제) 그래서 root-context.xml에 username = 아이디, password = 비밀번호

자기가 적은 데이터베이스 아이디와 비밀번호를 치면 오류없이 실행이 될 것이다.

 

 

 

 

Mapper XML 파일

 

xml 파일 생성

 

// 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="org.codehows.mapper.BoardMapper">
	
<select id="getList" resultType="org.codehows.domain.BoardVO">
<![CDATA[
	select * from tbl_board where bno > 0
]]>
</select>

</mapper>

 

XML을 작성할 때는 반드시 <mapper>의 namespace 속성값을 Mapper 인터페이스와 동일한 이름을 주는 것에 주의하고, <select> 태그의 id 속성값은 메서드의 이름과 일치하게 작성 해야한다. resultType 속성의 값은 select 쿼리의 결과를 특정 클래스의 객체로 만들기 위해서 설정.

XML에 사용한 CDATA 부분은 XML에서 부등호를 사용하기 위해서 사용한다.

 

XML에 SQL 문이 처리되었으니 BoardMapper 인터페이스에 SQL은 제거한다.

 

// BoardMapper.java

package org.codehows.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.codehows.domain.BoardVO;

public interface BoardMapper {
   
   //@Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();

}

인터페이스 수정 후 반드시 기존 테스트 코드를 통해서 기존과 동일하게 동작하는지 확

 

 

확인됨.

 

 

 

 

 

영속 영역의 CRUD 구현

 

create(insert) 처리

  • insert만 처리되고 생성된 PK 값을 알 필요가 없는경우
  • insert문이 실행되고 생성된 PK 값을 알아야 하는 경우

 

BoardMapper 인터페이스에는 위 상황들을 고려해서 다음과 같이 메서드를 추가 선언한다.

 

 

org.codehows.mapper.BoardMapper 인터페이스 일부

// BoardMapper.java

package org.codehows.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.codehows.domain.BoardVO;

public interface BoardMapper {
   
   //@Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();

   public void insert(BoardVO board);
   
   public void insertSelectKey(BoardVO board);
}

 

BoardMapper.xml은 내용 추가

 

// 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="org.codehows.mapper.BoardMapper">
	
<select id="getList" resultType="org.codehows.domain.BoardVO">
<![CDATA[
	select * from tbl_board where bno > 0
]]>
</select>

<insert id="insert">
	insert into tbl_board (bno, title, content, writer)
	values (seq_board.nextval, #{title}, #{content}, #{writer})
</insert>

<insert id="insertSelectKey">
	
	<selectKey keyProperty="bno" order="BEFORE"
		resultType="long">
		select seq_board.nextval from dual
	</selectKey>
	
	insert into tbl_board (bno, title, content, writer)
	values (#{bno}, #{title}, #{content}, #{writer})	
</insert>

</mapper>

 

 

BoardMapperTests클래스 일부

// BoardMapperTests.java

... (생략) ...

	@Test
	public void testInsert() {
		
		BoardVO board = new BoardVO();
		board.setTitle("새로 작성하는 글");
		board.setContent("새로 작성하는 내용");
		board.setWriter("newbie");
		
		mapper.insert(board);
		
		log.info(board);
	}

 

@SelectKey를 이용하는 경우 테스트 코드

// BoardMapperTests.java

... 생략 ...

	@Test
	public void testInsertSelectKey() {
		
		BoardVO board = new BoardVO();
		board.setTitle("새로 작성하는 글 select key");
		board.setContent("새로 작성하는 내용 select key");
		board.setWriter("newbie");
		
		mapper.insertSelectKey(board);
		
		log.info(board);
	}

testInsertSelectKey()의 테스트 결과의 일부

 

 

 

 

read(select) 처리

 

insert가 된 데이터를 조회하는 작업은 PK를 이용해서 처리하므로 BoardMapper의 파라미터 역시 BoardVO클래스의 bno타입 정보를 이용해서 처리한다.

// BoardMapper.java

package org.codehows.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.codehows.domain.BoardVO;

public interface BoardMapper {
   
   //@Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();

   public void insert(BoardVO board);
   
   public void insertSelectKey(BoardVO board);
   
   public BoardVO read(Long bno);			// << 추가
}

 

 

BoardMapper.xml에 추가되는 <select>

// BoardMapper.xml

... 생략 ...

<select id="read" resultType="org.codehows.domain.BoardVO">
	select * from tbl_board where bno = #{bno}
</select>
</mapper>

 

 

 

BoardMapperTests 클래스에 추가

// BoardMapperTests.java

... 생략 ...

	@Test
	public void testRead() {
		// 존재하는 게시물 번호로 테스트
		BoardVO board = mapper.read(5L);
		
		log.info(board);
	}

mapper.read()를 호출할 경우에는 현재 테이블에 있는 데이터 bno 값이 존재하는지 여부를 반드시 확인해야한다.

 

테스트 코드의 결과

 

 

 

delete 처리

 

특정한 데이터를 삭제하는 작업 역시 PK 값을 이용해서 처리하므로 조회하는 작업과 유사하게 처리한다.

등록, 삭제, 수정과 같은 DML 작업은 '몇 건의 데이터가 삭제(혹은 수정)되었는지'를 반환할 수있다.

 

 

 

BoardMapper.xml

 // BoardMapper.java
 
 package org.codehows.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.codehows.domain.BoardVO;

public interface BoardMapper {
 
 ... 생략 ...
 
 public int delete(Long bno);	<< 추가
}

 

BoardMapper.xml 일부

// BoardMapper.xml

... 생략 ...

<delete id="delete">
	delete from tbl_board where bno = #{bno}
</delete>

</mapper>

 

delete () 의 메서드 리턴 타입은 int로 지정해서 만일 정상적으로 데이터가 삭제되면 1이상의 값을 가지도록 작성한다.

테스트 코드는 현제 테이블에 존재하는 번호의 데이터를 삭제해 보고 '1'이라는 값이 출력되는지 확인한다.

해당 번호의 게시물이 없다면 '0'이 출력

 

 

BoardMapperTests 클래스

// BoardMapperTests.java

... 생략 ...

	@Test
	public void testDelete() {
		log.info("DELETE COUNT: " + mapper.delete(3L));
	}
}

testDelete()의 경우 3번 데이터가 존재했다면 다음과 같은 로그가 기록된다.

 

 

 

 

update 처리

 

update를 처리 . 게시물의 업데이트는 제목, 내용, 작성자를 수정한다고 가정한다. 업데이트할 때는 최종 수정시간을 데이터베이스 내 현재 시간으로 수정한다.

 

BoardMapper 인터페이스 일부

// BoardMapper.java

... 생략 ...

   public int update(BoardVO board);
}

 

 

BoardMapper.xml의 일부

// BoardMapper.xml

... 생략 ...

<update id="update">
	update tbl_board
	set title= #{title},
	content= #{content},
	writer = #{writer},
	updateDate = sysdate
	where bno = #{bno}
</update>

</mapper>

 

 

테스트 코드는 read()를 이용해서 가져온 BoardVO 객체의 일부를 수정하는 방식이나 직접 BoardVO객체를 생성해서 처리할 수 있다. 

BoardMapperTests 클래스

// BoardMapperTests.java

... 생략 ...

	@Test
	public void testUpdate() {
		BoardVO board = new BoardVO();
		// 실행전 존재하는 번호인지 확인 할 것
		board.setBno(5L);
		board.setTitle("수정된 제목");
		board.setContent("수정된 내용");
		board.setWriter("user00");
		
		int count = mapper.update(board);
		log.info("UPDATE COUNT: " + count);
	}
}

테스트 결과


https://rogi221.tistory.com/148

 

스프링 - Part 3 - 기본적인 웹 게시물 관리 03 (비즈니스 계층)

비즈니스 계층 고객의 요구사항을 반영하는 계층 업무의 단위로 설계 트랜잭션의 단위 여러 개의 Mapper나 DAO를 사용하는 경우가 존재함 xxxService의 형태로 작성 비지니스 계층의 설정 비즈니스

rogi221.tistory.com

 

728x90
반응형