JAVA6开发WebService (四)——SAAJ调用WebService

 前面写了个JAX-WS的小例子,看到用JAVA6开发WebService确实很简单,也很方便,不过前面也说了,JAVA有三种WebService规范,JAX-WS是其中一种,现在来看看JAXM&SAAJ。

 

    最近在做一个接口平台的项目,接口嘛,当然得涉及到对WebService的接口了,我们计划做成一个通用的平台,通过配置文件进行配置后就可以动态对某一个接口进行调用,但像前面的例子那样,每次都要生成一堆客户端代码,这可受不了。如果调用的接口唯一,生成一次客户端代码当然没问题,但如果要调用的接口是动态的,这就不好办了。因此,我需要了解SOAP更多底层的细节,由我自己来组织SOAP中的内容而不是完全由代码生成器生成。

 

    仍使用前面例子中的服务器端:

接口:

Java代码   收藏代码
  1. package com.why.server;  
  2.   
  3. import javax.jws.WebParam;  
  4. import javax.jws.WebService;  
  5. import javax.jws.soap.SOAPBinding;  
  6. import javax.xml.ws.soap.MTOM;  
  7.   
  8. /** 
  9.  *  
  10.  * @author why 
  11.  * 
  12.  */  
  13. @WebService(name="Hello")  
  14. @SOAPBinding(style = SOAPBinding.Style.RPC)  
  15. public interface Hello {  
  16.     public void printContext();  
  17.     public Customer selectCustomerByName(@WebParam(name = "c",header=true)Customer customer);  
  18.     public Customer selectMaxAgeCustomer(Customer c1, Customer c2);  
  19. }  

实现类:

Java代码   收藏代码
  1. package com.why.server;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.text.ParseException;  
  9. import java.text.SimpleDateFormat;  
  10. import java.util.Date;  
  11. import java.util.Set;  
  12. import javax.activation.DataHandler;  
  13. import javax.activation.FileDataSource;  
  14. import javax.annotation.Resource;  
  15. import javax.jws.WebService;  
  16. import javax.xml.ws.WebServiceContext;  
  17. import javax.xml.ws.handler.MessageContext;  
  18. import javax.xml.ws.soap.MTOM;  
  19.   
  20. /** 
  21.  *  
  22.  * 通过@MTOM注解启动MTOM传输方式,使用CXF实现时,这个注解放在接口或者实现类上都可以,使用JDK1.6自带实现时,需标注在实现类上 
  23.  * @author why 
  24.  * 
  25.  */  
  26. @WebService(serviceName="HelloService",portName="HelloServicePort",targetNamespace="http://service.why.com/",endpointInterface="com.why.server.Hello")  
  27. @MTOM  
  28. public class HelloImpl implements Hello {  
  29.       
  30.     @Resource  
  31.     private WebServiceContext context;  
  32.       
  33.     @Override  
  34.     public void printContext(){  
  35.         MessageContext ctx = context.getMessageContext();  
  36.         Set<String> set = ctx.keySet();  
  37.         for (String key : set) {  
  38.             System.out.println("{" + key + "," + ctx.get(key) +"}");  
  39.             try {  
  40.                 System.out.println("key.scope=" + ctx.getScope(key));  
  41.             } catch (Exception e) {  
  42.                 System.out.println(key + " is not exits");  
  43.             }  
  44.         }  
  45.     }  
  46.       
  47.     @Override  
  48.     public Customer selectCustomerByName(Customer customer) {  
  49.         if("why".equals(customer.getName())){  
  50.             customer.setId(1);  
  51.             try {  
  52.                 customer.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1985-10-07"));  
  53.             } catch (ParseException e) {  
  54.                 e.printStackTrace();  
  55.             }  
  56.             customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "why.jpg"))));  
  57.         }else{  
  58.             customer.setId(2);  
  59.             customer.setBirthday(new Date());  
  60.             customer.setImageData(new DataHandler(new FileDataSource(new File("c:"+ File.separator + "origin.jpg"))));  
  61.         }  
  62.         return customer;  
  63.     }  
  64.       
  65.     @Override  
  66.     public Customer selectMaxAgeCustomer(Customer c1, Customer c2) {  
  67.         try {  
  68.             // 输出接收到的附件  
  69.             System.out.println("c1.getImageData().getContentType()=" + c1.getImageData().getContentType());  
  70.             InputStream is = c1.getImageData().getInputStream();  
  71.             OutputStream os = new FileOutputStream("c:\\temp1.jpg");  
  72.             byte[] bytes = new byte[1024];  
  73.             int c;  
  74.             while ((c = is.read(bytes)) != -1) {  
  75.                 os.write(bytes, 0, c);  
  76.             }  
  77.             os.close();  
  78.               
  79.             System.out.println("c2.getImageData().getContentType()=" + c2.getImageData().getContentType());  
  80.             is = c2.getImageData().getInputStream();  
  81.             os = new FileOutputStream("c:\\temp2.jpg");  
  82.             bytes = new byte[1024];  
  83.             while ((c = is.read(bytes)) != -1) {  
  84.                 os.write(bytes, 0, c);  
  85.             }  
  86.             os.close();  
  87.         } catch (IOException e) {  
  88.             e.printStackTrace();  
  89.         }  
  90.           
  91.         if (c1.getBirthday().getTime() > c2.getBirthday().getTime()){  
  92.             return c2;  
  93.         }  
  94.         else{  
  95.             return c1;  
  96.         }  
  97.     }  
  98. }  

Customer类:

Java代码   收藏代码
  1. package com.why.server;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import javax.activation.DataHandler;  
  6. import javax.xml.bind.annotation.XmlAccessType;  
  7. import javax.xml.bind.annotation.XmlAccessorType;  
  8. import javax.xml.bind.annotation.XmlMimeType;  
  9. import javax.xml.bind.annotation.XmlRootElement;  
  10.   
  11. /** 
  12.  *  
  13.  * @author why 
  14.  * 
  15.  */  
  16. @XmlRootElement(name = "Customer")  
  17. @XmlAccessorType(XmlAccessType.FIELD)  
  18. public class Customer {  
  19.     private long id;  
  20.     private String name;  
  21.     private Date birthday;  
  22.     @XmlMimeType("application/octet-stream")  
  23.     private DataHandler imageData;  
  24.       
  25.     public long getId() {  
  26.         return id;  
  27.     }  
  28.     public void setId(long id) {  
  29.         this.id = id;  
  30.     }  
  31.     public String getName() {  
  32.         return name;  
  33.     }  
  34.     public void setName(String name) {  
  35.         this.name = name;  
  36.     }  
  37.     public Date getBirthday() {  
  38.         return birthday;  
  39.     }  
  40.     public void setBirthday(Date birthday) {  
  41.         this.birthday = birthday;  
  42.     }  
  43.     public DataHandler getImageData() {  
  44.         return imageData;  
  45.     }  
  46.     public void setImageData(DataHandler imageData) {  
  47.         this.imageData = imageData;  
  48.     }  
  49. }  

发布:

Java代码   收藏代码
  1. package com.why.server;  
  2.   
  3. import javax.xml.ws.Endpoint;  
  4.   
  5. /** 
  6.  *  
  7.  * @author why 
  8.  * 
  9.  */  
  10. public class SoapServer {  
  11.     public static void main(String[] args) {  
  12.         Endpoint.publish("http://localhost:8080/helloService",new HelloImpl());  
  13.   
  14.     }  
  15. }  

 

    这次不生成客户端类,而是通过自己组织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都有对应的接口:

Java代码   收藏代码
  1. // 获取SOAP连接工厂  
  2. SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();  
  3. // 从SOAP连接工厂创建SOAP连接对象  
  4. SOAPConnection connection = factory.createConnection();  
  5. // 获取消息工厂  
  6. MessageFactory mFactory = MessageFactory.newInstance();  
  7. // 从消息工厂创建SOAP消息对象  
  8. SOAPMessage message = mFactory.createMessage();  
  9. // 创建SOAPPart对象  
  10. SOAPPart part = message.getSOAPPart();  
  11. // 创建SOAP信封对象  
  12. SOAPEnvelope envelope = part.getEnvelope();  
  13. // 创建SOAPHeader对象  
  14. SOAPHeader header = message.getSOAPHeader();  
  15. // 创建SOAPBody对  
  16. SOAPBody body = envelope.getBody();  

 

    把我们需要传递的参数组织好,通过connection.call方法进行对WebService的调用,他仍然会给我们返回一个SOAPMessage对象,对应服务器端的三个函数,我分别写了对应的三个方法对其进行调用,以下是我的客户端类:

 

Java代码   收藏代码
  1. package com.why.client;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.FileOutputStream;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.net.URL;  
  7. import java.util.Iterator;  
  8. import java.util.UUID;  
  9. import javax.activation.DataHandler;  
  10. import javax.activation.FileDataSource;  
  11. import javax.xml.namespace.QName;  
  12. import javax.xml.soap.AttachmentPart;  
  13. import javax.xml.soap.MessageFactory;  
  14. import javax.xml.soap.SOAPBody;  
  15. import javax.xml.soap.SOAPBodyElement;  
  16. import javax.xml.soap.SOAPConnection;  
  17. import javax.xml.soap.SOAPConnectionFactory;  
  18. import javax.xml.soap.SOAPElement;  
  19. import javax.xml.soap.SOAPEnvelope;  
  20. import javax.xml.soap.SOAPHeader;  
  21. import javax.xml.soap.SOAPHeaderElement;  
  22. import javax.xml.soap.SOAPMessage;  
  23. import javax.xml.soap.SOAPPart;  
  24.   
  25. /** 
  26.  *  
  27.  * @author why 
  28.  * 
  29.  */  
  30. public class SoapClient {  
  31.     public static void main(String[] args) throws Exception{  
  32.           
  33.         printContext();  
  34.           
  35.         selectCustomerByName();  
  36.           
  37.         selectMaxAgeCustomer();  
  38.     }  
  39.       
  40.     /** 
  41.      * 调用一个无参函数 
  42.      * @throws Exception 
  43.      */  
  44.     public static void printContext() throws Exception{  
  45.         // 获取SOAP连接工厂  
  46.         SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();  
  47.         // 从SOAP连接工厂创建SOAP连接对象  
  48.         SOAPConnection connection = factory.createConnection();  
  49.         // 获取消息工厂  
  50.         MessageFactory mFactory = MessageFactory.newInstance();  
  51.         // 从消息工厂创建SOAP消息对象  
  52.         SOAPMessage message = mFactory.createMessage();  
  53.         // 创建SOAPPart对象  
  54.         SOAPPart part = message.getSOAPPart();  
  55.         // 创建SOAP信封对象  
  56.         SOAPEnvelope envelope = part.getEnvelope();  
  57.         // 创建SOAPHeader对象  
  58.         SOAPHeader header = message.getSOAPHeader();  
  59.         // 创建SOAPBody对象  
  60.         SOAPBody body = envelope.getBody();  
  61.           
  62.         // 创建XML的根元素  
  63.         SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server.why.com/""printContext""ns1"));  
  64.           
  65.         // 访问Web服务地址  
  66.         SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));  
  67.         // 控制台输出返回的SOAP消息  
  68.         OutputStream os = System.out;  
  69.         reMessage.writeTo(os);  
  70.           
  71.         connection.close();  
  72.     }  
  73.       
  74.     /** 
  75.      * 调用一个在soap:HEADER中传递参数的函数 
  76.      * @throws Exception 
  77.      */  
  78.     public static void selectCustomerByName() throws Exception{  
  79.         // 获取SOAP连接工厂  
  80.         SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();  
  81.         // 从SOAP连接工厂创建SOAP连接对象  
  82.         SOAPConnection connection = factory.createConnection();  
  83.         // 获取消息工厂  
  84.         MessageFactory mFactory = MessageFactory.newInstance();  
  85.         // 从消息工厂创建SOAP消息对象  
  86.         SOAPMessage message = mFactory.createMessage();  
  87.         // 创建SOAPPart对象  
  88.         SOAPPart part = message.getSOAPPart();  
  89.         // 创建SOAP信封对象  
  90.         SOAPEnvelope envelope = part.getEnvelope();  
  91.         // 创建SOAPHeader对象  
  92.         SOAPHeader header = message.getSOAPHeader();  
  93.         // 创建SOAPBody对象  
  94.         SOAPBody body = envelope.getBody();  
  95.           
  96.         // 创建XML的根元素  
  97.         SOAPHeaderElement headerElementRoot = header.addHeaderElement(new QName("http://server.why.com/""c""ns1"));  
  98.         SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server.why.com/""selectCustomerByName""ns1"));  
  99.         headerElementRoot.addChildElement(new QName("name")).addTextNode("why");  
  100.           
  101.         // 访问Web服务地址  
  102.         SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));  
  103.         // 控制台输出返回的SOAP消息  
  104.         OutputStream os = System.out;  
  105.         reMessage.writeTo(os);  
  106.           
  107.         // 输出SOAP消息中的附件  
  108.         Iterator<AttachmentPart> it = reMessage.getAttachments();  
  109.         while (it.hasNext()) {  
  110.             InputStream ins = it.next().getDataHandler().getInputStream();  
  111.             byte[] b = new byte[ins.available()];  
  112.             OutputStream ous = new FileOutputStream("c:\\aaa.jpg");  
  113.             while (ins.read(b) != -1) {  
  114.                 ous.write(b);  
  115.             }  
  116.             ous.close();  
  117.         }  
  118.         connection.close();  
  119.     }  
  120.       
  121.     /** 
  122.      * 调用一个在soap:Body中传递参数的函数 
  123.      * @throws Exception 
  124.      */  
  125.     public static void selectMaxAgeCustomer() throws Exception{  
  126.         // 获取SOAP连接工厂  
  127.         SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();  
  128.         // 从SOAP连接工厂创建SOAP连接对象  
  129.         SOAPConnection connection = factory.createConnection();  
  130.         // 获取消息工厂  
  131.         MessageFactory mFactory = MessageFactory.newInstance();  
  132.         // 从消息工厂创建SOAP消息对象  
  133.         SOAPMessage message = mFactory.createMessage();  
  134.         // 创建SOAPPart对象  
  135.         SOAPPart part = message.getSOAPPart();  
  136.         // 创建SOAP信封对象  
  137.         SOAPEnvelope envelope = part.getEnvelope();  
  138.         // 创建SOAPHeader对象  
  139.         SOAPHeader header = message.getSOAPHeader();  
  140.         // 创建SOAPBody对象  
  141.         SOAPBody body = envelope.getBody();  
  142.   
  143.         // 设置Content-Type  
  144.         MimeHeaders hd = message.getMimeHeaders();   
  145.         hd.setHeader("Content-Type""application/xop+xml; charset=utf-8; type=\"text/xml\"");  
  146.   
  147.         // 创建XML的根元素  
  148.         SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server.why.com/""selectMaxAgeCustomer""ns1"));  
  149.           
  150.         // 创建Customer实例1  
  151.         SOAPElement elementC1 = bodyElementRoot.addChildElement(new QName("arg0"));  
  152.         elementC1.addChildElement(new QName("id")).addTextNode("1");  
  153.         elementC1.addChildElement(new QName("name")).addTextNode("A");  
  154.         elementC1.addChildElement(new QName("birthday")).addTextNode("1989-01-28T00:00:00.000+08:00");  
  155.         // 创建附件对象  
  156.         AttachmentPart attachment = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c1.jpg")));  
  157.         // 设置Content-ID  
  158.         attachment.setContentId("<" + UUID.randomUUID().toString() + ">");  
  159.         attachment.setMimeHeader("Content-Transfer-Encoding""binary");  
  160.         message.addAttachmentPart(attachment);  
  161.         SOAPElement elementData = elementC1.addChildElement(new QName("imageData"));  
  162.           
  163.         // 添加XOP支持  
  164.         elementData.addChildElement(  
  165.                 new QName("http://www.w3.org/2004/08/xop/include""Include","xop"))  
  166.                 .addAttribute(new QName("href"),"cid:" + attachment.getContentId().replaceAll("<""").replaceAll(">"""));  
  167.           
  168.         // 创建Customer实例2  
  169.         SOAPElement elementC2 = bodyElementRoot.addChildElement(new QName("arg1"));  
  170.         elementC2.addChildElement(new QName("id")).addTextNode("2");  
  171.         elementC2.addChildElement(new QName("name")).addTextNode("B");  
  172.         elementC2.addChildElement(new QName("birthday")).addTextNode("1990-01-28T00:00:00.000+08:00");  
  173.         AttachmentPart attachment2 = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c2.jpg")));  
  174.         attachment2.setContentId("<" + UUID.randomUUID().toString() + ">");  
  175.         message.addAttachmentPart(attachment2);  
  176.         SOAPElement elementData2 = elementC2.addChildElement(new QName("imageData"));  
  177.           
  178.         elementData2.addChildElement(  
  179.                 new QName("http://www.w3.org/2004/08/xop/include""Include","xop"))  
  180.                 .addAttribute(new QName("href"),"cid:" + attachment2.getContentId().replaceAll("<""").replaceAll(">"""));  
  181.           
  182.         // 控制台输出发送的SOAP消息  
  183.         OutputStream os = new ByteArrayOutputStream();  
  184.         message.writeTo(os);  
  185.         String soapStr = os.toString();  
  186.         System.out.println("\n@@@@@@@@@@@@@@@@@@\n"+soapStr+"\n@@@@@@@@@@@@@@@@@@");  
  187.           
  188.         // 访问Web服务地址  
  189.         SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));  
  190.         // 控制台输出返回的SOAP消息  
  191.         OutputStream baos = new ByteArrayOutputStream();  
  192.         reMessage.writeTo(baos);  
  193.         String soapStr2 = baos.toString();  
  194.         System.out.println("\n#############\n"+soapStr2+"\n################");  
  195.           
  196. //      // 输出SOAP消息中的第一个子元素的元素名称  
  197.         System.out.println("\n<<<<<<<<<<<<<<<<<<<" + reMessage.getSOAPBody().getFirstChild().getLocalName());  
  198.         // 输出SOAP消息中的附件  
  199.         Iterator<AttachmentPart> it = reMessage.getAttachments();  
  200.         while (it.hasNext()) {  
  201.             InputStream ins = it.next().getDataHandler().getInputStream();  
  202.             byte[] b = new byte[ins.available()];  
  203.             OutputStream ous = new FileOutputStream("c:\\bbb.jpg");  
  204.             while (ins.read(b) != -1) {  
  205.                 ous.write(b);  
  206.             }  
  207.             ous.close();  
  208.         }  
  209.           
  210.         connection.close();  
  211.           
  212.     }  
  213. }  

 

    使用SAAJ创建附件时,需设置Content-Type=application/xop+xml; charset=utf-8; type="text/xml",否则服务器端获取不到这个附件,查看发送给服务器端的SOAP消息可以看到,默认Content-Type被置为text/xml; charset=utf-8,因此,需在代码中加入:

Java代码   收藏代码
  1. MimeHeaders hd = message.getMimeHeaders();   
  2. hd.setHeader("Content-Type""application/xop+xml; charset=utf-8; type=\"text/xml\"");  

 

    SOAPMessage有一个writeTo(OutputStream os)方法,可以将整个SOAP消息的内容写入一个输出流中,我们可以截获这个输出流的内容进行分析或再次整理。

你可能感兴趣的:(webservice)