加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 湛江站长网 (https://www.0759zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

JAX-RS入门 七: 数据处理(2)

发布时间:2021-02-22 12:20:58 所属栏目:大数据 来源:网络整理
导读:转自:http://liugang594.iteye.com/blog/1499813 上节介绍了JAX-RS中怎么与一些基础的对象进行交互,这节介绍JAXB和JSON的使用。 ? 一、JAXB 关于JAXB知识,可以去网上搜搜,或者要入门的话,可以看:http://liugang594.iteye.com/category/201713?。 为

转自:http://liugang594.iteye.com/blog/1499813


上节介绍了JAX-RS中怎么与一些基础的对象进行交互,这节介绍JAXB和JSON的使用。

?

一、JAXB

关于JAXB知识,可以去网上搜搜,或者要入门的话,可以看:http://liugang594.iteye.com/category/201713?。

为了在XML和对象间进行映射,修改一下Customer类,添加JAXB相关的annotations。如下:

Java代码??

收藏代码

  1. @XmlRootElement(name="customer")??
  2. @XmlAccessorType(XmlAccessType.FIELD)??
  3. public?class?Customer?{??
  4. ????@XmlAttribute??
  5. ????protected?int?id;??
  6. @XmlElement??
  7. protected?String?fullname;??
  8. public?Customer()?{}??
  9. int?getId()?{?return?this.id;?}??
  10. void?setId(int?id)?{?this.id?=?id;?}??
  11. public?String?getFullName()?{?this.fullname;?}??
  12. void?setFullName(String?name}?{?this.fullname?=?name;?}??
  13. }??

这里,对应的xml结构大致如下:

<customer?id="42">??
  • ????<fullname>Bill?Burke</fullname>??
  • </customer>??
  • 以上Customer类用JAXB处理,简单的如下:

    Customer?customer?=?new?Customer();??
  • customer.setId(42);??
  • customer.setName("Bill?Burke");??
  • ??
  • JAXBContext?ctx?=?JAXBContext.newInstance(Customer.class);??
  • StringWriter?writer?=?new?StringWriter();??
  • ctx.createMarshaller().marshal(customer,?writer);??
  • String?custString?=?writer.toString();??
  • customer?=?ctx.createUnmarshaller().unmarshal(new?StringReader(custString));??
  • JAX-RS规范规定:实现者需要自动支持marshalling和unmarshalling由@XmlRootElement或@XmlType约束的类对象,或者是包装在javax.xml.bind.JAXBElement中的对象。例如:

    @Path("/customers")??
  • class?CustomerResource?{??
  • @GET??
  • @Path("{id}")??
  • @Produces("application/xml")??
  • public?Customer?getCustomer(@PathParam("id")?int?id)?{??
  • ????????Customer?cust?=?findCustomer(id);??
  • ????????return?cust;??
  • ????}??
  • @POST??
  • @Consumes("application/xml")??
  • void?createCustomer(Customer?cust)?{??
  • ????????...??
  • 这里createCustomer(Customer)方法中的Customer参数即由内置的JAXB的转换来的。

    注:内置的JAXB处理器会处理交换类型是 application/xml、text/xml 或 application/*+xml 并且参数/返回值对象含有JAXB注释约束的类;另外,它也负责管理JAXBContext实例的创建和初始化,因为JAXBContext实例的创建是一个耗资源的操作,实现者通过会缓存他们以待下次使用。

    二、使用ContextResolvers管理你自己的JAXBContext

    你可以通过配置你的JAXBContext实例以得到你想要的输出。JAX-RS内置的JAXB提供器允许你插入你自己的JAXBContext实例,要想这样做,你需要实现一个类似于工厂类的操作javax.ws.rs.ext.ContextResoler,去覆盖缺省的JAXBContext的创建:

    interface?ContextResolver<T>?{??
  • ???????????T?getContext(Class<?>?type);??
  • 例如:

    @Provider??
  • class?CustomerResolver??
  • implements?ContextResolver<JAXBContext>?{??
  • private?JAXBContext?ctx;??
  • public?CustomerResolver()?{??
  • this.ctx?=?...;?//?initialize?it?the?way?you?want??
  • public?JAXBContext?getContext(Class<?>?type)?{??
  • if?(type.equals(Customer.class))?{??
  • ????????????return?ctx;??
  • ????????}?else?{??
  • null;??
  • ????????}??
  • 自定义的resolver类必须实现ContextResolver接口,并且这个类必须添加@javax.ws.rs.ext.Provider注释去表明它是一个JAX-RS组件。

    注:@Produces注释是可选的,它允许你为ContextResolver指定特定的交换数据类型,它允许你以其他格式输入,而非局限于XML。

    定义完自己的Resolver类后,就是注册它了。这里需要用到节2 (http://liugang594.iteye.com/blog/1491649) 中提到的javax.ws.rs.core.Application类,JAXB处理器会顺序查询所有注册的ContextResolver类,并调用它的getContext()方法,如果返回空,则继续找下一个,否则返回对应的JAXBContext对象;如果没有找着,则使用内置的对象。

    三、JAXB和JSON

    JAXB可以相当灵活以支持其他格式,而不仅限于xml格式。Jettison就是一个开源的JAXB适配器,可以用来输入或输出JSON格式。

    JSON是一个基于文本的、可以直接被JavaScript解析的是格式, 它是Ajax应用首选的交换格式。尽管对于JAX-RS并不要求支持JSON,不过多数实现者都会使用Jettison去支持JAXB声明的类对象与JSON之间的转换。

    JSON比XMl简单的多。 数据由"{}"包着,包含key/value对,值可以是带引号的字符串,boolean值(true/false),数据或者是这些值的数据类型,例如:

    ?

    {??
  • ????"id"?:?42,??
  • ????"name"?:?"Bill?Burke",250)"> ????"married"?:?true?,250)"> ????"kids"?:?[?"Molly",?"Abby"?]??
  • key/value之间用分号分隔,并以逗号为间隔符。

    * 使用BadgerFish进行XML-JSON转换

    1. xml元素名变成key,文本值变成一个内嵌的,key值为"$"的子元素值,例如:
      <customer>Bill Burke</customer> 变成 { "customer" : { "$" : "Bill Burke" }}
    2. 子元素变成值,例如:
      Xml代码??

      收藏代码

        <customer>??
      1. ??????????first>Bill</last>Burke>??
      ?变成:
      Js代码??

      收藏代码

        {?"customer"?:??
      1. ???????????{??
      2. ??????????????"first"?:?{?"$"?:?"Bill"},??
      3. ??????????????"last"?:?{?"$"?:?"Burke"?}??
      4. ????????????}??
      5. }??
    3. 多个同名元素值变成一个列表:
      ???????????phone>978-666-5555>978-555-2233customer??
    ?变成:
    ??????????{?"phone"?:?[?{?"$":?"978-666-5555"},?{?"$":"978-555-2233"}?]?}??
  • }??
  • ?
  • 属性变成一个以@开始的值,例如:
    Java代码??

    收藏代码

      <customer?id="42">??
    1. ???????????<name>Bill?Burke</name>??
    2. </customer>??
    ?变成:
    {?"customer"?:??
  • ?????????{???
  • ????????????"@id"?:?42,250)"> ????????????"name"?:?{"$":?"Bill?Burke"}??
  • ??????????}??
  • }??
  • ?
  • ?namespace会对应一个@xmlns属性值,缺省的namespace对应"$", 所有子元素和属性都使用namespace的前缀作为他们名字的一部分,例如:
    customer?xmlns="urn:cust"?xmlns:address="urn:address" ???????name>Bill?Burkeaddress:zip>02115>??
  • ?对应:
    ????{?"@xmlns"?:?{?"$"?:?"urn:cust",250)"> ????????????"address"?:?"urn:address"?}?,250)"> ????????"name"?:?{?"$"?:?"Bill?Burke",250)"> ??????????????"@xmlns"?:?{?"$"?:?"urn:cust",250)"> ??????????????"address"?:?"urn:address"?}?},250)"> ????????"address:zip"?:?{?"$"?:?"02115",250)"> ????????"@xmlns"?:?{?"$"?:?"urn:cust",250)"> ????????"address"?:?"urn:address"?}}??
  • ????}??
  • }??
  • * JSON和JSON?Schema

    BadgerFish对于Javascript程序员来说并不很直观,不建议在XmlSchema和JSon之间进行映射。另一个更好的方式是定义一个JSON的schema来进行java对象和json之间的映射。一个好的框架是Jackson。

    四、自定义输出

    除了xml和json外,还有很多很多其他的格式,JAX-RS只包含很少的一部分。下面要介绍怎么实现自己的转换器,这里假设没有JAXB,我们自己实现一个。

    * MessageBodyWriter

    首先实现JAXB-Marshalling支持。要实现java对象和xml之间的自动转换,我们需要创建一个实现javax.ws.rs.ext.MessageBodyWriter的接口:

    interface?MessageBodyWriter<T>?{??

  • ??????
  • boolean?isWriteable(Class<?>?type,?Type?genericType,250)"> ????????????Annotation?annotations[],?MediaType?mediaType);??
  • long?getSize(T?t,?Class<?>?type,?Annotation?annotations[],???
  • ????????????MediaType?mediaType);??
  • void?writeTo(T?t,250)"> ????????????MediaType?mediaType,250)"> ????????????MultivaluedMap<String,?Object>?httpHeaders,250)"> ????????????OutputStream?entityStream)?throws?IOException,?WebApplicationException;??????
  • }??
    • ?isWriteable()方法决定当前对象是否支持
    • getSize()方法决定Content-Length的值
    • writeTo()做最终的写出操作

    下面看JAXBMarshaller的实现:

    class?JAXBMarshaller?implements?MessageBodyWriter?{??
  • return?type.isAnnotationPresent(XmlRootElement. ????}??
  • 首先使用@Provider,告诉JAX-RS,这是一个可配置的JAX-RS组件;另外,必须添加@Produces,以告诉JAX-RS,这个MessageBodyWriter支持哪些交换类型。

    JAX-RS按照以后算法查找一个合适的MessageBodyWriter来输出一个对象:

    1. 首先查看@Produces,以确定是否是支持的交换数据类型
    2. 其他查找最优的匹配,例如对于 application/xml,找到三种可用的(application/*,*/*, application/xml),则 application/xml为最优
    3. 最后,得到可用列表以后,就会顺序调用MessageBodyWriter.isWriteable()。如果成功,刚输出,否则尝试下一个。

    对于getSize()方法,如果不能确定大小,则直接返回-1即可。

    增加缩进

    默认情况下,所有的空白和特殊字符都被去除。输出内容都在一行上。如果希望以格式化输出,则可以增加@Pretty可以保留缩进,例如:

    @Pretty??
  • int?id)?{...}??
  • 所以在自定义的Marsheller中需要处理这个annotation:

    void?writeTo(Object?target,250)"> ????Class<?>?type,250)"> ????Type?genericType,250)"> ????Annotation[]?annotations,250)"> ????MediaType?mediaType,250)"> ????MultivaluedMap<String,250)"> ????OutputStream?outputStream)?throws?IOException??
  • ????{??
  • try?{??
  • ????????????JAXBContext?ctx?=?JAXBContext.newInstance(type);??
  • ????????????Marshaller?m?=?ctx.createMarshaller();??
  • boolean?pretty?=?false;??
  • for?(Annotation?ann?:?annotations)?{??
  • ????????????????if?(ann.annotationType().equals(Pretty. ????????????????????pretty?=?true;??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????}??
  • if?(pretty)?{??
  • ????????????????marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,?true);??
  • ????????????m.marshal(target,?outputStream);??
  • catch?(JAXBException?ex)?{??
  • throw?new?RuntimeException(ex);??
  • 插入JAXBContext

    我们已经了解了怎么插入一个JAXBContext,这里我们需要知道怎么把它加入到自定义的Marshaller.

    我们需要找到一种方法,定位到一个ContextResoler类,这个类提供了JAXBContext对象,这个是通过javax.ws.rs.ext.Providers接口实现的:

    interface?Providers?{??
  • ????<T>?ContextResolver<T>?getContextResolver(Class<T>?contextType,250)"> ????????MediaType?mediaType);??
  • ????<T>?MessageBodyReader<T>??
  • ????????getMessageBodyReader(Class<T>?type,250)"> ????<T>?MessageBodyWriter<T>??
  • ????????getMessageBodyWriter(Class<T>?type,250)"> ????<T?extends?Throwable>?ExceptionMapper<T>??
  • ????????getExceptionMapper(Class<T>?type);??
  • ?使用Providers.getContextResolver()得到ContextResolver对象。所以我们需要在Marshaller里注入一个Providers对象:

    @Context??

  • protected?Providers?providers;??
  • ????????????JAXBContext?ctx?=? ????????????ContextResolver<JAXBContext>?resolver?=??
  • ????????????????providers.getContextResolver(JAXBContext.class,?mediaType);??
  • if?(resolver?!=?null)?{??
  • ????????????????ctx?=?resolver.getContext(type);??
  • if?(ctx?==? ????????????????//?create?one?ourselves??
  • ????????????????ctx?=?JAXBContext.newInstance(type);??
  • ????????????ctx.createMarshaller().marshal(target,sans-serif; font-size:14px; line-height:25.2px"> 这样就完成了Marshaller。

    * MessageBodyReader

    要自定义unmarshall,则需要用到javax.ws.rs.ext.MessageBodyReader接口了:

    interface?MessageBodyReader<T>?{??
  • boolean?isReadable(Class<?>?type,250)"> ????????Annotation?annotations[],250)"> T?readFrom(Class<T>?type,?MediaType?mediaType,250)"> ????????MultivaluedMap<String,?String>?httpHeaders,250)"> ????????InputStream?entityStream)??
  • 它和上面的Marshaller自定义过程非常类似。不细说:

    class?JAXBUnmarshaller?implements?MessageBodyReader?{??
  • ????。。。??
  • 注:这里使用了@Provider和@Consumes annotation。@Provider同上;@Consumes用于指定支持的交换格式。??

    读如下:

    Object?readFrom(Class<Object>,250)"> ????Annotation?annotations[],250)"> ????InputStream?entityStream)??
  • ????????JAXBContext?ctx?=?JAXBContext.newInstance(type);??
  • return?ctx.createUnmarshaller().unmarshal(outputStream);??
  • ????}?五、生命周期与环境??

    默认情况下,每个应用只创建一个MessageBodyReader、MessageBodyWriter和ContextResolver。如果想实例化多个对象,刚需要提供一个public的构造方法,以便JAX-RSS运行时传入所有需要的参数值,可能只需要包含一个以@Context注释的参数即可,例如:

    @Consumes("application/json")??

  • class?MyJsonReader?public?MyJsonReader(@Context?Providers?providers)?{??
  • this.providers?=?providers;??
  • }??
  • (编辑:PHP编程网 - 湛江站长网)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!