공항관리 시스템을 개발하면서 사용하였던 기본적인 CRUD 구현 개념에 대해서 다루고자 한다. 각각의 기능마다 추가적인 기능이 필요했고 조금씩 구현방식이 다른 부분이 있었지만, 기본적으로 작성했던 큰 틀에 대해서 정리하고자 한다.
위의 순서대로 구현한 각각의 레이어들은 다음과 같은 순서로 동작된다.
req > controller > service > dao > db > dao > service > controller > res
위 프로젝트에서는 이를 비교하지 않고 VO로만, 데이터를 주고 받고 처리하였지만, 이는 구분해서 사용할 필요가 있다. DB Layer와 View Layer 사이에서 Entity는 실제 테이블과 매핑되기 때문에 변경하게 되면, 다른 클래스에 영향을 미치고, DTO는 View와 통신하며 자주 변경되기 때문에 분리해줘야 한다.
데이터를 전달하기 위한 용도순수한 데이터 객체 (getter/setter)view & controller 사이에서 활용값 자체를 표현하는 용도equals and hashcode 오버라이딩실제
DB와 매핑되는 객체로서, 가장 중요한 핵심 클래스라고 할 수 있다.
우선 데이터를 주고받고 사용시에는 DTO를 데이터와 매핑이 되는 클래스는 Entity로 사용하면 된다. 이를 통해서 데이터의
정보은닉 및 캡슐화가 가능해지고,유연하게 데이터를 사용할 수 있게 된다. 이를 적용한다면, 아래와 같은 코드는 데이터와 매핑이 되는 클래스이므로 Entity로 구분하는 것이 올바른 사용법이다.
@Data
@EqualsAndHashCode(of = "flId")
public class flightLogVO {
@NotBlank(groups = {UpdateGroup.class, DeleteGroup.class})
private String flId;
@NotBlank
private String flTitle;
@NotBlank
private String flContent;
코드 생략...
}
DAO (Data Access Object)란, Service와 DB를 연결하는 역할을 하며, 실제로 DB에 접근하여 data를 삽입, 삭제, 조회, 수정 등의 CRUD 기능을 수행한다.
현재 프로젝트에서는 MyBatis가 DAO의 역할을 담당하여 수행한다.
/**
* 운항일지 관리 퍼시스턴스 레이어
*/
@Mapper
public interface FlightLogDAO {
/**
* 전체 레코드 수 조회
*
* @param paging
* @return 전체 레코드 수
*/
public long selectTotalRecord();
/**
* 전체 운항일지 조회
*
* @return 없으면 size = 0
*/
public List<flightLogVO> selectList(PaginationInfo paging);
/**
* 특정 운항일지 조회
*
* @param flId : 조회할 운항일지 아이디
* @return 없으면 null 반환
*/
public flightLogVO selectOne(String flId);
코드 생략...
}
위와 같이 주석을 포함하여 서비스 레이어에서 이용할 때, 명세의 역할을 하게 된다.
또한, @Mapper 어노테이션을 통하여 mybatis가 이를 인식하고, 매핑할 수 있게 된다.
<!-- mapper-context.xml 일부 코드 -->
<mybatis-spring:scan base-package="kr.or.ddit.**.dao"
annotation="org.apache.ibatis.annotations.Mapper"
factory-ref="sqlSessionFactory"
/>
<mapper namespace="kr.or.ddit.operate.flightLog.dao.FlightLogDAO">
<select id="selectTotalRecord">
SELECT COUNT(*)
FROM FLIGHT_LOG
</select>
<resultMap type="flightLogVO" id="flListMap" autoMapping="true">
<id property="flId" column="FL_ID" />
<result property="atchFileId" column="FL_ATCH_FILE" />
<association property="employee" javaType="EmployeeVO" autoMapping="true" />
</resultMap>
<select id="selectList" parameterType="PaginationInfo" resultMap="flListMap">
SELECT B.*
FROM (
SELECT ROWNUM RNUM, A.*
FROM (
SELECT
FL_ID, FL_TITLE, FL_CONTENT, FL_CRT_TS, FL_UPD_TS, FL_WRITER,
EMP_NM
FROM FLIGHT_LOG INNER JOIN EMPLOYEE ON FL_WRITER = EMP_NO
ORDER BY FL_CRT_TS DESC
) A
) B
</select>
코드 생략...
인터페이스를 사용하여 Service 및 DAO 레이어를 추상화하면
유연성과확장성을 높이며, 다양한 클래스를 만들고 사용할 수 있도록 한다.
/**
* 운항일지 관리 비즈니스 로직
*/
public interface FlightLogService {
/**
* 전체 운항일지 조회
*
* @return 없으면 size = 0
*/
public List<flightLogVO> retrieveList(PaginationInfo paging);
/**
* 특정 운항일지 조회
*
* @param flId : 조회할 운항일지 아이디
* @return 조회된 운항일지
* @throws PKNotFoundException : 해당 일지가 없는 경우
*/
public flightLogVO retrieveOne(String flId) throws PKNotFoundException;
코드 생략...
아래와 같이, service 인터페이스를 구현하고, 필요한 객체들을 주입받아서 실제 서비스를 구현한다.
@Service
public class FlightLogServiceImpl implements FlightLogService {
@Inject
private FlightLogDAO fLogDao;
@Inject
private AtchFileService atchService;
@Value("#{appInfo.flAtchPath}")
private Resource atchPath;
@Override
public List<flightLogVO> retrieveList(PaginationInfo paging) {
long totalRecord = fLogDao.selectTotalRecord();
paging.setTotalRecord(totalRecord);
return fLogDao.selectList(paging);
}
@Controller
@RequestMapping("/operate/flightlog")
public class FlightLogController {
@Inject
private FlightLogService fLogService;
@ModelAttribute("fLog")
public flightLogVO flightLog() {
return new flightLogVO();
}
@GetMapping("/main.do")
public String fLogMain() {
return "operate/flightLog/flightLogMain";
}
@GetMapping("/list.do")
public String fLogList(@RequestParam(name = "page", required = false, defaultValue = "1") long currentPage,
Model model) {
PaginationInfo<flightLogVO> paging = new PaginationInfo<>();
paging.setCurrentPage(currentPage);
List<flightLogVO> fLogList = fLogService.retrieveList(paging);
paging.setDataList(fLogList);
model.addAttribute("paging", paging);
return "operate/flightLog/flightLogList";
}
코드 생략...