[펌]Spring MVC 시작하기
SpringMVC Getting Started
나는 이전까지 Spring
이 웹 애플리케이션에만 사용되는 줄 알았는데, 그게 아니고 Console 이나 GUI 등 다양한 곳에 쓰일 수 있는 경량 컨테이너
라고 한다.
여러 곳을 찾아보니 Spring
은 AOP
와 DI
가 핵심이라는데, 이것들 보다는 Spring MVC
자체에 대해 사용법을 먼저 알아보고자 한다. 프로그래밍의 재미는, 만드는 것
이지 개념 학습
이 아니기 때문이다.
1. Architecture
View
- Controller
- Service
- Dao
- Model
- DB
이런 구조로 데이터가 흘러다닌다. DAO(Data Access Object)
와 Service
의 차이점은 여기에 의하면,
DAO : 단일 데이터 접근 / 갱신만 처리
Service : 여러 DAO
를 호출하여 여러번의 데이터 접근/갱신을 하며 이렇게 읽은 데이터에 대해 비즈니스 로직을 수행하고 하나의 트랜잭션으로 묶는다. Service
와 DAO
가 동일해지는 경우도 있는데, 이때는 비즈니스 로직이 단일 DB접근으로 끝나기 때문이다.
2. Spring MVC
Spring MVC
에 대해 알아야 할 사항은 모든 요청을 Dispatcher Servlet
이 받는 다는 것. 그래서 적절하게 처리할 Controller
를 URL
에 따라 선택하기 위해 Hanlder Mapping
을 이용하고, 선택된 Controller
는 요청을 처리하고 ModelAndView
를 돌려준다. Dispatcher Servlet
은 돌아오는View Name
을 바탕으로 View Resolver
를 호출해 View
를 얻고 여기에 Model
을 적용해 Response
를 만들어 Request
를 보냈던 Client
에게 돌려준다. 일단 그림을 먼저 보자.
(출처 - http://www.mkyong.com/spring-mvc/spring-mvc-hello-world-example/) Node.js
나 Backbone.js
를 하셨던 분이라면 무리 없이 이해가 가능할거다. Controller
나 View
는 역할도 비슷하고, Backbone
이나 Node
의Router
가 Handler Mapping
인 것도 비스무리 하다. 이름만 다를 뿐. 조금 다른점은 View
를 묶어 View Resolver
가 관리 한다는 것이다. 하지만 사실 Backbone
에서도 수 많은 View
를 배열이나 기타 등등을 통해 관리한다는 점을 보면, 프로그래머가 구현했어야 하는 걸 Spring MVC
가 해준다는 정도의 차이만 존재한다. 기능상으로는 별 차이가 없다. (아! 드디어 MVC 입문했다!)
3. Sample Code
Spring Tool Suite
로 SpringMVC
프로젝트 생성하면 나오는 샘플의 코드를 분석해 보자. import
구문은 제외한다.
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
중요한 부분은 @Controller
다. 원래는 XML
에 기술해야 하는것으로 아는데, 스프링 버전이 올라가면서 Annotation
만으로 해결이 가능해졌다. Controller
클래스 내부에는 각 URL
요청을 담당하는 메소드가 존재한다. @RequestMapping
어노테이션을 통해 등록하며, value
는 URL 경로를,method
는 HTTP Method 를 등록하면 된다. Home Controller
는 /
에 대한 요청밖에 없지만, User Controller
라면 /users
, /users/51041
등을 처리할 수 있는 여러 메소드가 있을 수 있다. Controller
의 @RequestMapping
메소드는 Model
이라는 파라미터를 받는데, 이건 return
문에서 지정한 Home
이라는 이름의 View
에 적용할Model Attribute
다. 이 serverTime
이란 값은, Backbone.js
를 사용하신 분이라면, Underscore Template
에 지정되는 <%= serverTime %>
정도로 이해하면 되실거다. 실제로 그러한가 View
를 보자.
// src/main/webapp/WEB-INF/views/home.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is ${serverTime}. </P>
</body>
</html>
그러하다. 그런데 만약, @RequestMapping
메소드에서 파라미터를 받는다면 어떻게 추출할까? Spring
에서 관리하는 예제인 Pet-Clinic 샘플을 보자.
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.GET)
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.clinicService.findOwnerById(ownerId);
model.addAttribute(owner);
return "owners/createOrUpdateOwnerForm";
}
이것도 별거 없다. @RequestMapping
에서 받은 {ownerId}
를 @PathVariable("onwerId")
로 처리하고 있다.
스프링은 위의 예처럼 String
으로 리턴값을 통해 View
를 지정하는 것이 아니라, ModelAndView
를 리턴하여 View
를 지정할 수 있다.
@RequestMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails");
mav.addObject(this.clinicService.findOwnerById(ownerId));
return mav;
}
String
을 리턴하는 형태와 똑같은 일을 한다. 두 가지 종류의 방법이 있을 뿐이다. 여기에 대해서 천조국 형님들도 똑같다 고 답변했다.
마지막으로 @ModelAttribute
를 살펴보려 했으나 좀 복잡한것 같다. 누구는 생략가능하다고 하고, 누구는 @ModelAttribute
를 붙여야 할 경우가 따로 있다고 설명하기도 한다. 그래서 마지막으로 SpringMVC Sample의 디렉토리 구조에서 XML들을 좀 살펴보고 가자. web.xml
은 root-context.xml
을 Root Spring Container
로 지정해 모든 필터와 서블렛들이 공유하도록 한다. 또한 servlet-context
를 이용해DispatcherServlet
클래스가 Front-end Controller
로 동작할 수 있도록 해 준다. 다시 말해 요청을 처리할 수 있도록 해 준다는 뜻이다. 코드를 보자.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
root-context.xml
의 내용은 아래와 같다. 옛날에는 무슨 역할을 했을지 모르겠지만, 내가 공부하는 이 시점(2014.02-03) 에는 별 내용이 없다. 아니면 샘플이 심플해서 별 내용이 없는 거겠지.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
</beans>
마지막으로 servlet-context.xml
에는 CSS나 Image 등 각종 리소스가 있는 statis
폴더를 지정하고. View
의 파일 타입과 폴더를 지정한다. 역시 코드를 보자.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.sample.sample" />
</beans:beans>
4. Summary
@Controller
: 컨트롤러 클래스 어노테이션@RequestMapping(value = "/", method = RequestMethod.GET)
: HTTP Request 핸들러 메소드 어노테이션model.addAttribute("serverTime", formattedDate );
:View
에 적용할Model Attribute
추가return "home";
: 돌려줄View
이름 지정,ModelAndView
를 리턴해줄 수도 있다.@PathVariable
: URL 요청에서 받은 파라미터 값을 추출할때 사용
References
출처: http://anster.tistory.com/142