16

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);
    }
}



アップデート

Jackson 構成を 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;
    }
}



私の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;
    }

}



私が間違っているアイデアはありますか?

ありがとう

4

9 に答える 9

16

sdouglassが示唆したように、Spring MVC は Jackson を自動的に検出し、 MappingJacksonHttpMessageConverterをセットアップして、JSON との間の変換を処理します。しかし、彼が指摘したように、コンバーターを機能させるには、コンバーターを明示的に構成する必要がありました。

私は以下を追加し、私の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

うまくいけば、誰かがこれが役に立つと思います。

于 2012-04-28T13:21:33.040 に答える
6

私が正しく思い出すと、Spring のドキュメントでは、Spring MVC はクラスパス上の Jackson を自動的に検出し、MappingJacksonHttpMessageConverter をセットアップして JSON との間の変換を処理すると述べていますが、そのコンバーターを手動/明示的に構成して取得する必要がある状況を経験したと思います。動作するもの。これを MVC 構成 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を参照してください

于 2012-04-25T22:11:08.287 に答える
5

その2014年で、この質問にいくつかの更新を追加したかったので、同じ問題を解決するのに役立ちました。

  1. Spring 3.2 で非推奨の AnnotationMethodHandlerAdapter を置き換えるコードの更新

        @構成
        パブリック クラス AppConfig {
    
    
        @Bean
        public RequestMappingHandlerAdapter  annotationMethodHandlerAdapter()
        {
            final RequestMappingHandlerAdapter annotationMethodHandlerAdapter = new RequestMappingHandlerAdapter();
            final MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
    
            List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>();
            httpMessageConverter.add(mappingJacksonHttpMessageConverter);
    
            String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
    
            annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
            annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
    
            return annotationMethodHandlerAdapter;
        }
    }
    
  2. HTTP/1.1 415 サポートされていないメディア タイプ エラー

正しいJSON構成を追加した後でも415エラーが発生する理由を突き止めるために何時間も費やした後、問題はサーバー側ではなくクライアント側にあることに最終的に気付きました. Spring が JSON を受け入れるためには、「Content-Type : application/json」と「Accept: application/json」の両方を http ヘッダーの一部として送信していることを確認する必要があります。私にとって具体的には、次のように設定する必要があったのは、Android アプリケーションの 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();
        }
    }
于 2014-03-19T19:29:25.460 に答える
2

POST リクエストの内容の記述子を追加してみてください。つまりcurl、ヘッダーに次を追加します。

Content-Type: application/json

追加しない場合は、実際に送信する内容に関係なくcurl、デフォルトが使用されます。text/html

また、PurchaseController.create() 受け入れられるタイプが であることを追加する必要がありapplication/jsonます。

于 2012-04-25T21:21:34.870 に答える
2

これは 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 つあったためです。

于 2014-10-22T03:13:55.517 に答える
2

私は同じ問題を抱えていましたが、コードの2つの変更によって解決されました:

  1. メソッドの引数に @PathVariable がありません。メソッドに @PathVariable がありませんでした
  2. ハンドラーインターセプターで使用していたメソッドが非推奨になり、いくつかの問題が発生したため、SpringConfig クラスの次のメソッド:

    public RequestMappingHandlerAdapter RequestMappingHandlerAdapter()
    {
        final RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
        final MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
        final String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
    
        requestMappingHandlerAdapter.getMessageConverters().add(0, mappingJacksonHttpMessageConverter);
        requestMappingHandlerAdapter.setSupportedMethods(supportedHttpMethods);
    
        return requestMappingHandlerAdapter;
    }
    
于 2013-12-11T07:24:46.577 に答える
0

私は同じ問題を抱えていて、それを解決しました。

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    
于 2015-08-29T01:06:17.403 に答える
0

私は一度経験し、jar ファイル jackson-mapper-asl.jar を追加することで最終的に解決しました。例外自体はそれを教えてくれませんが、これらすべての依存関係が含まれているかどうかを確認してください。

また、Bean を明示的に構成する必要はなく、@RequestMapping ステートメントに「consumes」を入れる必要もありません。私はSpring 3.1btwを使用しています。

contentType : "application/json" は、構成する必要がある唯一のものです。はい、クライアント側です。

于 2012-12-16T09:51:02.633 に答える