首先咱們來談一下爲何須要學習webService這樣的一個技術吧....html
若是咱們的網站須要提供一個天氣預報這樣一個需求的話,那咱們該怎麼作?????前端
天氣預報這麼一個功能並非簡單的JS組件就可以實現的,它的數據是依賴數據庫分析出來的,甚至須要衛星探測..咱們我的建站是不可能搞這麼一個數據庫的吧。java
那麼既然咱們本身幹不了,咱們能夠去找別人嗎???咱們從搜索引擎搜索,能夠發現不少提供天氣預報的網站,可是它返回的是一個網頁,而咱們僅僅須要的是對應的數據!android
咱們可能就在想,咱們能不能僅僅只要它返回的數據,而並非通過加工處理後返回的網頁呢??ios
因而乎,webService就誕生了,webservice就是一個部署在Web服務器上的,它向外界暴露出一個可以經過Web進行調用的API。也就是說:當咱們想要獲取天氣預報的信息,咱們能夠調用別人寫好的service服務,咱們調用就可以獲得結果了!web
但是咱們寫網站主流的就有好幾個平臺:Java、.net、PHP等等,那麼部署在Web服務器上的服務器也就是webserice怎麼可以就讓咱們不一樣的平臺都可以調用呢??spring
咱們知道java、.net這樣的平臺他們語言的基本數據類型、複雜數據類型就可能不同,那麼怎麼可以實現調用的呢???數據庫
來引用一段話apache
你們在寫應用程序查詢數據庫時,並無考慮過爲何能夠將查詢結果返回給上層的應用程序,甚至認爲,這就是數據庫應該作的,其實否則,這是數據庫經過TCP/IP協議與另外一個應用程序進行交流的結果,而上層是什麼樣的應用程序,是用什麼語言,數據庫自己並不知道,它只知道接收到了一份協議,這就是SQL92查詢標準協議。編程
不管是Java、.net、PHP等等的平臺,只要是網頁開發都是能夠經過http協議來進行通訊的,而且返回的數據要是通用的話,那麼咱們早就學過這樣的一種技術【XML】
因此webservice實際上就是http+XML
WebService,顧名思義就是基於Web的服務。它使用Web(HTTP)方式,接收和響應外部系統的某種請求。從而實現遠程調用.
咱們能夠調用互聯網上查詢天氣信息Web服務,而後將它嵌入到咱們的程序(C/S或B/S程序)當中來,當用戶從咱們的網點看到天氣信息時,他會認爲咱們爲他提供了不少的信息服務,但其實咱們什麼也沒有作,只是簡單調用了一下服務器上的一段代碼而已。
學習WebService能夠將你的服務(一段代碼)發佈到互聯網上讓別人去調用,也能夠調用別人機器上發佈的WebService,就像使用本身的代碼同樣.。
咱們在學習Java基礎網絡編程章節已經知道了Scoket這麼一個鏈接了。
public class SocketSer { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); boolean flag = true; while (flag) { //接收客戶端的請求 System.out.println("監聽客戶端的數據:"); Socket sc = ss.accept(); InputStream is = sc.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; len = is.read(buffer); String getData = new String(buffer, 0, len); System.out.println("從客戶端獲取的數據:" + getData); //業務處理 大小寫轉化 String outPutData = getData.toUpperCase(); //向客戶端寫數據 OutputStream os = sc.getOutputStream(); os.write(outPutData.getBytes("UTF-8")); //釋放資源 os.close(); is.close(); sc.close(); } ss.close(); } }
public class SocketClient { public static void main(String[] args) throws Exception { //獲取用戶輸入的數據 Scanner input = new Scanner(System.in); System.out.println("請輸入數據:"); String inputData = input.nextLine(); //開啓一個Socket端口 Socket sc = new Socket("127.0.0.1", 6666); OutputStream os = sc.getOutputStream(); os.write(inputData.getBytes()); //獲取服務端回傳的數據 InputStream is = sc.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; len = is.read(buffer); String getData = new String(buffer, 0, len); System.out.println("從服務端獲取的數據:" + getData); //是否流 is.close(); os.close(); sc.close(); } }
當咱們從客戶端輸入數據之後,那麼服務端就會把數據轉成是大寫
其實HTTP協議就是基於Socket對其進行封裝,咱們也能夠在IE瀏覽器中對其進行訪問.咱們同樣可以獲取獲得數據!
ISO的七層模型 : 物理層、數據鏈路層、網絡層、傳輸層、表示層、會話層、應用層
Socket訪問 : Socket屬於傳輸層,它是對Tcp/ip協議的實現,包含TCP/UDP,它是全部通訊協議的基礎,Http協議須要Socket支持,以Socket做爲基礎
Socket通訊特色:
Http協議訪問 :屬於應用層的協議,對Socket進行了封裝
**數據封裝不夠友好 :能夠用xml封裝數據 **
**但願給第三方應用提供web方式的服務 (http + xml) = web Service**
首先,咱們來嘗試一下調用別人寫好的webService,來體驗一把:咱們訪問www.webxml.com.cn/zh_cn/index…
進入到裏邊
當咱們輸入一個號碼,它就可以查詢出咱們的手機位置信息:
咱們如今要作的就是將這個服務讓咱們本身寫的應用程序中也能夠調用,那怎麼作呢???
public void get(String mobileCode ,String userID ) throws Exception{ URL url=new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+ "&userID="+userID); HttpURLConnection conn=(HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ //結果碼=200 InputStream is=conn.getInputStream(); //內存流 , ByteArrayOutputStream boas=new ByteArrayOutputStream(); byte[] buffer=new byte[1024]; int len=-1; while((len=is.read(buffer))!=-1){ boas.write(buffer, 0, len); } System.out.println("GET請求獲取的數據:"+boas.toString()); boas.close(); is.close(); } }
爲何要使用HttpClient工具:
HttpClient使用步驟以下:
//2.Post請求 :經過Http-Client 框架來模擬實現 Http請求 public void post(String mobileCode ,String userID) throws Exception{ /**HttpClient訪問網絡的實現步驟: * 1. 準備一個請求客戶端:瀏覽器 * 2. 準備請求方式: GET 、POST * 3. 設置要傳遞的參數 * 4.執行請求 * 5. 獲取結果 */ HttpClient client=new HttpClient(); PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo"); //3.設置請求參數 postMethod.setParameter("mobileCode", mobileCode); postMethod.setParameter("userID", userID); //4.執行請求 ,結果碼 int code=client.executeMethod(postMethod); //5. 獲取結果 String result=postMethod.getResponseBodyAsString(); System.out.println("Post請求的結果:"+result); } //2.Post請求 :經過Http-Client 框架來模擬實現 Http請求 public void soap() throws Exception{ HttpClient client=new HttpClient(); PostMethod postMethod=new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx"); //3.設置請求參數 postMethod.setRequestBody(new FileInputStream("c:/soap.xml")); //修改請求的頭部 postMethod.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); //4.執行請求 ,結果碼 int code=client.executeMethod(postMethod); System.out.println("結果碼:"+code); //5. 獲取結果 String result=postMethod.getResponseBodyAsString(); System.out.println("Post請求的結果:"+result); }
上面咱們使用的是GET方式或者使用Http-Client框架來調用webservice的服務,其實這兩種方式也有弊端
若是咱們能夠把整個對象傳遞進去,返回的結果更加友好的話,就好像咱們日常調用Java類同樣使用webservice就好咯!
Java也提供了相似的方法,把webservice服務搞成是Java類讓咱們本身調用,既然是Java類的話,那麼咱們使用起來就很是方便了!
把webservice服務搞成是Java類讓咱們本身調用其實就是Java幫咱們生成本地代理,再經過本地代理來訪問webservice
wsimport是Java自帶的一個命令,咱們想要使用該命令,就必須配置環境變量,而且jdk的版本最好是1.7或以上
值得注意的是:ide帶的JDK版本要和wsimport生成本地的版本一致,否則就用不了!!!
wsimport [opations] <wsdl_uri>
wsdl_uri:wsdl 的統一資源標識符
d :指定要輸出的文件的位置
s :表示要解析java的源碼 ,默認解析出的是class字節碼
p : 指定輸出的包名
首先咱們先把cmd的路徑退到桌面上:
而後對WSDL文件生成本地代理
該本地代理其實就是一堆的字節碼文件
將獲得的字節碼文件打包成jar,那麼咱們只要在項目中導入jar包,就能夠調用了!
語法
jar cvf test.jar【jar包的名稱】 打包目錄
原本我是想將本地代理的class文件生成jar包,而後導入到idea環境下,那麼直接調用就好了。但是idea總是報出找不到對應的類,找了半天也找不到,很煩呀!!!!我考慮瞭如下的幾種狀況
最後我仍是沒有找到辦法,若是知道是什麼緣由的,麻煩在評論中告訴我吧....所以此次的測試import,我就不只僅生成class字節碼文件,還生成了.java文件。我就直接使用java文件來測試了。
在zhongfucheng目錄下生成本地代理,把java源碼也帶上
因而我就把java源碼複製到個人項目中,用java源碼來進行測試
有的同窗可能會疑問,爲啥wsimport能那麼厲害,將http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
這麼一個url生成本地代理,其實咱們看了WSDL文件就知道了。
值得注意的是,本地代理僅僅是有其方法,類,並不能解析出具體的實現的。具體的操做其實仍是webservice去完成的。代理這麼一個概念就更加清晰了。
咱們在上一章節中已經使用wsimport生成本地代理來調用webservice的服務了,其實咱們本身寫的web應用程序也是能夠發佈webservice的
咱們發佈了webservice的話,那麼其餘人也是能夠調用咱們本身寫的webservice!
那麼咱們怎麼自定義webservice而後發佈出去呢???
在jdk 1.6 版本之後 ,**經過jax-ws 包提供對webservice的支持 **
寫一個實體:
public class Phone { private String name;//操做系統名 private String owner;//擁有者 private int total;//市場佔有率 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } }
發佈service,經過註解來讓WSDL文件更加可讀...
package cn.it.ws.d; import cn.it.ws.model.Phone; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; /* *手機的業務類,該業務類經過webservice 對外提供服務 * 1. 聲明: @webservice * 2. 發佈 EndPoint */ @WebService (serviceName="PhoneManager",//修改服務名 targetNamespace="http://dd.ws.it.cn") //修改命名空間 ,默認包名,取反 //聲明該業務類 對外提供webservice服務 ,默認只是對public 修飾的方法對外以webservice形式發佈 public class PhoneService { /**@WebMethod(operationName="getMObileInfo"): 修改方法名 * @WebResult(name="phone"):修改返回參數名 * @WebParam(name="osName"):修改輸入參數名 */ @WebMethod(operationName="getMObileInfo") public @WebResult(name="phone") Phone getPhoneInfo(@WebParam(name="osName")String osName){ Phone phone=new Phone(); if(osName.endsWith("android")){ phone.setName("android");phone.setOwner("google");phone.setTotal(80); }else if(osName.endsWith("ios")){ phone.setName("ios");phone.setOwner("apple");phone.setTotal(15); }else{ phone.setName("windows phone");phone.setOwner("microsoft");phone.setTotal(5); } return phone; } @WebMethod(exclude=true)//把該方法排除在外 public void sayHello(String city){ System.out.println("你好:"+city); } private void sayLuck(String city){ System.out.println("好友:"+city); } void sayGoodBye(String city){ System.out.println("拜拜:"+city); } protected void saySayalala(String city){ System.out.println("再見!"+city); } public static void main(String[] args) { String address1="http://127.0.0.1:8888/ws/phoneService"; // String address2="http://127.0.0.1:8888/ws/phoneManager"; /** * 發佈webservice服務 * 1.address:服務的地址 * 2:implementor 服務的實現對象 */ Endpoint.publish(address1, new PhoneService()); // Endpoint.publish(address2, new PhoneService()); System.out.println("wsdl地址 :"+address1+"?WSDL"); } }
@WebService // 添加了此註解,表明是一個WebService public class HelloWorld { // 非 static final private 方法默認會發布 public String sayHi(String name) { return "hello" + name; } @WebMethod(exclude=true) public void exclude(){ // 被註解排除的方法 } protected void protected1(){ //受保護的方法默認不發佈 } private void private1(){ // 私有方法默認不發佈 } public static void static1(){ // static 方法默認不發佈 } public final void final1(){ // final 方法默認不發佈 } }
生成的webservice可以在瀏覽器訪問
目前WebService的協議主要有SOAP1.1和1.2。
xmlns:soap="http://www.w3.org/2003/05/soap-envelope「
Soa(Service-Oriented Architecture) :面向服務的架構,它是一種思想,IBM大力倡導是即插即用的,IBM大力提倡,但願以組裝電腦的方式來開發應用
組成:
面向web的服務,面向web的組件 :WebService : 硬盤、cpu、內存條
企業服務總線 (EnterPrise Service Bus :ESB)。主板
uddi (Universal Description, Discovery and Integration)統一描述、發現、集成
import javax.jws.WebService; /**面向接口的webservice發佈方式 * * */ @WebService public interface JobService { public String getJob(); }
import javax.jws.WebService; @WebService(endpointInterface="cn.it.ws.e.JobService")//設置服務端點接口 ,指定對外提供服務的接口 public class JobServiceImpl implements JobService { @Override public String getJob() { return "JEE研發工程師|Android研發工程師|數據庫工程師|前端工程師|測試工程師|運維工程師"; } public void say(){ System.out.println("早上好!"); } }
import javax.xml.ws.Endpoint; public class Test { public static void main(String[] args) { JobService jobService=new JobServiceImpl(); String address="http://192.168.114.10:9999/ws/jobservice"; Endpoint.publish(address, jobService); System.out.println("wsdl地址:"+address+"?WSDL"); } }
Apache CXF 是一個開源的 Services 框架,CXF 幫助您來構建和開發 Services 這些 Services 能夠支持多種協議,好比:SOAP、POST/HTTP、RESTful HTTP CXF 大大簡化了 Service能夠自然地和 Spring 進行無縫集成。
CXF介紹 :soa的框架
* cxf 是 Celtrix (ESB框架)和 XFire(webserivice) 合併而成,而且捐給了apache
* CxF的核心是org.apache.cxf.Bus(總線),相似於Spring的 ApplicationContext
* CXF默認是依賴於Spring的
* Apache CXF 發行包中的jar,若是所有放到lib中,須要 JDK1.6 及以上,不然會報JAX-WS版本不一致的問題
* CXF 內置了Jetty服務器 ,它是servlet容器,比如tomcat
CXF特色
要想使用CXF框架,那麼就先導入jar包
接口
import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService(serviceName="languageManager") public interface LanguageService { public @WebResult(name="language")String getLanguage(@WebParam(name="position")int position); }
實現:
package cn.it.ws.cxf.a; import org.apache.cxf.frontend.ServerFactoryBean; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; /**開發語言排行描述服務 * * * @author 李俊 2015年5月17日 */ public class LanguageServiceImpl implements LanguageService { /* (non-Javadoc) * @see cn.it.ws.cxf.a.LanguageService#getLanguage(int) */ @Override public String getLanguage(int position){ String language=null; switch (position) { case 1: language="java"; break; case 2: language="C"; break; case 3: language="Objective-C"; break; case 4: language="C#"; break; default: break; } return language; } /**經過cxf框架發佈webservice * 1. ServerFactoryBean * - 不設置註解也能夠發佈webservice服務, 不支持註解 * - 不支持攔截器的添加 * 2. JaxWsServerFactoryBean * - 支持註解 * - 能夠添加攔截器 * 3. webservice 訪問流程: * 1. 檢測本地代理描述的wsdl是否與服務端的wsdl一致 ,俗稱爲握手 * 2. 經過soap協議實現通訊 ,採用的是post請求 , 數據封裝在知足soap規約的xml中 * 3. 返回數據 一樣採用的是soap通訊, 數據封裝在知足soap規約的xml中 * @param args public static void main(String[] args) { LanguageService languageService=new LanguageServiceImpl(); ServerFactoryBean bean=new ServerFactoryBean(); //Endpoint :地址 , 實現對象 bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService"); bean.setServiceClass(LanguageService.class);//對外提供webservcie的業務類或者接口 bean.setServiceBean(languageService);//服務的實現bean bean.create();//建立,發佈webservice System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL"); } */ public static void main(String[] args) { LanguageService languageService=new LanguageServiceImpl(); JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean(); //Endpoint :地址 , 實現對象 bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService"); bean.setServiceClass(LanguageService.class);//對外提供webservcie的業務類或者接口 bean.setServiceBean(languageService);//服務的實現bean //添加輸入攔截器 :輸入顯示日誌信息的攔截器 bean.getInInterceptors().add(new LoggingInInterceptor()); //添加輸出攔截器 :輸出顯示日誌信息的攔截器 bean.getOutInterceptors().add(new LoggingOutInterceptor()); bean.create();//建立,發佈webservice System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL"); } }
web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>CXF_Server</display-name> <!-- 添加 CXF 的Servlet ,處理 webservice的請求 --> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> <!-- Spring 監聽添加 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> </web-app>
實體:
public class Employee { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
接口:
package cn.it.ws.cxf.b; import java.util.List; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import cn.it.ws.cxf.bean.Employee; @WebService(serviceName="EmployeeService") public interface EmployeeManager { void add(@WebParam(name="employee")Employee employee); @WebResult(name="employees")List<Employee> query(); }
接口實現:
package cn.it.ws.cxf.b; import java.util.ArrayList; import java.util.List; import cn.it.ws.cxf.bean.Employee; /**員工管理的業務實現類 * @author 李俊 2015年5月17日 */ public class EmployeeManagerImpl implements EmployeeManager { private List<Employee> employees=new ArrayList<>(); @Override public void add(Employee employee){ //添加到集合中 employees.add(employee); } @Override public List<Employee> query(){ return employees; } }
Spring配置信息:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="employeeManagerImpl" class="cn.it.ws.cxf.b.EmployeeManagerImpl"></bean> <!-- 配置cxf 地址: http://192.168.114.10:8080/CXF_Server/ws/employeeManager 組成 : http://192.168.114.10:8080 +CXF_Server( 項目名)+ws(過濾的路徑)+/employeeManager(自定義部分) 服務類 : 服務的實現類: 攔截器 --> <jaxws:server address="/employeeManager" serviceClass="cn.it.ws.cxf.b.EmployeeManager"> <jaxws:serviceBean> <ref bean="employeeManagerImpl"/> </jaxws:serviceBean> <!-- 配置輸入顯示日誌信息的攔截器 --> <jaxws:inInterceptors> <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean> </jaxws:outInterceptors> </jaxws:server> </beans>
咱們的Intellij idea是一個很是好用的java ide,固然了,它也支持webservice開發。很是好用...因爲在網上見到的教程很是多,我就貼幾個我認爲比較好的教程:
咱們如今webservice就基本入門了,如今我想要作的就是本身寫的網站可以拿到天氣預報的信息,因而我去www.webxml.com.cn/zh_cn/index…找到了天氣預報的服務
這個是天氣預報的WSDL地址:ws.webxml.com.cn/WebServices…,那麼咱們只要解析該WSDL服務便可
若是不想獲得全部的信息,那麼咱們能夠在服務上找到咱們想要對應的數據,也就是說:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y