Spring으로 방명록 애플리케이션을 구현하는 시리즈입니다.
- [Spring] 방명록 애플리케이션 (1) - 환경 설정
- [Spring] 방명록 애플리케이션 (2) - 준비 단계 ( 스프링 활용하기 )
- [Spring] 방명록 애플리케이션 (3) - 구현
- [Spring] 방명록 애플리케이션 (4) - 정적 파일 처리 ( DefaultServletHandler )
- [Spring] 방명록 애플리케이션 (5) - 뷰 객체 생성 ( ViewResolver )
- [Spring] 방명록 애플리케이션 (6) - 예외 처리 ( ExceptionHandler )
- [Spring] 방명록 애플리케이션 (7) - 3 Layer Architecture와 Service 계층
- [Spring] 방명록 애플리케이션 (8) - 커넥션 풀 ( Connection Pool ) DBCP
- [Spring] 방명록 애플리케이션 (9) - Mybatis 환경 설정
- [Spring] 방명록 애플리케이션 (10) - Mybatis 적용
3 - Layer Architecture
3 - Layer Architecture는 소프트웨어 아키텍쳐 중 하나로써, 3개의 논리적인 계층 구조를 의미합니다.
스프링에서는 다음과 같이 3개의 계층으로 나눕니다.
1) 프레젠테이션 계층
사용자가 접근하는 계층으로, Service 계층으로 사용자 요청을 요청하는 계층
2) 서비스 계층
비즈니스 로직을 수행하는 계층
3) 데이터 액세스 계층
데이터에 접근하는 계층
이번 글에서는 서비스가 무엇을 하는지 다루려고 합니다.
Service 계층
지금까지는 DAO를 통해 DB에서 데이터를 가져온 후 컨트롤러에서 데이터를 활용하여 응답하는 방식이었습니다.
그런데 접근해야 하는 DAO가 많을 경우 컨트롤러는 코드가 복잡해집니다.
컨트롤러는 명령만 하는 간단한 구조로 되어 있는 것이 좋기 때문에 service 계층이 필요하게 되었습니다.
service 계층이 있으면 컨트롤러는 직접 DAO로부터 값을 가져오지 않고, service를 호출하여 service에서 DAO를 호출하도록 합니다.
즉 service에서 DAO에 접근하여 데이터를 가져온 후, 컨트롤러에 넘겨주는 방식이죠.
예를들면 게시판 목록을 보여 달라는 요청이 있다고 가정하겠습니다.
그러면 컨트롤러에서는 게시글의 목록은 물론 pagination 처리를 위한 코드도 있어야 할 것입니다.
그런데 paging 알고리즘을 컨트롤러에서 하는 것은 바람직하지 않기 때문에,
게시글의 목록과 pagination을 처리하는 과정을 service로 넘겨버리면 좋은 아키텍쳐가 되겠죠.
방명록 애플리케이션을 3 Layer Architecture로 수정
이제 방명록 애플리케이션을 3 - Layer로 바꿔보겠습니다.
GuestBookController
@Controller @RequestMapping("/main") public class GuestBookController { @Autowired private GuestbookService guestBookService; @RequestMapping(value="/", method=RequestMethod.GET) public String list(Model model) { List<guestbookvo> list = guestBookService.getList(); model.addAttribute("list", list); return "index"; } @RequestMapping(value="/", method=RequestMethod.POST) public String insert(GuestBookVO vo) { guestBookService.insert(vo); return "redirect:/main/"; } @RequestMapping(value="/deleteform", method=RequestMethod.GET) public String delete(@RequestParam Integer no, Model model) { model.addAttribute("no",no); return "deleteform"; } @RequestMapping(value="/delete", method=RequestMethod.POST) public String delete(GuestBookVO vo) { guestBookService.delete(vo); return "redirect:/main/"; } }
GuestBookService 객체를 주입받아서 GuestBookService 객체의 메서드만을 호출하고 있습니다.
직접 DAO에 접근하는 코드가 하나도 없는 것을 확인할 수 있습니다.
GuestbookService
@Service public class GuestbookService { @Autowired private GuestBookDAO guestBookDAO; public List<guestbookvo> getList(){ return guestBookDAO.getList(); } public boolean insert(GuestBookVO vo ) { return guestBookDAO.insert(vo); } public boolean delete(GuestBookVO vo) { String originPwd = guestBookDAO.getPwd(vo.getNo()); String inputPwd = guestBookDAO.getInputPwd(vo.getPwd()); if(!originPwd.equals(inputPwd) ) { return false; } return guestBookDAO.delete(vo.getNo()); } }
@Service 어노테이션을 작성하여 스캐닝 할 수 있도록 합니다.
GuestbookService 객체는 GuestBookDAO 객체를 주입 받습니다.
delete 메서드를 보시면 service의 진가를 볼 수 있습니다.
이 코드는 기존에 작성되었던 방명록 애플리케이션에서 컨트롤러의 delete() 메서드입니다.
service를 활용하지 않기 때문에 컨트롤러에서 비밀번호 검사를 확인합니다.
컨트롤러에서 복잡한 비즈니스를 처리하는 것은 바람직하지 않습니다.
반면 service를 활용하면, 컨트롤러에서는 service 메서드만 호출하고 비밀번호를 검사하는 비즈니스는 service에서 처리하게 됩니다.
복잡한 비즈니스라고 생각했을 때 service 계층이 있는 것이 훨씬 효율적인 아키텍쳐일 것입니다.
컨트롤러 역시 데이터를 가져와서 JSP에 전달만 하는 것이 바람직하구요.
DAO는 수정할 것이 없습니다.
마지막으로 @Service 어노테이션을 스캔할 수 있도록 applicationContext.xml 파일을 수정하겠습니다.
applicationContext.xml
이상으로 3 Layer Architecture 와 service 계층에 대해 알아보았습니다.
service 계층은 비즈니스 처리를 담당하는 계층으로써, DAO를 호출하여 데이터를 가져와서 Controller에 전달합니다.
앞으로 모든 예제는 3 Layer Architecture 구조로 작성할 것입니다.