`
zzc1684
  • 浏览: 1222882 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

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

阅读更多

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

 

一、JAXB

  

为了在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.     public int getId() { return this.id; }   
  10.     public void setId(int id) { this.id = id; }   
  11.     public String getFullName() { return this.fullname; }   
  12.     public void setFullName(String name} { this.fullname = name; }   
  13. }  

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

Java代码 复制代码 收藏代码
  1. <customer id="42">   
  2.     <fullname>Bill Burke</fullname>   
  3. </customer>   

以上Customer类用JAXB处理,简单的如下:

Java代码 复制代码 收藏代码
  1. Customer customer = new Customer();   
  2. customer.setId(42);   
  3. customer.setName("Bill Burke");   
  4.   
  5. JAXBContext ctx = JAXBContext.newInstance(Customer.class);   
  6. StringWriter writer = new StringWriter();   
  7.   
  8. ctx.createMarshaller().marshal(customer, writer);   
  9.   
  10. String custString = writer.toString();   
  11. customer = ctx.createUnmarshaller().unmarshal(new StringReader(custString));   

JAX-RS规范规定:实现者需要自动支持marshalling和unmarshalling由@XmlRootElement或@XmlType约束的类对象,或者是包装在javax.xml.bind.JAXBElement中的对象。例如:

Java代码 复制代码 收藏代码
  1. @Path("/customers")   
  2. public class CustomerResource {   
  3.   
  4.     @GET  
  5.     @Path("{id}")   
  6.     @Produces("application/xml")   
  7.     public Customer getCustomer(@PathParam("id"int id) {   
  8.         Customer cust = findCustomer(id);   
  9.         return cust;   
  10.     }   
  11.   
  12.     @POST  
  13.     @Consumes("application/xml")   
  14.     public void createCustomer(Customer cust) {   
  15.         ...   
  16.     }   
  17. }  

这里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的创建:

Java代码 复制代码 收藏代码
  1. public interface ContextResolver<T> {   
  2.            T getContext(Class<?> type);   
  3. }   

例如:

Java代码 复制代码 收藏代码
  1. @Provider  
  2. @Produces("application/xml")   
  3. public class CustomerResolver   
  4.         implements ContextResolver<JAXBContext> {   
  5.     private JAXBContext ctx;   
  6.   
  7.     public CustomerResolver() {   
  8.         this.ctx = ...; // initialize it the way you want   
  9.     }   
  10.   
  11.     public JAXBContext getContext(Class<?> type) {   
  12.         if (type.equals(Customer.class)) {   
  13.             return ctx;   
  14.         } else {   
  15.             return null;   
  16.         }   
  17.     }   
  18. }   

自定义的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),数据或者是这些值的数据类型,例如:

 

Java代码 复制代码 收藏代码
  1. {   
  2.     "id" : 42,   
  3.     "name" : "Bill Burke",   
  4.     "married" : true ,   
  5.     "kids" : [ "Molly""Abby" ]   
  6. }  

key/value之间用分号分隔,并以逗号为间隔符。

 

* 使用BadgerFish进行XML-JSON转换

  1. xml元素名变成key,文本值变成一个内嵌的,key值为"$"的子元素值,例如:
    <customer>Bill Burke</customer> 变成 { "customer" : { "$" : "Bill Burke" }}
  2. 子元素变成值,例如:
    Xml代码 复制代码 收藏代码
    1. <customer>  
    2.           <first>Bill</first>  
    3.           <last>Burke</last>  
    4. </customer>  
     变成:
    Js代码 复制代码 收藏代码
    1. "customer" :   
    2.            {   
    3.               "first" : { "$" : "Bill"},   
    4.               "last" : { "$" : "Burke" }   
    5.             }   
    6. }  
  3. 多个同名元素值变成一个列表:
    Xml代码 复制代码 收藏代码
    1. <customer>  
    2.            <phone>978-666-5555</phone>  
    3.            <phone>978-555-2233</phone>  
    4. </customer  
     变成:
    Js代码 复制代码 收藏代码
    1. "customer" :   
    2.           { "phone" : [ { "$""978-666-5555"}, { "$":"978-555-2233"} ] }   
    3. }  
     
  4. 属性变成一个以@开始的值,例如:
    Java代码 复制代码 收藏代码
    1. <customer id="42">   
    2.            <name>Bill Burke</name>   
    3. </customer>  
     变成:
    Xml代码 复制代码 收藏代码
    1. { "customer" :   
    2.          {    
    3.             "@id" : 42,   
    4.             "name" : {"$": "Bill Burke"}   
    5.           }   
    6. }  
     
  5.  namespace会对应一个@xmlns属性值,缺省的namespace对应"$", 所有子元素和属性都使用namespace的前缀作为他们名字的一部分,例如:
    Xml代码 复制代码 收藏代码
    1. <customer xmlns="urn:cust" xmlns:address="urn:address">  
    2.        <name>Bill Burke</name>  
    3.        <address:zip>02115</address:zip>  
    4. </customer>  
     对应:
    Java代码 复制代码 收藏代码
    1. "customer" :   
    2.     { "@xmlns" : { "$" : "urn:cust",   
    3.             "address" : "urn:address" } ,   
    4.         "name" : { "$" : "Bill Burke",   
    5.               "@xmlns" : { "$" : "urn:cust",   
    6.               "address" : "urn:address" } },   
    7.         "address:zip" : { "$" : "02115",   
    8.         "@xmlns" : { "$" : "urn:cust",   
    9.         "address" : "urn:address" }}   
    10.     }   
    11. }  

* 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的接口:

 

Java代码 复制代码 收藏代码
  1. public interface MessageBodyWriter<T> {   
  2.        
  3.     boolean isWriteable(Class<?> type, Type genericType,   
  4.             Annotation annotations[], MediaType mediaType);   
  5.        
  6.     long getSize(T t, Class<?> type, Type genericType, Annotation annotations[],    
  7.             MediaType mediaType);   
  8.   
  9.     void writeTo(T t, Class<?> type, Type genericType, Annotation annotations[],    
  10.             MediaType mediaType,    
  11.             MultivaluedMap<String, Object> httpHeaders,   
  12.             OutputStream entityStream) throws IOException, WebApplicationException;       
  13. }  
  •  isWriteable()方法决定当前对象是否支持
  • getSize()方法决定Content-Length的值
  • writeTo()做最终的写出操作

下面看JAXBMarshaller的实现:

Java代码 复制代码 收藏代码
  1. @Provider  
  2. @Produces("application/xml")   
  3. public class JAXBMarshaller implements MessageBodyWriter {   
  4.   
  5.     public boolean isWriteable(Class<?> type, Type genericType,   
  6.             Annotation annotations[], MediaType mediaType) {   
  7.         return type.isAnnotationPresent(XmlRootElement.class);   
  8.     }  

 

首先使用@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可以保留缩进,例如:

Java代码 复制代码 收藏代码
  1. @GET  
  2. @Path("{id}")   
  3. @Produces("application/xml")   
  4. @Pretty  
  5. public Customer getCustomer(@PathParam("id"int id) {...}  

 

所以在自定义的Marsheller中需要处理这个annotation:

Java代码 复制代码 收藏代码
  1. public void writeTo(Object target,   
  2.     Class<?> type,   
  3.     Type genericType,   
  4.     Annotation[] annotations,   
  5.     MediaType mediaType,   
  6.     MultivaluedMap<String, Object> httpHeaders,   
  7.     OutputStream outputStream) throws IOException   
  8.     {   
  9.   
  10.         try {   
  11.             JAXBContext ctx = JAXBContext.newInstance(type);   
  12.             Marshaller m = ctx.createMarshaller();   
  13.             boolean pretty = false;   
  14.             for (Annotation ann : annotations) {   
  15.                 if (ann.annotationType().equals(Pretty.class)) {   
  16.                     pretty = true;   
  17.                     break;   
  18.                 }   
  19.             }   
  20.   
  21.             if (pretty) {   
  22.                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);   
  23.             }   
  24.   
  25.             m.marshal(target, outputStream);   
  26.         } catch (JAXBException ex) {   
  27.             throw new RuntimeException(ex);   
  28.         }   
  29. }   

插入JAXBContext

 

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

 

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

Java代码 复制代码 收藏代码
  1. public interface Providers {   
  2.     <T> ContextResolver<T> getContextResolver(Class<T> contextType,   
  3.         MediaType mediaType);   
  4.   
  5.     <T> MessageBodyReader<T>   
  6.         getMessageBodyReader(Class<T> type, Type genericType,   
  7.             Annotation annotations[], MediaType mediaType);   
  8.   
  9.     <T> MessageBodyWriter<T>   
  10.         getMessageBodyWriter(Class<T> type, Type genericType,   
  11.             Annotation annotations[], MediaType mediaType);   
  12.   
  13.     <T extends Throwable> ExceptionMapper<T>   
  14.         getExceptionMapper(Class<T> type);   
  15.   
  16. }  

 使用Providers.getContextResolver()得到ContextResolver对象。所以我们需要在Marshaller里注入一个Providers对象:

 

Java代码 复制代码 收藏代码
  1. @Context  
  2. protected Providers providers;   
  3. public void writeTo(Object target,   
  4.     Class<?> type,   
  5.     Type genericType,   
  6.     Annotation[] annotations,   
  7.     MediaType mediaType,   
  8.     MultivaluedMap<String, Object> httpHeaders,   
  9.     OutputStream outputStream) throws IOException   
  10.     {   
  11.         try {   
  12.             JAXBContext ctx = null;   
  13.             ContextResolver<JAXBContext> resolver =   
  14.                 providers.getContextResolver(JAXBContext.class, mediaType);   
  15.             if (resolver != null) {   
  16.                 ctx = resolver.getContext(type);   
  17.             }   
  18.             if (ctx == null) {   
  19.                 // create one ourselves   
  20.                 ctx = JAXBContext.newInstance(type);   
  21.             }   
  22.             ctx.createMarshaller().marshal(target, outputStream);   
  23.         } catch (JAXBException ex) {   
  24.             throw new RuntimeException(ex);   
  25.         }   
  26. }  

这样就完成了Marshaller。

 

* MessageBodyReader

 

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

Java代码 复制代码 收藏代码
  1. public interface MessageBodyReader<T> {   
  2.   
  3. boolean isReadable(Class<?> type, Type genericType,   
  4.         Annotation annotations[], MediaType mediaType);   
  5.   
  6. T readFrom(Class<T> type, Type genericType,   
  7.         Annotation annotations[], MediaType mediaType,   
  8.         MultivaluedMap<String, String> httpHeaders,   
  9.         InputStream entityStream)   
  10.             throws IOException, WebApplicationException;   
  11. }  

它和上面的Marshaller自定义过程非常类似。不细说:

Java代码 复制代码 收藏代码
  1. @Provider  
  2. @Consumes("application/xml")   
  3. public class JAXBUnmarshaller implements MessageBodyReader {   
  4.   
  5.     public boolean isReadable(Class<?> type, Type genericType,   
  6.         Annotation annotations[], MediaType mediaType) {   
  7.         return type.isAnnotationPresent(XmlRootElement.class);   
  8.     }   
  9.     。。。   
  10. }  

注:这里使用了@Provider和@Consumes annotation。@Provider同上;@Consumes用于指定支持的交换格式。  

 

读如下:

Java代码 复制代码 收藏代码
  1. Object readFrom(Class<Object>, Type genericType,   
  2.     Annotation annotations[], MediaType mediaType,   
  3.     MultivaluedMap<String, String> httpHeaders,   
  4.     InputStream entityStream)   
  5.         throws IOException, WebApplicationException {   
  6.   
  7.     try {   
  8.         JAXBContext ctx = JAXBContext.newInstance(type);   
  9.         return ctx.createUnmarshaller().unmarshal(outputStream);   
  10.     } catch (JAXBException ex) {   
  11.         throw new RuntimeException(ex);   
  12.   
  13.     }   
  14.   
  15. }   

五、生命周期与环境  

 

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

 

Java代码 复制代码 收藏代码
  1. @Provider  
  2. @Consumes("application/json")   
  3. public class MyJsonReader implements MessageBodyReader {   
  4.   
  5.     public MyJsonReader(@Context Providers providers) {   
  6.         this.providers = providers;   
  7.     }   
  8.   
  9. }  
分享到:
评论

相关推荐

    JAX-RS入门jar包集合

    本资源“JAX-RS入门jar包集合”包含了开始学习和使用JAX-RS所需的基本库文件,这些jar包将帮助开发者快速搭建REST服务环境。下面我们将详细讲解JAX-RS的核心概念和关键组件,以及如何利用这些jar包进行实际开发。 1...

    CursoWebServices:Curso Java Web服务JAX-WS JAX-RS

    2. JAX-WS入门:介绍如何使用JAX-WS创建SOAP服务,包括服务端点接口、消息处理和部署描述符的配置。 3. JAX-WS高级特性:探讨服务端点实现、异常处理、消息传递模式和WS-Security等进阶话题。 4. JAX-RS基础:学习...

    quick-start-jax-rs

    【快速入门JAX-RS】 JAX-RS是Java API for RESTful Web Services的缩写,它是Java平台上的一个标准,用于构建RESTful Web服务。REST(Representational State Transfer)是一种网络应用程序的设计风格和开发方式,...

    WebService视频教程大全

    2. **JAX-RS**: JAX-RS是处理RESTful服务的Java标准。CXF提供了对JAX-RS的强大支持,允许开发者使用注解来快速创建资源类,定义HTTP方法和URL映射,从而构建RESTful服务。 【WebService视频教程内容预览】 在...

    apache-cxf-3.1.6

    此外,它还支持JAX-RS(Java API for RESTful Web Services)和JAX-WS(Java API for XML Web Services),使得开发RESTful服务和SOAP服务变得简单。 8. **安全性**: CXF提供了多种安全机制,如基本认证、OAuth、...

    webService DEMO

    Web服务(WebService)是一种基于网络的、松散耦合的软件模块,允许不同系统之间进行交互和数据交换。在Java中实现Web服务,通常使用SOAP(Simple Object Access Protocol)或REST(Representational State Transfer...

    cxf入门文档资料

    2. **JAX-WS与JAX-RS**:JAX-WS用于构建基于SOAP的Web服务,而JAX-RS则用于构建RESTful服务。CXF支持这两种Java API,使得开发者可以根据项目需求选择适合的服务模型。 3. **客户端开发**:在“手持客户端开发资料...

    JAXRS-HelloWorld

    本示例“JAXRS-HelloWorld”是学习JAX-RS基础知识的一个经典入门项目。 首先,我们来看一下这个项目的目录结构。根据提供的压缩包文件名“JAXRS-HelloWorld-master”,我们可以推测这是一个Git仓库的克隆,通常包含...

    WebService CXF学习-入门篇.pdf

    4. **JAX-RS**:Java API for RESTful Web Services,用于创建RESTful服务。 5. **SOAP**:支持1.1和1.2版本,以及WS-I Basic Profile、WS-Security、WS-Addressing等规范。 6. **WSDL**:Web服务描述语言,用于定义...

    初级Webservice教程代码资料(java)

    4. JAX-RS教程:JAX-RS利用HTTP方法(如GET、POST、PUT和DELETE)和资源URI来处理请求。学习如何使用@Path、@GET、@POST等注解创建REST服务,并理解JSON和XML之间的转换。 5. 客户端调用:无论是SOAP还是REST服务,...

    hello-world-apis:API API de grafos的世界您好

    2. **JSON序列化和反序列化**:API通常使用JSON作为数据交换格式。Java中,Jackson或Gson库可以方便地将Java对象转换为JSON字符串,反之亦然。 3. **HTTP客户端库**:如Apache HttpClient或OkHttp,用于从客户端...

    Java的webservice入门(视频+代码)

    SOAP允许开发者传递复杂的数据结构,并提供了错误处理机制。 2. **WSDL**:WSDL文档定义了Web Service的接口,包括服务提供的操作、消息格式、输入/输出参数、地址等信息。服务消费者通过读取WSDL可以知道如何与...

    java restFull及示例和Maven.rar

    - Jersey是JAX-RS(Java API for RESTful Web Services)的参考实现,用于创建RESTful服务。 - 注解驱动:使用@Path、@GET、@POST等注解来标记资源类和方法。 - 使用Response和Entity:返回HTTP响应,包括状态码...

    jaxws的小demo

    JAX-WS支持多种协议,包括SOAP、WSDL和UDDI,能够处理XML数据并进行网络通信。 2. **Web服务生命周期** - **创建服务端**:首先,我们需要定义一个Java接口,该接口将作为Web服务的API。然后,使用JAX-WS的注解...

    Web Service 入门

    Java中,JAX-RS(Java API for RESTful Web Services)是用于构建RESTful服务的标准API。 - 定义资源类:创建Java类表示资源,并使用`@Path`注解指定资源路径。 - 方法注解:在类的方法上使用`@GET`, `@POST`, `@...

    webservice入门教程

    2. JAX-RS:Java API for RESTful Web Services,提供了一种简化的方式来创建RESTful Web服务。 3. .NET中的Web服务:Microsoft提供了ASMX和WCF(Windows Communication Foundation)框架,用于构建和消费Web服务。 ...

    cfx web service

    - **数据绑定**:CXF支持多种数据绑定机制,如JAXB、Aegis等,方便处理XML和Java对象之间的转换。 - **MTOM/XOP**:支持Message Transmission Optimization Mechanism,可以提高大文件传输的效率。 - **国际化与本地...

    CXF入门教程及源码

    CXF是基于Apache基金会的项目,它提供了SOAP、RESTful、JAX-RS、JAX-WS等接口的支持,可以方便地创建Web服务。CXF的核心功能包括服务建模、绑定生成、服务实现和部署,以及客户端代理和服务代理的生成。它的设计...

    camel-manual-2.10.4.pdf

    - Apache CXF:一个智能的Web服务套件(包括JAX-WS和JAX-RS)。 - Apache Karaf:一个小型的基于OSGi的运行时环境,其中可以部署容器代理的应用程序。 - Apache MINA:一个高性能的NIO驱动的网络框架。 Camel的核心...

    Jersey User Guild

    Jersey 是一个开源的 JAX-RS (Java API for RESTful Web Services) 实现,用于构建 RESTful Web 服务和微服务。它由 Apache 软件基金会提供支持,是 Java 社区中用于 RESTful 服务开发的主要工具之一。Jersey 用户...

Global site tag (gtag.js) - Google Analytics