在第四天時瞭解了用jaxws如何去傳輸一個二進制文件,今天咱們將講述用Client上傳一個Java複雜類型,該複雜類型中有一個字段叫myPhoto,爲一個jpg/gif附件,服務端接受該上傳的複雜類型,並把其中的二進制字段中的圖片保存至本地。java
對於咱們來講,傳輸諸以下面這樣一種的數據結構更符合企業級webservice的應用。web
客戶ID:瀏覽器 |
XXXXtomcat |
客戶名:服務器 |
XXXX數據結構 |
客戶靚照:app |
目標: webapp
1. 客戶端用Webservice上傳一個帶有二進制附件的java複雜類型,服務端收到客戶端request後把java複雜類型讀出,並把該複雜類型中的二進制附件(字段)讀出後,以jpg格式保存至本地異步
package ctsjavacoe.ws.fromjava;ide import javax.jws.WebParam; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.soap.MTOM; import ctsjavacoe.ws.fromjava.bean.*; @WebService(name="MTOMCustomer") @SOAPBinding(style = SOAPBinding.Style.RPC) @MTOM public interface MTOMCustomer { public void uploadCustomerByName(@WebParam(name = "customer")Customer customer); } |
於前四天的教程有所不一樣,此次咱們先來製做一個Interface,代碼如上所示。
@MTOM註解用於開啓MTOM功能。
@WebService註解中的name屬性標註在接口類上,能夠指定wsdl中接口名稱,也就是生成的客戶端代碼中接口類的名字。
@SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息樣式,有兩個枚舉值:SOAPBinding.Style.DOCUMENT(默認)和 SOAPBinding.Style.RPC,能夠對比這兩種方式生成的wsdl會有所不一樣,並且生成的客戶端代碼也會有所不一樣。
該接口有一個抽象方法須要實現:
public void uploadCustomerByName();
注意該方法中的參數爲一個@WebParam。
這與其它的Webservice的@WebMethod所註釋的方法有所區別,由於這個parameter不爲一個java object,而是註釋成了@WebParam,來一塊兒看一下概念:
Ø @WebParam 註釋:
用於定製從單個參數至 Web Service 消息部件和 XML 元素的映射。
將此註釋應用於客戶機或服務器服務端點接口(SEI)上的方法,或者應用於 JavaBeans 端點的服務器端點實現類。
由@WebParam註釋的方法不會產生相應的如「GetPersonResponse.java」,」GetPerson.java」這樣的服務端代碼。
Ø @WebMethod 註釋:
表示做爲一項 Web Service 操做的方法。
將此註釋應用於客戶機或服務器服務端點接口(SEI)上的方法,或者應用於 JavaBeans 端點的服務器端點實現類。
僅支持在使用 @WebService 註釋來註釋的類上使用 @WebMethod 註釋。
有了接口咱們來寫實現吧。
package ctsjavacoe.ws.fromjava;
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 ctsjavacoe.ws.fromjava.bean.Customer;
@WebService(serviceName = "MTOMCustomerService", portName = "MTOMCustomerServicePort", targetNamespace = "http://fromjava.ws.ctsjavacoe/", endpointInter face = "ctsjavacoe.ws.fromjava.MTOMCustomer")
public class MTOMCustomerImpl implements MTOMCustomer { @Override public void uploadCustomerByName(Customer customer) { InputStream is = null; OutputStream os = null; try { System.out.println("customer====" + customer.getId() + " " + customer.getName()); System.out.println("generate jpg......"); is = customer.getMyPhoto().getInputStream(); os = new FileOutputStream("D:/upload/jaxwsupload/customer.jpg"); byte[] bytes = new byte[1024]; int c; while ((c = is.read(bytes)) != -1) { os.write(bytes, 0, c); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (os != null) { os.close(); os = null; } } catch (Exception e) { } try { if (is != null) { is.close(); is = null; } } catch (Exception e) { } } } } |
該實現類實現了接受一個來自於客戶端的帶有Customer數據結構的變量的Webservice請求。
服務端獲得Customer類型的變量,將其內容顯示在後臺的console上,而且把Customer變量中的myPhoto以二進制圖片格式存到:D:/upload/jaxwsupload/customer.jpg.
package ctsjavacoe.ws.fromjava.bean; 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; @XmlMimeType("application/octet-stream") private DataHandler myPhoto; //getter and setter ...... } |
MTOM 方式中要傳輸的附件必須使用javax.activation.DataHandler類,還要注意必須在類上使用 @XmlAccessorType(FIELD)註解,標註JAXB 在進行JAVA 對象與XML 之間進行轉換時只關注字段,而不關注屬性(getXXX()方法),不然發佈Web 服務時會報出現了兩個imageData 屬性的錯誤,緣由未知,多是BUG。
而後使用@XmlMimeType 註解標註這是一個附件類型的數據,這裏咱們標註imageData 是一個二進制文件,固然你也可使用具體的MIME類型,譬如:image/jpg、image/gif 等,但要考慮到客戶端是否支持。
此處的Webservice Server端生成的所有詳細過程請參見「第一天」教程中的描述。
1. 用wsgen來編譯生成相關的java文件,wsdl文件與xsd文件;
2. 這個例子將不會在server端工程的wssrc目錄中生成任何類,爲何:請看@WebMethod
與@WebParam的解釋。
3. 修改WebContent\WEB-INF目錄下的sun-jaxws.xml文件,加入:
<endpoint name=' MTOMCustomer ' implementation='ctsjavacoe.ws.fromjava.MTOMCustomer' url-pattern='/MTOMCustomerService' /> |
4.修改WebContent\WEB-INF目錄下的web.xml加入:
<servlet> <servlet-name>MTOMCustomer</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name> MTOMCustomer </servlet-name> <url-pattern>/ MTOMCustomerService </url-pattern> </servlet-mapping> |
5. 將JaxWSProject的WebContent目錄下的文件拷貝至tomcat的webapps\JaxWSSample
目錄下,並選擇所有覆蓋;
6.重啓Tomcat;
7.打開一個IE瀏覽器,輸入:
http://localhost:9090/JaxWSSample/MTOMCustomerService?wsdl,你應該能夠看到正確的輸出
此處的Webservice Client端生成的所有詳細過程請參見「第一天」教程中的描述。
1. 把Server端生成的wsdl與xsd拷貝至client工程的wsdl目錄下
2. 此處咱們不用也不能用polling方式來書寫異步的客戶端調用,由於服務端的方法爲帶@WebParam註釋,所以此處咱們使用SOAP客戶端調用來作這個客戶端的例子。所以咱們也不須要修改binding.xml文件了。
(服務端也可不用@WebParam來註釋方法,而使用通常的Java類型,此時會生成相應的服務端的Response代碼以及生成可供客戶端異步調用的代碼,這個練習就留給你們本身去作了)
3. 使用wsimport命令來生成client端調用時所須要的「句柄」
4. 把生成的句柄中的MTOMCustomerService.java這個文件打開,編輯它,將裏面兩處Url url=……的地方改爲你的Server端實際的Webservice的wsdl地址,而默認它是指向一個本地的wsdl文件的路徑
package ctsjavacoe.ws.fromjava; import ctsjavacoe.ws.fromjava.bean.*; 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 MTOMCustomerClient { public static void main(String[] args) { // TODO Auto-generated method stub Customer customer = new Customer(); String endPoint = "http://localhost:9090/JaxWSSample/MTOMCustomerService?wsdl"; try { QName qName = new QName("http://fromjava.ws.ctsjavacoe/", "MTOMCustomerService"); MTOMCustomerService customerService = new MTOMCustomerService( new URL(endPoint), qName); MTOMCustomer customerPort = customerService .getMTOMCustomerServicePort(); customer.setId(101); customer.setName("mk"); customer.setMyPhoto(new DataHandler(new FileDataSource( "D:/upload/wsphoto.jpg"))); customerPort.uploadCustomerByName(customer); } catch (Exception e) { e.printStackTrace(); } } } |
注意:
customer.setMyPhoto(newDataHandler(new FileDataSource(
"D:/upload/wsphoto.jpg")));
的用法。
ü 在d:\upload\目錄下放一個wsphoto.jpg文件
ü 在d:盤下創建目錄D:\upload\jaxwsupload
運行該客戶端,客戶端沒有任何輸出信息,咱們來看咱們的Tomcat的後臺console輸出:
再來看D:\upload\jaxwsupload目錄,多了一個customer.jpg的文件。
經過這5天的課程,基本能夠掌握使用jaxws編制Webservice,能夠應付通常的中小型工程了。
Webservice其實一點不神祕,就是一個Service層,無非是一些協議和規範須要掌握。
對於大型複雜系統尚有幾個Topic須要去解決:
ü WSSecurity
ü WSTransaction
ü XML加密
這些會在往後的高級課程中一一放出。
l -d指定生成的class文件的位置。
l -s指定生成的Javasource文件的位置。
l -r指定生成的resources文件的位置。如WSDL、XSD 的位置。
l -wsdl,-servicename,-portname 三個參數指定生成的 WSDL 文件中的 service 和 port 的名稱。 注意:這裏的SEI是一個 endpoint implementation class,而不是一個接口。必須先寫好一個endpoint的實現類,該類中用@WebService聲明好WebService,再將它編譯成 class文件,才能提供給wsgen使用。
Usage:wsimport [options] <WSDL_URI> 主要選項:
l -d指定生成的 class 文件的位置。
l -s指定生成的 Javasource 文件的位置。
l -wsdllocation指定生成的Java source中@WebService.WSDLLocation和 @WebServiceClient. wsdllocation的值