최근 모든 웹 개발은 거의 모델 2 방식을 사용한다고 해도 과언이 아니라고 합니다.
모델 2 방식은 MVC 구조를 응용한 방식으로, 화면과 데이터 처리를 분리해서 재사용이 가능하도록 하는 구조 라고 합니다.
좀 더 구체적으로, 컨트롤러가 모델 계층과 연동하여 필요한 데이터 처리를 하고, 그 결과를 뷰에 전송하는 구조 입니다.
모델(Model): 데이터 혹은 데이터를 처리하는 영역
뷰(View): 화면을 구성하는 영역
컨트롤러(Controller): 웹의 요청(Request)을 처리하는 영역
모델 2 방식의 장점은
1. 개발자와 웹 퍼블리셔의 영역을 분리할 수 있다.
2. 뷰의 교체나 변경과 같은 유지보수에 유용하다.
모델 2 방식의 한계
1. 각 컨트롤러 사이의 코드 중복
2. 개발자 간의 개발 패턴의 차이
모델 2 방식의 한계를 극복하고자 좀더 강제적인 형태인 Front Controller 방식이 등장합니다.
프런트 컨트롤러 패턴의 가장 중요한 변화는 전체 로직의 일부만을 컨트롤러가 처리하도록 변경 되었다는 점입니다.
위임(Delegation) 이라고 부르는데, 로직의 일부를 컨트롤러에게 위임하고,
모든 흐름의 제어는 프런트 컨트롤러에서 담당하는 구조 입니다.
이 구조를 사용할 경우, 개발자가 작성해야할 코드는 전체 로직의 일부분으로 한정되기 때문에,
각 개발자에게 할당되는 코드량이 줄어듭니다.
또, 모든 컨트롤러는 프론트 컨트롤러의 일부분을 구현하는 형태이므로, 좀 더 규격화된 코드를 작성하게 됩니다.
스프링 MVC의 경우는 다음과 같은 구조를 가집니다.
1. Front Controller --> 2. Controller --> 3. service --> 4. DAO --> 5. Mybatis(Mapper) --> 6. MySQL
--> 7. MyBatis --> 8. DAO --> 9. service --> 10. Controller --> 11. Front Controller --> 12. View
간단한 테스트를 통해서 스프링 MVC 작업을 해보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.aristatait.spring; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class SampleController { private static final Logger logger = LoggerFactory.getLogger(SampleController.class); @RequestMapping("doA") public void doA(){ logger.info("doA called........................"); } @RequestMapping("doB") public void doB(){ logger.info("doB called.........................."); } } | cs |
8번 라인을 보면 애노테이션으로 해당 파일이 Controller 역할을 한다는 것을 명시 한다.
이 컨트롤러에서는 doA 와 doB 라는 주소가 요청될때 로그가 출력되도록 로직이 구성되어 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.aristatait.spring; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class SampleController2 { private static final Logger LOGGER = LoggerFactory.getLogger(SampleController2.class); @RequestMapping("doC") public String doC(@ModelAttribute("msg") String msg){ LOGGER.info("doC called.........................."); return "result"; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.aristatait.spring; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.aristatait.domain.ProductVO; @Controller public class SampleController3 { private static final Logger LOGGER = LoggerFactory.getLogger(SampleController3.class); @RequestMapping("/doD") public String doC(Model model){ LOGGER.info("doD called.........................."); ProductVO product1 = new ProductVO("바나나", 3000); LOGGER.info("doD"); model.addAttribute(product1); return "productDetail"; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package com.aristatait.spring; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller public class SampleController4 { private static final Logger logger = LoggerFactory.getLogger(SampleController4.class); @RequestMapping("/doE") public String doE(RedirectAttributes rttr) { logger.info("doE called but redirect to /doF..........."); rttr.addFlashAttribute("msg", "This is the Message!! with redirected"); return "redirect:/doF"; } @RequestMapping("/doF") public void doF(String msg) { logger.info("doF called.................." + msg); } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.aristatait.spring; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.aristatait.domain.ProductVO; @Controller public class SampleController5 { @RequestMapping("/doJSON") public @ResponseBody ProductVO doJSON(){ ProductVO vo = new ProductVO("샘플상품", 30000); return vo; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package com.aristatait.spring; import javax.inject.Inject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration( locations = {"file:src/main/webapp/WEB-INF/spring/**/*.xml"}) public class SampleControllerJUnit { private static final Logger LOGGER = LoggerFactory.getLogger(SampleControllerJUnit.class); @Inject private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup(){ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); LOGGER.info("setup......................."); } @Test public void testDoA() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/doC")); } } | cs |
'Spring > Spring 수업' 카테고리의 다른 글
Spring 07. MyBatis 연결 설정하기 (3) | 2016.09.08 |
---|---|
Spring 06. 스프링 맛보기 2 Student (0) | 2016.09.08 |
Spring 05. 스프링 맛보기 Calculator (0) | 2016.09.07 |
Spring 04. MySQL 설정과 Spring 테스트 (0) | 2016.09.07 |
Spring 03. Tomcat 8 설치 및 사용 (0) | 2016.09.07 |