Basis Service
Basis Service는 Java 5부터 지원하는 Generics 개념을 기반으로 개발되었으며,
DAO 인터페이스/구현 클래스, Service 인터페이스/구현 클래스, 단위테스트케이스 등 기본 CRUD 기능이 모두 구현된
클래스를 상속받아서
쉽게 사용할 수 있는 기능을 제공하고 있다.
Basis Service는
AppFuse
(http://appfuse.org/display/APF/Home)의 개념과 소스 코드(템플릿 포함)를 참고하여 Anyframe에 맞게 수정되었다.
아래의 Basis Service 구성 클래스들을 활용한 샘플 코드들은 직접 작성하여 사용할 수도 있고, Anyframe Gen 툴을 통해 자동 생성되는 코드를 사용할 수도 있다.
Anyframe Gen에 대한 자세한 설명은
Tool 매뉴얼
을 참고하도록 한다.
Basis Service를 이용할 때 다음과 같은 장점을 얻을 수 있다.
- 도메인 모델를 생성하고, 이 객체를 중심으로 DB접근 영역까지의 기본 CRUD 코드들을 쉽게 작성 할 수
있다.
- Hibernate/JPA, Query Service 와 같은 DAO Framework을
지원한다.
다음은 Basis Service 사용 방법이다.

Domain Model 클래스 생성
BaseObject
BaseObject는 DB 테이블을 도메인 모델로 생성하며, 엔티티 클래스로 정의하도록 한다.
BaseObject는 다음
세가지 메소드로 구현되어 있으며,
BaseObject
를 상속받아 사용할 경우 세가지 메소드에 대해 오버라이드 해야한다.
package anyframe.core.basis.model;
public abstract class BaseObject implements Serializable {
//key=value 형태의 String을 return
public abstract String toString();
//객체 비교. 단, Hibernate을 사용하는 경우 primary key 는 이 메소드에서 비교하지 말아야 한다.
public abstract boolean equals(Object o);
//equals() 메소드를 오버라이드 할 경우에는 hashcode()를 반드시 오버라이드 할것.
public abstract int hashCode();
}
Samples
다음은 BaseObject 를 이용한 Users Domain 에 대한 샘플코드
Users.java
의 일부분이다. BaseObject에 선언되어 있는 메소드를 오버라이드 하였다.
@Entity
@Table(name = "USERS", schema = "PUBLIC")
public class Users extends BaseObject implements Serializable {
private String userId;
private String userName;
...중략
public String toString() {
StringBuffer sb = new StringBuffer(getClass().getSimpleName());
sb.append(" [");
sb.append("userId").append("='").append(getUserId()).append("', ");
sb.append("userName").append("='").append(getUserName()).append("', ");
...중략
sb.append("]");
return sb.toString();
}
public boolean equals(Object o) {
...중략
Users pojo = (Users) o;
if ((userName != null)
? (!userName.equals(pojo.userName))
: (pojo.userName != null)) {
return false;
}
...중략
}
public int hashCode() {
int result = 0;
result = ((userName != null) ? userName.hashCode() : 0);
...중략
}
}
DAO 클래스 생성
GenericDao
DAO 인터페이스 생성을 위해 GenericDao<T, PK extends Serializable>
Class를 이용한다.
여기서 T는 도메인 객체 타입으로 도메인 모델 클래스를 의미하고, PK는 도메인 객체의 Primary Key 타입을 의미한다.
다음은
GenericDao
에 정의되어 있는 단건조회, 데이터 존재여부 확인, 저장, 삭제, 리스트 조회와 관련한 메소드이다.
package anyframe.core.basis.dao;
public interface GenericDao<T, PK extends Serializable> {
// 단건조회
T get(PK id) throws Exception;
// 데이터 존재여부 확인
boolean exists(PK id) throws Exception;
// 저장
T save(T object) throws Exception;
// 삭제
void remove(PK id) throws Exception;
// 리스트 조회(페이징처리)
public Page getList(SearchVO searchVO) throws Exception;
}
GenericDaoHibernate
DAO 구현 클래스를 생성할 때 Hibernate/JPA를 활용하기 위한
GenericDaoHibernate
의
구조이다.
DAO 인터페이스에 선언된 메소드가 구현되어 있다.
package anyframe.core.basis.dao.hibernate;
public class GenericDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> {
...중략
public T get(PK id) throws Exception {...중략}
public boolean exists(PK id) throws Exception {...중략}
public T save(T object) throws Exception {...중략}
public void remove(PK id) throws Exception {...중략}
public Page getList(SearchVO searchVO) throws Exception {...중략}
}
GenericDaoQuery
DAO 구현 클래스를 생성할 때 Query Service 를 이용하기 위해
GenericDaoQuery
,
QueryDaoUtils
를 사용한다.
다음은 GenericDaoQuery 의 구조이며, QueryDaoUtils 는 primary key 와 query name을
위한 Utility 파일로 링크를 참조한다.
package anyframe.core.basis.dao.query;
public class GenericDaoQuery<T, PK extends Serializable>
extends AbstractDAO implements GenericDao<T, PK> {
...중략
public T get(PK id) throws Exception {...중략}
public boolean exists(PK id) throws Exception {...중략}
public T save(T object) throws Exception {...중략}
public void remove(PK id) throws Exception {...중략}
public Page getList(SearchVO searchVO) throws Exception {...중략}
Samples
앞서 소개된 Class 를 기반으로 하여 개발한
UsersDao.java
와
UsersDaoHibernateImpl.java
,
UserDaoQueryImpl.java
코드의 일부이다.
Hibernate 또는 Query Service 를 사용하기 위한 Configuration 은 각각의 Tech.Service 매뉴얼을
참조한다.
-
UserDao로 GenericDao를 상속받았으며, Page getList 메소드 를 오버라이드 하였다.
public interface UsersDao<Users, String> extends GenericDao {
// GenericDao 선언된 메소드 중 리스트 조회만 오버라이드 한 경우
// 나머지 단건조회, 데이터 존재여부 확인, 저장, 삭제 기능은 GenericDao 에 정의된 그대로 사용
Page getList(SearchVO searchVO) throws Exception;
}
-
Hibernate 을 이용한 DAO 구현으로 오버라이드 하려고 했던 메소드에 대해서만 코딩을 하였다.
오버라이드 하지 않은 메소드(단건조회, 데이터 존재여부 확인, 저장, 삭제)의 기능은
GenericDaoHibernate에 구현된 형태 그대로 사용한다.
@Repository("usersDao")
public class UsersDaoHibernateImpl
extends GenericDaoHibernate<Users, String> implements UsersDao {
public UsersDaoHibernateImpl() {
super(Users.class);
}
// GenericDaoHibernate 구현된 메소드 중 리스트 조회만 오버라이드 한 경우
// 나머지 단건조회, 데이터 존재여부 확인, 저장, 삭제 기능은 GenericDaoHibernate 에 정의된 그대로 사용
public Page getList(SearchVO searchVO) throws Exception {
...중략
}
}
-
Query Service를 이용한 DAO 구현소스의 일부분이다. 오버라이드 하지 않은 메소드(단건조회, 데이터
존재여부 확인, 저장, 삭제)의 기능은 GenericDaoQuery에 구현된 형태 그대로 사용한다.
@Repository("usersDao")
public class UsersDaoQueryImpl extends GenericDaoQuery<Users, String> implements UsersDao {
public UsersDaoQueryImpl() {
super(Users.class);
}
// GenericDaoQuery에 구현된 메소드 중 리스트 조회만 오버라이드 한 경우
// 나머지 단건조회, 데이터 존재여부 확인, 저장, 삭제 기능은 GenericDaoQuery 에 정의된 그대로 사용
public Page getList(SearchVO searchVO) throws Exception {
...중략
}
}
Service 클래스 생성
GenericManager
서비스 인터페이스는
GenericManager
를 사용한다.
GenericMager에는 단건조회, 데이터 존재여부 확인, 저장, 삭제, 리스트 조회에 관한 메소드가 선언되어 있다.
package anyframe.core.basis.service;
public interface GenericManager<T, PK extends Serializable> {
// 단건조회
T get(PK id) throws Exception;
// 데이터 존재여부 확인
boolean exists(PK id) throws Exception;
// 저장
T save(T object) throws Exception;
// 삭제
void remove(PK id) throws Exception;
// 리스트 조회(페이징 처리)
public Page getList(SearchVO searchVO) throws Exception;
}
GenericManagerImpl
서비스 구현 클래스는
GenericManagerImpl
을 사용하며 다음과 같은 구조로 되어 있다.
package anyframe.core.basis.service.impl;
public class GenericManagerImpl<T, PK extends Serializable> implements GenericManager<T, PK> {
protected final Log log = LogFactory.getLog(getClass());
protected GenericDao<T, PK> dao;
public GenericManagerImpl() {
}
public GenericManagerImpl(GenericDao<T, PK> genericDao) {
this.dao = genericDao;
}
public T get(PK id) throws Exception {
return dao.get(id);
}
...중략
}
Samples
다음은 GenericMager, GenericManagerImpl을 상속받은
UsersService.java
,
UsersServiceImpl.java
파일이며, 필요할 경우 오버라이드 하여 사용한다.
public interface UsersService extends GenericManager<Users, String> {
// GenericManager에 선언된 메소드 중 리스트 조회만 오버라이드 한 경우
// 나머지 단건조회, 데이터 존재여부 확인, 저장, 삭제 기능은 GenericManager 에 정의된 그대로 사용
Page getList(SearchVO searchVO) throws Exception;
}
public class UsersServiceImpl extends GenericManagerImpl<Users, String> implements UsersService {
UsersDao usersDao;
public UsersServiceImpl(UsersDao usersDao) {
super(usersDao);
this.usersDao = usersDao;
}
// GenericManagerImpl에 구현된 메소드 중 리스트 조회만 오버라이드 한 경우
// 나머지 단건조회, 데이터 존재여부 확인, 저장, 삭제 기능은 GenericManagerImpl 에 정의된 그대로 사용
public Page getList(SearchVO searchVO) throws Exception {
return this.usersDao.getList(searchVO);
}
}
Test Code 생성
Unit Test Case
Unit Test Case 작성을 위해 jMock을 사용한
BaseManagerMockTestCase
를 이용한다.
package anyframe.core.basis.service.impl;
@RunWith(JMock.class)
public abstract class BaseManagerMockTestCase {
final protected Log log = LogFactory.getLog(getClass());
protected ResourceBundle rb;
protected Mockery context = new JUnit4Mockery();
public BaseManagerMockTestCase() {중략...}
protected Object populate(Object obj) throws Exception {중략...}
}
Integration Test Case
Integration Test Case는 Basis Service 에서는 제공하지 않으며, Spring Framework의 Test를 이용한다.
Samples
다음은 BaseManagerMockTestCase 를 이용한 Unit Test Case
UsersServiceImplTest
파일이다.
Integration Test Case는 다음 링크된 소스
UsersDaoTest.java
를 참조한다.
public class UsersServiceImplTest extends BaseManagerMockTestCase {
private UsersServiceImpl service = null;
private UsersDao dao = null;
@Before
public void setUp() {
dao = context.mock(UsersDao.class);
service = new UsersServiceImpl(dao);
}
@After
public void tearDown() {
service = null;
}
@Test
public void testGetUsers() throws Exception {
log.debug("testing get...");
final String userId = new String("CpVpDcTwTcBwToFzAzGs");
final Users users = new Users();
// set expected behavior on dao
context.checking(new Expectations() {{
one(dao).get(with(equal(userId)));
will(returnValue(users));
}});
Users result = service.get(userId);
assertSame(users, result);
}
중략...
}
Resources
다운로드
샘플 테스트 코드를 포함하고 있는 anyframe-corebasis-src.zip 파일을 다운받은 후,
테스트 환경 설정
을 참조하여
위에서 제시한 예제 코드를 실행해 볼 수 있다.
| Name |
Download |
| anyframe-corebasis-src.zip
|
Download
|
참고자료