minikuma
9 min readJan 8, 2019

[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의 요청을 처리하는 하나의 대표 컨트롤러라 말할 수 있다.

Spring MVC 구조
  1. URL Pattern으로 요청
  2. Dispatcher Servlet은 요청 받은 URL이 어떤 Controller로 가야하는 지 선택
  3. Controller에 Request Payload(사용자에 의해 입력된 정보)를 떨군다.
  4. 처리된 결과는 사용자 브라우저에 표시되기 위한 정보로 변환(model)
  5. Controller에서 반환된 view name을 해석하고 실제로 구현된 view mapping을 요청
  6. 해당 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>
swagger-ui library

Dependency를 추가하게 되면 위와 같이 Swagger Library를 사용할 준비가 되었고, 실제 사용은 해당 Library(jar)의 경로를 지정해 주면 된다.

> Swagger API에 적용될 Controller 작성

> Swagger 적용 결과

<It is a waste of time? = 삽질? >

  1. 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 데이터를 반환하기 위해서는 어떻게 해야 할까?

  1. @ResponseBody annotation 추가
  2. @Controller -> @RestController annotation 변경
    참고로 @RestController = @Controller + @ResponseBody

추가로 application/json 를 수용하는 annotation의 구동방식으로 아래 그림을 참고하면 된다.

Message Converter가 등장하게 되는데, 다음 포스팅의 주제로 다뤄 볼 예정이다.