[Spring-MVC] Spring 5 MVC without web.xml
<Agenda>
Spring MVC with Java based Config로 개발 할 때 새로운 Configuration을 Dispatcher Servlet에 등록하기 위해서는 어떻게 해야 될까? 예제를 통해 알아보자.
<Concept>
기본적으로 Spring MVC를 이해하기 위해서는 Dispatcher Servlet의 개념을 이해해야 한다. Dispatcher Servlet은 Front Controller Pattern 기반으로 웹 상에서 유입되는 모든 요청을 받아서 응답하는 창구역할이라고 생각하면 쉽다.
즉, 모든 Resource의 요청을 처리하는 하나의 대표 컨트롤러라 말할 수 있다.
- URL Pattern으로 요청
- Dispatcher Servlet은 요청 받은 URL이 어떤 Controller로 가야하는 지 선택
- Controller에 Request Payload(사용자에 의해 입력된 정보)를 떨군다.
- 처리된 결과는 사용자 브라우저에 표시되기 위한 정보로 변환(model)
- Controller에서 반환된 view name을 해석하고 실제로 구현된 view mapping을 요청
- 해당 view(JSP, HTML)을 반환
<Example Requirement>
http://localhost:8080/ URL로 접속 시, 브라우저에 “Welcome to Spittr”를 출력하시오.
<Tech. Used>
- IntelliJ IDEA
- Java 8
- maven 3
- tomcat 8
- Spring 5
> Dispatcher Servlet 등록
AbstractAnnotationConfigDispatcherServletInitializer 정체?서블릿 3.0 환경에서 컨테이너는 클래스 패스내의 javax.servlet.ServletContainerInitializer 인터페이스를 구현(implement)한 모든 클래스를 찾아보도록 되어있다. 여기서 발견된 클래스들은 서블릿 컨테이너들을 설정하는 데 사용된다.
스프링은 SpringServletContainerInitializer의 구현을 제공하고 이것을 순차적으로 WebApplicationInitialize의 구현 클래스를 찾아 위임한다. 스프링 3.2+ 에서는 AbstractAnnotationConfigDispatcherServletInitializer라고 하는
WebApplicationInitializer의 편리한 기본 구현이 제공된다.
서블릿 3.0 컨테이너에 배포될 때 자동적으로 발견되어 서블릿 컨텍스트를 자동 초기화한다.
> Controller
> Result
<Add Requirement>
Swagger API Document를 적용하시오.
> Dispatcher Servlet에 Swagger Configuration 등록
> View Resolver, Swagger Resource(static resource) 등록
> Swagger static resource Library(jar) 사용을 위한 Dependency 추가
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Dependency를 추가하게 되면 위와 같이 Swagger Library를 사용할 준비가 되었고, 실제 사용은 해당 Library(jar)의 경로를 지정해 주면 된다.
> Swagger API에 적용될 Controller 작성
> Swagger 적용 결과
<It is a waste of time? = 삽질? >
- maven package 에러?
Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)
Solution?
pom.xml 에 아래 내용 추가 (Java based Config인 경우 2)으로 진행)
1) XML Configuration (web.xml 경로 지정 필요)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>[web.xml file path]</webXml>
</configuration>
</plugin>2) Java-based Configuration (web.xml 설정 미 사용)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
...
</configuration>
</plugin>
2. Swagger Configuration 등록 후 Tomcat 구동 에러?
Solution?
pom.xml에 아래 내용 추가
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
왜? Swagger 적용을 위해서는 위에 dependency가 필요할까?
An OpenAPI document that conforms to the OpenAPI Specification is itself a JSON object, which may be represented either in JSON or YAML format.
Swagger API Reference에 의하면 Swagger는 JSON Object로 정의되어 있음을 알 수 있는데, 만약 위해 Dependency를 추가하지 않으면 결국 Swagger의 JSON Object를 Mapping 할 수 없게 되어 위에 에러가 발생한다.
결국 Swagger API 등록하여 Document를 만들기 위해서는 JSON Object를 지원해야 한다.
참고: https://swagger.io/specification/
3. Controller vs RestController
Controller만 사용하였더니 아래와 같은 오류가 발생하였다.
Solution?
annotation의 정확한 동작을 알아야 한다. (Controller, RestController)
위 에러를 보면 결국 View Resolver가 해석한 view가 없다는 내용인데, 사실 난 JSON Object로 Return하고 싶었다.
나는 @Controller를 사용하였는데, 무엇이 잘못 되었을까?
@Controller는 View Resolver를 통해 사용자에게 text/html 데이터를 반환한다. 여기서 바로 알 수 있다. annotation이 잘못 되었음을…
그렇다면 application/json 데이터를 반환하기 위해서는 어떻게 해야 할까?
- @ResponseBody annotation 추가
- @Controller -> @RestController annotation 변경
참고로 @RestController = @Controller + @ResponseBody
추가로 application/json 를 수용하는 annotation의 구동방식으로 아래 그림을 참고하면 된다.
Message Converter가 등장하게 되는데, 다음 포스팅의 주제로 다뤄 볼 예정이다.