LoginSignup
2
2

More than 5 years have passed since last update.

jerseyでXHRで送られてきたJSONを処理する

Last updated at Posted at 2016-09-18

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を処理するには

  • マッピング
  • フィルター

が必要

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2