JAXWS
概述
JAX-WS = Java API For XML Web Service
JAX-WS规范定义了一组XML web services的Java API,它运行时实现会将这些API的调用转换成对应的soap消息,是Sun公司提出的一套关于WebService的开发标准。
JAXB
JAXB是Java Architecture for XML Binding的缩写,提供了一个快捷的方式将Java对象与XML进行转换,XML现在已经逐渐被JSON给替代。
在JAX-WS(Java的WebService规范之一)中,JDK1.6自带的版本JAX-WS2.1,其底层支持就是JAXB。
JAXB可以实现POJO对象与XML之间的相互转换
Unmarshaller类将XML数据反序列化为新创建的Java内容树的过程,并且可以在解组时有选择的验证XML数据。
Marshaller类将Java内容树序列化回XML数据的过程。
示例
步骤
-
定义POJO类Book.java,使用注解@XmlRootElement标注在类上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
package com.eh.webservice.demo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @Data @AllArgsConstructor @NoArgsConstructor @ToString public class Book { private long id; private String bookName; private double price; }
-
编写Marshaller工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
package com.eh.webservice.demo; import lombok.SneakyThrows; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.OutputStream; import java.io.Reader; public class MarshallerUtil { // pojo -> xml @SneakyThrows public static <T> void marshal(T t, OutputStream os) { JAXBContext jaxbContext = JAXBContext.newInstance(t.getClass()); Marshaller marshaller = jaxbContext.createMarshaller(); // 用来指定是否对已编组XML数据的属性名称使用换行和缩排进行格式化 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 用来指定字符编码格式 marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); // Java对象转换为XML格式,并且输出到指定输出流 marshaller.marshal(t, os); } // xml -> pojo @SneakyThrows public static <T> T unmarshal(Reader reader, Class<T> clazz) { JAXBContext jaxbContext = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); T t = (T) unmarshaller.unmarshal(reader); return t; } }
-
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
package com.eh.webservice.demo; import java.io.StringReader; public class MainTest { public static void main(String[] args) { Book book = new Book(100001L, "三国演义", 20.5); // pojo -> xml MarshallerUtil.marshal(book, System.out); /* 输出 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <book> <bookName>三国演义</bookName> <id>100001</id> <price>20.5</price> </book> */ // xml -> pojo String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + " <book>\n" + " <bookName>三国演义</bookName>\n" + " <id>100001</id>\n" + " <price>20.5</price>\n" + " </book>"; Book retBook = MarshallerUtil.unmarshal(new StringReader(xml), Book.class); System.out.println(retBook); } }
JAX-WS
JAX-WS可以完成wsdl到java的转换,即wsdl或合同契约优先。
在[webservice介绍]({{ref “webservice介绍”}})一章里使用手写的client调用server就属于code first,我们可以使用jax-ws一键生成,直接完成wsdl到java的转换,即contract first。
使用wsdl2java工具将wsdl转换成Java类
-
从cxf官网下载apache-cxf-3.4.0.tar.gz
-
解压
1
$ tar -zxvf apache-cxf-3.4.0.tar.gz -C ~/soft
-
进入到bin目录下执行wsdl2java
1 2 3 4 5 6
# david @ Davids-Macbook-Pro in ~/soft/apache-cxf-3.4.0/bin [20:10:22] $ pwd /Users/david/soft/apache-cxf-3.4.0/bin # 注意wsdlUrl 中的? 需要转义 $ ./wsdl2java http://localhost:9999/cxf\?wsdl # 此时会在bin目录下生成一个com文件夹
-
将com文件夹复制到client工程里,注意这里不需要再引入cxf相关jar包, 工程结构如下所示
-
编写测试类调用服务端方法
1 2 3 4 5 6 7 8
package com.eh.webservice.demo; public class ClientDemo { public static void main(String[] args) { HelloService helloService = new HelloServiceImplService().getHelloServiceImplPort(); System.out.println(helloService.sayHello("徐达")); } }
-
控制台输出:
1 2
objc[90096]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java (0x10750d4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1085244e0). One of the two will be used. Which one is undefined. hello, 徐达
重构client端工程
-
下面这4个文件暂时没用可以删除,将HelloService上的ObjectFactory注解去掉
1 2 3 4
ObjectFactory package-info.java SayHello SayHelloResponse
-
打包客户端工程
1
mvn package
-
mvn上传包,这里简单使用就直接放到lib中
-
删除HelloService和HelloServiceImplService
-
现在的目录结构就很清晰了, 直接进行客户端调用也是ok的。
使用client参数一并生成客户端访问代码
|
|