web-dev-qa-db-ja.com

RESTful POSTメソッドでパラメータにアクセスする方法

私のPOSTメソッドはこんな感じです:

@POST
@Consumes({"application/json"})
@Path("create/")
public void create(String param1, String param2){
    System.out.println("param1 = " + param1);
    System.out.println("param2 = " + param2);
}

NetbeansでJersey Clientを作成すると、postメソッドを呼び出すメソッドは次のようになります。

public void create(Object requestEntity){
    webResource.path("create").type(MediaType.APPLICATION_JSON).post(requestEntity);
}

このテストを実行すると

@Test
public void hello(){
    String json = "{param1=\"hello\",param2=\"hello2\"}";
    this.client.create(json);
}

サーバーに次のような出力が表示されます。

INFO: param1 = {param1="hello",param2="hello2"}
INFO: param2 = 

パラメータが正しい値を与えるように変更する必要がありますか。

115
Klaasvaak

あなたの@POSTメソッドは文字列の代わりにJSONオブジェクトを受け取るべきです。 JerseyはJSONオブジェクトの整列化と非整列化をサポートするためにJAXBを使用します(詳細については jerseyのドキュメントを参照 を参照)。以下のようなクラスを作成してください。

@XmlRootElement
public class MyJaxBean {
    @XmlElement public String param1;
    @XmlElement public String param2;
}

その場合、@POSTメソッドは次のようになります。

@POST @Consumes("application/json")
@Path("/create")
public void create(final MyJaxBean input) {
    System.out.println("param1 = " + input.param1);
    System.out.println("param2 = " + input.param2);
}

このメソッドは、HTTP POSTの本文としてJSONオブジェクトを受け取ることを想定しています。 JAX-RSは、HTTPメッセージのコンテンツ本体を注釈なしパラメータとして渡します。この場合はinputです。実際のメッセージは次のようになります。

POST /create HTTP/1.1
Content-Type: application/json
Content-Length: 35
Host: www.example.com

{"param1":"hello","param2":"world"}

このようにJSONを使用することは明白な理由で非常に一般的です。ただし、JavaScript以外のもので生成または消費している場合は、データを適切にエスケープするように注意する必要があります。 JAX-RSでは、これを実装するために MessageBodyReader および MessageBodyWriter を使用します。私は、Jerseyには、JSONのほかに、必要な型(たとえば、JavaプリミティブやJAXBラップクラス)の実装もすでにあると思います。 JAX-RSは、データを渡すための他のいくつかの方法をサポートしています。データは単純な引数渡しを使用して渡されるので、これらは新しいクラスの作成を必要としません。


HTML <FORM>

パラメータは、 @ FormParam を使用して注釈を付けられます。

@POST
@Path("/create")
public void create(@FormParam("param1") String param1,
                   @FormParam("param2") String param2) {
    ...
}

ブラウザは "application/x-www-form-urlencoded" を使用してフォームをエンコードします。 JAX-RSランタイムは、本体をデコードしてそれをメソッドに渡す処理を行います。これはあなたがネットワーク上で見るべきものです:

POST /create HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 25

param1=hello&param2=world

この場合の内容は URLエンコード です。

あなたがFormParamの名前を知らないならば、あなたは以下をすることができます:

@POST @Consumes("application/x-www-form-urlencoded")
@Path("/create")
public void create(final MultivaluedMap<String, String> formParams) {
    ...
}

HTTPヘッダ

HTTPヘッダを介してパラメータを渡したい場合は、 @ HeaderParam アノテーションを使用できます。

@POST
@Path("/create")
public void create(@HeaderParam("param1") String param1,
                   @HeaderParam("param2") String param2) {
    ...
}

これがHTTPメッセージの外観です。このPOSTには本文がありません。

POST /create HTTP/1.1
Content-Length: 0
Host: www.example.com
param1: hello
param2: world

このメソッドは一般化されたパラメータの受け渡しには使用しません。ただし、特定のHTTPヘッダーの値にアクセスする必要がある場合は本当に便利です。


HTTPクエリパラメータ

このメソッドは主にHTTP GETで使用されますが、POSTにも同様に適用可能です。それは @ QueryParam アノテーションを使います。

@POST
@Path("/create")
public void create(@QueryParam("param1") String param1,
                   @QueryParam("param2") String param2) {
    ...
}

前のテクニックのように、クエリ文字列を通してパラメータを渡すことはメッセージ本文を必要としません。これがHTTPメッセージです。

POST /create?param1=hello&param2=world HTTP/1.1
Content-Length: 0
Host: www.example.com

クライアント側では、 クエリパラメータのエンコード を正しく行うために特に注意する必要があります。クエリパラメータの使用は、一部のプロキシで強制されているURLの長さの制限、およびそれらのエンコードに関連する問題のために問題になる可能性があります。


HTTPパスパラメータ

パスパラメータは、HTTPリソースパスに埋め込まれていること以外はクエリパラメータと似ています。この方法は今日では支持されているようです。パスが実際にHTTPリソースを定義するものであるため、HTTPキャッシュに関して影響があります。 @ Path アノテーションが変更され、 @ PathParam が使用されるため、コードは他のコードと少し異なります。

@POST
@Path("/create/{param1}/{param2}")
public void create(@PathParam("param1") String param1,
                   @PathParam("param2") String param2) {
    ...
}

メッセージは、パラメータの名前がメッセージ内のどこにも含まれていないことを除いて、クエリパラメータバージョンと似ています。

POST /create/hello/world HTTP/1.1
Content-Length: 0
Host: www.example.com

このメソッドは、クエリパラメータのバージョンと同じエンコードの問題を共有しています。 パスセグメントは異なる方法でエンコードされています だからあなたもそこに注意する必要があります。


ご覧のとおり、それぞれの方法には長所と短所があります。選択は通常あなたのクライアントによって決定されます。 FORMベースのHTMLページを提供している場合は、@FormParamを使用します。クライアントがJavaScript + HTML 5ベースの場合は、おそらくJAXBベースのシリアル化とJSONオブジェクトを使用したいでしょう。 MessageBodyReader/Writerの実装はあなたに必要なエスケープの面倒を見なければなりません。あなたのクライアントがJavaベースであるが、良いXMLプロセッサ(例えば、Android)を持っていないなら、私はおそらくコンテンツボディがURLより適切に生成してエンコードするのが簡単であるのでFORMエンコーディングを使うでしょう。このmini-wikiエントリがJAX-RSでサポートされているさまざまな方法に光を当てることを願っています。

注:完全な開示のために、私は実際にはまだJerseyのこの機能を使用していません。 JAXB + JAX-RSアプリケーションが多数配備され、モバイルクライアントの分野に移行しているので、私たちはそれに慣れていました。 JSONは、HTML 5上のXMLまたはjQueryベースのソリューションよりもはるかに適しています。

338
D.Shawley