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消息的內容寫入一個輸出流中,我們可以截獲這個輸出流的內容進行分析或再次整理。

 

附件是我的工程(2010-11-15更新)


轉載自 :http://wuhongyu.iteye.com/blog/810571

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章