JaxWsProxyFactoryBean调用cxf搭建的webService服务传递不同类型参数

最近因为需要使用webservice做接口,在网上学习了下,期间遇到了一些小问题,服务端很顺利搭建完成,在浏览器访问http://xxx?wsdl也能访问到,但是在做客户端的时候,使用JaxWsProxyFactoryBean这个类传递对象出错,直接原因是接口的入参变量名用了arg0,导出报错(意外的元素 (uri:"", local:“XXX”)。所需元素为(none) ) ,可能是因为这个arg0变量冲突了. 废话不多说,分别说下用String为参数和用自定义的对象为参数两种情况的调用.

一.服务端

  1. 创建一个动态web项目
  2. lib目录导入jar包 (链接:https://pan.baidu.com/s/1NfrdhdQ0IiRZkw8-KCGz2w ),提取码:eu6k
  3. 创建模型 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方法的属性或具有共公访问权限的属性进行绑定,除非注

  1. 创建接口 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;
  }
}

  1. 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/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsd   http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsdhttp://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则说明服务端成功.
JaxWsProxyFactoryBean调用cxf搭建的webService服务传递不同类型参数JaxWsProxyFactoryBean调用cxf搭建的webService服务传递不同类型参数
接下来我们编写客户端代码,去访问这个接口:http://localhost:8080/myservice/services/HelloService?wsdl

二.客户端

  1. 创建另一个动态web项目,导入服务端用的包
  2. 创建模型 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 + “]”;
}

}

  1. 创建一个接口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调用等.

感谢观看,点个赞呗老铁