随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)
一、概念:Web Service用于消除不同平台、不同语言之间的实现差异,将现有的应用程序发布成开放式服务,从而允许互联网上任何地方、任何平台、任何语言的应用程序来访问该服务。对于Web Service的使用者而言,不管使用何种操作平台、何种编程语言,只要权限允许,都可以调用Web Service,至于Web Service底层是使用什么样的技术实现的对使用者是完全透明的。
二、Web Service特征:
1、自包含性:Web Service是自包含的,Web Service使用者无须安装任何附加软件,只要一种支持Web和XML的编程语言即可;Web Service服务提供者则只需要Web服务器和SOAP服务器。
2、自描述性:Web Service是自描述的,客户端和服务器都无须关心除请求和响应消息的内容和格式之外的任何内容,消息格式与消息内容一起传播,无须外部程序辅助。
2、封装性:Web Service是一种部署在Web应用上的对象,具备良好的封装性。对使用者而言,仅能看到服务描述,而该服务的具体实现、运行平台都是透明的,调用者无须关心,也无法关心。Web Service作为整体提供服务。
3、可编程性:Web Service并不提供图形用户界面,而是提供编程访问的API,Web Service调用者只需知道Web服务器的API接口,即可使用任何平台上的、任何编程语言来调用Web Service。
4、松散耦合:当Web Service的实现发生改变时,调用者无法感受到这种变化。对调用者而言,只要服务实现的接口没有变化,具体实现的改变是完全透明的。
5、高度的平台性:Web Service可以与其他的Web Service进行交互,具有语言和平台无关性,支持CORBA,EJB,DCOM等多种组件标准,支持各种通信协议如:HTTP,SMTP,FTP和RMI等。
6、使用标准协议:Web Service所有的公共协议都使用标准协议描述、传输和交换,这些标准协议在各种平台上完全相同。使用Web Service完全可以在不同供应商之间实现互操作。
7、高度的整合能力:由于Web Service采用简单的、易理解的标准Web协议作为通信协议,完全屏蔽了不同平台的差异,无论CORBA,EJB还是DCOM,都可以通过这种标准的协议进行互操作,实现系统的最高可整合性。
三、优势:
Web Service与其他网络集成技术相比,其优势在于:
1、Web Service使用SOAP作为基本的通信协议,更加简单、易用。
2、Web Service采用已经广泛使用的技术和协议,如XML、HTTP等,因此Web Service更容易掌握。
四、实例:
注:需要引入ksoap2-android-assembly-3.0.0-jar-with-dependencies.jar
下面通过调用http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx站点的提供的Web Service来实现天气预报功能,代码如下:
Activity:
package com.home.activity;
import java.util.ArrayList;
import java.util.List;
import org.ksoap2.serialization.SoapObject;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.home.util.WebServiceUtil;
import com.home.weatherforecast.R;
public class MyWeatherActivity extends Activity {
// 显示省份的列表
private Spinner provinceSpinner;
// 显示城市的列表
private Spinner citySpinner;
private TextView todayWeatherText;
private TextView tomorrowWeatherText;
private TextView afterdayWeatherText;
private TextView currentWeatherText;
private Handler handler;
// 省份集合
private List<String> provinces = new ArrayList<String>();
// 城市集合
private List<String> cities = new ArrayList<String>();
private SoapObject detail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
init();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
if (provinces != null) {
ArrayAdapter adapter = new ArrayAdapter(
MyWeatherActivity.this,
android.R.layout.simple_dropdown_item_1line,
provinces);
// 使用Spinner显示省份列表
provinceSpinner.setAdapter(adapter);
} else {
Toast.makeText(MyWeatherActivity.this, "网络异常",
Toast.LENGTH_SHORT).show();
}
}
if (msg.what == 2) {
if (cities != null) {
ArrayAdapter cityAdapter = new ArrayAdapter(
MyWeatherActivity.this,
android.R.layout.simple_dropdown_item_1line,
cities);
// 使用Spinner 显示城市列表
citySpinner.setAdapter(cityAdapter);
} else {
Toast.makeText(MyWeatherActivity.this, "网络异常",
Toast.LENGTH_SHORT).show();
}
}
if (msg.what == 3) {
String todayWeather = null;
String tomorrowWeather = null;
String afterdayWeather = null;
String currentWeather = null;
// 获取天气实况
currentWeather = detail.getProperty(4).toString();
int index = currentWeather.indexOf(":");
// 从实况天气中截取出提示信息
String prompt = currentWeather.substring(0, index + 1);
// 从实况天气中截取出天气内容
String content = currentWeather.substring(index + 1);
String newCurrentWeather = prompt + "\n" + content;
// 解析今天的天气情况
String date = detail.getProperty(7).toString();
todayWeather = "今天:" + date.split(" ")[0];
todayWeather = todayWeather + "\n天气:" + date.split(" ")[1];
todayWeather = todayWeather + "\n气温:"
+ detail.getProperty(8).toString();
todayWeather = todayWeather + "\n风力:"
+ detail.getProperty(9).toString() + "\n";
// 解析明天的天气情况
date = detail.getProperty(12).toString();
tomorrowWeather = "明天:" + date.split(" ")[0];
tomorrowWeather = tomorrowWeather + "\n天气:"
+ date.split(" ")[1];
tomorrowWeather = tomorrowWeather + "\n气温:"
+ detail.getProperty(13).toString();
tomorrowWeather = tomorrowWeather + "\n风力:"
+ detail.getProperty(14).toString() + "\n";
// 解析后天的天气情况
date = detail.getProperty(17).toString();
afterdayWeather = "后天:" + date.split(" ")[0];
afterdayWeather = afterdayWeather + "\n天气:"
+ date.split(" ")[1];
afterdayWeather = afterdayWeather + "\n气温:"
+ detail.getProperty(18).toString();
afterdayWeather = afterdayWeather + "\n风力:"
+ detail.getProperty(19).toString() + "\n";
// 更新当天的天气实况
currentWeatherText.setText(newCurrentWeather);
// 更新今天天气
todayWeatherText.setText(todayWeather);
// 更新明天天气
tomorrowWeatherText.setText(tomorrowWeather);
// 更新后天天气
afterdayWeatherText.setText(afterdayWeather);
}
}
};
new Thread() {
public void run() {
// 调用远程WebService获取省份列表
provinces = WebServiceUtil.getProvinceList();
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
}.start();
// 当省份Spinner的选择项改变时
provinceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
new Thread() {
public void run() {
// 调用远程WebService根据省份获取城市列表
cities = WebServiceUtil
.getCityListByProvince(provinceSpinner
.getSelectedItem().toString());
Message msg = new Message();
msg.what = 2;
handler.sendMessage(msg);
}
}.start();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
// 当城市Spinner的选择项被改变时
citySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// 根据城市获取天气信息
showWeather(citySpinner.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
/**
* 获取界面组件
*/
private void init() {
todayWeatherText = (TextView) findViewById(R.id.main_tv_weather_today);
tomorrowWeatherText = (TextView) findViewById(R.id.main_tv_weather_tomorrow);
afterdayWeatherText = (TextView) findViewById(R.id.main_tv_weather_afterday);
currentWeatherText = (TextView) findViewById(R.id.main_tv_weather_current);
provinceSpinner = (Spinner) findViewById(R.id.main_sp_province);
citySpinner = (Spinner) findViewById(R.id.main_sp_city);
}
/**
* 根据城市获取天气信息
*
* @param city
* 城市
*/
private void showWeather(final String city) {
new Thread() {
public void run() {
// 获取远程WebService返回的对象
detail = WebServiceUtil.getWeatherByCity(city);
Message msg = new Message();
msg.what = 3;
handler.sendMessage(msg);
}
}.start();
}
}
访问WebService的工具类(WebServiceUtil):
package com.home.util;
import java.util.ArrayList;
import java.util.List;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
public class WebServiceUtil {
// 定义WebService的命名空间
static final String SERVICE_NS = "http://WebXml.com.cn/";
// 定义WebService提供服务的URL
static final String SERVICE_URL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx";
/**
* 调用远程WebService获取省份列表
*
* @return List 省份列表
*/
public static List<String> getProvinceList() {
// 调用的方法
String methodName = "getRegionProvince";
// 创建HttpTransportSE传输对象
HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
// 使用SOAP1.1协议创建Envelope对象
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
// 实例化SoapObject对象
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
// 将SoapObject对象设置为SoapSerializationEnvelope对象的传出SOAP消息
envelope.bodyOut = soapObject;
// 设置与.NET提供的WebService保持较好的兼容性
envelope.dotNet = true;
try {
// 调用WebService
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
// 获取服务器响应返回的SOAP消息
SoapObject result = (SoapObject) envelope.bodyIn;
SoapObject detail = (SoapObject) result.getProperty(methodName
+ "Result");
// 解析服务器响应的SOAP消息
return parseProvinceOrCity(detail);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 根据省份获取城市列表
*
* @param province
* @return List 城市列表
*/
public static List<String> getCityListByProvince(String province) {
// 调用的方法
String methodName = "getSupportCityString";
// 创建HttpTransportSE传输对象
HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
// 实例化SoapObject对象
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
// 添加一个请求参数
soapObject.addProperty("theRegionCode", province);
// 使用SOAP1.1协议创建Envelope对象
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.bodyOut = soapObject;
// 设置与.NET提供的WebService保持较好的兼容性
envelope.dotNet = true;
try {
// 调用WebService
ht.call(SERVICE_NS + methodName, envelope);
if (envelope.getResponse() != null) {
// 获取服务器响应返回的SOAP消息
SoapObject result = (SoapObject) envelope.bodyIn;
SoapObject detail = (SoapObject) result.getProperty(methodName
+ "Result");
// 解析服务器响应的SOAP消息
return parseProvinceOrCity(detail);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解析服务器响应的SOAP消息
*
* @param detail
* SOAP消息
* @return List
*/
private static List<String> parseProvinceOrCity(SoapObject detail) {
ArrayList<String> result = new ArrayList<String>();
for (int i = 0; i < detail.getPropertyCount(); i++) {
// 解析出每个省份
result.add(detail.getProperty(i).toString().split(",")[0]);
}
return result;
}
/**
* 根据城市获取天气状况
*
* @param cityName
* 城市名称
* @return SoapObject
*/
public static SoapObject getWeatherByCity(String cityName) {
String methodName = "getWeather";
HttpTransportSE ht = new HttpTransportSE(SERVICE_URL);
ht.debug = true;
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
SoapObject soapObject = new SoapObject(SERVICE_NS, methodName);
soapObject.addProperty("theCityCode", cityName);
envelope.bodyOut = soapObject;
// 设置与.NET提供的WebService保持较好的兼容性
envelope.dotNet = true;
try {
ht.call(SERVICE_NS + methodName, envelope);
SoapObject result = (SoapObject) envelope.bodyIn;
SoapObject detail = (SoapObject) result.getProperty(methodName
+ "Result");
return detail;
} catch (Exception e) {
}
return null;
}
}
布局XML:
<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请选择省份:"
android:textSize="20dp" />
<!-- 让用户选择省份的Spinner -->
<Spinner
android:id="@+id/main_sp_province"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请选择城市:"
android:textSize="20dp" />
<!-- 让用户选择城市的Spinner -->
<Spinner
android:id="@+id/main_sp_city"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 显示今天天气的文本框 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/main_tv_weather_today"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 显示明天天气的文本框 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/main_tv_weather_tomorrow"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 显示后天天气的文本框 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/main_tv_weather_afterday"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 显示当前天气的文本框 -->
<TextView
android:id="@+id/main_tv_weather_current"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
附上图片效果: