복붙노트

[SPRING] 봄 : ResponseEntity <Void>를 사용하여 빈 HTTP 응답 반환

SPRING

봄 : ResponseEntity 를 사용하여 빈 HTTP 응답 반환

Spring (4.1.1)과 함께 REST API를 구현하고 있습니다. 특정 HTTP 요청의 경우 본문이없는 헤드를 응답으로 반환하려고합니다. 그러나 ResponseEntity 를 사용하면 작동하지 않는 것 같습니다. MockMvc 테스트에서 호출되면 406 (Not Accept)이 반환됩니다. 매개 변수 값 (새 ResponseEntity (HttpStatus.NOT_FOUND))없이 ResponseEntity 를 사용하면 문제가 없습니다.

방법:

@RequestMapping( method = RequestMethod.HEAD, value = Constants.KEY )
public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {

    LOG.debug( "taxonomyPackageExists queried with key: {0}", key ); //$NON-NLS-1$

    final TaxonomyKey taxonomyKey = TaxonomyKey.fromString( key );

    LOG.debug( "Taxonomy key created: {0}", taxonomyKey ); //$NON-NLS-1$

    if ( this.xbrlInstanceValidator.taxonomyPackageExists( taxonomyKey ) ) {

        LOG.debug( "Taxonomy package with key: {0} exists.", taxonomyKey ); //$NON-NLS-1$

        return new ResponseEntity<Void>( HttpStatus.OK );

    } else {

        LOG.debug( "Taxonomy package with key: {0} does NOT exist.", taxonomyKey ); //$NON-NLS-1$

        return new ResponseEntity<Void>( HttpStatus.NOT_FOUND );
    }

}

테스트 케이스 (TestNG) :

public class TaxonomyQueryControllerTest {

private XbrlInstanceValidator   xbrlInstanceValidatorMock;
private TaxonomyQueryController underTest;
private MockMvc                 mockMvc;

@BeforeMethod
public void setUp() {
    this.xbrlInstanceValidatorMock = createMock( XbrlInstanceValidator.class );
    this.underTest = new TaxonomyQueryController( this.xbrlInstanceValidatorMock );
    this.mockMvc = MockMvcBuilders.standaloneSetup( this.underTest ).build();
}

@Test
public void taxonomyPackageDoesNotExist() throws Exception {
    // record
    expect( this.xbrlInstanceValidatorMock.taxonomyPackageExists( anyObject( TaxonomyKey.class ) ) ).andStubReturn(
            false );

    // replay
    replay( this.xbrlInstanceValidatorMock );

    // do the test
    final String taxonomyKey = RestDataFixture.taxonomyKeyString;

    this.mockMvc.perform( head( "/taxonomypackages/{key}", taxonomyKey ).accept( //$NON-NLS-1$
            MediaType.APPLICATION_XML ) ).andExpect( status().isNotFound() );

}

}

이 스택 추적으로 실패합니다.

FAILED: taxonomyPackageDoesNotExist
java.lang.AssertionError: Status expected:<404> but was:<406>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:652)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:153)
at de.zeb.control.application.xbrlstandalonevalidator.restservice.TaxonomyQueryControllerTest.taxonomyPackageDoesNotExist(TaxonomyQueryControllerTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)

해결법

  1. ==============================

    1.본문없이 ResponseEntity를 반환하면 Spring은 ResponseEntity 반환 형식 선언에 제공된 형식 인수를 사용하여 본문 형식을 결정합니다.

    본문없이 ResponseEntity를 반환하면 Spring은 ResponseEntity 반환 형식 선언에 제공된 형식 인수를 사용하여 본문 형식을 결정합니다.

    그래서

    public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {
    

    그 타입은 무효가 될 것입니다. 그러면 Spring은 등록 된 모든 HttpMessageConverter 인스턴스를 순환하여 Void 유형의 본문을 작성할 수있는 인스턴스를 찾습니다. HttpMessageConverter가 없으므로 (기본 구성의 경우) 허용 가능한 응답을 생성 할 수 없으므로 406 Not Acceptable HTTP 응답을 반환합니다.

    ResponseEntity 을 사용하면 Spring은 응답 본문으로 String을 사용하고 처리기로 StringHttpMessageConverter를 찾습니다. StringHttpMessageHandler는 Accepted media type에 대한 컨텐트를 생성 할 수 있기 때문에 클라이언트가 요청한 application / xml을 처리 할 수 ​​있습니다.

    iddy85의 솔루션 (현재 잘못되었지만 ResponseEntity 를 제안하는 것처럼 보임)에서 본문의 유형이 Object로 유추됩니다. 클래스 패스에 올바른 라이브러리가 있다면 Spring은 XML HttpMessageConverter에 액세스하여 Object 유형의 application / xml을 생성하는 데 사용할 수 있습니다.

  2. ==============================

    2.메소드 구현이 모호합니다. 다음을 시도하여 코드를 약간 편집하고 HttpStatus.NO_CONTENT를 사용합니다. 예 : HttpStatus.OK 대신 204 개의 내용이 없습니다.

    메소드 구현이 모호합니다. 다음을 시도하여 코드를 약간 편집하고 HttpStatus.NO_CONTENT를 사용합니다. 예 : HttpStatus.OK 대신 204 개의 내용이 없습니다.

    204의 값은 무시되지만 404의 값은 무시됩니다.

      public ResponseEntity<?> taxonomyPackageExists( @PathVariable final String key ) {
                LOG.debug( "taxonomyPackageExists queried with key: {0}", key ); //$NON-NLS-1$
                final TaxonomyKey taxonomyKey = TaxonomyKey.fromString( key );
                LOG.debug( "Taxonomy key created: {0}", taxonomyKey ); //$NON-NLS-1$
    
                if ( this.xbrlInstanceValidator.taxonomyPackageExists( taxonomyKey ) ) {
                    LOG.debug( "Taxonomy package with key: {0} exists.", taxonomyKey ); //$NON-NLS-1$
                     return new ResponseEntity<T>(HttpStatus.NO_CONTENT);
                } else {
                   LOG.debug( "Taxonomy package with key: {0} does NOT exist.", taxonomyKey ); //$NON-NLS-1$
                    return new ResponseEntity<T>( HttpStatus.NOT_FOUND );
                }
    
        }
    
  3. ==============================

    3.또한 형식 매개 변수를 지정할 수 없습니다.이 매개 변수는 조금 더 깨끗하게 보이고 문서를 볼 때 Spring이 의도 한 것입니다.

    또한 형식 매개 변수를 지정할 수 없습니다.이 매개 변수는 조금 더 깨끗하게 보이고 문서를 볼 때 Spring이 의도 한 것입니다.

    @RequestMapping(method = RequestMethod.HEAD, value = Constants.KEY )
    public ResponseEntity taxonomyPackageExists( @PathVariable final String key ){
        // ...
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }
    
  4. ==============================

    4.Spring 4 MVC ResponseEntity.BodyBuilder 및 ResponseEntity Enhancements 예제에 따르면 다음과 같이 작성할 수 있습니다.

    Spring 4 MVC ResponseEntity.BodyBuilder 및 ResponseEntity Enhancements 예제에 따르면 다음과 같이 작성할 수 있습니다.

    ....
       return ResponseEntity.ok().build();
    ....
       return ResponseEntity.noContent().build();
    

    최신 정보:

    반환 값이 Optional 인 경우 편리한 메소드가 반환되며 ok () 또는 Found ()가 반환되지 않습니다.

    return ResponseEntity.of(optional)
    
  5. ==============================

    5.개인적으로, 빈 응답을 처리하기 위해, 나는 Integration Tests에서 MockMvcResponse 객체를 다음과 같이 사용한다.

    개인적으로, 빈 응답을 처리하기 위해, 나는 Integration Tests에서 MockMvcResponse 객체를 다음과 같이 사용한다.

    MockMvcResponse response = RestAssuredMockMvc.given()
                    .webAppContextSetup(webApplicationContext)
                    .when()
                    .get("/v1/ticket");
    
        assertThat(response.mockHttpServletResponse().getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
    

    내 컨트롤러에서 다음과 같은 특정 경우에 빈 응답을 반환합니다.

    return ResponseEntity.noContent().build();
    
  6. from https://stackoverflow.com/questions/26550124/spring-returning-empty-http-responses-with-responseentityvoid-doesnt-work by cc-by-sa and MIT license