JaxWsProxyFactoryBean调用cxf搭建的webService服务传递不同类型参数
最近因为需要使用webservice做接口,在网上学习了下,期间遇到了一些小问题,服务端很顺利搭建完成,在浏览器访问http://xxx?wsdl也能访问到,但是在做客户端的时候,使用JaxWsProxyFactoryBean这个类传递对象出错,直接原因是接口的入参变量名用了arg0,导出报错(意外的元素 (uri:"", local:“XXX”)。所需元素为(none) ) ,可能是因为这个arg0变量冲突了. 废话不多说,分别说下用String为参数和用自定义的对象为参数两种情况的调用.
一.服务端
- 创建一个动态web项目
- lib目录导入jar包 (链接:https://pan.baidu.com/s/1NfrdhdQ0IiRZkw8-KCGz2w ),提取码:eu6k
- 创建模型 HelloVo
package com.vo;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;>@XmlRootElement(name = “HelloVo”)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { “name”, “replyCode” })
public class HelloVo {
private String name;//名字
private String replyCode;//回复码
public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public String getReplyCode() {
return replyCode;
}public void setReplyCode(String replyCode) {
this.replyCode = replyCode;
}public HelloVo(String name, String replyCode) {
super();
this.name = name;
this.replyCode = replyCode;
}
public HelloVo() {
}@Override
public String toString() {
return “HelloVo [name=” + name + “, replyCode=” + replyCode + “]”;
}}
HelloVo的注解解释:
@XmlRootElement-指定XML根元素名称(可选)
@XmlAccessorType-控制属性或方法序列化
四种方案:
FIELD-对每个非静态,非瞬变属性JAXB工具自动绑定成XML,除非注明XmlTransient
NONE-不做任何处理
PROPERTY-对具有set/get方法的属性进行绑定,除非注明XmlTransient
PUBLIC_MEMBER -对有set/get方法的属性或具有共公访问权限的属性进行绑定,除非注
- 创建接口 HelloService
package com.service;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(targetNamespace = “http://service.com”, serviceName = “HelloService”)
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface HelloService {public String sayHello(@WebParam(name = “string1”) String string);
public HelloVo getName(@WebParam(name = “vo”) HelloVo vo);
}
5.创建实现类 HelloServiceImpl
package com.service.impl;
import com.service.HelloService;
public class HelloServiceImpl implements HelloService {@Override
public String sayHello(String string) {
return “来自服务器问候,你好:” + string;
}
}
- CXF的配置类: cxf-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.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:server id=“HelloService” serviceClass=“com.service.HelloService” address="/HelloService">
<jxws:serviceBean>
<bean class=“com.service.impl.HelloServiceImpl” />
</jaxws:serviceBean>
</jaxws:server>
</beans>
7.web.xml配置
<?xml version=“1.0” encoding=“UTF-8”?>
<web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns=“http://xmlns.jcp.org/xml/ns/javaee”
xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd”
id=“WebApp_ID” version=“2.5”>
<display-name>myservice
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 加载Spring容器配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener>
<!-- 配置spring配置选项 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/springContext*.xml</param-value>
</context-param><servlet>
<description>Apache CXF Endpoint</description>
<display-name>cxf</display-name>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet><servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
此时服务端代码已经完成,用eclipse添加一个服务,启动tomcat执行了.
浏览器地址栏输入 http://localhost:8080//myservice/services/HelloService?wsdl ,出现返回wsdl则说明服务端成功.
接下来我们编写客户端代码,去访问这个接口:http://localhost:8080/myservice/services/HelloService?wsdl
二.客户端
- 创建另一个动态web项目,导入服务端用的包
- 创建模型 HelloVo,直接拷贝服务端的HelloVo
package com.vo;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;>@XmlRootElement(name = “HelloVo”)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { “name”, “replyCode” })
public class HelloVo {
private String name;//名字
private String replyCode;//回复码
public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public String getReplyCode() {
return replyCode;
}public void setReplyCode(String replyCode) {
this.replyCode = replyCode;
}public HelloVo(String name, String replyCode) {
super();
this.name = name;
this.replyCode = replyCode;
}
public HelloVo() {
}@Override
public String toString() {
return “HelloVo [name=” + name + “, replyCode=” + replyCode + “]”;
}}
- 创建一个接口HelloService,要和服务端的一致,注意这个接口的全限定名要和服务端的一致
package com.service;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(targetNamespace = “http://service.com”, serviceName = “HelloService”)
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface HelloService {public String sayHello(@WebParam(name = “string1”) String string);
public HelloVo getName(@WebParam(name = “vo”) HelloVo vo);
}
4.建立测试类Test.java
package com.service.test;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.service.HelloService;
import com.vo.HelloVo;
public class test {public static void main(String[] args) throws Exception {
//test1();
test2();
}// 参数为String类型
private static void test1() {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloService.class);
factory.setAddress(“http://localhost:8080/myservice/services/HelloService?wsdl”);
// 添加输入拦截器 :输入显示日志信息的拦截器
factory.getInInterceptors().add(new LoggingInInterceptor());
// 添加输出拦截器 :输出显示日志信息的拦截器
factory.getOutInterceptors().add(new LoggingOutInterceptor());
HelloService userDao = (HelloService) factory.create();
// 看起来是调用本地接口,实则不是,毕竟本地都没有实现类
String sayHello = userDao.sayHello(“小黄”);
System.out.println(sayHello);
}
// 参数为自定义对象类型
private static void test2() {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloService.class);
factory.setAddress(“http://localhost:8080/myservice/services/HelloService?wsdl”);
// 添加输入拦截器 :输入显示日志信息的拦截器
factory.getInInterceptors().add(new LoggingInInterceptor());
// 添加输出拦截器 :输出显示日志信息的拦截器
factory.getOutInterceptors().add(new LoggingOutInterceptor());
HelloService userDao = (HelloService) factory.create();
// 看起来是调用本地接口,实则不是,毕竟本地都没有实现类
HelloVo name = userDao.getName(new HelloVo(“小明”, “01”));
System.out.println(name.toString());}
}
测试传递参数为String的时候,得到结果: 来自服务器问候,你好:小黄
测试传递参数为对象的时候,得到结果: HelloVo [name=你好小明, replyCode=OK]
三.注意点
1.创建HelloVo的时候如果加了有参构造,记得加上无参构造器(低级错误)
2.传递对象的时候,如果报错(Exception in thread “main” javax.xml.ws.soap.SOAPFaultException: Unmarshalling Error: 意外的元素 (uri:"", local:“json”)。所需元素为(none)),在HelloVo要加上注释,因为对象要解析为soap标签,从下面日志中看出,对象会转为特定便签
ID: 1
Address: http://localhost:8080/myservice/services/HelloService?wsdl
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[/], SOAPAction=[""]}
Payload:
<soap:Envelope xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body>
<ns2:vo xmlns:ns2=“http://service.com”>
<name>小明</name>
<replyCode>01</replyCode>
</ns2:vo>
</soap:Body>
</soap:Envelope>
3.参数名不要用arg0,估计是哪里冲突了
四.总结
本文只讲了传递普通参数(如String,int…)和自定义对象(HelloVo)两种方式,此外,无参数的情况和普通参数一样. 还有就是本文只是采用JaxWsProxyFactoryBean类调用,还有通过wsimport生成本地代码调用,用JaxWsDynamicClientFactory调用等.
感谢观看,点个赞呗老铁