一 JAX-WS簡介
1.1 什麼是JAX-WS
JAX-WS的全稱是JavaAPI for XML Web Service,目前流行的版本是JAX-WS 2.1。JAX-WS是用來簡化使用Java構造Web服務和Web服務用戶端的工作的技術。它提供了完整的'Web服務堆棧,可以減少開發和部署Web服務的難度。Java EE 6和JDK l.6.0_17及以上版本都支援JAX-WS 2.1。是以,使用正常的JDK就可以釋出服務端點,這使得Web服務的釋出變得非常簡單。
JAX-WS中內建了JAXB (Java Architecture for XML Binding)。JAXB主要用于将XML映射為Java代碼,便捷地支援資料綁定功能。在我的前一篇博文的介紹中,調用者和已釋出的Web服務之間通過SOAP傳遞資料,是以,通過JAX.B,開發者不需要自己将SOAP消息中的XML模式的消息轉換為Java代碼,也不必全面了解XML和SOAP解析,這使得Web服務的開發變得異常簡單。下面通過一個具體的示例來說明JAX-WS如何使用。
1.2 使用JAX-WS釋出天氣預報服務
某網站要釋出一個Web服務,主要提供全國各地的天氣預報資訊,包括最高氣溫、最低氣溫、平均氣溫、天氣描述(如晴、陰、多雲等)。該服務允許使用者查詢近3天的天氣狀況。
要釋出一個Web服務供第三方來使用,我們可以通過JAX-WS來完成。開發Web服務的基本思路是,設計并實作提供的服務接口,然後将服務接口“暴露”出去。下面就逐漸完成天氣預報服務的釋出。
1.設計并實作服務接口
針對天氣預報服務,我們提供使用者可以針對城市和日期查詢具體的天氣的服務,因為允許查詢近3天的天氣狀況,是以,接口設計如示例1所示。
示例1
@WebService(targetNamespace ="http://www.mytest.cn/ws/weather")
public interface WeatherService {
@WebMethod
List<TemperatureInfo>getWeathers(String city, List<Date> dates);
}
示例1中定義WeatherService接口,在該接口中提供的方法為getWeathers(),該方法允許傳人String類型參數city和List<Date>類型日期清單dates。傳回的結果是一個由Temperaturelnfo對象組成的List。具體的實作如示例2所示。
示例2
@WebService(targetNamespace ="http://www.mytest.cn/ws/weather")
public class WeatherServiceImpl implementsWeatherService {
@WebMethod(operationName= "getWeathers")
publicList<TemperatureInfo> getWeathers(String city, List<Date> dates) {
List<TemperatureInfo>list = new ArrayList<TemperatureInfo>();
for(Date date : dates) {
list.add(getTemperature(city,date));
}
returnlist;
}
@WebMethod(exclude= true)
publicTemperatureInfo getTemperature(String city, Date date) {
//模拟根據城市和日期擷取天氣資訊
returnnew TemperatureInfo(city, date, 28, 33, 31, "晴");
}
}
實體類Temperaturelnfo如何定義呢?如示例3所示。
示例3
@XmlRootElement(name ="TemperatureInfo")
public class TemperatureInfo {
//城市
privateString city;
//日期
privateDate date;
//最低溫度
privateint min;
//最高溫度
privateint max;
//平均氣溫
privateint average;
//描述
privateString desc;
//省略getter和setter方法
}
WeatherServiceImpl類提供了天氣預報的具體實作。到現在為止,已經實作了天氣預報服務,如果在同一個應用程式(或系統)中,我們可以輕松地調用該服務,但是如果我們希望其他的遠端應用程式也能夠像調用本地服務一樣調用這個天氣服務,應該怎麼辦呢?、下面就需要利用注解,将需要“暴露”的服務辨別出來。注解描述如何将伺服器端的服務實作作為Web服務來通路或者用戶端的Java類如何通路Web服務,在示例l和示例2中,我們使用了@WebService和@WebMethod來完成這項工作。
@javax.jws.WebService注解,辨別一個Java類或一個Java接口作為一個VVeb服務。一旦标注了@WebService,它就不再是一個普通的接口,它被稱為服務端點接口(Service Endpoint Interface)。當然,也可以僅僅在Java類中通過@WebService來進行辨別。@WebService注解有一系列屬性,用來設定Web服務的較長的描述資訊;包括:在示例l和示例2一-已使用的targetNamespace屬性,用來設定目标命名空間;serviceName屬性設定服務名;portName屬性設定端口名(Endpoint的名稱)等。
● 問題:設定屬性和不設定屬性的差別是什麼?
● 解答:注解用來辨別服務,在服務釋出時會産生WSDL檔案。如果不通過屬性具體描述要釋出的服務,在WSDL檔案中都是系統預設自動添加的資訊;如果通過屬性進行描述,WSDL檔案中就是屬性自定義的資訊,如服務名等。
盡管注解的屬性不是必須設定,但是,為了保證名稱的可讀性和釋出服務的正确性,建議設定targetNamespace屬性、serviceName屬性和portName屬性。
預設情況下,@WebService注解後的類的所有公共方法都會在WSDL檔案中被“暴露”出去,是以,需要通過@javax.jws.WebMethod進行标注。@WebMethod允許通過operationName設定釋出方法的名稱,如@WebMethod(operationName=”getWeathers”)。另外,在示例2中,公共方法getTemperature()不希望被暴露,是以,通過設定exclude屬性為true來實作。
在示例3中,對于實體類Tem peraturelnfo使用了@XmIRootElement注解。該注解是JAXB注解。JAXB提供了從XMLSchema到Java類的轉換機制。示例3中,@XmIRootElement注解映射Java類Temperaturelnfo到XML的根元素。在Temperatruelnfo類中的屬性預設映射為XML中的元素,即@XmIElement。@XmIRootElement和@XmlElement注解允許開發者定義XML元素的命名空間(通過namespace屬性)和名字(通過name屬性)。如果沒有特别的定義,JAXB運作時會預設使用類的名稱和類屬性的名稱作為XML元素的名稱。
除此之外,還有其他的注解,包括@WebResult和@WebParam等,若感興趣可以深入學習。
2.釋出天氣服務
在完成服務的開發之後,如何将其釋出出去昵?通過JAX-WS來釋出Web服務,最簡單的方式是通過Endpoint.publish()方法。具體如示例4所示。
示例4
public class Server {
//釋出服務
protectedServer() throws Exception {
System.out.println("啟動服務");
WeatherServiceImplweatherServiceImpl = new WeatherServiceImpl();
Stringaddress = "http://localhost:8084/WeatherService";
Endpoint.publish(address,weatherServiceImpl);
}
publicstatic void main(String args[]) throws Exception {
newServer();
System.out.println("服務準備就緒...");
Thread.sleep(2* 60 * 1000);
System.out.println("服務退出...");
System.exit(0);
}
}
示例4中,通過javax.xml.ws.Endpoint的API publish()方法來釋出Web服務,該方法接收兩個參數,分别是需要釋出的服務類和服務要釋出的位置。publish()方法預設使用一個輕量級的HTTP伺服器,該伺服器對應com.sun.net.httpserver類。
示例4中将天氣服務釋出出去了,是以,我們可以通過通路該位址來請求服務。在浏覽器中輸入http://localhost:8084/WeatherService?wsdl可以看到生成的WSDL檔案,如圖9所示。

成功生成了WSDL檔案,表示我們的天氣服務已經釋出成功了。其他應用程式就可以通路我們釋出的Web服務了。
1.2.3 使用JAX-WS調用服務
在http://localhost:8084/WeatherService釋出了一個Web服務,調用Web服務,并輸出天氣資訊。
有了Web服務,下面如何來調用它呢?對于調用Web服務的應用程式而言,可以得到的隻有WSDL檔案及描述資料類型的XSD (XMLSchema'Definition,XML結構定義)1檔案,如圖所示,通過通路http://localhost:8084/WeatherService?xsd=l進行檢視。
用戶端調用Web服務,需要基于XSD檔案和WSDL檔案來完成。它的實作原理如圖所示。
如圖所示,通過JAX-WS,開發人員可以像調用本地服務一樣調用一個遠端服務。當用戶端通過代理(Proxy)調用一個方法時,它将方法的參數轉換為SOAP消息,作為請求發送到伺服器端,即Web Service Endpoint。當收到傳回結果時,用戶端通過代理将SOAP轉換為傳回類型的執行個體對象。是以,服務端代理幫助我們完成了所有的工作,我們需要做的就是建立Service Endpoint Interface(SEI)來獲得代理類。
=========================================================
二 具體案例:
sql腳本
CREATE TABLE WeatherTable
(
weatherId INT PRIMARY KEY AUTO_INCREMENT,
weatherDate DATE NOT NULL,
city VARCHAR(50) NOT NULL,
minDegrees DOUBLE,
maxDegrees DOUBLE,
avgDegrees DOUBLE,
weatherDesc VARCHAR(50)
);
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-02','長沙',5,12,8,'晴');
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-03','長沙',4,11,7,'陰天');
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-04','長沙',3,10,6,'小雨');
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-02','株洲',5,12,8,'晴轉多雲');
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-03','株洲',4,11,7,'陰有小雨');
INSERT INTO WeatherTable(weatherDate,city,minDegrees,maxDegrees,avgDegrees,weatherDesc)
VALUES('2016-01-04','株洲',3,10,6,'小雨轉陰天');
實體類WeatherEntity.java
package com.obtk.entitys;
import java.io.Serializable;
public class WeatherEntity implements Serializable{
private static final long serialVersionUID = 2343174111180306664L;
private Integer weatherId;
private String city;
private String weatherDate;
private double minDegrees;
private double maxDegrees;
private double avgDegrees;
private String weatherDesc;
public Integer getWeatherId() {
return weatherId;
}
public void setWeatherId(Integer weatherId) {
this.weatherId = weatherId;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getWeatherDate() {
return weatherDate;
}
public void setWeatherDate(String weatherDate) {
this.weatherDate = weatherDate;
}
public double getMinDegrees() {
return minDegrees;
}
public void setMinDegrees(double minDegrees) {
this.minDegrees = minDegrees;
}
public double getMaxDegrees() {
return maxDegrees;
}
public void setMaxDegrees(double maxDegrees) {
this.maxDegrees = maxDegrees;
}
public double getAvgDegrees() {
return avgDegrees;
}
public void setAvgDegrees(double avgDegrees) {
this.avgDegrees = avgDegrees;
}
public String getWeatherDesc() {
return weatherDesc;
}
public void setWeatherDesc(String weatherDesc) {
this.weatherDesc = weatherDesc;
}
}
mybatis映射檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.obtk.dao.WeatherDao">
<select id="getWeather" parameterType="map" resultType="weatherEntity">
select * from WeatherTable where weatherDate=#{weatherDate} and city=#{city}
</select>
</mapper>
接口
package com.obtk.dao;
import java.util.HashMap;
import java.util.Map;
import com.obtk.entitys.WeatherEntity;
public interface WeatherDao {
WeatherEntity getWeather(Map parmaMap);
}
服務類
package com.obtk.serv;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
import org.apache.ibatis.session.SqlSession;
import com.obtk.dao.WeatherDao;
import com.obtk.entitys.WeatherEntity;
import com.obtk.utils.MybatisUtil;
@WebService
public class WeatherServ {
public WeatherEntity getWeather(String dateStr,String city){
SqlSession session=null;
Map parmaMap=new HashMap();
parmaMap.put("weatherDate", dateStr);
parmaMap.put("city", city);
WeatherEntity theWeather=null;
try {
session=MybatisUtil.getSession();
WeatherDao weatherDao = session.getMapper(WeatherDao.class);
theWeather=weatherDao.getWeather(parmaMap);
} catch (Exception e) {
e.printStackTrace();
}finally{
MybatisUtil.closeSession();
}
return theWeather;
}
}
釋出服務
package com.obtk.test;
import javax.xml.ws.Endpoint;
import com.obtk.serv.WeatherServ;
public class Mytest {
public static void main(String[] args) {
WeatherServ theServ=new WeatherServ();
//System.out.println(theServ.getWeather("2016-01-03","長沙").getWeatherDesc());
Endpoint.publish("http://192.168.1.105:911/weatherServ", theServ);
System.out.println("服務釋出成功...");
}
}
用戶端的操作請參考我的上一篇博文