一、Web Service 平台概述。
Web Service 平台主要涉及的技术有SOAP、WSDL、UDDI。
1.SOAP(简单对象访问协议):
①SOAP是一种具有扩展性的XML消息协议。SOAP消息是从SOAP发送者传至SOAP接收者的单路信息,任何应用程序都可以作为发送者或接收者。SOAP仅定义消息结构和消息处理的协议,与底层的传输协议独立。SOAP协议能通过HTTP、JMS、SMTP协议传输。
②一条SOAP消息就是一份特定的XML文档,SOAP消息包含三个主要元素:
必须的<Envelope.../>根元素,SOAP消息对应的XML文档以该元素为根元素。
可选的<Header..../>元素,包含SOAP消息的头信息。
必须的<Body..../>元素,包含所有的调用和响应信息。
2.WSDL(Web Service描述语言):
①WSDL使用XML描述Web Service,包括访问和使用Web Service所必需的信息,定义Web Service的位置、功能等描述信息。
②一份WSDL文件定义了三个方面的内容:
WHAT部分:定义Web Service所提供的操作(方法)。由WSDL的<types../>、<message../>、<portType../>定义。
HOW部分:定义如何访问Web Service,包括数据格式详情和访问时操作的必要协议。
WHERE部分:定义Web Service的位置,如何使用特定协议决定的网络地址。由<service../>元素定义。
③一份WSDL文档分为两个部分:
第一部分定义了服务接口,由<message../>和<portType../>两个元素组成。<message../>定义了 操作(方法)的交互方式。<portType../>可包含任意数量的<operation../>元素,每个<operation../>代表一个允许远程调用的操作(方法)。
第二部分定义了服务实现,由<binding../>和<service../>两个元素组成。<binding../>定义使用特定的通信协议,数据编码模型和底层通信协议,将Web Service服务接口定义映射到具体实现。<service../>包含一系列的<port../>元素,<port../>将会把绑定机制、服务访问协议和端点地址结合在一起。
WSDL2.0中: <portType../>改为<interface../> 、 <port../>改为<endpoint../>
3.UDDI(统一描述、发现和整合协议):
①UDDI是一套信息注册规范,特点是基于Web和分布式。
②UDDI的核心组件是UDDI的注册中心,它使用XML文件来描述企业及其提供的Web Service。
③UDDI的作用:Web Service提供者通过UDDI注册中心将Web Service的信息加入UDDI的注册中心,该Web Service就可以被Web Service使用者发现和使用。当Web Service使用者找到自己所需的服务后,即可将自己绑定到对应的Web Service提供者上,再根据服务对应的WSDL文档调用对方的服务。
二、Web Service 的使用。
1.下载ksoap2-android项目的JAR包,并将JAR包添加到Android项目的libs目录下。
2.使用ksoap2-android调用Web Service的操作,步骤如下:
①创建HttpTransportSE对象,该对象用于调用Web Service操作。
②创建SoapSerializationEnvelope对象。
③创建SoapObject对象,需要传入所要调用Web Service的命名空间、Web Service方法名。
④若需要传递参数给Web Service服务端,调用SoapObject对象的addProperty(String name,String value)方法设置参数。
⑤调用SoapSerializationEnvelope的setOutputSoapObject()方法,或直接对bodyOut属性赋值,将SoapObject对象设为SoapSerializationEnvelope的传出SOAP消息体。
⑥调用HttpTransportSE对象的call()方法,将SoapSerializationEnvelope对象作为参数调用远程的Web Service。
⑦调用完成后,访问SoapSerializationEnvelope对象的bodyIn属性或者getResponse()方法,该属性返回一个SoapObject对象,代表Web Service的返回消息,解析该对象,即可获取调用Web Service的返回值。
3.天气预报Web Service实现代码。
注意:以下代码可以实现得到省份和城市的功能,但是天气状态gwtWeather()方法一直出现空指针异常,研究了很久不知道为什么,如果有知道的朋友,可以发个评论指导一下,谢谢了!
/**
* WebService工具类
* WebService工具类
*
*/
public class WebServiceUtil {
/**
* Web Service的URL或者URL+"?wsdl" 都可以
* Web Service的服务地址和WSDL文档地址
*/
private static final String SERVICE_URL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx";
// private static final String SERVICE_URL ="http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl";
/**
* Web Service的命名空间
*/
private static final String SERVICE_NS = "http://WebXml.com.cn/";
/**
* 返回省份的集合
*
* @return
*/
public static List<String> getProvinceList() {
/**
* 需要调用的方法名:getRegionProince
* 参数:无。返回值:省份名称与对应的ID,一维字符串数组.
* 格式:Array[0]="上海,31112",英文逗号
*/
final String methodName = "getRegionProvince";
/**
* 封装省份的集合
*/
final List<String> list = new ArrayList<String>();
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
// soapObject.addProperty(name, value);
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
try {
/**
* 调用Web Service 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
ht.call(SERVICE_NS + methodName, envelope);
//第一个方法得到返回的数据
// if(envelope.getResponse()!=null){
// SoapObject response=(SoapObject) envelope.bodyIn;
// SoapObject result =(SoapObject)response.getProperty(methodName+"Result");
//得到每个省份与对应ID
// for(int i=0;i<result.getPropertyCount();i++){
// //省份名称,ID 英文逗号
// String provinceAndId =result.getProperty(i).toString();
// String province =provinceAndId.split(",")[0];
// System.out.println(province);
// list.add(province);
// }
// }
//第二种方法得到返回值
if (envelope.getResponse() != null) {
SoapObject result = (SoapObject) envelope.getResponse();
// 得到每个省份与对应ID
for (int i = 0; i < result.getPropertyCount(); i++) {
// 格式:省份名称,ID 英文逗号
String provinceAndId = result.getProperty(i).toString();
String province = provinceAndId.split(",")[0];
list.add(province);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 返回城市/地区的集合
*
* @param province
* 省份的名称或ID
* @return
*/
public static List<String> getCityList(String province) {
/**
* 需要调用的方法名:getSupportCityString 参数:theRegionCode 类型:字符串。
* 返回值:城市名称与对应的ID,一维字符串数组,Array[0]="长沙,11112",英文逗号
*/
final String methodName = "getSupportCityString";
/**
* 封装城市的集合
*/
final List<String> list = new ArrayList<String>();
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
soapObject.addProperty("theRegionCode", province);
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
try {
/**
* 调用Web Service 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
SoapObject result = (SoapObject) envelope.getResponse();
// 得到每个城市与对应ID
for (int i = 0; i < result.getPropertyCount(); i++) {
// 格式:城市名称,ID 英文逗号
String cityAndId = result.getProperty(i).toString();
String city = cityAndId.split(",")[0];
list.add(city);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 返回所在城市的天气状况SoapObject对象
*
* @param province
* 城市
* @return
*/
public static SoapObject getWeather(String city) {
/**
* 需要调用的方法名:getWeather
* 参数:theCityCode 类型:字符串。
* 参数:theUserID 用户ID,免费用户填写空字符串 theUserID = ""
* 返回值:天气情况,一维字符串数组
*/
final String methodName = "getWeather";
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
soapObject.addProperty("theCityCode", city);
soapObject.addProperty("theUserID", "");
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
/**
* 接收返回信息的SoapObject
*/
SoapObject soap = null;
try {
/**
* 调用Web Service
* 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
System.out.println("here is excute1");
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
System.out.println("here is excute2");
soap = (SoapObject) envelope.getResponse();
System.out.println(soap.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
return soap;
}
}
*/
public class WebServiceUtil {
/**
* Web Service的URL或者URL+"?wsdl" 都可以
* Web Service的服务地址和WSDL文档地址
*/
private static final String SERVICE_URL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx";
// private static final String SERVICE_URL ="http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl";
/**
* Web Service的命名空间
*/
private static final String SERVICE_NS = "http://WebXml.com.cn/";
/**
* 返回省份的集合
*
* @return
*/
public static List<String> getProvinceList() {
/**
* 需要调用的方法名:getRegionProince
* 参数:无。返回值:省份名称与对应的ID,一维字符串数组.
* 格式:Array[0]="上海,31112",英文逗号
*/
final String methodName = "getRegionProvince";
/**
* 封装省份的集合
*/
final List<String> list = new ArrayList<String>();
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
// soapObject.addProperty(name, value);
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
try {
/**
* 调用Web Service 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
ht.call(SERVICE_NS + methodName, envelope);
//第一个方法得到返回的数据
// if(envelope.getResponse()!=null){
// SoapObject response=(SoapObject) envelope.bodyIn;
// SoapObject result =(SoapObject)response.getProperty(methodName+"Result");
//得到每个省份与对应ID
// for(int i=0;i<result.getPropertyCount();i++){
// //省份名称,ID 英文逗号
// String provinceAndId =result.getProperty(i).toString();
// String province =provinceAndId.split(",")[0];
// System.out.println(province);
// list.add(province);
// }
// }
//第二种方法得到返回值
if (envelope.getResponse() != null) {
SoapObject result = (SoapObject) envelope.getResponse();
// 得到每个省份与对应ID
for (int i = 0; i < result.getPropertyCount(); i++) {
// 格式:省份名称,ID 英文逗号
String provinceAndId = result.getProperty(i).toString();
String province = provinceAndId.split(",")[0];
list.add(province);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 返回城市/地区的集合
*
* @param province
* 省份的名称或ID
* @return
*/
public static List<String> getCityList(String province) {
/**
* 需要调用的方法名:getSupportCityString 参数:theRegionCode 类型:字符串。
* 返回值:城市名称与对应的ID,一维字符串数组,Array[0]="长沙,11112",英文逗号
*/
final String methodName = "getSupportCityString";
/**
* 封装城市的集合
*/
final List<String> list = new ArrayList<String>();
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
soapObject.addProperty("theRegionCode", province);
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
try {
/**
* 调用Web Service 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
SoapObject result = (SoapObject) envelope.getResponse();
// 得到每个城市与对应ID
for (int i = 0; i < result.getPropertyCount(); i++) {
// 格式:城市名称,ID 英文逗号
String cityAndId = result.getProperty(i).toString();
String city = cityAndId.split(",")[0];
list.add(city);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 返回所在城市的天气状况SoapObject对象
*
* @param province
* 城市
* @return
*/
public static SoapObject getWeather(String city) {
/**
* 需要调用的方法名:getWeather
* 参数:theCityCode 类型:字符串。
* 参数:theUserID 用户ID,免费用户填写空字符串 theUserID = ""
* 返回值:天气情况,一维字符串数组
*/
final String methodName = "getWeather";
/**
* 获取HttpTransportSE对象
*/
final HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
/**
* 创建SoapObject对象,参数:命名空间和方法名称
*/
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
/**
* 添加参数 若你调用的方法需要参数,则需要添加参数,否则不用添加参数
*/
soapObject.addProperty("theCityCode", city);
soapObject.addProperty("theUserID", "");
/**
* 使用SOAP1.1协议创建SoapSerializationEnvelope对象
*/
final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
/**
* 设置传出的SOAP消息体,以下两个方式都可以
*/
// envelope.bodyOut=soapObject;
envelope.setOutputSoapObject(soapObject);
/**
* 设置与.NET提供的Web Service保持较好的兼容
*/
envelope.dotNet = true;
/**
* 接收返回信息的SoapObject
*/
SoapObject soap = null;
try {
/**
* 调用Web Service
* 第一个参数:命名空间+方法名称
* 第二个参数:SoapSerializationEnvelope对象
*/
System.out.println("here is excute1");
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
System.out.println("here is excute2");
soap = (SoapObject) envelope.getResponse();
System.out.println(soap.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
return soap;
}
}
/**
* 主Activity
*/
public class MainActicity extends Activity {
private Spinner provinceSp;
private Spinner citySp;
private MyAdapter adapter;
private List<String> provinceList;
private List<String> cityList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
provinceSp = (Spinner) findViewById(R.id.provinceSp);
citySp = (Spinner) findViewById(R.id.citySp);
ProvinceAsyncTask task = new ProvinceAsyncTask();
task.execute();
provinceSp.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
String province = provinceList.get(position);
CityAsyncTask task=new CityAsyncTask();
task.execute(province);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
citySp.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
String city=cityList.get(position);
WeatherAsyncTask task=new WeatherAsyncTask();
task.execute(city);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
/**
* 得到省份的异步类
*/
class ProvinceAsyncTask extends AsyncTask<Void, Void, List<String>> {
@Override
protected List<String> doInBackground(Void... params) {
provinceList = WebServiceUtil.getProvinceList();
return provinceList;
}
@Override
protected void onPostExecute(List<String> result) {
if (result != null) {
adapter = new MyAdapter(result, MainActicity3.this);
provinceSp.setAdapter(adapter);
}
}
}
/**
*得到城市的异步类
*/
class CityAsyncTask extends AsyncTask<String, Void, List<String>> {
@Override
protected List<String> doInBackground(String... params) {
cityList = WebServiceUtil.getCityList(params[0]);
return cityList;
}
@Override
protected void onPostExecute(List<String> result) {
if (result != null) {
adapter = new MyAdapter(result, MainActicity3.this);
citySp.setAdapter(adapter);
}
}
}
/**
*得到天气状况的异步类
*/
class WeatherAsyncTask extends AsyncTask<String, Void, SoapObject> {
@Override
protected SoapObject doInBackground(String... params) {
SoapObject soap = WebServiceUtil.getWeather(params[0]);
if(soap==null){
System.out.println("here is execute");
}
return soap;
}
@Override
protected void onPostExecute(SoapObject soap) {
if (soap != null) {
}
}
}
}
/**
*布局文件
*/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="省份:"/>
<Spinner
android:id="@+id/provinceSp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="城市:"/>
<Spinner
android:id="@+id/citySp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="省份:"/>
<Spinner
android:id="@+id/provinceSp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="城市:"/>
<Spinner
android:id="@+id/citySp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"/>
</LinearLayout>
</LinearLayout>