영속성 비즈니스 계층
테이블의 컬럼 구조를 반영하는 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;
}
//인터페이스 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 클래스는
스프링을 이용하여
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 설정 및 생성하기
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>
히카리->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를 만들어준다.
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();
}
}
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
':: IT > Spring' 카테고리의 다른 글
AOP (0) | 2020.05.20 |
---|---|
[스프링프레임워크] 컨트롤러 작성, DAO,DTO,VO설명, 상세보기 (0) | 2020.05.14 |
[스프링프레임워크]오라클 테이블 생성과 Dummy 데이터 생성, (0) | 2020.05.12 |
[스프링프레임워크] 스프링프레임워크 폴더 생성, spring MVC 설명, DI, IoC, 스프링 MVC 프로젝트 기초 설정, (0) | 2020.05.11 |