下面的复制内容仅作以后可能的找不到和知识管理的用途。
WebService是SOA的一种较好的实现方式,它将应用程序的不同功能单元通过中立的契约(独立于硬件平台、操作系统和编程语言)联系起来,使得各种形式的功能单元更好的集成。
W3C对他的定义是:
A Web service is a software system designed to support interoperable machine-to-machine interaction over a network. It has an interface described in a machine-processable format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP messages......"
Web service是一个软件系统,为了支持跨网络的机器之间相互操作交互而设计。它有一个机器可识别的描述格式(特别是WSDL)。不同的系统之间可以通过SOAP消息在规定的方式下相互调用。(英文不好,请指正!)
简单的说,WebService是一种独立于特定语言、特定平台,基于网络的、分布式的模块化组件。是一个能够使用xml消息通过网络来访问的Interface,这个Interface描述了一组可访问的操作。
WebService一般分为两种:
REST式WebService,基于HTTP协议;
RPC式WebService,基于SOAP协议,不过SOAP也是基于HTTP传输的。
狭义上的WebService是指第二种RPC式的WebService,也就是我们常说的那种。
JAVA中有三种WebService规范,分别是JAX-WS(JAX-RPC)、JAX-RS、JAXM&SAAJ。
这里先说JAX-WS(Java API For XML-WebService),JDK1.6 自带的版本为JAX-WS2.1,其底层支持为JAXB。早期的JAVA Web服务规范JAX-RPC(Java API ForXML-Remote Procedure Call)目前已经被JAX-WS 规范取代,JAX-WS 是JAX-RPC 的演进版本,但JAX-WS 并不完全向后兼容JAX-RPC。
废话不多说了,先来写一个最简单的例子:
服务器端:
在想要发布为WebService的类上加上注解@WebService,这个类的方法就变为WebService的方法了,再通过Endpoint的publish方法,发布这个服务,到此,一个最简单的WebService搞定。运行main方法,在浏览器里输入”http://localhost:8080/com.why.webservice.Hello?wsdl “ 会看到你的WSDL信息。
不过需要注意一 下, 有的同学如果不加@SOAPBinding(style = SOAPBinding.Style.RPC)这行代码会报错:
com.sun.xml.internal.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.why.webservice.jaxws.SayHello is not found. Have you run APT to generate them?
网上资料说只要将JDK升级到1.6u17就可以了,我直接升级到了1.6u22(1.6.0_22-b04),问题解决!
- package com.why.webservice;
-
- import javax.jws.WebService;
- import javax.xml.ws.Endpoint;
-
-
-
-
-
-
- @WebService
- public class Hello {
-
- public String sayHello(String name) {
- return "Hello " + name;
- }
-
- public static void main(String[] args){
- Endpoint.publish("http://localhost:8080/com.why.webservice.Hello", new Hello());
- System.out.println("Success");
- }
- }
客户端:
在命令行输入命令 wsimport -p [包名] -keep [发布的服务地址?wsdl] 生成客户端代码,如生成本例的客户端代码”wsimport -p com.why.client -keep http://localhost:8080/com.why.webservice.Hello?wsdl“,当然,前提是你已经配好了JAVA环境变量。控制台会显示
利用这些生成的客户端代码,就可以调用这个WebService服务了:
- package com.why.client;
-
-
-
-
-
-
- public class HelloClient {
-
-
-
-
- public static void main(String[] args) {
- Hello hello = new HelloService().getHelloPort();
- String s = hello.sayHello("why");
- System.out.println(s);
- }
- }
执行代码,输出:Hello why
2。
上一篇写了个最简单的小例子,只是为了说明JAVA6开发Web Service很方便,这一篇稍微深入一点,写个稍微有点代表性的小例子。
依然使用 JAX-WS(jdk自带的实现)方式,这次要在服务中使用一个复杂类型Customer,并实现附件传输的功能,这里使用MTOM的附件传输方式。MTOM(SOAP Message Transmission Optimization Mechanism)是SOAP 消息传输优化机制,MTOM可以在SOAP 消息中发送二进制数据。
先来看Customer类:
- package com.why.server;
-
- import java.util.Date;
-
- import javax.activation.DataHandler;
- import javax.xml.bind.annotation.XmlAccessType;
- import javax.xml.bind.annotation.XmlAccessorType;
- import javax.xml.bind.annotation.XmlMimeType;
- import javax.xml.bind.annotation.XmlRootElement;
-
- @XmlRootElement(name = "Customer")
- @XmlAccessorType(XmlAccessType.FIELD)
- public class Customer {
- private long id;
- private String name;
- private Date birthday;
- @XmlMimeType("application/octet-stream")
- private DataHandler imageData;
-
-
- ......
- }
MTOM 方式中要传输的附件必须使用javax.activation.DataHandler 类,还要注意必须在类上使用@XmlAccessorType(FIELD)注解,标注JAXB 在进行JAVA 对象与XML 之间进行转换时只关注字段,而不关注属性(getXXX()方法),否则发布Web 服务时会报出现了两个imageData 属性的错误,原因未知,可能是BUG。
然后使用@XmlMimeType 注解标注这是一个附件类型的数据,这里我们标注imageData 是一个二进制文件,当然你也可以使用具体的MIME类型,譬如:image/jpg、image/gif 等,但要考虑到客户端是否支持。
接口类:
- package com.why.server;
-
- import javax.jws.WebParam;
- import javax.jws.WebService;
- import javax.xml.ws.soap.MTOM;
-
-
-
-
-
-
- @WebService(name="Hello")
- @SOAPBinding(style = SOAPBinding.Style.RPC)
- @MTOM
- public interface Hello {
- public void printContext();
- public Customer selectCustomerByName(@WebParam(name = "customer")Customer customer);
- public Customer selectMaxAgeCustomer(Customer c1, Customer c2);
- }
@MTOM注解用于开启MTOM功能。
@WebService注解中的name属性标注在接口类上,可以指定wsdl中接口名称,也就是生成的客户端代码中接口类的名字。
@SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息样式,有两个枚举值:SOAPBinding.Style.DOCUMENT(默认)和SOAPBinding.Style.RPC,可以对比这两种方式生成的wsdl会有所不同,而且生成的客户端代码也会有所不同。
实现类:
- package com.why.server;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Set;
- import javax.activation.DataHandler;
- import javax.activation.FileDataSource;
- import javax.annotation.Resource;
- import javax.jws.WebService;
- import javax.xml.ws.WebServiceContext;
- import javax.xml.ws.handler.MessageContext;
-
-
-
-
-
-
- @WebService(serviceName="HelloService",portName="HelloServicePort",targetNamespace="http://service./",endpointInterface="com.why.server.Hello")
- public class HelloImpl implements Hello {
-
- @Resource
- private WebServiceContext context;
-
- @Override
- public void printContext(){
- MessageContext ctx = context.getMessageContext();
- Set<String> set = ctx.keySet();
- for (String key : set) {
- System.out.println("{" + key + "," + ctx.get(key) +"}");
- try {
- System.out.println("key.scope=" + ctx.getScope(key));
- } catch (Exception e) {
- System.out.println(key + " is not exits");
- }
- }
- }
-
- @Override
- public Customer selectCustomerByName(Customer customer) {
- if("why".equals(customer.getName())){
- customer.setId(1);
- try {
- customer.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1985-10-07"));
- } catch (ParseException e) {
- e.printStackTrace();
- }
- customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "why.jpg"))));
- }else{
- customer.setId(2);
- customer.setBirthday(new Date());
- customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "origin.jpg"))));
- }
- return customer;
- }
-
- @Override
- public Customer selectMaxAgeCustomer(Customer c1, Customer c2) {
- try {
-
- System.out.println("c1.getImageData().getContentType()=" + c1.getImageData().getContentType());
- InputStream is = c2.getImageData().getInputStream();
- OutputStream os = new FileOutputStream("c:\\temp1.jpg");
- byte[] bytes = new byte[1024];
- int c;
- while ((c = is.read(bytes)) != -1) {
- os.write(bytes, 0, c);
- }
- os.close();
-
- System.out.println("c2.getImageData().getContentType()=" + c2.getImageData().getContentType());
- is = c2.getImageData().getInputStream();
- os = new FileOutputStream("c:\\temp2.jpg");
- bytes = new byte[1024];
- while ((c = is.read(bytes)) != -1) {
- os.write(bytes, 0, c);
- }
- os.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (c1.getBirthday().getTime() > c2.getBirthday().getTime()){
- return c2;
- }
- else{
- return c1;
- }
- }
- }
@WebService注解的serviceName属性指定wsdl中service节点的name属性值。portName属性指定wsdl中service节点下port节点name属性值。targetNamespace属性指定wsdl根节点definitions的targetNamespace属性值。endpointInterface属性指定要发布的WebService接口的全路径名,当实现类实现了多个接口时,需要通过此属性标注哪个类是WebService的服务端点接口(SEI)。
在这个类中,通过@Resource注解注入了一个WebServiceContext对象,这个对象即是WebService的上下文环境。
发布这个服务:
- package com.why.server;
-
- import javax.xml.ws.Endpoint;
-
-
-
-
-
-
- public class SoapServer {
- public static void main(String[] args) {
- Endpoint.publish("http://localhost:8080/helloService",new HelloImpl());
- }
- }
在命令行键入“wsimport -p com.why.client -keep http://localhost:8080/helloService?wsdl”生成客户端代码,拷贝到工程相应文件夹里,这时,就可以调用这个服务了:
- package com.why.client;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.GregorianCalendar;
- import javax.activation.DataHandler;
- import javax.activation.DataSource;
- import javax.activation.FileDataSource;
- import javax.xml.datatype.DatatypeConfigurationException;
- import javax.xml.datatype.DatatypeFactory;
- import javax.xml.namespace.QName;
-
-
-
-
-
-
- public class SoapClient {
- public static void main(String[] args) throws ParseException, MalformedURLException {
- QName qName = new QName("http://service./","HelloService");
- HelloService helloService = new HelloService(new URL("http://127.0.0.1:8080/helloService?wsdl"),qName);
- Hello hello = (Hello) helloService.getPort(Hello.class);
-
- hello.printContext();
-
- System.out.println("---------------------------------------------------");
-
- Customer customer = new Customer();
- customer.setName("why");
- DataSource ds = hello.selectCustomerByName(customer).getImageData().getDataSource();
- String attachmentMimeType = ds.getContentType();
- System.out.println(attachmentMimeType);
- try {
- InputStream is = ds.getInputStream();
- OutputStream os = new FileOutputStream("c:\\why_temp.jpg");
- byte[] bytes = new byte[1024];
- int c;
- while ((c = is.read(bytes)) != -1) {
- os.write(bytes, 0, c);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- System.out.println("########################################");
-
- Customer c1 = new Customer();
- c1.setId(1);
- c1.setName("why");
- GregorianCalendar calendar = (GregorianCalendar)GregorianCalendar.getInstance();
- calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1985-10-07"));
- try {
- c1.setBirthday(DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar));
- } catch (DatatypeConfigurationException e) {
- e.printStackTrace();
- }
- c1.setImageData(new DataHandler(new FileDataSource("c:\\c1.jpg")));
-
- Customer c2 = new Customer();
- c2.setId(2);
- c2.setName("abc");
- calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1986-10-07"));
- try {
- c2.setBirthday(DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar));
- } catch (DatatypeConfigurationException e) {
- e.printStackTrace();
- }
- c2.setImageData(new DataHandler(new FileDataSource("c:\\c2.jpg")));
-
- Customer c = hello.selectMaxAgeCustomer(c1,c2);
- System.out.println(c.getName());
-
- }
- }
附件是我的工程,当然运行这个程序,需先在C盘建立几个文件c1.jpg、c2.jpg、origin.jpg和why.jpg。
3。
要了解WebService,光能写代码不行啊,这说说WebService最基本的概念。
首先WebService要知道几个最基本的概念:
1、XML以及XML Schema
XML 是Web Service表示数据的基本格式。XML是一套通用的数据表示格式,与平台无关,这就使不同语言构建的系统之间相互传递数据成为可能。
XML Schema-XSD 拥有一套标准的、可扩展的数据类型系统,Web Service即是用XSD来作为数据类型系统的。由于不同语言之间数据类型也不尽相同,因此,数据传输过程中,必须将其转化为一种通用的数据类型,即XSD的数据类型。
2、SOAP
SOAP(Simple Object Access Protocol),简单对象访问协议,它是基于XML格式的消息交换协议。SOAP定义了一个envelope对象,使用envelope来包装要传递的消息,而消息本身可以采用自身特定的词汇,使用namespace来区分彼此。简单的说,在WebService中传递的东西是一封信,SOAP就是信的通用格式,他定义了一封信应该有信封,信封里装着信的内容,信封(envlope)的格式是固定的,而信的内容(要传递的数据)你可以自己定义。
3、WSDL
WSDL(Web Service Description Language),Web Service描述语言,使用XML语言对Web Service及其函数、参数、返回值、数据类型等信息进行描述。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。
4、UDDI
UDDI(Universal Description Discovery and Integration),统一描述、发现和集成协议。UDDI 是一种目录服务,企业可以使用它对 Web services 进行注册和搜索。UDDI是一个分布式的互联网服务注册机制,他实现了一组可公开访问的接 口,通过这些接口,网络服务可以向服务信息库注册其服务信息、服务需求者可以找到分散在世界各地的网络服务。UDDI 并不像 WSDL 和 SOAP 一样深入人心,因为很多时候,使用者知道 Web 服务的位置(通常位于公司的企业内部网中)。
5、远程过程调用(RPC)与消息传递
Web service本身实际是在实现应用程序间的通信,实现通信的方式有两种:远程过程调用(RPC)和消息传递(DOCUMENT)。使用RPC的时候,客户端的概念是调用服务器上的远程过程,通常方式为实例化一个远程对象并调用其方法和属性。消息传递的概念是,客户端向服务器发送消息,然后等待服务器的回应。消息传递系统强调的是消息的发送和回应,而不是远程对象的界面。他们最大不同就是RPC不能通过Schema 来校验,而Document 类型是可以的。因此document 类型webservice成为主流 ,Document也是JAX-WS默认的实现方式。
有一种说法是,Web Service = SOAP + WSDL + HTTP。其中,SOAP协议是web service的主体,它通过HTTP或者SMTP等应用层协议进行通讯,自身使用XML文件来描述程序的函数方法和参数信息,从而完成不同主机的异构系统间的服务处理。这里的WSDL(Web Services Description Language)web 服务描述语言也是一个XML文档,它通过HTTP向公众发布,公告客户端程序关于某个具体的 Web service服务的URL信息、方法的命名,参数,返回值等。
SOAP协议简介
上面说了,SOAP是一种基于XML的消息通讯格式,用于网络上,不同平台,不同语言的应用程序间的通讯。一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
Envelope 标识XML 文档一条 SOAP 消息
Header 包含头部信息的XML标签
Body 包含所有的调用和响应的主体信息的标签
Fault 错误信息标签。
SOAP 消息的基本结构是
- <?xml version="1.0" encoding="UTF-8"?>
- <soap:Envelope xmlns:soap="http://schemas./soap/envelope/">
- <soap:Header>
- ...
- </soap:Header>
- <soap:Body>
- ...
- <soap:Fault>
- ...
- </soap:Fault>
- </soap:Body>
- </soap:Envelope>
soap:Envelope是SOAP中根元素元素。Envelope元素中可以包含多个可选的Header元素,必须同时包含一个Body元素。Header元素必须是Envelope元素的直接子元素,并且要位于Body元素之前。
soap:Header与HTTP请求中的Headers类似,用于传送一些基础的通用的数据,例如安全、事务等方面的信息。Header不是SOAP消息中的必需元素,但他是扩展SOAP协议的一个功能非常强大的功能。Header有两个非常重要的属性
soap:Body是SOAP消息中必需的元素,用于传送实际的业务数据或错误信息。
soap:Fault是soap:Body的子元素,用于传送错误信息,当有错误发生时才需要次标签。
可参考:http://askcuix./blog/211005
WSDL简介
WSDL是WebService的描述语言,也是使用xml编写,用于描述、也可定位WebService,还不属于W3C标准。WSDL主要包含以下几个元素:
definitions WSDL的根节点,主要包括:name属性,WebService服务名,可通过@WebService注解的serviceName 更改;targetNamespace属性,命名空间,可通过@WebService注解的targetNamespace更改。
types web service 使用的数据类型,他是独立与机器和语言的类型定义,这些类型被message标签所引用。
message web service 使用的消息,他定义了WebService函数的参数。在WSDL中,输入输出参数要分开定义,使用 不同的message标签体标识。message定义的输入输出参数被portType标签所引用。
portType web service 执行的操作。引用message标签定义的内容来描述函数信息(函数名,输入输出参数等)。
binding web service 使用的通信协议。将portType中定义的服务绑定到SOAP协议,这部分XML 指定最终发布的 WebService的SOAP 消息封装格式、发布地址等。
service 这个元素的name 属性指定服务名称(这里与根元素的name 属性相同),子元素port的name 属性指定port 名称,子元素address的location 属性指定Web 服务的地址。
WSDL的基本结构是:
- <definitions>
- <types>
- ...
- </types>
- <message>
- ...
- </message>
- <portType>
- ...
- </portType>
- <binding>
- ...
- </binding>
- <service>
- ...
- </service>
- </definitions>
可参考:http://www.w3school.com.cn/wsdl/index.asp
我就不浪费资源粘一大段WSDL和SOAP的实例过来了,上一篇写了个小例子,发布后在浏览器输入“服务地址”+ “?wsdl”就可以查看(如那个例子的WSDL地址是http://127.0.0.1:8080/helloService?wsdl)。SOAP可以使用一个HTTP监听工具查看(我使用的是HTTPAnalyzerFullV5),或者通过CXF的实现发布程序,使用CXF的拦截器可以看到SOAP消息内容。
将上一篇的代码更改为CXF实现:
首先下载CXF的包,我下的是apache-cxf-2.3.0.zip,将lib下的jar包引入工程路径,将发布服务的代码更改为:
- public static void main(String[] args) {
-
-
-
- JaxWsServerFactoryBean soapFactoryBean = new JaxWsServerFactoryBean();
- soapFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
- soapFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
- soapFactoryBean.setServiceClass(HelloImpl.class);
- soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService");
- soapFactoryBean.create();
- }
- }
这样,就可以在控制台看到SOAP的消息内容了,信息: Inbound Message是服务器端接受到的内容,信息: Outbound Message是服务器返回给客户端的内容。当然,使用CXF的实现方式时,客户端调用也可以使用CXF的特有方式:
-
-
-
-
-
-
- JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
- soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService");
- soapFactoryBean.setServiceClass(Hello.class);
- Object o = soapFactoryBean.create();
- Hello hello = (Hello) o;
注意,当使用不同的WebService实现时,其生成的WSDL内容可能会稍有差异,但总体上都是一样的。
Apache CXF下载地址 :http://cxf./download.html
附件是上一篇中例子的工程,有一点点修改,我把lib里的CXF的jar包删了,太大了,不让上传,想看的同学可以到上面的地址下载CXF相应的包,解压后将lib里的东东拷到我工程的lib目录里就OK了,当然还得先在C盘建立几个测试文件c1.jpg、c2.jpg、origin.jpg和why.jpg。
4。
前面写了个JAX-WS的小例子,看到用JAVA6开发WebService确实很简单,也很方便,不过前面也说了,JAVA有三种WebService规范,JAX-WS是其中一种,现在来看看JAXM&SAAJ。
最近在做一个接口平台的项目,接口嘛,当然得涉及到对WebService的接口了,我们计划做成一个通用的平台,通过配置文件进行配置后就可以动态对某一个接口进行调用,但像前面的例子那样,每次都要生成一堆客户端代码,这可受不了。如果调用的接口唯一,生成一次客户端代码当然没问题,但如果要调用的接口是动态的,这就不好办了。因此,我需要了解SOAP更多底层的细节,由我自己来组织SOAP中的内容而不是完全由代码生成器生成。
仍使用前面例子中的服务器端:
接口:
- package com.why.server;
-
- import javax.jws.WebParam;
- import javax.jws.WebService;
- import javax.jws.soap.SOAPBinding;
- import javax.xml.ws.soap.MTOM;
-
-
-
-
-
-
- @WebService(name="Hello")
- @SOAPBinding(style = SOAPBinding.Style.RPC)
- public interface Hello {
- public void printContext();
- public Customer selectCustomerByName(@WebParam(name = "c",header=true)Customer customer);
- public Customer selectMaxAgeCustomer(Customer c1, Customer c2);
- }
实现类:
- package com.why.server;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Set;
- import javax.activation.DataHandler;
- import javax.activation.FileDataSource;
- import javax.annotation.Resource;
- import javax.jws.WebService;
- import javax.xml.ws.WebServiceContext;
- import javax.xml.ws.handler.MessageContext;
- import javax.xml.ws.soap.MTOM;
-
-
-
-
-
-
-
- @WebService(serviceName="HelloService",portName="HelloServicePort",targetNamespace="http://service./",endpointInterface="com.why.server.Hello")
- @MTOM
- public class HelloImpl implements Hello {
-
- @Resource
- private WebServiceContext context;
-
- @Override
- public void printContext(){
- MessageContext ctx = context.getMessageContext();
- Set<String> set = ctx.keySet();
- for (String key : set) {
- System.out.println("{" + key + "," + ctx.get(key) +"}");
- try {
- System.out.println("key.scope=" + ctx.getScope(key));
- } catch (Exception e) {
- System.out.println(key + " is not exits");
- }
- }
- }
-
- @Override
- public Customer selectCustomerByName(Customer customer) {
- if("why".equals(customer.getName())){
- customer.setId(1);
- try {
- customer.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1985-10-07"));
- } catch (ParseException e) {
- e.printStackTrace();
- }
- customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "why.jpg"))));
- }else{
- customer.setId(2);
- customer.setBirthday(new Date());
- customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "origin.jpg"))));
- }
- return customer;
- }
-
- @Override
- public Customer selectMaxAgeCustomer(Customer c1, Customer c2) {
- try {
-
- System.out.println("c1.getImageData().getContentType()=" + c1.getImageData().getContentType());
- InputStream is = c1.getImageData().getInputStream();
- OutputStream os = new FileOutputStream("c:\\temp1.jpg");
- byte[] bytes = new byte[1024];
- int c;
- while ((c = is.read(bytes)) != -1) {
- os.write(bytes, 0, c);
- }
- os.close();
-
- System.out.println("c2.getImageData().getContentType()=" + c2.getImageData().getContentType());
- is = c2.getImageData().getInputStream();
- os = new FileOutputStream("c:\\temp2.jpg");
- bytes = new byte[1024];
- while ((c = is.read(bytes)) != -1) {
- os.write(bytes, 0, c);
- }
- os.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- if (c1.getBirthday().getTime() > c2.getBirthday().getTime()){
- return c2;
- }
- else{
- return c1;
- }
- }
- }
Customer类:
- package com.why.server;
-
- import java.util.Date;
-
- import javax.activation.DataHandler;
- import javax.xml.bind.annotation.XmlAccessType;
- import javax.xml.bind.annotation.XmlAccessorType;
- import javax.xml.bind.annotation.XmlMimeType;
- import javax.xml.bind.annotation.XmlRootElement;
-
-
-
-
-
-
- @XmlRootElement(name = "Customer")
- @XmlAccessorType(XmlAccessType.FIELD)
- public class Customer {
- private long id;
- private String name;
- private Date birthday;
- @XmlMimeType("application/octet-stream")
- private DataHandler imageData;
-
- public long getId() {
- return id;
- }
- public void setId(long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Date getBirthday() {
- return birthday;
- }
- public void setBirthday(Date birthday) {
- this.birthday = birthday;
- }
- public DataHandler getImageData() {
- return imageData;
- }
- public void setImageData(DataHandler imageData) {
- this.imageData = imageData;
- }
- }
发布:
- package com.why.server;
-
- import javax.xml.ws.Endpoint;
-
-
-
-
-
-
- public class SoapServer {
- public static void main(String[] args) {
- Endpoint.publish("http://localhost:8080/helloService",new HelloImpl());
-
- }
- }
这次不生成客户端类,而是通过自己组织SOAP消息,向服务器发送请求。首先,我们需要一个到WebService服务的连接(就像Connection之于JDBC),通过javax.xml.soap.SOAPConnectionFactory的createConnection()可以获得一个WebService连接。获得连接之后,我们就可以组织我们的SOAP消息了。通过javax.xml.soap.MessageFactory的createMessage()方法,获得一个javax.xml.soap.SOAPMessage,SOAPMessage就是我们SOAP消息的入口。我们知道,SOAP其实就是一个XML,有了SOAPMessage这个入口,剩下的就是对XML的组织和解析了。对于SOAP消息的各个部分,SOAPMessage都有对应的接口:
-
- SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
-
- SOAPConnection connection = factory.createConnection();
-
- MessageFactory mFactory = MessageFactory.newInstance();
-
- SOAPMessage message = mFactory.createMessage();
-
- SOAPPart part = message.getSOAPPart();
-
- SOAPEnvelope envelope = part.getEnvelope();
-
- SOAPHeader header = message.getSOAPHeader();
-
- SOAPBody body = envelope.getBody();
把我们需要传递的参数组织好,通过connection.call方法进行对WebService的调用,他仍然会给我们返回一个SOAPMessage对象,对应服务器端的三个函数,我分别写了对应的三个方法对其进行调用,以下是我的客户端类:
- package com.why.client;
- import java.io.ByteArrayOutputStream;
- import java.io.FileOutputStream;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.URL;
- import java.util.Iterator;
- import java.util.UUID;
- import javax.activation.DataHandler;
- import javax.activation.FileDataSource;
- import javax.xml.namespace.QName;
- import javax.xml.soap.AttachmentPart;
- import javax.xml.soap.MessageFactory;
- import javax.xml.soap.SOAPBody;
- import javax.xml.soap.SOAPBodyElement;
- import javax.xml.soap.SOAPConnection;
- import javax.xml.soap.SOAPConnectionFactory;
- import javax.xml.soap.SOAPElement;
- import javax.xml.soap.SOAPEnvelope;
- import javax.xml.soap.SOAPHeader;
- import javax.xml.soap.SOAPHeaderElement;
- import javax.xml.soap.SOAPMessage;
- import javax.xml.soap.SOAPPart;
-
-
-
-
-
-
- public class SoapClient {
- public static void main(String[] args) throws Exception{
-
- printContext();
-
- selectCustomerByName();
-
- selectMaxAgeCustomer();
- }
-
-
-
-
-
- public static void printContext() throws Exception{
-
- SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
-
- SOAPConnection connection = factory.createConnection();
-
- MessageFactory mFactory = MessageFactory.newInstance();
-
- SOAPMessage message = mFactory.createMessage();
-
- SOAPPart part = message.getSOAPPart();
-
- SOAPEnvelope envelope = part.getEnvelope();
-
- SOAPHeader header = message.getSOAPHeader();
-
- SOAPBody body = envelope.getBody();
-
-
- SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server./", "printContext", "ns1"));
-
-
- SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));
-
- OutputStream os = System.out;
- reMessage.writeTo(os);
-
- connection.close();
- }
-
-
-
-
-
- public static void selectCustomerByName() throws Exception{
-
- SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
-
- SOAPConnection connection = factory.createConnection();
-
- MessageFactory mFactory = MessageFactory.newInstance();
-
- SOAPMessage message = mFactory.createMessage();
-
- SOAPPart part = message.getSOAPPart();
-
- SOAPEnvelope envelope = part.getEnvelope();
-
- SOAPHeader header = message.getSOAPHeader();
-
- SOAPBody body = envelope.getBody();
-
-
- SOAPHeaderElement headerElementRoot = header.addHeaderElement(new QName("http://server./", "c", "ns1"));
- SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server./", "selectCustomerByName", "ns1"));
- headerElementRoot.addChildElement(new QName("name")).addTextNode("why");
-
-
- SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));
-
- OutputStream os = System.out;
- reMessage.writeTo(os);
-
-
- Iterator<AttachmentPart> it = reMessage.getAttachments();
- while (it.hasNext()) {
- InputStream ins = it.next().getDataHandler().getInputStream();
- byte[] b = new byte[ins.available()];
- OutputStream ous = new FileOutputStream("c:\\aaa.jpg");
- while (ins.read(b) != -1) {
- ous.write(b);
- }
- ous.close();
- }
- connection.close();
- }
-
-
-
-
-
- public static void selectMaxAgeCustomer() throws Exception{
-
- SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
-
- SOAPConnection connection = factory.createConnection();
-
- MessageFactory mFactory = MessageFactory.newInstance();
-
- SOAPMessage message = mFactory.createMessage();
-
- SOAPPart part = message.getSOAPPart();
-
- SOAPEnvelope envelope = part.getEnvelope();
-
- SOAPHeader header = message.getSOAPHeader();
-
- SOAPBody body = envelope.getBody();
-
-
- MimeHeaders hd = message.getMimeHeaders();
- hd.setHeader("Content-Type", "application/xop+xml; charset=utf-8; type=\"text/xml\"");
-
-
- SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server./", "selectMaxAgeCustomer", "ns1"));
-
-
- SOAPElement elementC1 = bodyElementRoot.addChildElement(new QName("arg0"));
- elementC1.addChildElement(new QName("id")).addTextNode("1");
- elementC1.addChildElement(new QName("name")).addTextNode("A");
- elementC1.addChildElement(new QName("birthday")).addTextNode("1989-01-28T00:00:00.000+08:00");
-
- AttachmentPart attachment = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c1.jpg")));
-
- attachment.setContentId("<" + UUID.randomUUID().toString() + ">");
- attachment.setMimeHeader("Content-Transfer-Encoding", "binary");
- message.addAttachmentPart(attachment);
- SOAPElement elementData = elementC1.addChildElement(new QName("imageData"));
-
-
- elementData.addChildElement(
- new QName("http://www./2004/08/xop/include", "Include","xop"))
- .addAttribute(new QName("href"),"cid:" + attachment.getContentId().replaceAll("<", "").replaceAll(">", ""));
-
-
- SOAPElement elementC2 = bodyElementRoot.addChildElement(new QName("arg1"));
- elementC2.addChildElement(new QName("id")).addTextNode("2");
- elementC2.addChildElement(new QName("name")).addTextNode("B");
- elementC2.addChildElement(new QName("birthday")).addTextNode("1990-01-28T00:00:00.000+08:00");
- AttachmentPart attachment2 = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c2.jpg")));
- attachment2.setContentId("<" + UUID.randomUUID().toString() + ">");
- message.addAttachmentPart(attachment2);
- SOAPElement elementData2 = elementC2.addChildElement(new QName("imageData"));
-
- elementData2.addChildElement(
- new QName("http://www./2004/08/xop/include", "Include","xop"))
- .addAttribute(new QName("href"),"cid:" + attachment2.getContentId().replaceAll("<", "").replaceAll(">", ""));
-
-
- OutputStream os = new ByteArrayOutputStream();
- message.writeTo(os);
- String soapStr = os.toString();
- System.out.println("\n@@@@@@@@@@@@@@@@@@\n"+soapStr+"\n@@@@@@@@@@@@@@@@@@");
-
-
- SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));
-
- OutputStream baos = new ByteArrayOutputStream();
- reMessage.writeTo(baos);
- String soapStr2 = baos.toString();
- System.out.println("\n#############\n"+soapStr2+"\n################");
-
-
- System.out.println("\n<<<<<<<<<<<<<<<<<<<" + reMessage.getSOAPBody().getFirstChild().getLocalName());
-
- Iterator<AttachmentPart> it = reMessage.getAttachments();
- while (it.hasNext()) {
- InputStream ins = it.next().getDataHandler().getInputStream();
- byte[] b = new byte[ins.available()];
- OutputStream ous = new FileOutputStream("c:\\bbb.jpg");
- while (ins.read(b) != -1) {
- ous.write(b);
- }
- ous.close();
- }
-
- connection.close();
-
- }
- }
使用SAAJ创建附件时,需设置Content-Type=application/xop+xml; charset=utf-8; type="text/xml",否则服务器端获取不到这个附件,查看发送给服务器端的SOAP消息可以看到,默认Content-Type被置为text/xml; charset=utf-8,因此,需在代码中加入:
- MimeHeaders hd = message.getMimeHeaders();
- hd.setHeader("Content-Type", "application/xop+xml; charset=utf-8; type=\"text/xml\"");
SOAPMessage有一个writeTo(OutputStream os)方法,可以将整个SOAP消息的内容写入一个输出流中,我们可以截获这个输出流的内容进行分析或再次整理。
附件是我的工程(2010-11-15更新)