WebService——WebService详解
目录
- WebService
- 1、概述
- 2、Java WebService规范
- 2.1、JAX-WS
- 2.2、JAXM&SAAJ
- 2.3、JAX-RS
- 3、服务端实现(JAX-WS)
- 4、WSDL
- 5、UDDI
- 6、实现客户端
- 6.1、wsimport生成客户端(JAX-WS)
- 6.2、Service编程调用(JAX-WS)
- 6.3、HttpURLConnection调用
- 6.4、HttpClient调用
- 6.5、Hutool工具包调用
- 7、注解描述WSDL
WebService
1、概述
Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。
简单的说,WebService就是一种跨编程语言和跨操作系统平台的远程调用技术。所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然。跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。 远程调用,就是一台计算机的应用可以调用其他计算机上的应用。例如:支付宝,支付宝并没有银行卡等数据,它只是去调用银行提供的接口来获得数据。还有天气预报等,也是气象局把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能。
WebService原理:
XML,SOAP和WSDL就是构成WebService平台的三大技术 。
- WebService采用Http协议来在客户端和服务端之间传输数据。WebService使用XML来封装数据,XML主要的优点在于它是跨平台的。
- WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议规定的。
- WebService服务器端首先要通过一个WSDL文件来说明自己有什么服务可以对外调用。简单的说,WSDL就像是一个说明书,用于描述WebService及其方法、参数和返回值。 WSDL文件保存在Web服务器上,通过一个url地址就可以访问到它。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。
2、Java WebService规范
Java 中共有三种WebService 规范,分别是JAXM&SAAJ、JAX-WS(JAX-RPC)、JAX-RS。
2.1、JAX-WS
JAX-WS (JavaTM API for XML-Based Web Services) 规范是一组 XML web services 的 JAVA API。JAX-WS 允许开发者可以选择 RPC-oriented 或者 message-oriented 来实现自己的 web services。
在 JAX-WS 中,一个远程调用可以转换为一个基于 XML 的协议例如 SOAP。在使用 JAX-WS 过程中,开发者不需要编写任何生成和处理 SOAP 消息的代码。JAX-WS 的运行时实现会将这些 API 的调用转换成为对应的 SOAP 消息。
在服务器端,用户只需要通过 Java 语言定义远程调用所需要实现的接口 SEI (service endpoint interface),并提供相关的实现,通过调用 JAX-WS 的服务发布接口就可以将其发布为 WebService 接口。
在客户端,用户可以通过 JAX-WS 的 API 创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。
当然 JAX-WS 也提供了一组针对底层消息进行操作的 API 调用,你可以通过 Dispatch 直接使用 SOAP 消息或 XML 消息发送请求或者使用 Provider 处理 SOAP 或 XML 消息。
通过 web service 所提供的互操作环境,我们可以用 JAX-WS 轻松实现 JAVA 平台与其他编程环境 (.net 等) 的互操作。
JAX-WS 与 JAX-RPC 之间的关系:
Sun 最开始的 web services 的实现是 JAX-RPC 1.1 (JSR 101)。这个实现是基于 Java 的 RPC, 并不完全支持 schema 规范,同时没有对 Binding 和 Parsing 定义标准的实现。
JAX-WS2.0 (JSR 224) 是 Sun 新的 web services 协议栈,是一个完全基于标准的实现。在 binding 层,使用的是 the Java Architecture for XML Binding (JAXB, JSR 222),在 parsing 层,使用的是 the Streaming API for XML (StAX, JSR 173),同时它还完全支持 schema 规范。
2.2、JAXM&SAAJ
JAXM(JAVA API For XML Message)主要定义了包含了发送和接收消息所需的API,相当于Web 服务的服务器端,其API 位于javax.messaging.*包,它是Java EE 的可选包,因此你需要单独下载。
SAAJ(SOAP With Attachment API For Java,JSR 67)是与JAXM 搭配使用的API,为构建SOAP 包和解析SOAP 包提供了重要的支持,支持附件传输,它在服务器端、客户端都需要使用。这里还要提到的是SAAJ 规范,其API 位于javax.xml.soap.*包。
JAXM&SAAJ 与JAX-WS 都是基于SOAP 的Web 服务,相比之下JAXM&SAAJ 暴漏了SOAP更多的底层细节,编码比较麻烦,而JAX-WS 更加抽象,隐藏了更多的细节,更加面向对象,实现起来你基本上不需要关心SOAP 的任何细节。那么如果你想控制SOAP 消息的更多细节,可以使用JAXM&SAAJ。
2.3、JAX-RS
JAX-RS 是JAVA 针对REST(Representation State Transfer)风格制定的一套Web 服务规范,由于推出的较晚,该规范(JSR 311,目前JAX-RS 的版本为1.0)并随JDK1.6 一起发行。
基于JAX-RS实现的框架有Jersey,RESTEasy等。这两个框架创建的应用可以很方便地部署到Servlet 容器中,比如Tomcat,JBoss等。值得一提的是RESTEasy是由JBoss公司开发的,所以将用RESTEasy框架实现的应用部署到JBoss服务器上,可以实现很多额外的功能。
3、服务端实现(JAX-WS)
编写SEI(Service Endpoint Interface),SEI在webservice中称为portType,在java中就是普通接口:
public interface UserService { public String sayHi(String name); public String work(String work); public User getUser(User user); }
public class User { private int id; private String name; private Date birthday; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", birthday=" + birthday + '}'; } }
编写SEI实现类,此类作为webservice提供服务类:
//@WebService表示该类是一个服务类,需要发布其中的public方法 @WebService public class UserServiceImpl implements UserService { @Override public String sayHi(String name) { return "Hi, " + name; } @Override public String work(String work) { return "He is working " + work; } @Override public User getUser(User user) { user.setName(user.getName() + "-service"); return user; } }
发布服务,Endpoint类发布服务,publish方法,两个参数:
- 服务地址;
- 服务实现类;
public class Server { public static void main(String[] args) { //发布WebService String wsAddress = "http://localhost:8888/demo/ws"; Endpoint endpoint = Endpoint.publish(wsAddress, new UserServiceImpl()); System.out.println("webservice发布成功:" + endpoint.isPublished()); } }
测试服务是否发布成功,通过阅读wsdl,确定客户端调用的接口、方法、参数和返回值存在,证明服务发布成功:
//浏览器输入 http://localhost:8888/demo/ws?wsdl 来获取wsdl文件进行阅读 //wsdl,是以XML文件形式来描述WebService的”说明书”,有了说明书,我们才可以知道如何使用或是调用这个服务.
4、WSDL
WSDL(Web Services Description Language), web服务描述语言,他是webservice服务端使用说明书,说明服务端接口、方法、参数和返回值,WSDL是随服务发布成功,自动生成,无需编写。
文档结构:
- Service:相关端口的集合,包括其关联的接口、操作、消息等
- Binding:特定端口类型的具体协议和数据格式规范
- portType:服务端点,描述 web service可被执行的操作方法,以及相关的消息,通过binding指向portType
- message:定义一个操作(方法)的数据参数
- types:定义 web service 使用的全部数据类型
阅读方式:
- 先看service标签,看相应port的binding属性,然后通过值查找上面的binding标签。
- 通过binding标签可以获得具体协议等信息,然后查看binding的type属性
- 通过binding的type属性,查找对应的portType,可以获得可操作的方法和参数、返回值等。
- 通过portType下的operation标签的message属性,可以向上查找message获取具体的数据参数信息。
5、UDDI
UDDI 是一种目录服务,企业可以使用它对 Web services 进行注册和搜索。
如果我们要使用一种服务,但是不知道地址(wsdl等),我们就可以在UDDI中查找。 大部分情况下,我们都是知道服务地址的。
6、实现客户端
可以使用以下几种方式调用Web Service接口:
- JAX-WS:Java API for XML Web Services,是Java SE 6及以上版本中自带的Web Service框架。通过JAX-WS API,可以使用Java注解方式定义Web Service接口,并使用Java SE自带的wsimport工具生成客户端代码,调用Web Service接口。
- Apache Axis2:是一个基于Java的Web Service框架。通过Axis2,可以使用WSDL文件生成客户端代码,调用Web Service接口。
- Apache CXF:也是一个基于Java的Web Service框架。通过CXF,可以使用Java注解方式定义Web Service接口,并使用CXF自带的wsdl2java工具生成客户端代码,调用Web Service接口。
- Spring Web Services:是一个基于Spring框架的Web Service框架。通过Spring Web Services,可以使用Java注解方式定义Web Service接口,并使用Spring自带的wsdl2java工具生成客户端代码,调用Web Service接口。
- Java自带的HttpURLConnection类:可以使用Java自带的HttpURLConnection类发送SOAP消息,并解析响应消息,实现Web Service的调用。
- 使用框架封装的方式:例如,使用Spring框架的WebServiceTemplate类,可以简化Web Service的调用过程,并提供更高层次的抽象。
- Apache HttpClient:是一个开源的HTTP客户端库,可以用于发送SOAP消息,并解析响应消息,实现Web Service的调用。
- Hutool:是一个Java工具包,其中包含了很多方便实用的工具类和方法,其中也包括了调用Web Service接口的相关工具类,例如SoapClient和HttpSoapClient。
6.1、wsimport生成客户端(JAX-WS)
该种方式使用简单,但一些关键的元素在代码生成时写死在生成代码中,不方便维护,所以仅用于测试。
wsimport是jdk自带的webservice客户端工具,可以根据wsdl文档生成客户端调用代码(java代码)位于JAVA_HOME/bin目录下。
语法:
wsimport [options]
可用选项如下:
-b 指定 jaxws/jaxb 绑定文件或附加模式 (每个 都必须具有自己的 -b) -B 将此选项传递给 JAXB 模式编译器 -catalog 指定用于解析外部实体引用的目录文件 支持 TR9401, XCatalog 和 OASIS XML 目录格式。 -d 指定放置生成的输出文件的位置 -encoding 指定源文件所使用的字符编码 -extension 允许供应商扩展 - 不按规范 指定功能。使用扩展可能会 导致应用程序不可移植或 无法与其他实现进行互操作 -help 显示帮助 -httpproxy:: 指定 HTTP 代理服务器 (端口默认为 8080) -keep 保留生成的文件 -p 指定目标程序包 -quiet 隐藏 wsimport 输出 -s 指定放置生成的源文件的位置 -target 按给定的 JAXWS 规范版本生成代码 默认为 2.2, 接受的值为 2.0, 2.1 和 2.2 例如, 2.0 将为 JAXWS 2.0 规范生成兼容的代码 -verbose 有关编译器在执行什么操作的输出消息 -version 输出版本信息 -wsdllocation @WebServiceClient.wsdlLocation 值 -clientjar 创建生成的 Artifact 的 jar 文件以及 调用 Web 服务所需的 WSDL 元数据。 -generateJWS 生成存根 JWS 实现文件 -implDestDir 指定生成 JWS 实现文件的位置 -implServiceName 生成的 JWS 实现的服务名的本地部分 -implPortName 生成的 JWS 实现的端口名的本地部分 \扩展: -XadditionalHeaders 映射标头不绑定到请求或响应消息不绑定到 Java 方法参数 -Xauthfile 用于传送以下格式的授权信息的文件: http://username:password@example.org/stock?wsdl -Xdebug 输出调试信息 -Xno-addressing-databinding 允许 W3C EndpointReferenceType 到 Java 的绑定 -Xnocompile 不编译生成的 Java 文件 -XdisableAuthenticator 禁用由 JAX-WS RI 使用的验证程序, 将忽略 -Xauthfile 选项 (如果设置) -XdisableSSLHostnameVerification 在提取 wsdl 时禁用 SSL 主机名 验证
实例,生成客户端代码:
wsimport -encoding utf8 -keep -p pers.zhang.demo.client -Xnocompile http://localhost:8888/demo/ws?wsdl # - utf8编码 # - 包名pers.zhang.demo.client # - Xnocompile不编译
日期处理工具类:
public class DateUtils { /** * 将Date类转换为XMLGregorianCalendar * * @param date * @return */ public static XMLGregorianCalendar dateToXmlDate(Date date){ Calendar cal = Calendar.getInstance(); cal.setTime(date); DatatypeFactory dtf = null; try { dtf = DatatypeFactory.newInstance(); XMLGregorianCalendar dateType = dtf.newXMLGregorianCalendar(); dateType.setYear(cal.get(Calendar.YEAR)); //由于Calendar.MONTH取值范围为0~11,需要加1 dateType.setMonth(cal.get(Calendar.MONTH)+1); dateType.setDay(cal.get(Calendar.DAY_OF_MONTH)); dateType.setHour(cal.get(Calendar.HOUR_OF_DAY)); dateType.setMinute(cal.get(Calendar.MINUTE)); dateType.setSecond(cal.get(Calendar.SECOND)); return dateType; } catch (DatatypeConfigurationException e) { e.printStackTrace(); } return null; } /** * 将XMLGregorianCalendar转换为Date * * @param cal * @return */ public static Date xmlDate2Date(XMLGregorianCalendar cal){ return cal.toGregorianCalendar().getTime(); } }
客户端:
public class Client { public static void main(String[] args) { //1. 创建一个webservice的客户端 UserServiceImplService userService = new UserServiceImplService(); //2, 获取远程服务实现对象 UserServiceImpl us = userService.getUserServiceImplPort(); //3. 直接调用远程服务实现对象的方法 String hi = us.sayHi("tom"); System.out.println(hi); String work = us.work("Java"); System.out.println(work); User user = new User(); user.setId(100); user.setName("jerry"); user.setBirthday(DateUtils.dateToXmlDate(new Date())); User u = us.getUser(user); System.out.println(u.getId() + "," + u.getName() + "," + u.getBirthday()); } }
输出:
Hi, tom He is working Java 100,jerry-service,2023-12-20T21:10:49+08:00
6.2、Service编程调用(JAX-WS)
该种方式可以自定义命名空间,服务视图名等元素,方便以后维护,是一种标准的开发方式 。
服务接口:
//指明portType元素的的name属性值 @WebService(name = "UserServiceImpl") public interface UserService { public String sayHi(String name); public String work(String work); public User getUser(User user); }
客户端:
public class Client2 { public static void main(String[] args) throws IOException { //创建WSDL文件的URL URL wsdlDocumentLocation = new URL("http://localhost:8888/demo/ws?wsdl"); //创建服务名称 //1. namespaceURI-命名空间地址即definitions元素的targetNamespace属性值 //2. localPart 服务名即service元素的name属性值 QName serviceName = new QName("http://server.demo.zhang.pers/", "UserServiceImplService"); Service service = Service.create(wsdlDocumentLocation, serviceName); //获取服务实现类 UserService接口中需要@WebService(name = "UserServiceImpl")指明portType的name UserService us = service.getPort(UserService.class); //调用方法 String tom = us.sayHi("tom"); System.out.println(tom); String work = us.work("Java"); System.out.println(work); User user = new User(); user.setId(100); user.setName("jerry"); user.setBirthday(new Date()); User u = us.getUser(user); System.out.println(u.getId() + "," + u.getName() + "," + u.getBirthday()); } }
输出:
Hi, tom He is working Java 100,jerry-service,Wed Dec 20 22:59:26 CST 2023
6.3、HttpURLConnection调用
这种方式是由自己编写客户端,手动拼接请求体,不再由工具生成,比较麻烦:
- 第一步:创建服务地址
- 第二步:打开一个通向服务地址的连接
- 第三步:设置参数
- 第四步:组织SOAP数据,发送请求
- 第五步:接收服务端响应
首先需要查看请求体的xml结构定义,即schemaLocation的地址。访问http://localhost:8888/demo/ws?xsd=1:
public class Client3 { public static void main(String[] args) throws Exception { //第一步:创建服务地址,不是WSDL地址 URL url = new URL("http://localhost:8888/demo/ws"); //第二步:打开一个通向服务地址的连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //第三步:设置参数 //3.1发送方式设置:POST必须大写 connection.setRequestMethod("POST"); //3.2设置数据格式:content-type connection.setRequestProperty("content-type", "text/xml;charset=UTF-8"); //3.3设置输入输出,因为默认新创建的connection没有读写权限, connection.setDoInput(true); connection.setDoOutput(true); //第四步:组织SOAP数据,发送请求 User user = new User(); user.setId(100); user.setName("jerry"); user.setBirthday(new Date()); String soapXML = getUserXML(user); OutputStream os = connection.getOutputStream(); os.write(soapXML.getBytes()); //第五步:接收服务端响应,打印,解析 int responseCode = connection.getResponseCode(); if(200 == responseCode){//表示服务端响应成功 InputStream is = connection.getInputStream(); //将字节流转换为字符流 InputStreamReader isr = new InputStreamReader(is,"utf-8"); //使用缓存区 BufferedReader br = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); String temp = null; while(null != (temp = br.readLine())){ sb.append(temp); } //输出响应体xml System.out.println(sb.toString()); //解析xml DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new ByteArrayInputStream(sb.toString().getBytes())); NodeList nodeList = doc.getElementsByTagName("return").item(0).getChildNodes(); System.out.println("解析User:"); System.out.println("birthday:" + nodeList.item(0).getFirstChild().getNodeValue()); System.out.println("id:" + nodeList.item(1).getFirstChild().getNodeValue()); System.out.println("name:" + nodeList.item(2).getFirstChild().getNodeValue()); is.close(); isr.close(); br.close(); } os.close(); } public static String getSayHiXML(String name){ String soapXML = "" +"" +"" +"" + "" + name + "" +"" +"" +""; return soapXML; } public static String getWorkXML(String name){ String soapXML = "" +"" +"" +"" + "" + name + "" +"" +"" +""; return soapXML; } public static String getUserXML(User user){ String soapXML = "" +"" +"" +"" + "" + "" + DateUtils.dateToXmlDate(user.getBirthday()) + "" + "" + user.getId() + "" + "" + user.getName() + "" + "" +"" +"" +""; return soapXML; } }
输出:
2023-12-21T14:55:41+08:00100jerry-service 解析User: birthday:2023-12-21T14:55:41+08:00 id:100 name:jerry-service
6.4、HttpClient调用
该方式类似HttpURLConnection,都需要手动拼接参数请求体。
org.apache.httpcomponents httpclient 4.5.5
public class Client4 { public static void main(String[] args) throws Exception { CloseableHttpClient httpClient = HttpClients.createDefault(); //请求地址和方式 HttpPost httpPost = new HttpPost("http://localhost:8888/demo/ws"); //请求头 httpPost.setHeader("content-type", "text/xml;charset=UTF-8"); //拼接参数 User user = new User(); user.setId(100); user.setName("jerry"); user.setBirthday(new Date()); String soapXML = getUserXML(user); //设置请求体 ByteArrayEntity entity = new ByteArrayEntity(soapXML.getBytes()); httpPost.setEntity(entity); //执行请求 CloseableHttpResponse response = httpClient.execute(httpPost); //如果响应200 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //获取响应体 String res = EntityUtils.toString(response.getEntity()); //关闭HttpEntity的流实体 EntityUtils.consume(response.getEntity()); //打印响应体 System.out.println(res); //解析 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new ByteArrayInputStream(res.getBytes())); NodeList nodeList = doc.getElementsByTagName("return").item(0).getChildNodes(); System.out.println("解析User:"); System.out.println("birthday:" + nodeList.item(0).getFirstChild().getNodeValue()); System.out.println("id:" + nodeList.item(1).getFirstChild().getNodeValue()); System.out.println("name:" + nodeList.item(2).getFirstChild().getNodeValue()); } } public static String getUserXML(User user){ String soapXML = "" +"" +"" +"" + "" + "" + DateUtils.dateToXmlDate(user.getBirthday()) + "" + "" + user.getId() + "" + "" + user.getName() + "" + "" +"" +"" +""; return soapXML; } }
输出:
2023-12-21T15:22:11+08:00100jerry-service 解析User: birthday:2023-12-21T15:22:11+08:00 id:100 name:jerry-service
6.5、Hutool工具包调用
Hutool封装了Http的调用过程,链式调用简单快捷。
cn.hutool hutool-all 5.8.20
public class Client5 { public static void main(String[] args) { //wsdl文档地址 SoapClient soapClient = SoapClient.create("http://localhost:8888/demo/ws?wsdl") //参数1:方法名,需添加命名空间前缀; 参数2:命名空间 .setMethod("ns2:sayHi", "http://server.demo.zhang.pers/") //编码 .setCharset(CharsetUtil.CHARSET_UTF_8) //参数,不使用方法的命名空间前缀 .setParam("arg0", "tom", false); //发送请求 String send = soapClient.send(true); System.out.println(send); //wsdl文档地址 SoapClient soapClient1 = SoapClient.create("http://localhost:8888/demo/ws?wsdl") //参数1:方法名,需添加命名空间前缀; 参数2:命名空间 .setMethod("ns2:work", "http://server.demo.zhang.pers/") //编码 .setCharset(CharsetUtil.CHARSET_UTF_8) //参数,不使用方法的命名空间前缀 .setParam("arg0", "jerry", false); //发送请求 String send1 = soapClient1.send(true); System.out.println(send1); Map param = new HashMap(); param.put("birthday", DateUtils.dateToXmlDate(new Date())); param.put("id", 100); param.put("name", "acton"); //wsdl文档地址 SoapClient soapClient2 = SoapClient.create("http://localhost:8888/demo/ws?wsdl") //参数1:方法名,需添加命名空间前缀; 参数2:命名空间 .setMethod("ns2:getUser", "http://server.demo.zhang.pers/") //编码 .setCharset(CharsetUtil.CHARSET_UTF_8) //参数,不使用方法的命名空间前缀 .setParam("arg0", param, false); //发送请求 String send2 = soapClient2.send(true); System.out.println(send2); } }
输出:
Hi, tom He is working jerry 2023-12-21T16:07:46+08:00 100 acton-service
7、注解描述WSDL
通过注解,可以更加形像的描述Web服务。对自动生成的wsdl文档进行修改,为使用者提供一个更加清晰的wsdl文档。
WebService的注解都位于javax.jws包下: @WebService-定义服务,在类上边 targetNamespace:指定命名空间 name:portType的名称 portName:port的名称 serviceName:服务名称 endpointInterface:SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法,可通过此注解指定要发布服务的接口。 @WebMethod-定义方法,在公开方法上边 operationName:方法名 exclude:设置为true表示此方法不是webservice方法,反之则表示webservice方法,默认是false @WebResult-定义返回值,在方法返回值前边 name:返回结果值的名称 @WebParam-定义参数,在方法参数前边 name:指定参数的名称
示例:
@WebService( targetNamespace = "http://server.weather/", portName = "WeatherSOAPPort", serviceName = "WeatherWSS", name = "WeatherSOAP" ) public class WeatherInterfaceImpl implements WeatherInterface { @WebMethod( operationName = "getWeather", exclude = false ) @Override public @WebResult(name = "result") String queryWeather(@WebParam(name = "cityName") String cityName) { System.out.println("获取城市名:" + cityName); String weather = "暴雨"; return weather; } }
发布后,访问wsdl文件: