规范
规范只是接口,如JAX-WS和JAX-RS有CXF具体实现,有三种规范:JAXM&SAAJ(暴露了更多细节),JAX-WS和JAX-RS(rest风格的服务规范)。
JAX-WS(JAX-RPC):
底层使用JAXB,JAX-RPC已被JAX-WS替换,位于javax.xml.ws.* 提供api操作web服务。 WS-MetaData:是JAX-WS的依赖规范,位于javax.jws.*
实例
1. Service EndPoint Interface
(使用@Method和@WebService 标注接口为web服务)
@WebService public interface IHelloService { Customer selectMaxAgeStudent(Customer c1, Customer c2); Customer selectMaxLongNameStudent(Customer c1, Customer c2); }
2. 实现类:
类如果实现有多个接口,要使用 @WebService endpointInterface 指定哪个接口是SEI
3. 参数:
SEI中参数的类,使用JAXB注解告诉CXF 完成XML和Java Object间处理,如@XmlRootElement。
@XmlRootElement(name = "Customer") public class Customer { private long id; private String name; private Date birthday; }
4. 发布服务:
使用 javax.xml.ws.Endpint.publish 发布服务,通过 url?wsdl可查看生成的wsdl文件
public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:8080/helloService", new HelloServiceImpl()); }
5. 查看wsdl
访问 http://127.0.0.1:8080/helloService?wsdl地址
分析WSDL的构成
<wsdl:definitions :
name(实现类+Service),targetNamespace
<wsdl:type:
Xs:element:
web service中complex数据类型的元素定义
Xxx(方法名称)和XxxResponse:对参数和返回值的元素定义
<xs:complexType:
通过name关联到 xs:element,为前面定义的元素指定具体的封装内容
<wsdl:message
将参数、返回值和异常封装为消息
<wsdl:portType
Name为接口名称
<wsdl:operation :哪些方法,<wsdl:input <wsdl:output 指定操作的输入输出,使用message绑定前面声明过的消息。
<wsdl:binding
绑定webservice到SOAP协议,指定消息封装格式、发布地址
<wsdl:service
Name: 服务名称,
<wsdl:port name指定port名称,
<soap:address location指定web服务的地址
实例如下:
<xs:complexType name="selectMaxAgeStudentMethod"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="tns:customer" /> <xs:element minOccurs="0" name="arg1" type="tns:customer" /> </xs:sequence> </xs:complexType>
可以在SEI中指定参数和返回值的名称,如:
@WebResult(name = "method") Customer selectMaxAgeStudent(@WebParam(name = "c1") Customer c1, @WebParam(name = "c2") Customer c2);
客户端
1. 根据wsdl生成java文件
常用的方式就是 wsdljava –p 包路径–d 目标文件夹 wsdl 的url,如
wsdl2java -p net.ilkj.soap.client –d E:\ http://127.0.0.1:8080/helloService?wsdl
2. 使用JaxWsProxyFactoryBean创建webservice的代理进行调用。
public static void main(String[] args) throws ParseException { JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean(); soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService"); soapFactoryBean.setServiceClass(IHelloService.class); IHelloService helloService = (IHelloService) soapFactoryBean.create(); Customer c1 = new Customer(); c1.setId(1); c1.setName("A"); GregorianCalendar calendar = (GregorianCalendar) GregorianCalendar .getInstance(); calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1989-01-28")); c1.setBirthday(new XMLGregorianCalendarImpl(calendar)); Customer c2 = new Customer(); c2.setId(2); c2.setName("B"); calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1990-01-28")); c2.setBirthday(new XMLGregorianCalendarImpl(calendar)); System.out.println(helloService.selectMaxAgeStudent(c1, c2).getName()); }
当wsdl可以访问,webservice 不一定能访问,还和web service的实现有关,wsdl只是接口的一种xml表示
SOAP消息格式
将【实例】中的发布改为使用 JaxWsServerFactoryBean,加入日志拦截器到输入和输出拦截器中。
1: public static void main(String[] args) {
2: JaxWsServerFactoryBean soapFactoryBean = new JaxWsServerFactoryBean();
3: soapFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
4: soapFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
5: // 注意这里是实现类不是接口
6: soapFactoryBean.setServiceClass(HelloServiceImpl.class);
7: soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService");
8: soapFactoryBean.create();
9:
10: }
11:
效果如下:
<soap:Envelope
<soap:header
<soap:Body
Inbound Message输出的是服务器端接收到的 SOAP 信息,Outbound Message输出的服务器端响应的 SOAP 信息,SOAP 的 Headers:{}的前面是 SOAP 消息的标识、编码方式、MIME类型,Headers:{}熟悉 HTTP 应该很容易看懂这里面的消息报头的作用,Headers:{}后面的Payload(有效负载,也叫净荷)的 XML 就是 SOAP 消息的真正内容,我们看到 SOAP 消息内容被封装为<soap:Envelope …SOAP 信封,在信封之间的内容就是 SOAP 消息正文。
输入和输出参数
对参数使用 @WebParam(name=’c2’ mode=Mode.OUT) 可定义参数显示的名称为c2,且为out类型的. Mode可以有IN,OUT,INOUT类型,对于后两种会作为返回值,客户端生成代码是Holder<Customer> c3
服务端 SEI:
@WebService<