1. 개요

이 기사는 Spring MVC 프로젝트에서 컨텐츠 협상을 구현하는 방법을 설명합니다.

일반적으로 요청의 미디어 유형을 결정하는 세 가지 옵션이 있습니다.

  • 요청에 URL 접미사 (확장자) 사용 (예 : .xml / .json )
  • 요청에서 URL 매개 변수 사용 (예 : ? format = json )
  • 요청에서 Accept 헤더 사용

기본적으로 이것은 Spring 컨텐츠 협상 관리자가이 세 가지 전략을 사용하려고 시도하는 순서입니다. 그리고 이들 중 어느 것도 활성화되지 않은 경우 기본 콘텐츠 유형으로 대체하도록 지정할 수 있습니다.

2. 콘텐츠 협상 전략

필요한 의존성부터 시작하겠습니다. JSON 및 XML 표현으로 작업하고 있으므로이 기사에서는 Jackson for JSON을 사용합니다.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.2</version>
</dependency>

XML 지원을 위해 JAXB, XStream 또는 최신 Jackson-XML 지원을 사용할 수 있습니다.

우리가 사용 설명했기 때문에 수락 에 헤더 에 이전 기사 HttpMessageConverters , 깊이의 처음 두 전략의 초점을 수 있습니다.

3. URL 접미사 전략

기본적으로이 전략은 비활성화되어 있지만 프레임 워크는 URL에서 바로 경로 확장을 확인하여 출력 콘텐츠 유형을 결정할 수 있습니다.

구성에 들어가기 전에 예를 간단히 살펴 보겠습니다. 일반적인 Spring 컨트롤러에는 다음과 같은 간단한 API 메서드 구현이 있습니다.

@RequestMapping(
  value = "/employee/{id}", 
  produces = { "application/json", "application/xml" }, 
  method = RequestMethod.GET)
public @ResponseBody Employee getEmployeeById(@PathVariable long id) {
    return employeeMap.get(id);
}

리소스의 미디어 유형을 지정하기 위해 JSON 확장을 사용하여 호출 해 보겠습니다.

curl http://localhost:8080/spring-mvc-basics/employee/10.json

JSON 확장을 사용하면 다음과 같은 결과를 얻을 수 있습니다.

{
    "id": 10,
    "name": "Test Employee",
    "contactNumber": "999-999-9999"
}

XML에서 요청-응답은 다음과 같이 표시됩니다.

curl http://localhost:8080/spring-mvc-basics/employee/10.xml

Response body :

<employee>
    <contactNumber>999-999-9999</contactNumber>
    <id>10</id>
    <name>Test Employee</name>
</employee>

이제 확장을 사용하지 않거나 구성되지 않은 확장을 사용하면 기본 콘텐츠 유형이 반환됩니다.

curl http://localhost:8080/spring-mvc-basics/employee/10

이제 Java 및 XML 구성을 사용하여이 전략을 설정하는 방법을 살펴 보겠습니다.

3.1. 자바 구성

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(false).
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON); 
}

세부 사항을 살펴 보겠습니다.

첫째, 우리는 경로 확장 전략을 활성화하고 있습니다. Spring Framework 5.2.4 부터 콘텐츠 협상을위한 경로 확장 사용을 막기 위해 favorPathExtension (boolean) 메서드가 더 이상 사용되지 않는다는 점도  언급 할 가치가 있습니다.

그런 다음 URL 매개 변수 전략과 Accept 헤더 전략을 비활성화합니다 . 콘텐츠 유형을 결정하는 경로 확장 방식에만 의존하기를 원하기 때문입니다.

그런 다음 Java Activation Framework를 끕니다. JAF는 수신 요청이 우리가 구성한 전략과 일치하지 않는 경우 출력 형식을 선택하는 대체 메커니즘으로 사용할 수 있습니다. JSON을 기본 콘텐츠 유형으로 구성 할 것이기 때문에 비활성화합니다. 있습니다 useJaf ()  메소드가 스프링 프레임 워크 (5) 추천되지 않습니다 .

마지막으로 JSON을 기본값으로 설정합니다. 즉, 두 가지 전략이 일치하지 않으면 들어오는 모든 요청이 JSON을 제공하는 컨트롤러 메서드에 매핑됩니다.

3.2. XML 구성

또한 XML 만 사용하여 동일한 정확한 구성을 간략히 살펴 보겠습니다.

<bean id="contentNegotiationManager" 
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="favorParameter" value="false"/>
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />
</bean>

4. URL 매개 변수 전략

이전 섹션에서 경로 확장을 사용했습니다. 이제 경로 매개 변수를 사용하도록 Spring MVC를 설정하겠습니다.

favorParameter  속성 을 true 로 설정하여이 전략을 활성화 할 수 있습니다  .

이전 예제에서 어떻게 작동하는지 간단히 살펴 보겠습니다.

curl http://localhost:8080/spring-mvc-basics/employee/10?mediaType=json

그리고 JSON Response body은 다음과 같습니다.

{
    "id": 10,
    "name": "Test Employee",
    "contactNumber": "999-999-9999"
}

XML 매개 변수를 사용하면 출력이 XML 형식으로 표시됩니다.

curl http://localhost:8080/spring-mvc-basics/employee/10?mediaType=xml

Response body :

<employee>
    <contactNumber>999-999-9999</contactNumber>
    <id>10</id>
    <name>Test Employee</name>
</employee>

이제 구성을 수행해 보겠습니다. 먼저 Java를 사용한 다음 XML을 사용합니다.

4.1. 자바 구성

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false).
    favorParameter(true).
    parameterName("mediaType").
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML). 
    mediaType("json", MediaType.APPLICATION_JSON); 
}

이 구성을 읽어 보겠습니다.

먼저, 경로 확장 및 Accept 헤더 전략은 물론 JAF도 사용할 수 없습니다.

나머지 구성은 동일합니다.

4.2. XML 구성

<bean id="contentNegotiationManager" 
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="true"/>
    <property name="parameterName" value="mediaType"/>
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />

    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
</bean>

또한 두 가지 전략 (확장 및 매개 변수)을 동시에 활성화 할 수 있습니다 .

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(true).
    parameterName("mediaType").
    ignoreAcceptHeader(true).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML). 
    mediaType("json", MediaType.APPLICATION_JSON); 
}

이 경우 Spring은 먼저 경로 확장을 찾고, 이것이 없으면 경로 매개 변수를 찾습니다. 입력 요청에서이 두 가지를 모두 사용할 수없는 경우 기본 콘텐츠 유형이 다시 반환됩니다.

5. 수락 헤더 전략

(가) 경우  수락 헤더가 활성화되어, 스프링 MVC는 표현 유형을 결정하기 위해 들어오는 요청에서 그 가치를 찾습니다.

이 접근 방식을 활성화하려면 ignoreAcceptHeader 의 값 을 false로 설정해야하며 Accept 헤더 에만 의존하고 있음을 알 수 있도록 다른 두 전략을 비활성화합니다 .

5.1. 자바 구성

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true).
    favorParameter(false).
    parameterName("mediaType").
    ignoreAcceptHeader(false).
    useJaf(false).
    defaultContentType(MediaType.APPLICATION_JSON).
    mediaType("xml", MediaType.APPLICATION_XML). 
    mediaType("json", MediaType.APPLICATION_JSON); 
}

5.2. XML 구성

<bean id="contentNegotiationManager" 
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="true" />
    <property name="favorParameter" value="false"/>
    <property name="parameterName" value="mediaType"/>
    <property name="ignoreAcceptHeader" value="false" />
    <property name="defaultContentType" value="application/json" />
    <property name="useJaf" value="false" />

    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
</bean>

마지막으로 콘텐츠 협상 관리자를 전체 구성에 플러그인하여 전환해야합니다.

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

6. 결론

그리고 우리는 끝났습니다. Spring MVC에서 콘텐츠 협상이 어떻게 작동하는지 살펴 보았고 콘텐츠 유형을 결정하기 위해 다양한 전략을 사용하도록 설정하는 몇 가지 예에 집중했습니다.

이 기사의 전체 구현은 GitHub 에서 찾을 수 있습니다 .