WebService开发笔记 1 -- 利用cxf开发WebService竟然如此简单WebService开发笔记 1 -- 利用cxf开发WebServ
WebService开发笔记 1 -- 利用cxf开发WebService竟然如此简单
WebService开发笔记 1 -- 利用cxf开发WebService竟然如此简单
现在的项目中需要用到SOA概念的地方越来越多,最近我接手的一个项目中就提出了这样的业务要求,需要在.net开发的客户端系统中访问java开发的web系统,这样的业务需求自然需要通过WebService进行信息数据的操作。下面就将我们在开发中摸索的一点经验教训总结以下,以供大家参考.
在WebService开发笔记 2 -- VS 2005 访问WebServcie更简单中作一个跨平台访问WebServcie服务的例子....
在WebService开发笔记 3 -- 增强访问 WebService 的安全性通过一个简单的用户口令验证机制来加强一下WebService的安全性....
我们项目的整个架构使用的比较流行的WSH MVC组合,即webwork2 + Spring + Hibernate;
1.首先集成Apacha CXF WebService 到 Spring 框架中;
apache cxf 下载地址:http://people.apache.org/dist/incubator/cxf/2.0.4-incubator/apache-cxf-2.0.4-incubator.zip
在spring context配置文件中引入以下cxf配置
<import resource="classpath*:META-INF/cxf/cxf.xml" /><import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" /><import resource="classpath*:META-INF/cxf/cxf-servlet.xml" />
在web.xml中添加过滤器:
<servlet><servlet-name>CXFServlet</servlet-name><servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class></servlet><servlet-mapping><servlet-name>CXFServlet</servlet-name><url-pattern>/services/*</url-pattern></servlet-mapping>
2.开发服务端WebService接口:
/** * WebService接口定义类. * * 使用@WebService将接口中的所有方法输出为Web Service. * 可用annotation对设置方法、参数和返回值在WSDL中的定义. */@WebServicepublic interface WebServiceSample {/** * 一个简单的方法,返回一个字符串 * @param hello * @return */String say(String hello);/** * 稍微复杂一些的方法,传递一个对象给服务端处理 * @param user * @return */String sayUserName(@WebParam(name = "user") UserDTO user);/** * 最复杂的方法,返回一个List封装的对象集合 * @return */public @WebResult(partName="o")ListObject findUsers();}
由简单到复杂定义了三个接口,模拟业务需求;
3.实现接口
/** * WebService实现类. * * 使用@WebService指向Interface定义类即可. */@WebService(endpointInterface = "cn.org.coral.biz.examples.webservice.WebServiceSample")public class WebServiceSampleImpl implements WebServiceSample {public String sayUserName(UserDTO user) {return "hello "+user.getName();}public String say(String hello) {return "hello "+hello;}public ListObject findUsers() {ArrayList<Object> list = new ArrayList<Object>();list.add(instancUser(1,"lib"));list.add(instancUser(2,"mld"));list.add(instancUser(3,"lq"));list.add(instancUser(4,"gj"));ListObject o = new ListObject();o.setList(list);return o;}private UserDTO instancUser(Integer id,String name){UserDTO user = new UserDTO();user.setId(id);user.setName(name);return user;}}
4.依赖的两个类:用户对象与List对象
/** * Web Service传输User信息的DTO. * * 分离entity类与web service接口间的耦合,隔绝entity类的修改对接口的影响. * 使用JAXB 2.0的annotation标注JAVA-XML映射,尽量使用默认约定. * */@XmlAccessorType(XmlAccessType.FIELD)@XmlType(name = "User")public class UserDTO {protected Integer id;protected String name;public Integer getId() {return id;}public void setId(Integer value) {id = value;}public String getName() {return name;}public void setName(String value) {name = value;}}
关于List对象,参照了有关JWS的一个问题中的描述:DK6.0 自带的WebService中 WebMethod的参数好像不能是ArrayList 或者其他List
传递List需要将List 包装在其他对象内部才行 (个人理解 如有不对请指出) ,我在实践中也遇到了此类问题.通过以下封装的对象即可以传递List对象.
/** * <p>Java class for listObject complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * <complexType name="listObject"> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="list" type="{http://www.w3.org/2001/XMLSchema}anyType" maxOccurs="unbounded" minOccurs="0"/> * </sequence> * </restriction> * </complexContent> * </complexType> * </pre> * * */@XmlAccessorType(XmlAccessType.FIELD)@XmlType(name = "listObject", propOrder = { "list" })public class ListObject {@XmlElement(nillable = true)protected List<Object> list;/** * Gets the value of the list property. * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the list property. * * <p> * For example, to add a new item, do as follows: * <pre> * getList().add(newItem); * </pre> * * * <p> * Objects of the following type(s) are allowed in the list * {@link Object } * * */public List<Object> getList() {if (list == null) {list = new ArrayList<Object>();}return this.list;}public void setList(ArrayList<Object> list) {this.list = list;}}
5.WebService 服务端 spring 配置文件 ws-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><jaxws:endpoint id="webServiceSample"address="/WebServiceSample" implementor="cn.org.coral.biz.examples.webservice.WebServiceSampleImpl"/></beans>
WebService 客户端 spring 配置文件 wsclient-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><!-- ws client --><bean id="identityValidateServiceClient" factory-method="create" /><bean id="identityValidateServiceClientFactory"/><property name="address"value="http://88.148.29.54:8080/coral/services/IdentityValidateService"/></bean></beans>
6.发布到tomcat服务器以后通过以下地址即可查看自定义的webservice接口生成的wsdl:
http://88.148.29.54:8080/aio/services/WebServiceSample?wsdl
7.调用WebService接口的Junit单元测试程序
package test.coral.sample;import org.springframework.test.AbstractDependencyInjectionSpringContextTests;import cn.org.coral.biz.examples.webservice.WebServiceSample;import cn.org.coral.biz.examples.webservice.dto.UserDTO;public class TestWebServiceSample extendsAbstractDependencyInjectionSpringContextTests {WebServiceSample webServiceSampleClient;public void setWebServiceSampleClient(WebServiceSample webServiceSampleClient) {this.webServiceSampleClient = webServiceSampleClient;}@Overrideprotected String[] getConfigLocations() {setAutowireMode(AUTOWIRE_BY_NAME); //spring 客户端配置文件保存位置return new String[] { "classpath:/cn/org/coral/biz/examples/webservice/wsclient-context.xml" };}public void testWSClinet(){Assert.hasText(webServiceSampleClient.say(" world"));}}
信息: Interceptor has thrown exception, unwinding noworg.apache.cxf.interceptor.Fault: Marshalling Error: class com.color.webterminal.ws.dto.UserDTO nor any of its super class is known to this context.at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:207)at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:63)
报上面错误啊,按照楼主的做的代码,Help me/** * Web Service传输User信息的DTO. * * 分离entity类与web service接口间的耦合,隔绝entity类的修改对接口的影响. * 使用JAXB 2.0的annotation标注JAVA-XML映射,尽量使用默认约定. * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "User") public class UserDTO { protected Integer id; protected String name; public Integer getId() { return id; } public void setId(Integer value) { id = value; } public String getName() { return name; } public void setName(String value) { name = value; } } <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"><jaxws:client id="wsdlLocation" servicename="code"><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-http.xml"/> <!-- ws client --><bean id="identityValidateServiceClient" factory-method="create"> <property name="bus" ref="cxf" /> </bean> <bean id="identityValidateServiceClientFactory"/><property name="address"value="http://88.148.29.54:8080/coral/services/IdentityValidateService"/></bean></beans>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-http.xml"/> <!-- ws client --><bean id="identityValidateServiceClient" factory-method="create"> <property name="bus" value="#cxf" /> </bean> <bean id="identityValidateServiceClientFactory"/><property name="address"value="http://88.148.29.54:8080/coral/services/IdentityValidateService"/></bean></beans>
多谢楼上回复,按照你的配置,问题已经解决。但是你这段配置有一个错误
<property name="bus" value="#cxf" />
这一行应该配置在 identityValidateServiceClientFactory 这个 bean 中,如果配置在 identityValidateServiceClient 这个 bean ,会报找不到 property 的错误。
另外,应该写成 <property name="bus" ref="cxf">
按照你的写法会出现 classcast 错误:不能把 String 转成 Bus 对象。
我修改了你的配置,如下:
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-http.xml"/> <!-- ws client --><bean id="identityValidateServiceClient" factory-method="create"> </bean> <bean id="identityValidateServiceClientFactory"/><property name="address"value="http://88.148.29.54:8080/coral/services/IdentityValidateService"/> <property name="bus" ref="cxf" /></bean></beans>
- <wsdl:definitions name="WebServiceSampleImplService" targetNamespace="http://impl.cxf.prince.com/" xmlns:ns1="http://cxf.prince.com/" xmlns:ns2="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.cxf.prince.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import location="http://localhost:8080/cxfjaxb/WebServiceSample?wsdl=WebServiceSample.wsdl" namespace="http://cxf.prince.com/" />
- <wsdl:message name="sayUserNameResponse">
<wsdl:part element="ns1:sayUserNameResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="sayResponse">
<wsdl:part element="ns1:sayResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="findUsersResponse">
<wsdl:part element="ns1:findUsersResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="say">
<wsdl:part element="ns1:say" name="parameters" />
</wsdl:message>
- <wsdl:message name="sayUserName">
<wsdl:part element="ns1:sayUserName" name="parameters" />
</wsdl:message>
- <wsdl:message name="findUsers">
<wsdl:part element="ns1:findUsers" name="parameters" />
</wsdl:message>
- <wsdl:binding name="WebServiceSampleImplServiceSoapBinding" type="ns1:WebServiceSample">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="sayUserName">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="sayUserName">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="sayUserNameResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="findUsers">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="findUsers">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="findUsersResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="say">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="say">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="sayResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="WebServiceSampleImplService">
- <wsdl:port binding="tns:WebServiceSampleImplServiceSoapBinding" name="WebServiceSampleImplPort">
<soap:address location="http://localhost:8080/cxfjaxb/WebServiceSample" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>- <wsdl:definitions name="WebServiceSampleImplService" targetNamespace="http://impl.cxf.prince.com/" xmlns:ns1="http://cxf.prince.com/" xmlns:ns2="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.cxf.prince.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import location="http://localhost:8080/cxfjaxb/WebServiceSample?wsdl=WebServiceSample.wsdl" namespace="http://cxf.prince.com/" />
- <wsdl:message name="sayUserNameResponse">
<wsdl:part element="ns1:sayUserNameResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="sayResponse">
<wsdl:part element="ns1:sayResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="findUsersResponse">
<wsdl:part element="ns1:findUsersResponse" name="parameters" />
</wsdl:message>
- <wsdl:message name="say">
<wsdl:part element="ns1:say" name="parameters" />
</wsdl:message>
- <wsdl:message name="sayUserName">
<wsdl:part element="ns1:sayUserName" name="parameters" />
</wsdl:message>
- <wsdl:message name="findUsers">
<wsdl:part element="ns1:findUsers" name="parameters" />
</wsdl:message>
- <wsdl:binding name="WebServiceSampleImplServiceSoapBinding" type="ns1:WebServiceSample">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="sayUserName">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="sayUserName">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="sayUserNameResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="findUsers">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="findUsers">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="findUsersResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
- <wsdl:operation name="say">
<soap:operation soapAction="" style="document" />
- <wsdl:input name="say">
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output name="sayResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="WebServiceSampleImplService">
- <wsdl:port binding="tns:WebServiceSampleImplServiceSoapBinding" name="WebServiceSampleImplPort">
<soap:address location="http://localhost:8080/cxfjaxb/WebServiceSample" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
如果实现一个返回List类型的接口,可以获得list的大小,但是list里的对象都为空;如果用楼主的listobject来封装,在执行listobject.getList()方法时,取得的为空
不知道这个应该怎么解决,谢谢!