복붙노트

[SPRING] JSON을 REST API에 게시

SPRING

JSON을 REST API에 게시

JSON 요청을 수락 할 REST API를 만들고 있습니다.

내가 CURL을 사용하여 테스트하고있다.

curl -i -POST -H 'Accept: application/json' -d '{"id":1,"pan":11111}' http://localhost:8080/PurchaseAPIServer/api/purchase

하지만 다음과 같은 오류가 발생했습니다 :

HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 25 Apr 2012 21:36:14 GMT

The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().

디버깅 할 때 컨트롤러에서 동작을 만들지 않습니다.

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.app.model.Purchase;
import com.app.service.IPurchaseService;

@Controller
public class PurchaseController {

    @Autowired
    private IPurchaseService purchaseService;

    @RequestMapping(value = "purchase", method = RequestMethod.GET)
    @ResponseBody
    public final List<Purchase> getAll() {
        return purchaseService.getAll();
    }

    @RequestMapping(value = "purchase", method = RequestMethod.POST)
    @ResponseStatus( HttpStatus.CREATED )
    public void create(@RequestBody final Purchase entity) {
        purchaseService.addPurchase(entity);
    }
}

AppConfig.java에 Jackson 구성을 추가했습니다.

@Configuration
@ComponentScan(basePackages = "com.app")
public class AppConfig {

    @Bean
    public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
    {
        final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
        final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();

        HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter };

        String[] supportedHttpMethods = { "POST", "GET", "HEAD" };

        annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
        annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);

        return annotationMethodHandlerAdapter;
    }
}

내 GET이 올바르게 작동 중입니다.

curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Apr 2012 21:19:55 GMT

[{"id":1,"pan":111}]

하지만 POST를 시도 할 때 다음과 같은 결과를 얻습니다.

curl -i -X POST -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Thu, 26 Apr 2012 21:29:56 GMT
Connection: close

The request sent by the client was syntactically incorrect ().

내 모델 :

@Entity
@XmlRootElement
public class Purchase implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 6603477834338392140L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private Long pan;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getPan() {
        return pan;
    }

    public void setPan(Long pan) {
        this.pan = pan;
    }

}

내가 잘못 가고있는 어떤 생각?

감사

해결법

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

    1.sdouglass가 제안한 것처럼 Spring MVC는 자동으로 Jackson을 감지하고 JSON과의 변환을 처리하는 MappingJacksonHttpMessageConverter를 설정합니다. 하지만 나는 명시 적으로 작동하도록 변환기를 구성하는 명확성이 필요했습니다.

    sdouglass가 제안한 것처럼 Spring MVC는 자동으로 Jackson을 감지하고 JSON과의 변환을 처리하는 MappingJacksonHttpMessageConverter를 설정합니다. 하지만 나는 명시 적으로 작동하도록 변환기를 구성하는 명확성이 필요했습니다.

    다음을 추가하고 CURL GET 요청이 작동 중입니다. 만세.

    AppConfig.java

    @Configuration
    @ComponentScan(basePackages = "com.app")
    public class AppConfig {
    
        @Bean
        public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
        {
            final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
            final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
    
            HttpMessageConverter<?>[] httpMessageConverter = { mappingJacksonHttpMessageConverter };
    
            String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
    
            annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
            annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
    
            return annotationMethodHandlerAdapter;
        }
    }
    

    curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase
    
    HTTP/1.1 200 OK
    Server: Apache-Coyote/1.1
    Content-Type: application/json
    Transfer-Encoding: chunked
    Date: Thu, 26 Apr 2012 21:19:55 GMT
    
    [{"id":1,"pan":111}]
    

    하지만 다음 CURL POST는 여전히 작동하지 않습니다 (컨트롤러 작업을 수행하지 않고 콘솔 디버그 정보를 제공하지 마십시오).

    curl -i -X POST -H "Content-Type:application/json"  http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"
    
    HTTP/1.1 400 Bad Request
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=utf-8
    Content-Length: 971
    Date: Thu, 26 Apr 2012 21:29:56 GMT
    Connection: close
    
    The request sent by the client was syntactically incorrect ().
    

    그래서 Logback을 추가하여 디버깅을 시작했습니다.

    <configuration>
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
                </pattern>
            </encoder>
        </appender>
    
        <appender name="FILE" class="ch.qos.logback.core.FileAppender">
            <file>/home/thomas/springApps/purchaseapi.log</file>
            <encoder>
                <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n
                </pattern>
            </encoder>
        </appender>
    
        <logger name="org.hibernate" level="DEBUG" />
    
        <logger name="org.springframework" level="TRACE" />
        <logger name="org.springframework.transaction" level="INFO" />
        <logger name="org.springframework.security" level="INFO" /> <!-- to debug security related issues (DEBUG) -->
        <logger name="org.springframework.web.servlet.mvc" level="TRACE" /> <!-- some serialization issues are at trace level here: org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod -->
    
        <!-- our service -->
        <logger name="com.app" level="DEBUG" />
        <!-- <logger name="com.app" level="INFO" /> --><!-- to follow if setup is being executed -->
    
        <root level="INFO">
            <appender-ref ref="FILE" />
        </root>
    
    </configuration>
    

    TRACE 레벨 디버깅을 org.springframework.web.servlet.mvc에 추가하면이 문제에 대한 답을 얻을 수있었습니다.

    2012-04-28 14:17:44,579 DEBUG [http-bio-8080-exec-3] o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor [AbstractMessageConverterMethodArgumentResolver.java:117] Reading [com.app.model.Purchase] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@74a14fed]
    2012-04-28 14:17:44,604 TRACE [http-bio-8080-exec-3] o.s.w.s.m.m.a.ServletInvocableHandlerMethod [InvocableHandlerMethod.java:159] Error resolving argument [0] [type=com.app.model.Purchase]
    HandlerMethod details: 
    Controller [com.app.controller.PurchaseController]
    Method [public void com.app.controller.PurchaseController.create(com.app.model.Purchase)]
    
    org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected character ('p' (code 112)): was expecting double-quote to start field name
    

    내 CURL POST를 다음과 같이 변경했습니다.

    curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase -d '{"pan":11111}'
    HTTP/1.1 201 Created
    Server: Apache-Coyote/1.1
    Content-Length: 0
    Date: Sat, 28 Apr 2012 13:19:40 GMT
    

    잘만되면 누군가는 이것을 유용하다고 생각합니다.

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

    2.스프링 문서가 스프링 캠퍼스를 자동으로 감지하고 JSON과의 변환을 처리하기 위해 MappingJacksonHttpMessageConverter를 설정한다고 말한 바 있습니다. 그러나 수동으로 / 명시 적으로 해당 변환기를 설정해야하는 상황을 경험 한 것 같습니다. 일할 것들. MVC config XML에이 값을 추가하려고 할 수 있습니다.

    스프링 문서가 스프링 캠퍼스를 자동으로 감지하고 JSON과의 변환을 처리하기 위해 MappingJacksonHttpMessageConverter를 설정한다고 말한 바 있습니다. 그러나 수동으로 / 명시 적으로 해당 변환기를 설정해야하는 상황을 경험 한 것 같습니다. 일할 것들. MVC config XML에이 값을 추가하려고 할 수 있습니다.

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            </list>
        </property>
    </bean>
    

    업데이트 : 게시 된 JSON의 형식을 올바로 지정하는 것이므로 https://stackoverflow.com/a/10363876/433789를 참조하십시오.

  3. ==============================

    3.2014 년에이 질문에 대한 몇 가지 업데이트를 추가하여 동일한 문제를 해결하는 데 도움이되었습니다.

    2014 년에이 질문에 대한 몇 가지 업데이트를 추가하여 동일한 문제를 해결하는 데 도움이되었습니다.

    왜 내가 올바른 JSON 구성을 추가 한 후에도 415 오류가 발생하는 이유를 알아 내려고 많은 시간을 보냈다. 마침내 문제는 서버 쪽이 아니라 클라이언트 쪽이었습니다. Spring이 JSON을 받아들이게하려면 http 헤더의 일부로 "Content-Type : application / json"과 "Accept : application / json"을 모두 전송해야합니다. 나를 위해 구체적으로 안드로이드 응용 프로그램 HttpUrlConnection로 설정했다 :

        public static String doPost(final String urlString,final String requestBodyString) throws IOException {
            final URL url = new URL(urlString);
    
            final HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            try {
              urlConnection.setReadTimeout(10000 /* milliseconds */);
              urlConnection.setConnectTimeout(15000 /* milliseconds */);
              urlConnection.setRequestProperty("Content-Type", "application/json");
              urlConnection.setRequestProperty("Accept", "application/json");
              urlConnection.setDoOutput(true);
              urlConnection.setRequestMethod("POST");
              urlConnection.setChunkedStreamingMode(0);
    
              urlConnection.connect();
    
              final PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
              out.print(requestBodyString);
              out.close();
    
              final InputStream in = new BufferedInputStream(urlConnection.getInputStream());
              final String response =  readIt(in);
    
              in.close(); //important to close the stream
    
              return response;
    
            } finally {
              urlConnection.disconnect();
            }
        }
    
  4. ==============================

    4.POST 요청에있는 설명자를 추가하십시오. 즉, 헤더를 말리기 위해 추가하십시오.

    POST 요청에있는 설명자를 추가하십시오. 즉, 헤더를 말리기 위해 추가하십시오.

    Content-Type: application/json
    

    추가하지 않으면 curl은 실제로 보낸 내용에 관계없이 기본 text / html을 사용합니다.

    또한, PurchaseController.create ()에서 당신은 받아 들여지는 타입이 application / json이라는 것을 추가해야만합니다.

  5. ==============================

    5.내 코드에서 두 가지 변경 사항으로 해결 된 동일한 문제가 발생했습니다.

    내 코드에서 두 가지 변경 사항으로 해결 된 동일한 문제가 발생했습니다.

  6. ==============================

    6.다음은 yoram givon의 답변 - https://stackoverflow.com/a/22516235/1019307과 유사한 단위 테스트 솔루션입니다.

    다음은 yoram givon의 답변 - https://stackoverflow.com/a/22516235/1019307과 유사한 단위 테스트 솔루션입니다.

    public class JSONFormatTest
    {
        MockMvc mockMvc;
    
        // The controller used doesn't seem to be important though YMMV
        @InjectMocks
        ActivityController controller;  
    
        @Before
        public void setup()
        {
            MockitoAnnotations.initMocks(this);
    
            this.mockMvc = standaloneSetup(controller).setMessageConverters(new MappingJackson2HttpMessageConverter())
                    .build();
        }
    
        @Test
        public void thatSaveNewDataCollectionUsesHttpCreated() throws Exception
        {
            String jsonContent = getHereJSON02();
            this.mockMvc
                    .perform(
                         post("/data_collections").content(jsonContent).contentType(MediaType.APPLICATION_JSON)
                                    .accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isCreated());
        }
    
        private String getHereJSON01()
        {
            return "{\"dataCollectionId\":0,\"name\":\"Sat_016\",\"type\":\"httpUploadedFiles\"," ...
        }
    }
    

    유닛 테스트를 실행하면 print ()는 예외를 포함하여 MockHttpServletRequest를 출력합니다.

    Eclipse에서 (다른 IDE에서이를 수행하는 방법에 대해 잘 모름) 예외 링크를 클릭하면 예외에 대한 등록 정보 대화 상자가 열립니다. 해당 예외를 해제하려면 '사용함'상자를 선택하십시오.

    단위 테스트를 디버그하면 Eclipse에서 예외가 발생합니다. 그것을 검사하면 문제가 드러날 것입니다. 필자의 경우 JSON에 동일한 엔티티가 2 개 있었기 때문입니다.

  7. ==============================

    7.나는 jar 파일 jackson-mapper-asl.jar을 추가하여 한 번 경험했고 마침내 해결했습니다. 예외 자체가 그것을 알려주지는 않지만 모든 종속성을 포함했는지 확인하십시오.

    나는 jar 파일 jackson-mapper-asl.jar을 추가하여 한 번 경험했고 마침내 해결했습니다. 예외 자체가 그것을 알려주지는 않지만 모든 종속성을 포함했는지 확인하십시오.

    그리고 당신은 실제로 bean을 명시 적으로 설정할 필요가 없으며 @RequestMapping 문에 "consumes"를 넣을 필요가 없습니다. 저는 봄 3.1 btw를 사용하고 있습니다.

    contentType : "application / json"만 구성해야합니다. 네, 고객 측.

  8. ==============================

    8.앱 구성에 다음 코드를 추가하십시오.

    앱 구성에 다음 코드를 추가하십시오.

    <mvc:annotation-driven>
      <mvc:message-converters>
          <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
              <property name="objectMapper" ref="jacksonObjectMapper" />
          </bean>
      </mvc:message-converters>
    

  9. ==============================

    9.나는 똑같은 문제를 안고 그것을 해결했다.

    나는 똑같은 문제를 안고 그것을 해결했다.

    1은 해당 스레드에서 설명한대로 MappingJackson2HttpMessageConverter를 추가합니다 (섹션 4 참조). http://www.baeldung.com/spring-httpmessageconverter-rest

    2 올바른 명령을 사용하십시오 (이스케이프 기호 사용).

    curl -i -X POST -H "Content-Type:application/json" -d "{\"id\":\"id1\",\"password\":\"password1\"}" http://localhost:8080/user    
    
  10. from https://stackoverflow.com/questions/10323957/posting-json-to-rest-api by cc-by-sa and MIT license