最近学习做Webservice项目,模仿物流发货,A公司每向B公司一车货,发2次消息,分A出发时和到达B时,2消息内容相同。消息包含车号、司机、货物清单及可能是集装箱等。wsdl文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:tsr="http://hjs.com/services/atob/lgsservice/v1.0/"
xmlns:tns="http://hjs.com/schema/atob/logistics/"
xmlns:resp="http://hjs.com/schema/atob/common/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="LGSService"
targetNamespace="http://hjs.com/services/atob/lgsservice/v1.0/">
<!-- Revision History -->
<!--
v1.0 - 25 Jul 16 - For client review
-->
<wsdl:types>
<xsd:schema targetNamespace="http://hjs.com/schema/atob/logistics/">
<xsd:include schemaLocation="ABLGS.xsd"/>
</xsd:schema>
<xsd:schema targetNamespace="http://hjs.com/schema/atob/common/">
<xsd:include schemaLocation="ResponseMessage.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="CommonResponse">
<wsdl:part name="payload" element="resp:ResponseMessage"></wsdl:part>
</wsdl:message>
<wsdl:message name="CargoArrivalRequest">
<wsdl:part name="payload" element="tns:CargoArrival"></wsdl:part>
</wsdl:message>
<wsdl:message name="CargoPreannounceRequest">
<wsdl:part name="payload" element="tns:CargoPreannounce"></wsdl:part>
</wsdl:message>
<wsdl:portType name="LGSService">
<wsdl:operation name="CargoArrival">
<wsdl:input name="CargoArrivalRequest" message="tsr:CargoArrivalRequest"/>
<wsdl:output name="CargoArrivalResponse" message="tsr:CommonResponse"/>
</wsdl:operation>
<wsdl:operation name="CargoPreannounce">
<wsdl:input name="CargoPreannounceRequest" message="tsr:CargoPreannounceRequest"/>
<wsdl:output name="CargoPreannounceResponse" message="tsr:CommonResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="LGSServiceSOAP" type="tsr:LGSService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="CargoArrival">
<soap:operation soapAction="http://hjs.com/services/atob/lgsservice/v1.0/CargoArrival"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="CargoPreannounce">
<soap:operation soapAction="http://hjs.com/services/atob/lgsservice/v1.0/CargoPreannounce"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="LGSService">
<wsdl:port name="LGSServiceSOAP" binding="tsr:LGSServiceSOAP">
<soap:address location="http://localhost:8090/services/atob/lgsservice/v1.0/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
用wsimport生成相应的类,主要的是接口LGSService,
@WebService(name = "LGSService", targetNamespace = "http://hjs.com/services/atob/lgsservice/v1.0/")
@XmlSeeAlso({
com.hjs.schema.atob.logistics.ObjectFactory.class,
com.hjs.schema.atob.common.ObjectFactory.class
})
public interface LGSService {
@WebMethod(operationName = "CargoArrival", action = "http://hjs.com/services/atob/lgsservice/v1.0/CargoArrival")
@RequestWrapper(localName = "CargoArrival", targetNamespace = "http://hjs.com/schema/atob/logistics/", className = "com.hjs.schema.atob.logistics.CargoArrival")
@ResponseWrapper(localName = "ResponseMessage", targetNamespace = "http://hjs.com/schema/atob/common/", className = "com.hjs.schema.atob.common.ResponseMessageType")
public void cargoArrival(
@WebParam(name = "Head", targetNamespace = "http://hjs.com/schema/atob/logistics/")
com.hjs.schema.atob.logistics.BaseMessageType.Head head,
@WebParam(name = "LGS", targetNamespace = "http://hjs.com/schema/atob/logistics/")
List<LGSType> lgs,
@WebParam(name = "REFF_NO", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> reffNO,
@WebParam(name = "SENDER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> sender,
@WebParam(name = "RECEIVER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> receiver,
@WebParam(name = "RECEIVED_DTTM", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<XMLGregorianCalendar> receivedDTTM,
@WebParam(name = "ACKNSTAT", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> acknstat,
@WebParam(name = "ACKNREMARK", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> acknremark);
@WebMethod(operationName = "CargoPreannounce", action = "http://hjs.com/services/atob/lgsservice/v1.0/CargoPreannounce")
@RequestWrapper(localName = "CargoPreannounce", targetNamespace = "http://hjs.com/schema/atob/logistics/", className = "com.hjs.schema.atob.logistics.CargoPreannounce")
@ResponseWrapper(localName = "ResponseMessage", targetNamespace = "http://hjs.com/schema/atob/common/", className = "com.hjs.schema.atob.common.ResponseMessageType")
public void cargoPreannounce(
@WebParam(name = "Head", targetNamespace = "http://hjs.com/schema/atob/logistics/")
com.hjs.schema.atob.logistics.BaseMessageType.Head head,
@WebParam(name = "LGS", targetNamespace = "")
List<LGSType> lgs,
@WebParam(name = "REFF_NO", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> reffNO,
@WebParam(name = "SENDER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> sender,
@WebParam(name = "RECEIVER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> receiver,
@WebParam(name = "RECEIVED_DTTM", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<XMLGregorianCalendar> receivedDTTM,
@WebParam(name = "ACKNSTAT", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> acknstat,
@WebParam(name = "ACKNREMARK", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> acknremark);
}
再做一个类LGSServiceImpl实现此接口
@WebService(name = "LGSService", targetNamespace = "http://hjs.com/services/atob/lgsservice/v1.0/")
@BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)public class LGSServiceImpl implements LGSService {
@Override
public void cargoArrival(Head head, List<LGSType> lgs, Holder<BigInteger> reffNO, Holder<String> sender,
Holder<String> receiver, Holder<XMLGregorianCalendar> receivedDTTM, Holder<BigInteger> acknstat,
Holder<String> acknremark) {
// 代码省略。。。
}
@Override
public void cargoPreannounce(Head head, List<LGSType> lgs, Holder<BigInteger> reffNO, Holder<String> sender,
Holder<String> receiver, Holder<XMLGregorianCalendar> receivedDTTM, Holder<BigInteger> acknstat,
Holder<String> acknremark) {
// 代码省略。。。
}
}
发布此服务
LGSService ls = new LGSServiceImpl();
Endpoint.publish("http://localhost:8090/services/atob/lgsservice/v1.0/", ls);
可以正常发布,打开http://localhost:8090/services/atob/lgsservice/v1.0/?wsdl,可以看到wsdl,但那是系统生成的,看起来别扭,也不方便客户端查看。
为了能让客户端查看原装的wsdl和其它schema,可以以META-DATA方式发布,如
LGSService ls = new LGSServiceImpl();
Endpoint lgsendpoint = Endpoint.create(ls);
List<File> metadataFile = new ArrayList<File>();
metadataFile.add( new File("src/META-INF/wsdl/LGSService.wsdl"));
metadataFile.add( new File("src/META-INF/wsdl/BaseMessage.xsd"));
metadataFile.add( new File("src/META-INF/wsdl/ABAWBS.xsd"));
metadataFile.add( new File("src/META-INF/wsdl/CONTAINER.xsd"));
metadataFile.add( new File("src/META-INF/wsdl/ABLGS.xsd"));
metadataFile.add( new File("src/META-INF/wsdl/ResponseMessage.xsd"));
List<Source> metadata = new ArrayList<Source>();
try {
for(File file : metadataFile){
Source source = new StreamSource(new FileInputStream(file));
source.setSystemId(file.toURI().toURL().toExternalForm());
metadata.add(source);
}
lgsendpoint.setMetadata(metadata);
lgsendpoint.publish("http://localhost:8090/services/atob/lgsservice/v1.0/");
} catch (FileNotFoundException | MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
不能成功发布,系统报错:
服务器运行时错误: More than one schema for the target namespace http://hjs.com/schema/atob/logistics/
想了好久,什么问题?查看JAX-WS文档及网上资料,感觉是系统无法辨别是生成的wsdl和xsd还是原装META的,应该在类上指定,加上注释
serviceName = "LGSService", portName = "LGSServiceSOAP",
再发布,系统报:
Method cargoPreannounce is exposed as WebMethod,
but there is no corresponding wsdl operation with name {http://hjs.com/services/atob/lgsservice/v1.0/}cargoPreannounce in the wsdl:portType{http://hjs.com/services/atob/lgsservice/v1.0/}LGSService
原来是方法上没有加注释,那就加上吧
@WebMethod(operationName = "CargoArrival", action = "http://hjs.com/services/atob/lgsservice/v1.0/CargoArrival")
@RequestWrapper(localName = "CargoArrival", targetNamespace = "http://hjs.com/schema/atob/logistics/", className = "com.hjs.schema.atob.logistics.CargoArrival")
@ResponseWrapper(localName = "ResponseMessage", targetNamespace = "http://hjs.com/schema/atob/common/", className = "com.hjs.schema.atob.common.ResponseMessageType")
再发布,还有错:
javax.xml.ws.WebServiceException: class com.hjs.schema.atob.logistics.CargoPreannounce do not have a property of the name arg0
再找资料,认为类内的方法参数与xsd不一致。参考接口方法的参数,全部复制到实现类里
public void cargoArrival(
@WebParam(name = "Head", targetNamespace = "http://hjs.com/schema/atob/logistics/")
com.hjs.schema.atob.logistics.BaseMessageType.Head head,
@WebParam(name = "LGS", targetNamespace = "http://hjs.com/schema/atob/logistics/")
List<LGSType> lgs,
@WebParam(name = "REFF_NO", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> reffNO,
@WebParam(name = "SENDER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> sender,
@WebParam(name = "RECEIVER", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> receiver,
@WebParam(name = "RECEIVED_DTTM", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<XMLGregorianCalendar> receivedDTTM,
@WebParam(name = "ACKNSTAT", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<BigInteger> acknstat,
@WebParam(name = "ACKNREMARK", targetNamespace = "http://hjs.com/schema/atob/common/", mode = WebParam.Mode.OUT)
Holder<String> acknremark
) {
// 省略代码。。。
}
发布!OK啦!打开wsdl,与原装的一致。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. -->
<wsdl:definitions name="LGSService" targetNamespace="http://hjs.com/services/atob/lgsservice/v1.0/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://hjs.com/schema/atob/logistics/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:resp="http://hjs.com/schema/atob/common/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tsr="http://hjs.com/services/atob/lgsservice/v1.0/">
<!-- Revision History -->
<!-- v1.0 - 25 Jul 13 - For client review -->
<wsdl:types>
<xsd:schema targetNamespace="http://hjs.com/schema/atob/logistics/">
<xsd:include schemaLocation="http://localhost:8090/services/atob/lgsservice/v1.0/?xsd=2"/>
</xsd:schema>
<xsd:schema targetNamespace="http://hjs.com/schema/atob/common/">
<xsd:include schemaLocation="http://localhost:8090/services/atob/lgsservice/v1.0/?xsd=5"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="CommonResponse">
<wsdl:part name="payload" element="resp:ResponseMessage"/>
</wsdl:message>
<wsdl:message name="CargoArrivalRequest">
<wsdl:part name="payload" element="tns:CargoArrival"/>
</wsdl:message>
<wsdl:message name="CargoPreannounceRequest">
<wsdl:part name="payload" element="tns:CargoPreannounce"/>
</wsdl:message>
分别打开每一个xsd,也与原装发布的一致。算是成功发布了吧。
总结:在写实现类时,要按JAX-WS的要求,或参考接口,分别加上相应的注释,不只是简单实现。
本文记录了在使用Java发布Web Service时遇到的问题及解决过程。从wsimport生成接口和实现类,到通过META-INF发布自定义wsdl,期间遇到了多个错误,包括:多schema目标命名空间错误、wsdl操作缺失、方法参数与wsdl不匹配等。通过查阅文档和添加正确注解,最终成功发布并验证了wsdl和xsd的一致性。
3352

被折叠的 条评论
为什么被折叠?



