영속성 비즈니스 계층

테이블의 컬럼 구조를 반영하는 VO(Value Object)

1. VO클래스 작성

테이블 설계를 기준으로 작성

영속성_비즈니스 계층

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

위의 과정 전에
먼저 JDBC 연결을 테스트하는 과정을 반드시 거친다.

1. 영속 계층의 구현 준비

거의 모든 웹 애플리케이션의 최종 목적은
데이터 베이스에 데이터를 기록하거나,
원하는 데이터를 가져오는 것이 목적이기 때문

2. Mapper 인터페이스의 Mapper XML 

MyBatis 는 SQL을 처리하는데, 어노테이션이나 XML을 이용할 수 있다. 

간단한 SQL일 경우 : 어노테이션을 이용하여 처리 

복잡하거나 검색 SQL : XML로 처리. 

XML의 경우 
단순 텍스트를 수정하는 과정만으로 처리가 끝나지만, 

어노테이션의 경우 
코드를 수정하고, 다시 빌드하는 등, 유지 보수성이 떨어진다. 

 

 

//BoardVO.java

package com.ohj.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 만들기

 

//인터페이스  BoardMapper

package com.ohj.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import com.ohj.domain.BoardVO;


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

BoardMapper 인터페이스 작성시,

필요한 SQL을 어노테이션의 속성값으로 처리 할 수 있다.

주의사항 : SQL 작성할 때 ';' 이 없도록 작성 해야한다.BoardMapper 인터페이스 작성 시,

필요한 SQL을 어노테이션의 속성값으로 처리할 수 있다.

주의사항 : SQL 작성할 때 ';' 이 없도록 작성해야 한다.

select문 뒤에 bno 컬럼 조건을 주어서 Primary key(PK)를 이용하도록 한다.

SQL Developer 에서 먼저
SQL이 문제 없이 실행 가능한 지를 확인
데이터 베이스의 commit 여부를 확인.

 

 

실제 작업하기 전 test 코드를 만들어 본다.

BoardMapperTests 클래스는 

스프링을 이용하여 

 

실제 작업하기 전 test 코드를 만들어 본다.

package com.ohj.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 com.ohj.mapper.BoardMapper;

//lombok : 선언해준 겟터셋터를 자동으로 만들어주고 tostring을 자동으로 만들어주고 생성자도 생성해준다.
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)
	BoardMapper mapper;
	
	@Test
	public void testGetList() {
		//forEach :리스트를 반환해줌
      mapper.getList().forEach(board -> log.info(board));
      
      
	}// testGetList END

}//BoardMapperTests END

실행해보기

콘솔창에 결과 값이 나온다.

 

Mybatis 설정 및 생성하기

 

MyBatis를 설치해준다.

 

가장 기본적인 xml 문서를 만들어주는 것이다(mybatis 관련)
generatorConfig -> BoardMapper 로 바꿔준다.
만들어진 결과물

 

결과 코드를 수정해준다.
불필요한 코드를 삭제 해준다 (주석을 건 내용은 예시문)

 

XML을 작성할 때 주의 사항

<mapper> 의 namespace 속성 값 : Mapper 인터페이스와 동일한 이름
<select> 태그의 id 속성 값 : 메서드 이름과 일치.
resultType 속성 값 : select 쿼링 결과를 특정 클래스의 객체로 자동 생성하기 위함

 

<?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">
<!--
<generatorConfiguration>
  <context id="context1">
    <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" />
    <javaModelGenerator targetPackage="???" targetProject="???" />
    <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" />
    <table schema="???" tableName="???">
      <columnOverride column="???" property="???" />
    </table>
  </context>
</generatorConfiguration> -->

 // 내부에서 사용할 메서드는 여기있다고 알려주고
<mapper namespace = "com.ohj.mapper.BoardMapper">
	// 메서드명과 id가 동일, resultType은 리턴 타입과 동일(BoardVO)
	<select id = "getList" resultType="com.ohj.domain.BoardVO">
   		 // 시작태그와 닫는태그의 기호가 <> 이기 때문에 부호표시를 위해 CDATA로 묶어놓은 것
		<![CDATA[
			select * from tbl_board where bno > 0
		]]>
	</select>

</mapper>

 

generatorConfiguration.xml에 설정해 놨으므로 해당 내용들은 주석 처리 해준다. (이름을 BoardMapper 바꿔준다.)

히카리->JDBC 코드를 단축(커넥션 풀)
마이바티스 - > 쿼리문을 XML에 정리

 

tbl_board 테이블은 PK칼럼으로 bno를 이용하고,

시퀀스를 이용하여

데이터가 추가 될때 마다 자동으로 번호가 만들어지는 방식을 사용.

이처럼 자동으로 PK값이 정해지는 경우 처리 방법

insert만 처리 되고 생성된 px값을 알 팔요가 없는 경우

insert문이 실행되고 생성 된 PK값을 알아야 할 경우

BoardMapper 인터페이스 수정 : 위의 상황을 고려하여 메소드를 추가 선언

 

//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">
<!--
<generatorConfiguration>
  <context id="context1">
    <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" />
    <javaModelGenerator targetPackage="???" targetProject="???" />
    <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" />
    <table schema="???" tableName="???">
      <columnOverride column="???" property="???" />
    </table>
  </context>
</generatorConfiguration> -->


<mapper namespace = "com.ohj.mapper.BoardMapper">
	<!-- BoardMapper.java-->
	<select id = "getList" resultType="com.ohj.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>

 

//BoardMapper.java

package com.ohj.mapper;

import java.util.List;

//XML파일에 작성 해놨음으로 주석 처리한다.
//import org.apache.ibatis.annotations.Select;
import com.ohj.domain.BoardVO;


public interface BoardMapper {

//BoardMapper.XML파일에 작성 해놨음으로 주석 처리한다.
// @Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();
   
   //단순히 insert만 해주는 메소드
   public void insert(BoardVO board);
   //insert를 해줬을 때 해당 VO 멤버 값을 꺼낼 수 있는 메소드
   public void insertSelectKey(BoardVO board);
   
}

 

<insert id="insert"> : 단순히 시퀀스의 다음 값을 구해서 insert 할 때 사용

 

insert into SQL 문:

몇 건의 데이터가 변경 되었는지 만을 알려주기 떄문에

추가된 데이터의 PK값을 알 수는 없지만,

한번의 SQL처리만으로 작업이 완료 된다는 장점이 있다.

 

<insert id="insertSelectKey"> : @SelectKey 라는 어노테이션을 사용.

 

@SelestKey:

주로 PK 값을 미이(before)SQL문을 통하여 처리해두고,

특정한 이름으로 결과를 보관하는 방식

 

@Insert 할 때 SQL 문을 보면 #{bno}와 같이 이미 처리된 결과를 이용.

 

 

테스트 코드의

각 메서드에서 마지막에 log.info(board)를 작성하는 이유:

lombok이 만들어조는 toString()을 이용하여 

bno 멤버 변수(인스턴스 변수)의 값을 알아보기 위함.

 

//BoardMapperTests.java

package com.ohj.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 com.ohj.domain.BoardVO;

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)
   BoardMapper mapper;
   
   @Test
   public void testGetList() {
      // 리스트 반환(board객체를 print 출력하면 toString 메소드에 의해서 객체에 대한 번지수가 나온다.)
      mapper.getList().forEach(board -> log.info(board));  
   }// testGetList END
   
   @Test
   public void testInsert() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글");
	   board.setContent("새로 작성하는 내용");
	   board.setWriter("newbie");
	   
	   mapper.insert(board);
	   
	   log.info(board);
   }//testInsert() END
   
   @Test
   public void testInsertSelectKey() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 SelectKey");
	   board.setContent("새로 작성하는 내용 SelectKey");
	   board.setWriter("newbie");
	   
	   mapper.insertSelectKey(board);
	   
	   //이유 : 롬복이 자동으로 tosrtinf을 이용하요 객체를 만들어주고 그 객체가 가지고 있는 값을 각각 확인해보기 위해서
	   log.info(board);
   }//testInsertSelectKey() END
   
   
}// BoardMapperTests END

 

실행 결과

INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1a968a59, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@4667ae56, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@77cd7a0, org.springframework.test.context.support.DirtiesContextTestExecutionListener@204f30ec, org.springframework.test.context.transaction.TransactionalTestExecutionListener@e25b2fe, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@754ba872]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@589838eb, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@42dafa95, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@6500df86, org.springframework.test.context.support.DirtiesContextTestExecutionListener@402a079c, org.springframework.test.context.transaction.TransactionalTestExecutionListener@59ec2012, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@4cf777e8]
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [file:src/main/webapp/WEB-INF/spring/root-context.xml]
INFO : org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@7791a895: startup date [Wed May 13 11:36:14 KST 2020]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
INFO : jdbc.connection - 1. Connection opened
INFO : jdbc.audit - 1. Connection.new Connection returned 
INFO : com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy.getNetworkTimeout()I)
INFO : jdbc.audit - 1. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 1. Connection.setAutoCommit(true) returned 
INFO : jdbc.audit - 1. Connection.isValid(1) returned true
INFO : jdbc.audit - 1. Connection.getTransactionIsolation() returned 2
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
INFO : jdbc.connection - 2. Connection opened
INFO : jdbc.audit - 2. Connection.new Connection returned 
INFO : jdbc.audit - 2. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 2. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 3. Connection opened
INFO : jdbc.audit - 3. Connection.new Connection returned 
INFO : jdbc.audit - 3. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 3. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 4. Connection opened
INFO : jdbc.audit - 4. Connection.new Connection returned 
INFO : jdbc.audit - 4. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 4. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 5. Connection opened
INFO : jdbc.audit - 5. Connection.new Connection returned 
INFO : jdbc.audit - 5. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 5. Connection.setAutoCommit(true) returned 
INFO : jdbc.audit - 1. Connection.getAutoCommit() returned true
INFO : com.ohj.persistence.DataSourceTests - org.apache.ibatis.session.defaults.DefaultSqlSession@2d6764b2
INFO : com.ohj.persistence.DataSourceTests - HikariProxyConnection@1877062907 wrapping net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy@79351f41
INFO : jdbc.connection - 6. Connection opened
INFO : jdbc.audit - 6. Connection.new Connection returned 
INFO : jdbc.audit - 6. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 6. Connection.setAutoCommit(true) returned 
INFO : jdbc.audit - 1. Connection.clearWarnings() returned 
INFO : jdbc.audit - 1. Connection.getAutoCommit() returned true
INFO : jdbc.connection - 7. Connection opened
INFO : jdbc.audit - 7. Connection.new Connection returned 
INFO : jdbc.audit - 7. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 7. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 8. Connection opened
INFO : jdbc.audit - 8. Connection.new Connection returned 
INFO : jdbc.audit - 8. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 8. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 9. Connection opened
INFO : jdbc.audit - 9. Connection.new Connection returned 
INFO : jdbc.audit - 9. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 9. Connection.setAutoCommit(true) returned 
INFO : jdbc.connection - 10. Connection opened
INFO : jdbc.audit - 10. Connection.new Connection returned 
INFO : jdbc.audit - 10. Connection.setReadOnly(false) returned 
INFO : jdbc.audit - 10. Connection.setAutoCommit(true) returned 
INFO : jdbc.audit - 1. PreparedStatement.new PreparedStatement returned 
INFO : jdbc.audit - 1. Connection.prepareStatement(select * from tbl_board where bno > 0) returned net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy@7096b474
INFO : jdbc.sqlonly - select * from tbl_board where bno > 0 

INFO : jdbc.sqltiming - select * from tbl_board where bno > 0 
 {executed in 56 msec}
INFO : jdbc.audit - 1. PreparedStatement.execute() returned true
INFO : jdbc.resultset - 1. ResultSet.new ResultSet returned 
INFO : jdbc.audit - 1. PreparedStatement.getResultSet() returned net.sf.log4jdbc.sql.jdbcapi.ResultSetSpy@2f9a01c1
INFO : jdbc.resultset - 1. ResultSet.getMetaData() returned oracle.jdbc.driver.OracleResultSetMetaData@458342d3
INFO : jdbc.resultset - 1. ResultSet.getType() returned 1003
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(BNO) returned 1
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(TITLE) returned 테스트제목
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(CONTENT) returned 테스트 내용
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(WRITER) returned user00
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(REGDATE) returned 2020-05-12 10:24:30.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(UPDATEDATE) returned 2020-05-12 10:24:30.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(BNO) returned 2
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(TITLE) returned 테스트제목
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(CONTENT) returned 테스트 내용1
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(WRITER) returned user01
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(REGDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(UPDATEDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(BNO) returned 3
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(TITLE) returned 테스트제목
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(CONTENT) returned 테스트 내용2
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(WRITER) returned user02
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(REGDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(UPDATEDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(BNO) returned 4
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(TITLE) returned 테스트제목
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(CONTENT) returned 테스트 내용3
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(WRITER) returned user03
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(REGDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(UPDATEDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(BNO) returned 5
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(TITLE) returned 테스트제목
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(CONTENT) returned 테스트 내용4
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getString(WRITER) returned user04
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(REGDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultset - 1. ResultSet.getTimestamp(UPDATEDATE) returned 2020-05-12 10:24:42.0
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultsettable - 
|----|------|--------|-------|----------------------|----------------------|
|bno |title |content |writer |regdate               |updatedate            |
|----|------|--------|-------|----------------------|----------------------|
|1   |테스트제목 |테스트 내용  |user00 |2020-05-12 10:24:30.0 |2020-05-12 10:24:30.0 |
|2   |테스트제목 |테스트 내용1 |user01 |2020-05-12 10:24:42.0 |2020-05-12 10:24:42.0 |
|3   |테스트제목 |테스트 내용2 |user02 |2020-05-12 10:24:42.0 |2020-05-12 10:24:42.0 |
|4   |테스트제목 |테스트 내용3 |user03 |2020-05-12 10:24:42.0 |2020-05-12 10:24:42.0 |
|5   |테스트제목 |테스트 내용4 |user04 |2020-05-12 10:24:42.0 |2020-05-12 10:24:42.0 |
|----|------|--------|-------|----------------------|----------------------|

INFO : jdbc.resultset - 1. ResultSet.next() returned false
INFO : jdbc.resultset - 1. ResultSet.close() returned void
INFO : jdbc.audit - 1. Connection.getMetaData() returned oracle.jdbc.driver.OracleDatabaseMetaData@665e9289
INFO : jdbc.audit - 1. PreparedStatement.isClosed() returned false
INFO : jdbc.audit - 1. PreparedStatement.close() returned 
INFO : jdbc.audit - 1. Connection.clearWarnings() returned 
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=1, title=테스트제목, content=테스트 내용, writer=user00, regdate=Tue May 12 10:24:30 KST 2020, updateDate=Tue May 12 10:24:30 KST 2020)
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=2, title=테스트제목, content=테스트 내용1, writer=user01, regdate=Tue May 12 10:24:42 KST 2020, updateDate=Tue May 12 10:24:42 KST 2020)
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=3, title=테스트제목, content=테스트 내용2, writer=user02, regdate=Tue May 12 10:24:42 KST 2020, updateDate=Tue May 12 10:24:42 KST 2020)
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=4, title=테스트제목, content=테스트 내용3, writer=user03, regdate=Tue May 12 10:24:42 KST 2020, updateDate=Tue May 12 10:24:42 KST 2020)
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=5, title=테스트제목, content=테스트 내용4, writer=user04, regdate=Tue May 12 10:24:42 KST 2020, updateDate=Tue May 12 10:24:42 KST 2020)
INFO : jdbc.audit - 1. Connection.getAutoCommit() returned true
INFO : jdbc.audit - 1. PreparedStatement.new PreparedStatement returned 
INFO : jdbc.audit - 1. Connection.prepareStatement(select seq_board.nextval from dual) returned net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy@350ec41e
INFO : jdbc.sqlonly - select seq_board.nextval from dual 

INFO : jdbc.sqltiming - select seq_board.nextval from dual 
 {executed in 8 msec}
INFO : jdbc.audit - 1. PreparedStatement.execute() returned true
INFO : jdbc.resultset - 1. ResultSet.new ResultSet returned 
INFO : jdbc.audit - 1. PreparedStatement.getResultSet() returned net.sf.log4jdbc.sql.jdbcapi.ResultSetSpy@69637b10
INFO : jdbc.resultset - 1. ResultSet.getMetaData() returned oracle.jdbc.driver.OracleResultSetMetaData@71984c3
INFO : jdbc.resultset - 1. ResultSet.getType() returned 1003
INFO : jdbc.resultset - 1. ResultSet.next() returned true
INFO : jdbc.resultset - 1. ResultSet.getLong(NEXTVAL) returned 6
INFO : jdbc.resultset - 1. ResultSet.wasNull() returned false
INFO : jdbc.resultsettable - 
|--------|
|nextval |
|--------|
|6       |
|--------|

INFO : jdbc.resultset - 1. ResultSet.next() returned false
INFO : jdbc.resultset - 1. ResultSet.close() returned void
INFO : jdbc.audit - 1. Connection.getMetaData() returned oracle.jdbc.driver.OracleDatabaseMetaData@665e9289
INFO : jdbc.audit - 1. PreparedStatement.isClosed() returned false
INFO : jdbc.audit - 1. PreparedStatement.close() returned 
INFO : jdbc.audit - 1. PreparedStatement.new PreparedStatement returned 
INFO : jdbc.audit - 1. Connection.prepareStatement(insert into tbl_board(bno, title, content, writer)
		values (?, ?, ?, ?)) returned net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy@470a696f
INFO : jdbc.audit - 1. PreparedStatement.setLong(1, 6) returned 
INFO : jdbc.audit - 1. PreparedStatement.setString(2, "새로 작성하는 글 SelectKey") returned 
INFO : jdbc.audit - 1. PreparedStatement.setString(3, "새로 작성하는 내용 SelectKey") returned 
INFO : jdbc.audit - 1. PreparedStatement.setString(4, "newbie") returned 
INFO : jdbc.sqlonly - insert into tbl_board(bno, title, content, writer) values (6, '새로 작성하는 글 SelectKey', '새로 작성하는 
내용 SelectKey', 'newbie') 

INFO : jdbc.sqltiming - insert into tbl_board(bno, title, content, writer) values (6, '새로 작성하는 글 SelectKey', '새로 작성하는 
내용 SelectKey', 'newbie') 
 {executed in 3 msec}
INFO : jdbc.audit - 1. PreparedStatement.execute() returned false
INFO : jdbc.audit - 1. PreparedStatement.getUpdateCount() returned 1
INFO : jdbc.audit - 1. PreparedStatement.isClosed() returned false
INFO : jdbc.audit - 1. PreparedStatement.close() returned 
INFO : jdbc.audit - 1. Connection.clearWarnings() returned 
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=6, title=새로 작성하는 글 SelectKey, content=새로 작성하는 내용 SelectKey, writer=newbie, regdate=null, updateDate=null)
INFO : jdbc.audit - 1. Connection.getAutoCommit() returned true
INFO : jdbc.audit - 1. PreparedStatement.new PreparedStatement returned 
INFO : jdbc.audit - 1. Connection.prepareStatement(insert into tbl_board(bno, title, content, writer)
		values (seq_board.nextval, ?, ?, ?)) returned net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy@28d6290
INFO : jdbc.audit - 1. PreparedStatement.setString(1, "새로 작성하는 글") returned 
INFO : jdbc.audit - 1. PreparedStatement.setString(2, "새로 작성하는 내용") returned 
INFO : jdbc.audit - 1. PreparedStatement.setString(3, "newbie") returned 
INFO : jdbc.sqlonly - insert into tbl_board(bno, title, content, writer) values (seq_board.nextval, '새로 작성하는 글', 
'새로 작성하는 내용', 'newbie') 

INFO : jdbc.sqltiming - insert into tbl_board(bno, title, content, writer) values (seq_board.nextval, '새로 작성하는 글', 
'새로 작성하는 내용', 'newbie') 
 {executed in 3 msec}
INFO : jdbc.audit - 1. PreparedStatement.execute() returned false
INFO : jdbc.audit - 1. PreparedStatement.getUpdateCount() returned 1
INFO : jdbc.audit - 1. PreparedStatement.isClosed() returned false
INFO : jdbc.audit - 1. PreparedStatement.close() returned 
INFO : jdbc.audit - 1. Connection.clearWarnings() returned 
INFO : com.ohj.mapper.BoardMapperTests - BoardVO(bno=null, title=새로 작성하는 글, content=새로 작성하는 내용, writer=newbie, regdate=null, updateDate=null)
INFO : jdbc.connection - 11. Connection opened
INFO : jdbc.audit - 11. Connection.new Connection returned 
INFO : com.ohj.persistence.JDBCTests - net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy@77602954
INFO : jdbc.connection - 11. Connection closed
INFO : jdbc.audit - 11. Connection.close() returned 
INFO : org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@7791a895: startup date [Wed May 13 11:36:14 KST 2020]; root of context hierarchy
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : jdbc.connection - 1. Connection closed
INFO : jdbc.audit - 1. Connection.close() returned 
INFO : jdbc.connection - 2. Connection closed
INFO : jdbc.audit - 2. Connection.close() returned 
INFO : jdbc.connection - 3. Connection closed
INFO : jdbc.audit - 3. Connection.close() returned 
INFO : jdbc.connection - 4. Connection closed
INFO : jdbc.audit - 4. Connection.close() returned 
INFO : jdbc.connection - 5. Connection closed
INFO : jdbc.audit - 5. Connection.close() returned 
INFO : jdbc.connection - 6. Connection closed
INFO : jdbc.audit - 6. Connection.close() returned 
INFO : jdbc.connection - 7. Connection closed
INFO : jdbc.audit - 7. Connection.close() returned 
INFO : jdbc.connection - 8. Connection closed
INFO : jdbc.audit - 8. Connection.close() returned 
INFO : jdbc.connection - 9. Connection closed
INFO : jdbc.audit - 9. Connection.close() returned 
INFO : jdbc.connection - 10. Connection closed
INFO : jdbc.audit - 10. Connection.close() returned 
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

 

테스트 결과의 마지막을 살펴보면

BoardVO 클래스의 toString()을 이용해 bno멤버변수의값을 알아보기 위한 것이다

 

실행결과를 보면 

'select seq_board.nextval from dual'쿼리가 먼저 실행되고

여기서 생성된 결과를 이용하여

bno값을 처리 되는 것을 볼 수 있다.

 

테스트 코드의 마지막 부분을 보면

BoardVO 객체의 bno값이 지정된 것을 확인할 수 있다.

* 참고 : 시퀸스의 값이므로 테스트 할 때 마다 다른 값이 나온다.

시퀸스 값: 중복 없는 값을 위한 것일 뿐 다른 의미는 없다.

 

@SelectKey를 이용하는 방식은

SQL을 한번더 실행하는 부담이 있기는 하지만,

자동으로 추가되는 PK값을 확인해야하는 상황에서 유용하게 사용될 수 있다.

 

전체 조회 -@어노테이션
		-  XML
레코드 삽입 - xml
			1.insert
            2.미리 PK값을 꺼내서 insert
            
(상세보기(BoardVO 객체를 리턴 받는다), 삭제, 수정)

 

insert가 된 데이터를 조회하는 작업

PK를 이용하여 처리하므로

BoardMapper 의 파라미터 역시 BoardVO 클래스의 bno 타입 정보를 이용하여 작업

//BoardMapper.java

package com.ohj.mapper;

import java.util.List;

//XML파일에 작성 해놨음으로 주석 처리한다.
//import org.apache.ibatis.annotations.Select;
import com.ohj.domain.BoardVO;


public interface BoardMapper {

//BoardMapper.XML파일에 작성 해놨음으로 주석 처리한다.
// @Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();
   
   //단순히 insert만 해주는 메소드
   public void insert(BoardVO board);
   //insert를 해줬을 때 해당 VO 멤버 값을 꺼낼 수 있는 메소드
   public void insertSelectKey(BoardVO board);
   //지정한 글 한 개만 보여주는 메소드
   public BoardVO read(long bno);
   
}

//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">
<!--
<generatorConfiguration>
  <context id="context1">
    <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" />
    <javaModelGenerator targetPackage="???" targetProject="???" />
    <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" />
    <table schema="???" tableName="???">
      <columnOverride column="???" property="???" />
    </table>
  </context>
</generatorConfiguration> -->


<mapper namespace = "com.ohj.mapper.BoardMapper">
	<!-- BoardMapper.java-->
	<select id = "getList" resultType="com.ohj.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>
	
	<select id="read" resultType="com.ohj.domain.BoardVO">
	 select * from tbl_board where bno=#{bno}
	</select>

</mapper>

 

마이바티스는

Mapper인터페이스의 리턴타입에 맞게 select의 결과를 처리하기 때문에

tbl_board 테이블 내 모든 컬럼은 BoardVO의

bno, title, content, writer regdate, updateDate 속성 값으로 처리 된다.

 

마이바티스는 bno라는 컬럼이 존재하면

BoardVO인스튼서의 setBno()를 호출하여 해당 데이터를 세팅한다.

 

마이바티스의 모든 파라미터와 리턴 타입의 처리는

get 파라미터명(), set 컬럼명() 의 규칙으로 호출된다.

테스트 코드(BoardMapperTests.java)

현재 테이블에 존재하는 데이터의 bno 컬럼의 값을 이용해서 확인.

데이터 읽기에 의한 테스트 메서드 추가

//BoardMapperTests.java


package com.ohj.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 com.ohj.domain.BoardVO;

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)
   BoardMapper mapper;
   
   @Test
   public void testGetList() {
      // 리스트 반환(board객체를 print 출력하면 toString 메소드에 의해서 객체에 대한 번지수가 나온다.)
      mapper.getList().forEach(board -> log.info(board));  
   }// testGetList END
   
   @Test
   public void testInsert() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글");
	   board.setContent("새로 작성하는 내용");
	   board.setWriter("newbie");
	   
	   mapper.insert(board);
	   
	   log.info(board);
   }//testInsert() END
   
   @Test
   public void testInsertSelectKey() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 SelectKey");
	   board.setContent("새로 작성하는 내용 SelectKey");
	   board.setWriter("newbie");
	   
	   mapper.insertSelectKey(board);
	   
	   //이유 : 롬복이 자동으로 tosrtinf을 이용하요 객체를 만들어주고 그 객체가 가지고 있는 값을 각각 확인해보기 위해서
	   log.info(board);
   }//testInsertSelectKey() END
   
   @Test
   public void testRead() {
	   //존재하는 게시물 번호로 테스트
	   BoardVO board = mapper.read(5L);//5L :long 타입이기 때문에 대문자 L을 써준다.
	   log.info(board);
   }
   
   
}// BoardMapperTests END

 

 

삭제하기

 

package com.ohj.mapper;

import java.util.List;

//XML파일에 작성 해놨음으로 주석 처리한다.
//import org.apache.ibatis.annotations.Select;
import com.ohj.domain.BoardVO;


public interface BoardMapper {

//BoardMapper.XML파일에 작성 해놨음으로 주석 처리한다.
// @Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();
   
   //단순히 insert만 해주는 메소드
   public void insert(BoardVO board);
   //insert를 해줬을 때 해당 VO 멤버 값을 꺼낼 수 있는 메소드
   public void insertSelectKey(BoardVO board);
   //지정한 글 한 개만 보여주는 메소드
   public BoardVO read(long bno);
   //삭제하기
   public int delete(long bno);
   
   
}

<?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">
<!--
<generatorConfiguration>
  <context id="context1">
    <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" />
    <javaModelGenerator targetPackage="???" targetProject="???" />
    <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" />
    <table schema="???" tableName="???">
      <columnOverride column="???" property="???" />
    </table>
  </context>
</generatorConfiguration> -->


<mapper namespace = "com.ohj.mapper.BoardMapper">
	<!-- BoardMapper.java-->
	<select id = "getList" resultType="com.ohj.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>
	
	<select id="read" resultType="com.ohj.domain.BoardVO">
	 select * from tbl_board where bno=#{bno}
	</select>
	
	<delete id="delete">
		delete from tbl_board where bno = #{bno}
	</delete>
	

</mapper>

 

package com.ohj.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 com.ohj.domain.BoardVO;

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)
   BoardMapper mapper;
   
   @Test
   public void testGetList() {
      // 리스트 반환(board객체를 print 출력하면 toString 메소드에 의해서 객체에 대한 번지수가 나온다.)
      mapper.getList().forEach(board -> log.info(board));  
   }// testGetList END
   
   @Test
   public void testInsert() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글");
	   board.setContent("새로 작성하는 내용");
	   board.setWriter("newbie");
	   
	   mapper.insert(board);
	   
	   log.info(board);
   }//testInsert() END
   
   @Test
   public void testInsertSelectKey() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 SelectKey");
	   board.setContent("새로 작성하는 내용 SelectKey");
	   board.setWriter("newbie");
	   
	   mapper.insertSelectKey(board);
	   
	   //이유 : 롬복이 자동으로 tosrtinf을 이용하요 객체를 만들어주고 그 객체가 가지고 있는 값을 각각 확인해보기 위해서
	   log.info(board);
   }//testInsertSelectKey() END
   
   @Test
   public void testRead() {
	   //존재하는 게시물 번호로 테스트
	   BoardVO board = mapper.read(5L);//5L :long 타입이기 때문에 대문자 L을 써준다.
	   log.info(board);
   }
   
   @Test
   public void testDelete() {
	   log.info("DELETE COUNT:" + mapper.delete(3L));   
   }
   
   
}// BoardMapperTests END

 

수정하기

 

게시물의 업데이트는 제목, 내용, 작성자를 수정한다고 가정

업데이트할 때에는

최종 수정시간을 데이터베이스 내의 현재 시간으로 수정한다

 

업데이트와 딜리트와 마찬가지로 

'몇 개의 데이터가 수정되었는가'를 반환 받을 수 있도록 int 타입으로 메서드의 리턴 값을 설계

 

 

package com.ohj.mapper;

import java.util.List;

//XML파일에 작성 해놨음으로 주석 처리한다.
//import org.apache.ibatis.annotations.Select;
import com.ohj.domain.BoardVO;


public interface BoardMapper {

//BoardMapper.XML파일에 작성 해놨음으로 주석 처리한다.
// @Select("select * from tbl_board where bno > 0")
   public List<BoardVO> getList();
   
   //단순히 insert만 해주는 메소드
   public void insert(BoardVO board);
   //insert를 해줬을 때 해당 VO 멤버 값을 꺼낼 수 있는 메소드
   public void insertSelectKey(BoardVO board);
   //지정한 글 한 개만 보여주는 메소드
   public BoardVO read(long bno);
   //삭제하기
   public int delete(long bno);
   //수정하기
   public int update(BoardVO board);
   
}

<?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">
<!--
<generatorConfiguration>
  <context id="context1">
    <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" />
    <javaModelGenerator targetPackage="???" targetProject="???" />
    <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" />
    <table schema="???" tableName="???">
      <columnOverride column="???" property="???" />
    </table>
  </context>
</generatorConfiguration> -->


<mapper namespace = "com.ohj.mapper.BoardMapper">
	<!-- BoardMapper.java-->
	<select id = "getList" resultType="com.ohj.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>
	
	<select id="read" resultType="com.ohj.domain.BoardVO">
	 select * from tbl_board where bno=#{bno}
	</select>
	
	<delete id="delete">
		delete from tbl_board where bno = #{bno}
	</delete>
	
	<update id="update">
		update tbl_board
		set title = #{title}, content = #{content}, writer = #{writer}, updateDate = sysdate
		where bno = #{bno}
	</update>
	

</mapper>

//BoardMapperTests.java

package com.ohj.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 com.ohj.domain.BoardVO;

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)
   BoardMapper mapper;
   
   @Test
   public void testGetList() {
      // 리스트 반환(board객체를 print 출력하면 toString 메소드에 의해서 객체에 대한 번지수가 나온다.)
      mapper.getList().forEach(board -> log.info(board));  
   }// testGetList END
   
   @Test
   public void testInsert() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글");
	   board.setContent("새로 작성하는 내용");
	   board.setWriter("newbie");
	   
	   mapper.insert(board);
	   
	   log.info(board);
   }//testInsert() END
   
   @Test
   public void testInsertSelectKey() {
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 SelectKey");
	   board.setContent("새로 작성하는 내용 SelectKey");
	   board.setWriter("newbie");
	   
	   mapper.insertSelectKey(board);
	   
	   //이유 : 롬복이 자동으로 tosrtinf을 이용하요 객체를 만들어주고 그 객체가 가지고 있는 값을 각각 확인해보기 위해서
	   log.info(board);
   }//testInsertSelectKey() END
   
   @Test
   public void testRead() {
	   //존재하는 게시물 번호로 테스트
	   BoardVO board = mapper.read(5L);//5L :long 타입이기 때문에 대문자 L을 써준다.
	   log.info(board);
   }
   
   @Test
   public void testDelete() {
	   log.info("DELETE COUNT:" + mapper.delete(3L));   
   }
   
   @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);   
   }
   
   
}// BoardMapperTests END

 

비즈니스 계층: 로직을 기준으로 해서 처리

 

예) 쇼핑몰에서 상품을 구매한다고 가정

해당 쇼핑몰의 로직 예: 물건을 구매한 회원에게는 포인트를 올려준다

 

영속계층의 설계 : 상품과 회원을 나누어서 설계

비즈니스 계층 설계 : 상품영역과 회원영역을 동시에 사용하여 하나의 로직을 처리

 

 

구매서비스 - 상품 처리 객체

               - 회원 처리 객체

 

현재 단일 테이블을 사용하고 있기 때문에 위와 같은 구조는 아니지만,

설계를 할 때는 원칙적으로 영역을 구분하여 작성

일반적으로 비즈니스 영역에 있는 객체들을 서비스(Service)라는 용어로 사용

 

 

1. 비즈니스 계층의 설정

 

1-1. 비즈니스 계층을 위한 패키지 작성

패키지를 추가

2. 비즈니스 계층 설계

 

각 계층 간의 연결은 인터페이스를 이용하요 느슨한 연결(결합)을 한다.

게시물을

BoardService 인터페이스와 인터페이스를 구현 받는 BoardServicBoardServiceImple를 만들어준다.

BoardService 인터페이스
BoardServiceImpl 

 

 

2. BoardService 인터페이스에 메서드 선언 추가

 

BoardService 매서드 설계시,

메서드 이름은 현실적인 로직의 이름을 사용

명백하게 반환해야하는 데이터가 있는(select)메서드 :  리턴타입을 명시

 

get() : 게시물을 특정한 게시물을 가져오는 메서드

getList(): 전체 리스트를 구하는 메서드.

 

이 두가지 메서드는 처음부터 리턴 타입을 결정하여 진행

 

 

 

package com.ohj.service;

import java.util.List;

import com.ohj.domain.BoardVO;

public interface BoardService {
	
	//BoardMepper.java 와 연결 된다.
	
	public void register(BoardVO board); // 새 글을 등록 할 때 사용
	
	public BoardVO get(Long bno); //내가 지정한 글 번호의 레코드를 꺼내올 때 사용
	
	public boolean modify(BoardVO board); // 기존 글을 수정 할 때 사용
	
	public boolean remove(Long bno); //해당 글을 삭제 할 때
	
	public List<BoardVO> getList();// 전체 데이터를 조회할 때

}

 

BoardService를 저장하는 순간,

BoardServiceImpl에 오류가 발생하면 마우스를 대고 add를 해주면 아래와 같은 코드가 생성 된다.

package com.ohj.service;

import java.util.List;

import com.ohj.domain.BoardVO;

public class BoardServiceImpl implements BoardService {

	public BoardServiceImpl() {
		
	}

	@Override
	public void register(BoardVO board) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public BoardVO get(Long bno) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean modify(BoardVO board) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean remove(Long bno) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public List<BoardVO> getList() {
		// TODO Auto-generated method stub
		return null;
	}

}

 

추가

 

 

 

클래스 선언부에 어노테이션 추가

 

package com.ohj.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired; // 빈을 자동 주입
import org.springframework.stereotype.Service; //역할 알려주는애안에 있는 서비스(Service라고 어노테이션을 달면 얘는 서비스 역할을 하는애다 라고 알려주는 것)

import com.ohj.domain.BoardVO;
//수정 삭제 메소드를 가지고 있음
import com.ohj.mapper.BoardMapper;

//소스트리를 자동으로 만들어줌
//lombok으로 소스들이 매우 줄어들게 됨
import lombok.AllArgsConstructor;// 전체 값을 모두 받는 클래스(생성자)
import lombok.Setter; //toString으로 자동으로 변환해주기 위한 setter import
import lombok.extern.log4j.Log4j; //로그 값 찍어주는 것(콘솔창 찍어주는 것)


@Log4j
@Service
//스프링 4.3 부터는 단일 파라미터를 뱓는 생성자의 경우, 필요한 파라미터를 자동으로 주입 가능.
@AllArgsConstructor // 모든 파라미터를 이용하는 생성자를 생성
public class BoardServiceImpl implements BoardService {

	//비즈니스 계층에서 사용하기 때문에 서비스 어노테이션을 붙여 준다.
	//일을 수행하기 위해 mepper를 주입해야하는데 오토와이어드를 붙여 준다.
	// lombok이 자동 생성자를 생성해주기 때문에 기본 생성자는 없애준다.
	//public BoardServiceImpl() {	
	//}

	@Override
	public void register(BoardVO board) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public BoardVO get(Long bno) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean modify(BoardVO board) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean remove(Long bno) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public List<BoardVO> getList() {
		// TODO Auto-generated method stub
		return null;
	}

}

 

BoardMapper 객체를 위한 멤버(인스턴스) 변수 선언

 

package com.ohj.service;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired; // 빈을 자동 주입
import org.springframework.stereotype.Service; //역할 알려주는애안에 있는 서비스(Service라고 어노테이션을 달면 얘는 서비스 역할을 하는애다 라고 알려주는 것)

import com.ohj.domain.BoardVO;
//수정 삭제 메소드를 가지고 있음
import com.ohj.mapper.BoardMapper;

//소스트리를 자동으로 만들어줌
//lombok으로 소스들이 매우 줄어들게 됨
import lombok.AllArgsConstructor;// 전체 값을 모두 받는 클래스(생성자)
import lombok.Setter; //toString으로 자동으로 변환해주기 위한 setter import
import lombok.extern.log4j.Log4j; //로그 값 찍어주는 것(콘솔창 찍어주는 것)


@Log4j
@Service
//스프링 4.3 부터는 단일 파라미터를 뱓는 생성자의 경우, 필요한 파라미터를 자동으로 주입 가능.
@AllArgsConstructor // 모든 파라미터를 이용하는 생성자를 생성
public class BoardServiceImpl implements BoardService {

	//비즈니스 계층에서 사용하기 때문에 서비스 어노테이션을 붙여 준다.
	//일을 수행하기 위해 mepper를 주입해야하는데 오토와이어드를 붙여 준다.
	// lombok이 자동 생성자를 생성해주기 때문에 기본 생성자는 없애준다.
	//public BoardServiceImpl() {	
	//}
	
	@Setter(onMethod_ = @Autowired)
	private BoardMapper Mapper;

	@Override
	public void register(BoardVO board) {
		log.info("register" + board);
		Mapper.insertSelectKey(board);
		
	}

	@Override
	public BoardVO get(Long bno) {
		log.info("get...." + bno);
		return Mapper.read(bno);
	}

	@Override
	public boolean modify(BoardVO board) {
		log.info("modify...." + board);
		return Mapper.update(board)==1;// 값이 1일 떄 지워준다.
	}

	@Override
	public boolean remove(Long bno) {
		log.info("remove...." + bno);
		return Mapper.delete(bno)==1;
	
	}

	@Override
	public List<BoardVO> getList() {
		log.info("getList....");
		return Mapper.getList();
	}

}

 

spring의 서비스 어노테이션을 빨리 찾기 위해서 위 코드를 넣어준다.

 

 

package com.ohj.service;

import static org.junit.Assert.assertNotNull;

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;

@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class BoardServiceTests {
   @Setter(onMethod_ = {@Autowired})
   private BoardService service;
   
   @Test
   public void testExist() { // 주입이 잘 되는지 확인을 위한 testExist 메서드
      log.info(service);
      assertNotNull(service);
   }//testExist() END 
   
}//BoardServiceTests CLASS END

실행 후 성공 시 콘솔창 

package com.ohj.service;

import static org.junit.Assert.assertNotNull;

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 com.ohj.domain.BoardVO;

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

@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class BoardServiceTests {
   @Setter(onMethod_ = {@Autowired})
   private BoardService service;
   
   @Test
   public void testExist() { // 주입이 잘 되는지 확인을 위한 testExist 메서드
      log.info(service);
      assertNotNull(service);
   }//testExist() END 
   
   @Test
   public void testRegister() {
	   
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 테스트 ");
	   board.setContent("새로 작성하는 내용 테스트");
	   board.setWriter("newbie test");
	   
	   service.register(board);
	   log.info("생성된 게시물의 번호:" + board.getBno());
   }
   
}//BoardServiceTests CLASS END

package com.ohj.service;

import static org.junit.Assert.assertNotNull;

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 com.ohj.domain.BoardVO;

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

@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class BoardServiceTests {
   @Setter(onMethod_ = {@Autowired})
   private BoardService service;
   
   @Test
   public void testExist() { // 주입이 잘 되는지 확인을 위한 testExist 메서드
      log.info(service);
      assertNotNull(service);
   }//testExist() END 
   
   @Test
   public void testRegister() {
	   
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 테스트 ");
	   board.setContent("새로 작성하는 내용 테스트");
	   board.setWriter("newbie test");
	   
	   service.register(board);
	   log.info("생성된 게시물의 번호:" + board.getBno());
   }
   
   
   //하나의 글만 가져오는 메소드 테스트
   @Test
   public void testGet() {
	   log.info(service.get(1L));
   }
   
}//BoardServiceTests CLASS END

package com.ohj.service;

import static org.junit.Assert.assertNotNull;

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 com.ohj.domain.BoardVO;

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

@Log4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class BoardServiceTests {
   @Setter(onMethod_ = {@Autowired})
   private BoardService service;
   
   @Test
   public void testExist() { // 주입이 잘 되는지 확인을 위한 testExist 메서드
      log.info(service);
      assertNotNull(service);
   }//testExist() END 
   
   @Test
   public void testRegister() {
	   
	   BoardVO board = new BoardVO();
	   board.setTitle("새로 작성하는 글 테스트 ");
	   board.setContent("새로 작성하는 내용 테스트");
	   board.setWriter("newbie test");
	   
	   service.register(board);
	   log.info("생성된 게시물의 번호:" + board.getBno());
   }
   
   
   //하나의 글만 가져오는 메소드 테스트
   @Test
   public void testGet() {
	   log.info(service.get(1L));
   }
   
   //삭제 테스트
   public void testDelete() {
	   //게시물 번호이 존재여부를 확인 하고 테스트 할 것
	   log.info("REMOVE RESULT:" + service.remove(7L));
   }
  
   //수정 테스트
   public void testUptate() {
	   BoardVO board = service.get(1L);
	   
	   if(board == null) {
		   return;
	   }
	   
	   board.setTitle("제목을 수정테스트 합니다.");

	   log.info("MODIFY RESULT:" + service.modify(board));
   }
   
   
}//BoardServiceTests CLASS END

+ Recent posts