百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Spring整合CXF 发布webservice接口服务器和客户端,WSDL简单解析

yuyutoo 2024-10-26 16:09 1 浏览 0 评论

在垮平台通讯中有很多的接口方式,这里做个简单的webservice接口。发布webservice接口的方式也多种多样,这里做个基于CXF的webservice接口。首先做点知识储备,javax.jws包中常用的注解,参考链接:http://blog.csdn.net/w410589502/article/details/51742004

下面开始,这里Spring用的4.2的,CXF用的3.2的,JDK是1.8的,这里只要是1.6及以后的就没问题了,主要是要用javax.jws的包

服务端webservice接口

package com.lovo.webservice;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

/**
 * SOAP协议的webservice接口
 * @author WZH
 *服务器端,服务提供者
 */

/*
 * @WebService 标记为一个webservice接口
 * 1.targetNamespace:指定你想要的名称空间,默认认是使用接口实现类的包名的反缀,
 * 但是在实际测试中发现cxf+spring编写webservice的时候,targetNamespace要指向
 * 服务类的接口所在的包名而不是实现类的包名,否则,在客户端将不能识别可用的服务
 * 2.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。
 * 缺省值为 Java 类的简单名称 + Service。(字符串)
 * 3.portName:  wsdl:portName。缺省值为 WebService.name+Port。
 * 
 * @SOAPBinding 消息绑定, 这个标记怎么说,我这里测试的时候加不加都无所谓,但是有同仁说过
 * 不加这个有时候会出现客户端无法识别,有的人又报错,所以还是加上吧
 * Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException: 
 * runtime modeler error: Wrapper class org.soap.service.jaxws.Add is not found. Have you run APT to generate them?
 */
@WebService(targetNamespace ="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface IHelloService {
    
    /*
     * @WebResult 注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
     * 或者应用于 JavaBeans 端点的服务器端点实现类
     * 1.name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的
     * 2.targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE 时才使用此参数。(字符串)
     * 
     * @WebMethod 注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
     * 或者应用于 JavaBeans 端点的服务器端点实现类。
     * 1.operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
     * 
     * @WebParam 注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射
     * 1.name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,
     * 那么这是用于表示参数的 wsdl:part 属性的名称。如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。
     * 如果操作是文档类型、参数类型为 BARE 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
     */
    
    @WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
    @WebMethod(operationName="sayHello1")
    public String hello(@WebParam(name="msg")String message);
}

服务端接口实现类

package com.lovo.webservice.impl;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

import org.springframework.stereotype.Service;

import com.lovo.webservice.IHelloService;

/*
 * endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口,简单的说就写接口的全路径
 */
@WebService(endpointInterface="com.lovo.webservice.IHelloService")
@SOAPBinding(style=Style.RPC)
public class HelloServiceImpl implements IHelloService {

    @Override
    public String hello(String message) {
        
        return "你好" + message;
    }

}

前面的两段代码只是简单的java加上一些注解,下面把代码整合入Spring的web工程
web.xml 配置
需在web.xml中配置CXF

 <!-- 启动CXF框架 web service-->
  <servlet>
    <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>/webservice/*</url-pattern>
  </servlet-mapping>

完整的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Spring</display-name>
  
    <context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>Spring.root</param-value>
  </context-param>


<!--    spring容器启动 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
  </context-param>
    
 <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.xml</param-value>
  </context-param>
  
  <!--   指定日志刷新的时间,单位毫秒 -->
  <context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>60000</param-value>
  </context-param>  
    
       <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

<!-- 配置欢迎页面 -->
<welcome-file-list>  
    <welcome-file>index.jsp</welcome-file>  
</welcome-file-list>  

<!--      字符过滤器 -->

<filter>  
    <filter-name>characterEncodingFilter</filter-name>  
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
    <init-param>  
        <param-name>encoding</param-name>  
        <param-value>UTF-8</param-value>  
    </init-param>  
    <init-param>  
        <param-name>forceEncoding</param-name>  
        <param-value>true</param-value>  
    </init-param>  
</filter>  
<filter-mapping>  
    <filter-name>characterEncodingFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>

<!--  <filter>
    <filter-name>encoding</filter-name>
    <filter-class>com.lovo.filter.EncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping> -->

 <!-- 启动CXF框架 web service-->
  <servlet>
    <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>/webservice/*</url-pattern>
  </servlet-mapping>
  
  <!--   配置核心控制器 -->
<servlet>
    <servlet-name>Spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping> 
  

</web-app>

配置cxf的配置文件,这个也可以直接配置在Spring的配置文件中,看项目风格吧

<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://cxf.apache.org/jaxws
 http://cxf.apache.org/schemas/jaxws.xsd">

    <!--CXF配置 这里因为是3.x的CXF 只需要引用一个文件就好-->
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    

    <!-- id是接口名,不重复就好,serviceClass 是接口的路径,address是对外暴露的地址名,bean classs是引用的接口的实现类 -->
     <jaxws:server id="helloService" serviceClass="com.lovo.webservice.IHelloService" address="/HelloService">
        <jaxws:serviceBean>
            <bean class="com.lovo.webservice.impl.HelloServiceImpl"></bean>
        </jaxws:serviceBean>
    </jaxws:server> 
    
</beans>

在application.xml中引入cxf.xml

<!--CXF配置 -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:/cxf-beans.xml"/>

完整的application.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:jaxws="http://cxf.apache.org/jaxws" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                        http://www.springframework.org/schema/task
                        http://www.springframework.org/schema/task/spring-task-3.0.xsd
                        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <!-- 开启自动扫描机制 -->
    <context:component-scan base-package="com"></context:component-scan>
    <!-- <context:property-placeholder location="classpath:mysql.properties"/> -->
    <!-- 配置数据库连接池 -->


    <!-- 商业数据源 c3p0, apache提供的DBCP -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"></property>
        <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:oracle"></property>
        <property name="user" value="system"></property>
        <property name="password" value="Password01"></property>
        <property name="initialPoolSize" value="15"></property><!-- 初始化连接数的数量 -->
        <property name="minPoolSize" value="15"></property>
        <property name="maxPoolSize" value="100"></property>
        <property name="acquireIncrement" value="5"></property>
        <property name="maxStatements" value="200"></property>
        <property name="maxIdleTime" value="200"></property><!-- 超时时间 -->
        <property name="checkoutTimeout" value="2000"></property><!-- 多长时间回收一次超时连接 -->
    </bean>

    <!-- SessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <!-- 如果有多包需要取类别名的话,使用,或;分割 -->
        <property name="typeAliasesPackage" value="com.lovo.beans"></property>
    </bean>

    <!-- 将Session与Mapper直接进行关联 -->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lovo.mapper"></property>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="txManage"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!-- session实例化 -->

    <!-- 声明事物 -->
    <tx:advice id="txAdvice" transaction-manager="txManage">
        <tx:attributes>
            <tx:method name="*" read-only="true"></tx:method>
            <tx:method name="add*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <tx:method name="save*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <tx:method name="insert*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>

            <tx:method name="update*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <tx:method name="modify*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <tx:method name="change*" propagation="REQUIRED" read-only="false"
                rollback-for="java.lang.Exception" isolation="REPEATABLE_READ"></tx:method>

            <tx:method name="delete*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <tx:method name="remove*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>
            <!-- 添加了一个删除方法的命名 -->
            <tx:method name="del*" read-only="false" propagation="REQUIRED"
                isolation="REPEATABLE_READ" rollback-for="java.lang.Exception"></tx:method>

            <tx:method name="select*" read-only="true" propagation="SUPPORTS"></tx:method>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"></tx:method>
            <tx:method name="get*" read-only="true" propagation="SUPPORTS"></tx:method>


        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="serviceMethods"
            expression="execution(* com.lovo.service.impl.*.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"></aop:advisor>
    </aop:config>



    <!-- 开启切面功能 -->
    <aop:aspectj-autoproxy />

    <!--CXF配置 -->
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:/cxf-beans.xml"/>
</beans>

下面来测试下发布是否成功,我这里是tomcat 工程名是Spring,拦截的是webservice,所以访问的地址是:http://localhost:8080/Spring/webservice?wsdl

出现界面

右键连接地址可以下载wsdl

这样就发布了一个简单的webservice接口,下面在发布一个接口以便wsdl的时候做对比,然后再发布一个rest风格的接口

package com.lovo.webservice;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

/**
 * SOAP协议的webservice接口
 * @author WZH
 *服务器端,服务提供者
 */

/*
 * @WebService 标记为一个webservice接口
 * 1.targetNamespace:指定你想要的名称空间,默认认是使用接口实现类的包名的反缀,
 * 但是在实际测试中发现cxf+spring编写webservice的时候,targetNamespace要指向
 * 服务类的接口所在的包名而不是实现类的包名,否则,在客户端将不能识别可用的服务
 * 2.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。
 * 缺省值为 Java 类的简单名称 + Service。(字符串)
 * 3.portName:  wsdl:portName。缺省值为 WebService.name+Port。
 * 
 * @SOAPBinding 消息绑定, 这个标记怎么说,我这里测试的时候加不加都无所谓,但是有同仁说过
 * 不加这个有时候会出现客户端无法识别,有的人又报错,所以还是加上吧
 * Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException: 
 * runtime modeler error: Wrapper class org.soap.service.jaxws.Add is not found. Have you run APT to generate them?
 */
@WebService(targetNamespace ="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface IHelloService {
    
    /*
     * @WebResult 注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
     * 或者应用于 JavaBeans 端点的服务器端点实现类
     * 1.name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的
     * 2.targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE 时才使用此参数。(字符串)
     * 
     * @WebMethod 注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,
     * 或者应用于 JavaBeans 端点的服务器端点实现类。
     * 1.operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
     * 
     * @WebParam 注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射
     * 1.name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,
     * 那么这是用于表示参数的 wsdl:part 属性的名称。如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。
     * 如果操作是文档类型、参数类型为 BARE 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
     */
    
    @WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
    @WebMethod(operationName="sayHello1")
    public String hello(@WebParam(name="msg")String message);
    
    @WebResult(name="loginRequest",targetNamespace="http://webservice.lovo.com/")
    @WebMethod(operationName="login")
    public String login(@WebParam(name="userName")String userName,@WebParam(name="password")String password);
}

这里需要特别注意,targetNamespace中路径结尾需写反斜杠/不然会出现问题

package com.lovo.webservice.impl;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

import org.springframework.stereotype.Service;

import com.lovo.webservice.IHelloService;

/*
 * endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口,简单的说就写接口的全路径
 */
@WebService(endpointInterface="com.lovo.webservice.IHelloService")
@SOAPBinding(style=Style.RPC)
public class HelloServiceImpl implements IHelloService {

    @Override
    public String hello(String message) {
        
        return "你好" + message;
    }

    @Override
    public String login(String userName, String password) {
        String req = null;
        //这里做个假的登录验证
        if("小明".equals(userName)&&"123456".equals(password))
        {
            req = "登录成功";
        }else
        {
            req = "登录失败";
        }
        return req;
    }

}

这个时候再访问wsdl的网址就看见有两个方法了

下载wsdl

<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
xmlns:tns="http://webservice.lovo.com" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 
name="HelloService" 
targetNamespace="http://webservice.lovo.com/">
  <wsdl:message name="loginResponse">
    <wsdl:part name="loginRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1Response">
    <wsdl:part name="helloRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1">
    <wsdl:part name="msg" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="login">
    <wsdl:part name="userName" type="xsd:string">
    </wsdl:part>
    <wsdl:part name="password" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="IHelloService">
    <wsdl:operation name="sayHello1">
      <wsdl:input message="tns:sayHello1" name="sayHello1">
    </wsdl:input>
      <wsdl:output message="tns:sayHello1Response" name="sayHello1Response">
    </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <wsdl:input message="tns:login" name="login">
    </wsdl:input>
      <wsdl:output message="tns:loginResponse" name="loginResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloServiceSoapBinding" type="tns:IHelloService">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sayHello1">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="sayHello1">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHello1Response">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="login">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="loginResponse">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HelloService">
    <wsdl:port binding="tns:HelloServiceSoapBinding" name="HellowServicePort">
      <soap:address location="http://localhost:8080/Spring/webservice/HelloService"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

阅读wsdl的方法详细的阅读方式方式可以看这篇文章:http://blog.csdn.net/liuchunming033/article/details/41210151

拿到一个wsdl,个人一般是先看最后,也就是wsdl:service部分。wsdl:service:存放接口名和接口地址

<!--多个接口放在一起为一个service name为视图服务名-->
  <wsdl:service name="HelloService">
    <!-- 一个port表示一个接口 name表示刚刚绑定的name,就是portName这个参数 -->
    <wsdl:port binding="tns:HelloServiceSoapBinding" name="HellowServicePort">
       <!-- address表示接口对象的地址 -->
      <soap:address location="http://localhost:8080/Spring/webservice/HelloService"/>
    </wsdl:port>
  </wsdl:service>

然后再看binding部分,也就是wsdl:binding
wsdl:binding:每个端口定义消息格式和协议细节

<!-- 把接口进行soap绑定 type为接口名 name对应 service中的binding参数-->
  <wsdl:binding name="HelloServiceSoapBinding" type="tns:IHelloService">
    <!--指明绑定的协议为http soap协议,类型为rpc 这里就是@SOAPBinding那个注解指定了为rpc ,如果不指定默认为document-->
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <!--具体方法的bnding类型,接口中有多少个方法就有多少个operation 其中name表示方法名 literal文本-->
    <wsdl:operation name="sayHello1">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="sayHello1">
        <!--方法的命名空间namespace 就是方法@WebResult注解中指定的targetNamespace-->
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHello1Response">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="login">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="loginResponse">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

再看portType部分,wsdl:portType
wsdl:portType:描述webservice可被执行的操作,以及相关的消息,通过binding指向portType

  <!--name表示接口名-->
  <wsdl:portType name="IHelloService">
    <!--接口中有很多方法,没个opertion就表示一个方法名,name为方法名,为代码中@WebMethod中定义的operationName-->
    <wsdl:operation name="sayHello1">
      <!--通过message可以查看方法中对应的参数,input表示传入,output表示返回-->
      <wsdl:input message="tns:sayHello1" name="sayHello1">
    </wsdl:input>
      <wsdl:output message="tns:sayHello1Response" name="sayHello1Response">
    </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <wsdl:input message="tns:login" name="login">
    </wsdl:input>
      <wsdl:output message="tns:loginResponse" name="loginResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>

在看message,wsdl:message
wsdl:message:定义一个操作(方法)的数据参数(可有多个参数)

  <!--login方法的返回值定义,一般为方法名+response 这里方法只有一个简单的返回值,类型为String-->
  <wsdl:message name="loginResponse">
    <wsdl:part name="loginRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1Response">
    <wsdl:part name="helloRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1">
    <wsdl:part name="msg" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <!--name对应portType中的operation name属性对应的值。login方法好传入的参数,有几个参数就有几个part-->
  <wsdl:message name="login">
    <!--参数名为userName,参数类型为String-->
    <wsdl:part name="userName" type="xsd:string">
    </wsdl:part>
    <wsdl:part name="password" type="xsd:string">
    </wsdl:part>
  </wsdl:message>

最后还是需要看看开始部分

<!--name 表示接口名,targetNamespace表示接口的命名空间-->
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
xmlns:tns="http://webservice.lovo.com" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 
name="HelloService" 
targetNamespace="http://webservice.lovo.com/">

这么一个简单的xml就解析完了
完整的xml文档

<!--name 表示接口名,targetNamespace表示接口的命名空间-->
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
xmlns:tns="http://webservice.lovo.com" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 
name="HelloService" 
targetNamespace="http://webservice.lovo.com/">
  <!--login方法的返回值定义,一般为方法名+response 这里方法只有一个简单的返回值,类型为String-->
  <wsdl:message name="loginResponse">
    <wsdl:part name="loginRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1Response">
    <wsdl:part name="helloRequest" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="sayHello1">
    <wsdl:part name="msg" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <!--name对应portType中的operation name属性对应的值。login方法好传入的参数,有几个参数就有几个part-->
  <wsdl:message name="login">
    <!--参数名为userName,参数类型为String-->
    <wsdl:part name="userName" type="xsd:string">
    </wsdl:part>
    <wsdl:part name="password" type="xsd:string">
    </wsdl:part>
  </wsdl:message>
  <!--name表示接口名-->
  <wsdl:portType name="IHelloService">
    <!--接口中有很多方法,没个opertion就表示一个方法名,name为方法名,为代码中@WebMethod中定义的operationName-->
    <wsdl:operation name="sayHello1">
      <!--通过message可以查看方法中对应的参数,input表示传入,output表示返回-->
      <wsdl:input message="tns:sayHello1" name="sayHello1">
    </wsdl:input>
      <wsdl:output message="tns:sayHello1Response" name="sayHello1Response">
    </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <wsdl:input message="tns:login" name="login">
    </wsdl:input>
      <wsdl:output message="tns:loginResponse" name="loginResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <!-- 把接口进行soap绑定 type为接口名 name对应 service中的binding参数-->
  <wsdl:binding name="HelloServiceSoapBinding" type="tns:IHelloService">
    <!--指明绑定的协议为http soap协议,类型为rpc 这里就是@SOAPBinding那个注解指定了为rpc ,如果不指定默认为document-->
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <!--具体方法的bnding类型,接口中有多少个方法就有多少个operation 其中name表示方法名 literal文本-->
    <wsdl:operation name="sayHello1">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="sayHello1">
        <!--方法的命名空间namespace 就是方法@WebResult注解中指定的targetNamespace-->
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHello1Response">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="login">
      <soap:operation soapAction="" style="rpc"/>
      <wsdl:input name="login">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:input>
      <wsdl:output name="loginResponse">
        <soap:body namespace="http://webservice.lovo.com/" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <!--多个接口放在一起为一个service name为视图服务名-->
  <wsdl:service name="HelloService">
    <!-- 一个port表示一个接口 name表示刚刚绑定的name,就是portName这个参数 -->
    <wsdl:port binding="tns:HelloServiceSoapBinding" name="HellowServicePort">
       <!-- address表示接口对象的地址 -->
      <soap:address location="http://localhost:8080/Spring/webservice/HelloService"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

wsdl阅读完成了,需要的参数都明白了,下面就可以做个简单的客户端进行调用,webService客户端调用的方法有很多,我们这里简单的做几个。
一:Service编程方式
特点:可以自定义关键元素,方便以后维护,是一种标准的开发方式
首先写一个客户端调用对象

package com.lovo.client;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

/**
 * 客户端调用者,根据wsdl初始化接口对象
 * @author WZH
 *
 *targetNamespace 对应wsdl抬头 targetNamespace,serviceName和portName分别对应wsdl结尾的wsdl:service name="HelloService"
 *和wsdl:port binding="tns:HelloServiceSoapBinding" name="HellowServicePort">
 *因为wsdl文档中有指定SOAP类型,所以需书写类型 <soap:operation soapAction="" style="rpc"/>
 */
@WebService(targetNamespace="http://webservice.lovo.com/",serviceName="HelloService",portName="HellowServicePort")
@SOAPBinding(style=Style.RPC)
public interface HellowService {
    /**
     * 方法名对应wsdl wsdl:operation name="login"
     * @param username 参数名对应 wsdl:part name="userName" type="xsd:string"
     * @param password
     * @return
     * 
     * 方法名映射 <wsdl:operation name="login">
     *  地址映射<soap:body namespace="http://webservice.lovo.com" use="literal"/>
     * 参数映射:<wsdl:part name="userName" type="xsd:string"> <wsdl:part name="password" type="xsd:string">
     */
    @WebResult(name="login",targetNamespace="http://webservice.lovo.com/")
    @WebMethod(operationName = "login")
    public String login(@WebParam(name = "userName")String username , @WebParam(name = "password")String password);
    
    @WebResult(name="helloRequest",targetNamespace="http://webservice.lovo.com/")
    @WebMethod(operationName="sayHello1")
    public String hello(@WebParam(name="msg")String msg);
    
}

这里需要特别注意,targetNamespace中路径结尾需写反斜杠/不然会出现问题

准备工作做好了,可以做个客户端的调用了

package com.lovo.client;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

public class wsClient {
    
    /**
     * XML 类 第一个参数表示地址,第二个参数表示端口名
     * 这里第一个参数是wsdl 表头targetNamespace
     * 第二个参数是service name
     */
    private static final QName SERVICE_NAME =  new QName("http://webservice.lovo.com/", "HelloService");
    private static final QName PORT_NAME = new QName("http://webservice.lovo.com/", "HellowServicePort");
    
    //编程方式一 begin -----------------------
    public static void testSayHello()
    {
        try {
            //创建Serivce业务类
            Service service = Service.create(SERVICE_NAME);
            //连接地址  <soap:address location="http://localhost:8080/Spring/webservice/HelloService"/>
            String endPointAddress = "http://localhost:8080/Spring/webservice/HelloService";
            //配置业务访问参数 portName, bindingId, endpointAddress,
            //这里因为是SOPA11的所有配置11,SOAP现在有11和12两种 可通过xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 判断
            service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endPointAddress);
            
            //把本地客户端的接口与网络上的WSDL连接起来
            HellowService hs = service.getPort(HellowService.class);
            System.out.println(hs.hello("小明"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    //end-------------------------------------
    
    
    //编程方式二 begin  不知道为什么 Service.create报错,可能是jar原因-----------------------
    public static void testSayHello2()
    {
        try 
        {
            //创建WSDL的URL,注意不是服务地址  
            URL url = new URL("http://localhost:8080/Spring/webservice?wsdl");
            //创建服务名,代码有写成了静态常量,这里直接引用
            
            //创建服务视图
            javax.xml.ws.Service service = Service.create(url, SERVICE_NAME);
            //获取服务实例
            HellowService hs = service.getPort(new QName("http://webservice.lovo.com/", "HellowServicePort"), HellowService.class);
            System.out.println(hs.hello("小明"));
            
        } catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
    
    
    //end-------------------------------------
    
    public static void main(String[] args) {
        //testSayHello();
        testSayHello2();
    }

}

剩下的等有空的再完善

相关推荐

jQuery VS AngularJS 你更钟爱哪个?

在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...

Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0

在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...

如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例

要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...

编程技巧:Jquery实时验证,指定长度的「负小数」

为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

编程技巧:Jquery实时验证,指定长度的「正小数」

为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...

jquery.validate检查数组全部验证

问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...

Vue进阶(幺叁肆):npm查看包版本信息

第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...

layui中使用lay-verify进行条件校验

一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...

jQuery是什么?如何使用? jquery是什么功能组件

jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...

django框架的表单form的理解和用法-9

表单呈现...

jquery对上传文件的检测判断 jquery实现文件上传

总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...

Nodejs之MEAN栈开发(四)-- form验证及图片上传

这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...

大数据开发基础之JAVA jquery 大数据java实战

上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...

推荐四个开源的jQuery可视化表单设计器

jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...

取消回复欢迎 发表评论: