在Apache CXF JAX-RS中映射扩展内容类型

时间:2012-04-03 20:15:40

标签: mapping cxf content-type jax-rs

JAX-RS提供了一种在@Produces中指定内容类型的绝妙方式,框架将自动从客户端的HTTP Accept标题中确定最佳内容类型,并且奇迹奇迹,甚至在将信息返回给调用者时,将您的对象转换为该类型(例如,使用JAXB的XML或使用Jackson的JSON)。

我的(工作)客户端,正如客户经常做的那样,通过请求我通过URL中的扩展名指定内容类型,使得简单的工作变得更加困难,例如: api/widgets.json。这将迫使我使用各种getWidgetsXXX()方法,一个使用@Produces("application/json"),另一个使用@Produces("application/xml")等。

但我正在使用Apache CXF,我很高兴发现我可以configure CXF使用jaxrs.extensions init参数将各种扩展映射到内容类型!

<!-- registers extension mappings -->
<init-param>
  <param-name>jaxrs.extensions</param-name>
  <param-value>
    xml=application/xml
    json=application/json
  </param-value>
</init-param>

但我完全没有关于它如何在现实世界中运作的文档。我天真地以为我可以使用带扩展名的路径注释一个方法,它会模仿Accepts标题:

@Path("/widgets.{extension}")
@GET
@Produces({ "application/json", "application/xml" })
public List<Widget> getWidgets();

所以我用api/widgets.json来调用它,它返回XML!这特别奇怪,因为JAX-RS指定默认内容类型是列出的第一个。

在哪里可以找到如何使用CXF扩展内容类型映射?

P.S。我没有使用Spring。

4 个答案:

答案 0 :(得分:4)

<jaxrs:server>作品中添加以下内容:

<jaxrs:extensionMappings>
    <entry key="json" value="application/json" />
    <entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>

来源:http://cxf.apache.org/docs/jax-rs.html#JAX-RS-Debugging

答案 1 :(得分:1)

不知道这对你有没有帮助,但我也面临同样的问题,在我的JAX-RS服务中引入类似的东西。我使用 JAX-RS_Content_Negotiation 实现了此功能。以下位置有详细信息。

https://docs.jboss.org/resteasy/docs/3.0.6.Final/userguide/html/JAX-RS_Content_Negotiation.html

您只需要将媒体类型映射到您想要的值

 <context-param>
        <param-name>resteasy.media.type.mappings</param-name>
        <param-value>
          html : text/html, json : application/json, xml :           
           application/xml
       </param-value>
 </context-param>


 @GET
        @Path("/second/{param}")
        @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
        public Response printStudent(@PathParam("param") String msg) {


}

现在我可以像这样访问我的服务,并且响应是根据我放在最后的扩展

http://localhost:8080/RESTfulExample/rest/message/second/bill.json

你可以在网址的末尾加上.xml或.json,服务会相应地生成响应。

答案 2 :(得分:0)

在您的情况下,我会声明方法@Produces内容类型*/*(即完整的通配符),然后自己进行内容协商。您可能正在查看这样的方法签名:

@javax.ws.rs.GET
@javax.ws.rs.Path("{filename}")
@javax.ws.rs.Produces("*/*")
javax.ws.rs.core.Response getDirectoryOrFileContents(
        @javax.ws.rs.PathParam("filename") String filename,
        @javax.ws.rs.core.Context javax.ws.rs.core.HttpHeaders headers);

这使您可以访问所需的文件名 - 一种猜测要传递的媒体类型的方法 - 以及完整的HTTP标头集(提示:使用headers.getAcceptableMediaTypes()),这提供了另一种方式。如何平衡两者可能是“有趣的”。 (我必须要做的代码非常特定于我的应用程序的内部模型,因此对您来说可能不太有用。)然后通过构造Response返回结果,这会让您非常接近控制客户回来的东西。

是的,这比让CXF为你处理所有这些工作要多得多(它通常会生成很多样板来完成所有这些工作)但在复杂的情况下你会对控制感到高兴。

答案 3 :(得分:0)

您猜测时,扩展程序会模仿Accept标题。但是,您不能在@Path注释中声明扩展名:

@Path("/widgets")
@GET
@Produces({ "application/json", "application/xml" })
public List<Widget> getWidgets();

然后,您可以致电widgets.xmlwidgets.json