jersey
JAX-RSの実装で簡単にRestfulなWebサービスが作成できる
プロトタイプの作成
maven archetypeからプロトタイプを作成します。
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example \
-DarchetypeVersion=2.23.2
simple-serviceというプロジェクトが作成されます。
mainを実行し、http://localhost:8080/myapp/myresource にアクセスするとGot it!と表示されるはずです。
JSONを受け取れるようにする
まずPOMを確認するとJSONを扱うためにはコメントアウトを外してくださいと書かれている箇所があります。
<!-- uncomment this to get JSON support:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
-->
こちらのコメントアウトを外しましょう。
これでJSONを受け取れるはず・・・
と以下のようなリソースを作成
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void viewJSON(HashMap<String,String> map){
for(String s:map.keySet()){
System.out.println(s + ":" + map.get(s));
}
}
DHCなどで適当なJSONを送ってみると・・・415(Unsupported Mediatype)
どうやらマッピングを行う必要があるらしい。
まずマッピングに必要な依存性を追加して
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
以下のようなマッピングを行うクラスを作成し
@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public MyObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
return new ObjectMapper();
}
}
さらにResourceConfigにも以下を追加しないといけない
.register(MyObjectMapperProvider.class)
.register(JacksonFeature.class);
これでJSONが受け取れるようになりました。
XHRに対応する
以下のようなhtmlを書きXHRでjsonを送信するテストを行う。
<html>
<head>
<title>test</title>
</head>
<body>
<script type="text/javascript">
<!--
window.onload = function()
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://localhost:8080/myapp/myresource");
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(JSON.stringify({"key":"value"}));
};
// -->
</script>
</body>
</html>
コンソール上に以下のようなエラーメッセージがでて弾かれる
test.html:1 XMLHttpRequest cannot load http://localhost:8080/myapp/myresource. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
これが同一生成元ポリシーというやつで、特定の条件を満たすXHRにはプリフライトというリクエストを送り安全かどうか確かめる。
そして「安全ですよ」というリクエストが帰ってきたら正式にリクエストを送るというもの。
「安全ですよ」というリクエストを返すのをすべてのリソースに書くのは手間だし実装上よくないのでfilterを使いすべてのリクエストに対して「安全ですよ」というリクエストを返すようにする。
public class CORSResponseFilter
implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
headers.add("Access-Control-Allow-Headers", "Content-Type");
}
}
上記のようなfilterを作成して、ResourceConfigにも追加
.register(CORSResponseFilter.class);
これでjerseyでXHRで送られてきたJSONを処理できるようになりました。
まとめ
jerseyでXHRで送られてきたJSONを処理するには
- マッピング
- フィルター
が必要