Java Web 入门
本章代码: https://github.com/zhaoqian/study-test/tree/master/credo-test/src/main/java/org/credo/jaxws/study1
package org.credo.jaxws.study1; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style=Style.RPC) public interface TimeSEIServer { @WebMethod String getTimeAsString(); @WebMethod Long getTimeAsLong(); }
SIB示例:
package org.credo.jaxws.study1; import java.util.Date; import javax.jws.WebService; @WebService(endpointInterface="org.credo.jaxws.study1.TimeSEIServer") public class TimeSIBServerImpl implements TimeSEIServer { @Override public String getTimeAsString() { return new Date().toString(); } @Override public Long getTimeAsLong() { return new Date().getTime(); } }启动服务:
package org.credo.jaxws.study1; import javax.xml.ws.Endpoint; public class TimeServerPublisher { public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:9876/ts", new TimeSIBServerImpl()); } }
输入http://127.0.0.1:9876/ts 页面,即可看到如下数据
Endpoint | Information | ||||||||||
|
|
http://127.0.0.1:9876/ts?wsdl 则是这个webservice的wsdl.
<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://study1.jaxws.credo.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://study1.jaxws.credo.org/" name="TimeSIBServerImplService"> <types></types> <message name="getTimeAsString"></message> <message name="getTimeAsStringResponse"> <part name="return" type="xsd:string"></part> </message> <message name="getTimeAsLong"></message> <message name="getTimeAsLongResponse"> <part name="return" type="xsd:long"></part> </message> <portType name="TimeSEIServer"> <operation name="getTimeAsString"> <input wsam:Action="http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsStringRequest" message="tns:getTimeAsString"></input> <output wsam:Action="http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsStringResponse" message="tns:getTimeAsStringResponse"></output> </operation> <operation name="getTimeAsLong"> <input wsam:Action="http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsLongRequest" message="tns:getTimeAsLong"></input> <output wsam:Action="http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsLongResponse" message="tns:getTimeAsLongResponse"></output> </operation> </portType> <binding name="TimeSIBServerImplPortBinding" type="tns:TimeSEIServer"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding> <operation name="getTimeAsString"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://study1.jaxws.credo.org/"></soap:body> </input> <output> <soap:body use="literal" namespace="http://study1.jaxws.credo.org/"></soap:body> </output> </operation> <operation name="getTimeAsLong"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://study1.jaxws.credo.org/"></soap:body> </input> <output> <soap:body use="literal" namespace="http://study1.jaxws.credo.org/"></soap:body> </output> </operation> </binding> <service name="TimeSIBServerImplService"> <port name="TimeSIBServerImplPort" binding="tns:TimeSIBServerImplPortBinding"> <soap:address location="http://127.0.0.1:9876/ts"></soap:address> </port> </service> </definitions>
靠近wsdl前面部分的"portType"节.
该节将已经发布的Web服务提供的服务操作组织在一起.
在本例中,服务操作就是getTimeAsString和getTimeAsLong.是在SEI中定义,SIB中实现的两方法.WSDL的portType节点就像一个java接口.只提供了服务操作的抽象定义.而没有提供具体实现细节.在Web服务定义的每一个服务操作中都包括一个输入消息和输出消息.输入消息代表这web服务的输入参数.在Web服务运行时环境中,每一个输入,输出消息都是一个SOAP文档.
另外一部分是在WSDL后面的"service"节.
本例中URL: http://localhost:9876/ts 中所请求的服务的位置.这个URL通常成为服务端点(Service endpoint).由它来告诉调用服务的客户端.该服务增援才可以被访问.
第一部分:
定义了服务接口,他在WSDL中由<message../>元素和<portType.../>两个元素组成,
其中<message.../>元素定义了操作的交互方式.
而<portType.../>元素里则可以包含N个<operation.../>元素,每个<operation.../>元素代表一个允许远程调用的操作(就是方法).
第二部分:
定义了服务实现.由binding和service元素组成
binding定义了特定的通信协议,数据编码模型和底层通信协议.将WebService服务接口定义映射到具体实现.
而service元素就包含一系列的port元素,每个元素将把绑定机制,服务访问协议,端点地址结合在一起.
通过CXF 转换WSDL为Java文件,指定UTF-8
ApacheCXF wsdl2java 指定编码:
wsdl2java -encoding utf-8 wsdl网址
apache cxf生成文件如下:
package org.credo.jaxws.study1.simpleRequest.cxfGenerate; import javax.jws.WebMethod; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.Action; @WebService(targetNamespace = "http://study1.jaxws.credo.org/", name = "TimeSEIServer") @SOAPBinding(style = SOAPBinding.Style.RPC) public interface TimeSEIServer { @WebResult(name = "return", targetNamespace = "http://study1.jaxws.credo.org/", partName = "return") @Action(input = "http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsLongRequest", output = "http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsLongResponse") @WebMethod public long getTimeAsLong(); @WebResult(name = "return", targetNamespace = "http://study1.jaxws.credo.org/", partName = "return") @Action(input = "http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsStringRequest", output = "http://study1.jaxws.credo.org/TimeSEIServer/getTimeAsStringResponse") @WebMethod public java.lang.String getTimeAsString(); }另一个TimeSIBServerImplService
package org.credo.jaxws.study1.simpleRequest.cxfGenerate; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceFeature; import javax.xml.ws.Service; @WebServiceClient(name = "TimeSIBServerImplService", wsdlLocation = "http://127.0.0.1:9876/ts?wsdl", targetNamespace = "http://study1.jaxws.credo.org/") public class TimeSIBServerImplService extends Service { public final static URL WSDL_LOCATION; public final static QName SERVICE = new QName("http://study1.jaxws.credo.org/", "TimeSIBServerImplService"); public final static QName TimeSIBServerImplPort = new QName("http://study1.jaxws.credo.org/", "TimeSIBServerImplPort"); static { URL url = null; try { url = new URL("http://127.0.0.1:9876/ts?wsdl"); } catch (MalformedURLException e) { java.util.logging.Logger.getLogger(TimeSIBServerImplService.class.getName()) .log(java.util.logging.Level.INFO, "Can not initialize the default wsdl from {0}", "http://127.0.0.1:9876/ts?wsdl"); } WSDL_LOCATION = url; } public TimeSIBServerImplService(URL wsdlLocation) { super(wsdlLocation, SERVICE); } public TimeSIBServerImplService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public TimeSIBServerImplService() { super(WSDL_LOCATION, SERVICE); } //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2 //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1 //compliant code instead. public TimeSIBServerImplService(WebServiceFeature ... features) { super(WSDL_LOCATION, SERVICE, features); } //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2 //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1 //compliant code instead. public TimeSIBServerImplService(URL wsdlLocation, WebServiceFeature ... features) { super(wsdlLocation, SERVICE, features); } //This constructor requires JAX-WS API 2.2. You will need to endorse the 2.2 //API jar or re-run wsdl2java with "-frontend jaxws21" to generate JAX-WS 2.1 //compliant code instead. public TimeSIBServerImplService(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) { super(wsdlLocation, serviceName, features); } /** * * @return * returns TimeSEIServer */ @WebEndpoint(name = "TimeSIBServerImplPort") public TimeSEIServer getTimeSIBServerImplPort() { return super.getPort(TimeSIBServerImplPort, TimeSEIServer.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. * @return * returns TimeSEIServer */ @WebEndpoint(name = "TimeSIBServerImplPort") public TimeSEIServer getTimeSIBServerImplPort(WebServiceFeature... features) { return super.getPort(TimeSIBServerImplPort, TimeSEIServer.class, features); } }简单请求的main方法:
package org.credo.jaxws.study1.simpleRequest; import java.net.MalformedURLException; import java.net.URL; import org.credo.jaxws.study1.simpleRequest.cxfGenerate.TimeSEIServer; import org.credo.jaxws.study1.simpleRequest.cxfGenerate.TimeSIBServerImplService; import org.credo.jaxws.study1.simpleRequest.webservicelog.LogResolver; public class RequestTime { public static void main(String[] args) throws MalformedURLException { String wsdl="http://127.0.0.1:9876/ts?wsdl"; URL url=new URL(wsdl); TimeSIBServerImplService service= new TimeSIBServerImplService(url); //service.setHandlerResolver(new LogResolver()); TimeSEIServer timeSEIServer = service.getTimeSIBServerImplPort(); System.out.println("timeSEIServer.getTimeAsLong():"+timeSEIServer.getTimeAsLong()); System.out.println("timeSEIServer.getTimeAsString():"+timeSEIServer.getTimeAsString()); } }输出:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getTimeAsLong xmlns:ns2="http://study1.jaxws.credo.org/"/></S:Body></S:Envelope> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns2:getTimeAsLongResponse xmlns:ns2="http://study1.jaxws.credo.org/"><return>1416379645456</return></ns2:getTimeAsLongResponse></S:Body></S:Envelope> timeSEIServer.getTimeAsLong():1416379645456 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getTimeAsString xmlns:ns2="http://study1.jaxws.credo.org/"/></S:Body></S:Envelope> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns2:getTimeAsStringResponse xmlns:ns2="http://study1.jaxws.credo.org/"><return>Wed Nov 19 14:47:25 CST 2014</return></ns2:getTimeAsStringResponse></S:Body></S:Envelope> timeSEIServer.getTimeAsString():Wed Nov 19 14:47:25 CST 2014
A: Example HTTP request for the TimeServer service
POST http://127.0.0.1:9876/ts HTTP/ 1.1 Accept: text/xml Accept: multipart/* Accept: application/soap User-Agent: SOAP::Lite/Perl/0.69 Content-Length: 434 Content-Type: text/xml; charset=utf-8 SOAPAction: "" <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope soap:encodingStyle="http:// schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/ envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://ts.ch01/ xmlns:xsd ="http://www.w3.org/2001/XMLSchema"> <soap:Body> <tns:getTimeAsString xsi:nil="true" /> </soap:Body> </soap:Envelope>
解析:
1.这个HTTP请求的第一行指定了方法为POST.在SOAP请求中,通常都是POST方式.而不是get.因为只有POST请求才有body域,可以用它来封装一个SOAP消息.在第一行请求的URL之后是HTTP协议的版本号,1.1(现行版本.)
2.在HTTP头之后,都是一些由冒号分割的键值对.这些键值对在HTTP请求头中出现的顺序是任意的."Accept"键连续出现了3次.
以MIME(Multipurpose Internet Mail Extension)类型/子类型的方式出现.分别是 text/xml. multpart/*和application/soap.这三个键值对分别表明了请求者客户端可以分别处理
3.SOAP主体: 两个回车换行.此行用来作为HTTP头数据和Body数据域的分割符.Body域在POST请求下通常是必须的.但可能为空.
本例中,HTTP的body域包含一个SOAP文档.一般被称为SOAP信封(SOAP Envelope).因为Envelope就是信封的意思.SOAP主体包含一个命名为"getTimeAsString" 的xml元素.这个名称也就是客户端调用的服务操作方法的名称.
B:返回信息
HTTP/1.1 200 OK Content-Length: 323 Content-Type: text/xml; charset=utf-8 Client-Date: Mon, 28 Apr 2008 02:12:54 GMT Client-Peer: 127.0.0.1:9876 Client-Response-Num: 1 <?xml version="1.0" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soapenv:Body> <ans:getTimeAsStringResponse xmlns:ans="http://ts.ch01/"> <return>Mon Apr 28 14:12:54 CST 2008</return> </ans:getTimeAsStringResponse> </soapenv:Body> </soapenv:Envelope>