WebService開發(C#)+Java呼叫-教程
注:1.本文重點講如何實現
2.本文包括WebService介面開發、JavaWeb呼叫等問題
3.原始碼已提交到github,Webservice介面:https://github.com/Bobo-peng/WebService
JavaWeb呼叫:
一、WebService簡介
1.什麼是WebService?
WebService是一種跨語言、誇平臺的遠端呼叫技術,或者說叫作一種技術標準。之所以叫WebService,是因為和Web服務類似,基於http協議(使用抓包就可以看到是http傳送請求和接收結果),其主要作用在於向外暴露介面。
說直白一點,就是這個技術標準想要達到的目的是:開啟一個服務,並留出介面,讓其他人來呼叫(重點是可以遠端呼叫)。舉例:使用者檢視一個網站的資料,一般就是檢視該網站就完了;但是使用者不喜歡用該網站公司的網頁佈局,想自己做一個炫酷的網頁來展示一下資料,但是獲取不到網站公司的資料庫(資料庫不可能對外公開),這時就用WebService開發幾個介面提供給使用者,這些介面返回使用者想要的資料(資料格式可以自定義,使用json或者xml等),使用者就像調函式一樣間接獲取了想要的資料,然後去開發自己的網頁、展示。
2.WebService介面體驗
看一下常用的WebService介面-天氣預報,這是國家氣象局提供的天氣預報介面:
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx
第一個介面:
不傳引數,返回所以可查詢的城市:
其他的介面可以自己點開根據說明看看。
在連線的後面加上?wsdl
http://www.webxml.com.cn/webservices/weatherwebservice.asmx?wsdl
這個相當於介面的說明檔案,上面有每個介面的介面名稱,介面引數等資訊,通過檢視這個檔案,就知道怎呼叫的時候填什麼引數(後面詳細介紹)。
所以,自己開發一個天氣預報的網站其實很簡單(從這裡呼叫介面即可)。
二、C# 開發WebService介面
這裡用C#開發,是因為剛做了個專案用的是C#,後面呼叫使用Java開發,後面介紹。
1.新建工程
開發環境:VS2013
自動生成一個介面:HelloWorld()
[WebMethod]的意思是向外暴露介面
什麼都不用開發,點選執行:
點選呼叫:返回Hello World
2.新增介面函式
新增一個兩個int型的數相加的函式介面,感受一下:
[WebMethod]
public int Add(int a, int b)
{
return a + b;
}
傳入引數、呼叫:
3.介面返回資料庫資料
為了讓功能更豐富一些,通過介面獲取資料庫的資料。大概步驟是:
(1)介面傳進引數
(2)WebService服務連線收據庫,根據傳入的引數查詢資料庫
(3)將資料封裝成xml返回給使用者
舉例:使用者輸入"Tom"同學的名字,想要查詢他的成績。
為了說明問題,用sqlserver建一張表:
假設資料庫資料是這樣的(沒有實際意義,只說明問題):
目標是將根據Name查詢資料並以Xml的資料格式返回。
首先定義函式介面:
[WebMethod]
public string GetdbData(string Name)
{
//資料庫操作
string strcon = "server = localhost,1433;uid = sa; pwd = 123456; database = MyDataBase";
string strSQL = "select Name,Chinese,Math,English from Student where Name = @name";
SqlConnection con = new SqlConnection(strcon);
SqlCommand cmd = new SqlCommand(strSQL, con);
cmd.Parameters.Add("@name", SqlDbType.VarChar);
cmd.Parameters["@name"].Value = Name;
DataSet ds = new DataSet();
try
{
SqlDataAdapter DA = new SqlDataAdapter(cmd);
DA.Fill(ds, "tb");
}
catch (SqlException E)
{
throw new Exception(E.Message);
}
con.Close();//關閉資料庫
//封裝xml
XDocument xDoc = new XDocument();
//建立一個根節點
XElement root = new XElement("Root");
xDoc.Add(root); //將根節點加入到XML物件中
try
{
for (int i = 0; ds.Tables.Count > 0 && i < ds.Tables[0].Rows.Count; i++)
{
//建立一個子節點
XElement xele = new XElement("Data" + (i + 1).ToString());
root.Add(xele);
for (int j = 0; j < e.Length; j++)
{
xele.SetElementValue(e[j], ds.Tables[0].Rows[i].ItemArray[j]);
}
}
//儲存xml檔案
LogWriteLock.EnterWriteLock();
xDoc.Save(CurrPath + "student.xml");
LogWriteLock.ExitWriteLock();
}
catch (SqlException E)
{
throw new Exception(E.Message);
}
return xDoc.ToString();
}
}
測試:
並儲存為student.xml檔案
查詢的結果和資料庫裡的資料相符合,資料庫有4個Tom,查詢到4個。
這裡的資料庫連線操作可以檢視另外一篇:C# SqlCommand 資料庫連線操作
4.部署服務
開題說了WebService介面可以遠端呼叫,這是它的優勢或者說是主要的功能。首先得把開發好的部署起來,這裡只說明在C#開發,部署在Windows平臺,其他的形式的貨平臺的開發和部署不做講述。
步驟:
(1)開啟IIS: 計算機管理->服務和應用程式->Internet資訊服務(IIS)管理器;
(2)新增網站: 在網站選項上右鍵->新增網站… 。鍵入網站名稱,選擇webservice釋出檔案包的路徑,分配埠,點選確定即可。
(3)設定.NET版本:(開發的時候選的4.0)
(4)開啟目錄瀏覽許可權
緊接著就和除錯的時候一樣了:
三、Java呼叫
1.Java的簡單呼叫
開發環境:Eclipse
新建一個Java工程:
新建一個類:WebServiceTest
Java呼叫WebService需要依賴幾個jar包:
在工程下建一個lib資料夾,將依賴的jar包放進去(依賴包可以下載本文Java工程需要的所有jar包)
然後需要把路徑也需要新增進來:
路徑加進來,圖示和沒加是有區別的:
定義一個方法:public static void GetStudent()
public static void GetStudent()
{
try {
String url ="http://localhost:9999/WebService.asmx";
String namespace = "http://tempuri.org/";
Service service = new Service();
Call call = (Call) service.createCall();
QName qname = new QName(namespace, "GetdbData"); //設定名稱空間和需要呼叫的方法名
call.setOperationName(qname);
call.setTargetEndpointAddress(url);
call.setSOAPActionURI(namespace + "GetdbData");
call.addParameter(new QName(namespace,"Name"), org.apache.axis.encoding.XMLType.XSD_STRING, javax.xml.rpc.ParameterMode.IN);// 介面的引數
call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING);//設定返回型別
String result = (String) call.invoke(new Object[] {"Tom"});
System.out.println("結果: \n" + result);
} catch (Exception e) {
System.err.println(e.toString());
}
}
說明:(1)url是剛才部署的路徑,這裡如果部署在遠端,就填遠端的IP和埠
(2)namespace是C#開發WebService介面時候自動生成的,也可以自己任意修改,兩邊保持一致即可。
(3)"GetdbData"是介面名,"Name"是引數名,"Tom"是引數值,如果沒有引數就不需要call.addParameter這個函式,而invoke函式變為:String result = (String) call.invoke(new Object[] {}); 如果有多個引數,就需要call.addParameter多次,然後
call.invoke(new Object[] {“引數1”,"引數2"}
執行結果:
2.JavaWeb簡單的展示
既然都做到這了,索性做個頁面展示一下。
(1)新建一個Web工程(選擇動態Web工程):
工程名:StudentShow
新建完,工程包含這麼多:
(2)在src下新建一個Class,命名為Student
編寫Get和Set方法:
package com.service.entity;
public class Student {
private String Name;//學生姓名
private String Chinese;//語文
private String Math;//數學
private String English;//英語
public String getName() {
return Name;
}
public void setName(String name) {
this.Name = name;
}
public String getChinese() {
return Chinese;
}
public void setChinese(String chinese) {
this.Chinese = chinese;
}
public String getMath() {
return Math;
}
public void setMath(String math) {
this.Math = math;
}
public String getEnglish() {
return English;
}
public void setEnglish(String english) {
this.English = english;
}
}
(3)再新建一個Class,命名為:StudentService
作用:呼叫WebService介面,解析xml檔案
package com.service;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.service.entity.Student;
public class StudentService {
public List<Student> GetStudentInfo(String Name)
{
List<Student> stulist = new ArrayList<Student>();
try {
String url ="http://localhost:9999/WebService.asmx";
String namespace = "http://tempuri.org/";
Service service = new Service();
Call call = (Call) service.createCall();
QName qname = new QName(namespace, "GetdbData"); //設定名稱空間和需要呼叫的方法名
call.setOperationName(qname);
call.setTargetEndpointAddress(url);
call.setSOAPActionURI(namespace + "GetdbData");
call.addParameter(new QName(namespace,"Name"), org.apache.axis.encoding.XMLType.XSD_STRING, javax.xml.rpc.ParameterMode.IN);// 介面的引數
call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING);//設定返回型別
String result = (String) call.invoke(new Object[] {Name});
System.out.println("結果: \n" + result);
stulist = PreaseXml(result);
}
catch (Exception e) {
System.err.println(e.toString());
}
return stulist;
}
//解析Xml
private List<Student> PreaseXml(String resxml)
{
List<Student> tlist = new ArrayList<Student>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
StringReader sr = new StringReader(resxml);
InputSource is = new InputSource(sr);
Document document = builder.parse(is);
//獲取所有Root所有節點的集合
NodeList rootList = document.getElementsByTagName("Root");
//通過NodeList的getLength()
int rootCnt = rootList.getLength();
for(int i = 0; i < rootCnt; i++){
Node root = rootList.item(i);
NodeList childNodes = root.getChildNodes();
//遍歷childNodes獲取每隔節點的節點名和節點值
for(int j = 1; j < childNodes.getLength();){
Student mlist=new Student();
if(childNodes.item(j).getNodeType() == Node.ELEMENT_NODE){
//獲取節點的節點名
System.out.print("第"+ (j+1) + "節點:"+childNodes.item(j).getNodeName()+" ");
//獲取型別節點的節點值
System.out.println("節點值:" + childNodes.item(j).getTextContent());
mlist.setName(childNodes.item(j).getChildNodes().item(1).getTextContent());
mlist.setChinese(childNodes.item(j).getChildNodes().item(3).getTextContent());
mlist.setMath(childNodes.item(j).getChildNodes().item(5).getTextContent());
mlist.setEnglish(childNodes.item(j).getChildNodes().item(7).getTextContent());
j +=2;
}
tlist.add(mlist);
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return tlist;
}
}
(4)再新建一個Class,命名為:StudentServlet
作用:接收jsp請求
package com.service.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.annotation.WebServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.service.StudentService;
@WebServlet("/StudentServlet")
public class StudentServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 處理響應資料的格式和編碼,通知瀏覽器資料的顯示方式
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println("doGet!");
System.out.println ("doGet1");
String Name=request.getParameter("name");
StudentService ws = new StudentService();
List list = ws.GetStudentInfo(Name);
request.setAttribute("list",list);
request.getRequestDispatcher("/student.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
(5)新建student.jsp檔案,style是從網上找的
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" import="com.service.entity.*,java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>學生資訊</title>
</head>
<body>
<style type="text/css">
table.dataintable {
margin-top:15px;
border-collapse:collapse;
border:1px solid #aaa;
width:100%;
}
table.dataintable th {
vertical-align:baseline;
padding:5px 15px 5px 6px;
background-color:#3F3F3F;
border:1px solid #3F3F3F;
text-align:left;
color:#fff;
}
table.dataintable td {
vertical-align:text-top;
padding:6px 15px 6px 6px;
border:1px solid #aaa;
}
table.dataintable tr:nth-child(odd) {
background-color:#F5F5F5;
}
table.dataintable tr:nth-child(even) {
background-color:#fff;
}
</style>
<form action ="StudentServlet" method="get">
輸入姓名:<input type="text" name="name"/>
<input type="submit" value="查詢" />
</form>
</div>
<table class="dataintable">
<tr>
<th>姓名</th>
<th>語文</th>
<th>數學</th>
<th>英語</th>
</tr>
<c:forEach items="${list}" var="stu">
<tr>
<td><b>${stu.getName()}</b></td>
<td>${stu.getChinese()}</td>
<td>${stu.getMath()}</td>
<td>${stu.getEnglish()}</td>
</tr>
</c:forEach>
</body>
</html>
對於JavaWeb中頁面請求和servlet返回請求結果可以參考Jsp頁面請求-Servlet返回結果
(6)最後的效果: