2017-03-01 9 views
1

すべてのエンドポイントは、XMLとJSONのような複数の形式で応答を返すことができます。Jerseyを使用したクエリパラメータの動的応答形式私のWebサービスAPIの

https://example.com/rest/countries?format=xml 
https://example.com/rest/countries?format=json 

私のすべてのエンドポイントrurrentlyこの例のように似て実装されています:

@GET 
@Path("/countries") 
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) 
public Response getCountries(@QueryParam("format") String format) { 

    if(format.equalsIgnoreCase("xml")) { 
     Countries countries = getResponseFromSomewhere(); 
     String xml = toXmlWithJaxB(countries); 
     return Response.ok(xml, MediaType.APPLICATION_XML).build(); 
    } 
    else if(format.equalsIgnoreCase("json")) { 
     Countries countries = getResponseFromSomewhere(); 
     String json = toJsonWithJackson(countries); 
     return Response.ok(json, MediaType.APPLICATION_JSON).build(); 
    } 
    else { 
     return Response.status(415).entity("Invalid format"); 
    } 
} 

は、この問題に対するより一般的な解決策はあります。この要求にURIのは次のように応答フォーマットは、クエリパラメータによって決定されます私は手動で各エンドポイントのフォーマットをチェックして処理する必要はありませんか? ジャクソンまたはジャージーはすでにそのためのソリューションを提供していますか?

答えて

2

カスタムを実装する必要なく、Jerseyにはフォーマットの「拡張子」をチェックするUriConnegFilterがあります。例

https://example.com/rest/countries.xml 
https://example.com/rest/countries.json 

のためにあなたは、マッピング

final Map<String, MediaType> mappings = new HashMap<>(); 
mappings.put("json", MediaType.APPLICATION_JSON_TYPE); 
mappings.put("xml", MediaType.APPLICATION_XML_TYPE); 

return new ResourceConfig() 
     .property(ServerProperties.MEDIA_TYPE_MAPPINGS, mappings); 

を設定する必要がありますここでは、単にメディアタイプの拡張をマッピングしています。ジャージーは残りをするでしょう。

実際にクエリパラメータを使用する場合は、@PreMatchingContainerRequestFilterと入力してクエリパラメータを確認し、それに応じてAcceptヘッダーを設定します。

@Provider 
@PreMatching 
@Priority(3000) 
public static class QueryConnegFilter implements ContainerRequestFilter { 

    private static final Map<String, String> mappings; 

    static { 
     Map<String, String> map = new HashMap<>(); 
     map.put("xml", MediaType.APPLICATION_XML); 
     map.put("json", MediaType.APPLICATION_JSON); 
     mappings = Collections.unmodifiableMap(map); 
    } 

    @Override 
    public void filter(ContainerRequestContext request) throws IOException { 
     final String format = request.getUriInfo().getQueryParameters().getFirst("format"); 
     if (format != null) { 
      final String mediaType = mappings.get(format); 
      if (mediaType != null) { 
       request.getHeaders().putSingle(HttpHeaders.ACCEPT, mediaType); 
      } 
     } 
    } 
} 

次にアプリケーションに登録するだけで済みます。今、あなたはここで

https://example.com/rest/countries?format=xml 
https://example.com/rest/countries?format=json 

を行うことができますフォーマットはリクエストパラメータとして渡す必要がある

import org.glassfish.jersey.filter.LoggingFilter; 
import org.glassfish.jersey.server.ResourceConfig; 
import org.glassfish.jersey.server.ServerProperties; 
import org.glassfish.jersey.test.JerseyTest; 
import org.junit.Test; 

import javax.annotation.Priority; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.container.PreMatching; 
import javax.ws.rs.core.HttpHeaders; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.ext.Provider; 
import javax.xml.bind.annotation.XmlRootElement; 
import java.io.IOException; 
import java.util.Collections; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.logging.Logger; 

import static org.hamcrest.CoreMatchers.containsString; 
import static org.hamcrest.CoreMatchers.is; 
import static org.hamcrest.MatcherAssert.assertThat; 

/** 
* Run it like any other JUnit test. Only two required dependencies: 
* 
* <dependency> 
* <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId> 
* <version>${jersey2.version}</version> 
* </dependency> 
* <dependency> 
* <groupId>org.glassfish.jersey.media</groupId> 
* <artifactId>jersey-media-json-jackson</artifactId> 
* <version>${jersey2.version}</version> 
* </dependency> 
* 
* @author Paul Samsotha. 
*/ 
public class UriConnegTests extends JerseyTest { 

    @XmlRootElement 
    public static class Model { 
     private String message; 
     public Model() {} 
     public Model(String message) { this.message = message; } 
     public String getMessage() { return this.message; } 
     public void setMessage(String message) { this.message = message; } 
    } 


    @Path("test") 
    public static class TestResource { 
     @GET 
     @Produces({"application/json", "application/xml"}) 
     public Model get() { 
      return new Model("Hello World"); 
     } 
    } 

    @Provider 
    @PreMatching 
    @Priority(3000) 
    public static class QueryConnegFilter implements ContainerRequestFilter { 

     private static final Map<String, String> mappings; 

     static { 
      Map<String, String> map = new HashMap<>(); 
      map.put("xml", MediaType.APPLICATION_XML); 
      map.put("json", MediaType.APPLICATION_JSON); 
      mappings = Collections.unmodifiableMap(map); 
     } 

     @Override 
     public void filter(ContainerRequestContext request) throws IOException { 
      final String format = request.getUriInfo().getQueryParameters().getFirst("format"); 
      if (format != null) { 
       final String mediaType = mappings.get(format); 
       if (mediaType != null) { 
        request.getHeaders().putSingle(HttpHeaders.ACCEPT, mediaType); 
       } 
      } 
     } 
    } 

    @Override 
    public ResourceConfig configure() { 
     final Map<String, MediaType> mappings = new HashMap<>(); 
     mappings.put("json", MediaType.APPLICATION_JSON_TYPE); 
     mappings.put("xml", MediaType.APPLICATION_XML_TYPE); 
     return new ResourceConfig() 
       .register(TestResource.class) 
       .register(QueryConnegFilter.class) 
       .register(new LoggingFilter(Logger.getAnonymousLogger(), true)) 
       .property(ServerProperties.MEDIA_TYPE_MAPPINGS, mappings); 
    } 

    @Test 
    public void returnsXmlFromExtension() { 
     final String expected = "<message>Hello World</message>"; 
     final String data = target("test.xml") 
       .request() 
       .get(String.class); 
     assertThat(data, containsString(expected)); 
    } 

    @Test 
    public void returnsJsonFromExtension() { 
     final String expected = "{\"message\":\"Hello World\"}"; 
     final String data = target("test.json") 
       .request() 
       .get(String.class); 
     assertThat(data, is(expected)); 
    } 

    @Test 
    public void returnsXmlFromQuery() { 
     final String expected = "<message>Hello World</message>"; 
     final String data = target("test") 
       .queryParam("format", "xml") 
       .request() 
       .get(String.class); 
     assertThat(data, containsString(expected)); 
    } 

    @Test 
    public void returnsJsonFromQuery() { 
     final String expected = "{\"message\":\"Hello World\"}"; 
     final String data = target("test") 
       .queryParam("format", "json") 
       .request() 
       .get(String.class); 
     assertThat(data, is(expected)); 
    } 
} 
1

ジャージーは、XML/JSONにオブジェクトの変換を可能にします。

  1. XmlRootElementが含ま
  2. であなたの国のBeanがエンティティのメソッドに注釈付きオブジェクトをパスし、ジャージが
  3. それを構築しましょう注釈あなたのクラスパスにジャージ-JSONの依存関係を追加する必要があります
  4. クライアントこの場合、ヘッダーで受け入れるものを指定する必要があります。実際には、クエリのパラメータを必要としません。即ち受け入れる:アプリケーション/ JSON又はアプリケーション/ XMLを

    国の国= getResponseFromSomewhere()。
    Response.ok()エンティティ(国).build();

+0

上記の両方のオプションとの完全な作業テストです。ヘッダー内のフォーマットを渡すことは私の選択肢ではありません。 – eztam

+1

ヘッダーを使用しないと、あなたはそれを持っていると思います。あなたはさらに、toxml/tojsonメソッドを汎用の "toFormat"メソッドの背後にあるユーティリティに抽象化することができます。これはロジックを押し戻し、サービスクラスでコードがよりきれいに見えるようにします。それともこの記事はhttp://stackoverflow.com/questions/20212405/how-to-set-accept-header-on-the-server-side-in-jersey-1-x-for-an-incoming-を助けます要求する。 – caburse

関連する問題