Java JDK wsimport.exe 根据 wsdl 文件生成类文件 与 WebService WSDL 文件结构详解

目录

wsimport wsdl 文件工具简介

wsimport 根据 wsdl 文件生成类文件

WSDL 文件结构剖析

服务方法数据类型说明

@WebResult 与 @WebParam

学生实体验证示例


wsimport wsdl 文件工具简介

1、Java JDK 的 bin文件夹下有一个 wsimport.exe 工具,可依据 wsdl 文件生成相应的类文件,将生成好的类文件拷贝到需要使用的项目中,就可以像调用本地的类一样调用 webService 提供的方法。

2、wsimport.exe 工具可以用于非 Java 的 webService 服务器,如用 C# 、.net 等语言编写的 WebService 服务端,只要得到了其 wsdl 文件,则通过 wsimport 即可生成 Java 客户端实现。

3、只要在电脑上配置了 Java JDK 的环境变量,则可以在任意目录下使用 cmd 窗口执行 wsimport 命令,如下所示可以看到命令的格式、以及参数、使用示例等。

C:\Users\Administrator.SC-201707281232>wsimport
缺少 WSDL_URI

用法: wsimport [options] <WSDL_URI>
\其中 [options] 包括:
  -b <path>                 指定 jaxws/jaxb 绑定文件或附加模式
                            (每个 <path> 都必须具有自己的 -b)
  -B<jaxbOption>            将此选项传递给 JAXB 模式编译器
  -catalog <file>           指定用于解析外部实体引用的目录文件
                            支持 TR9401, XCatalog 和 OASIS XML 目录格式。
  -d <directory>            指定放置生成的输出文件的位置
  -encoding <encoding>      指定源文件所使用的字符编码
  -extension                允许供应商扩展 - 不按规范
                            指定功能。使用扩展可能会
                            导致应用程序不可移植或
                            无法与其他实现进行互操作
  -help                     显示帮助
  -httpproxy:<host>:<port>  指定 HTTP 代理服务器 (端口默认为 8080)
  -keep                     保留生成的文件
  -p <pkg>                  指定目标程序包
  -quiet                    隐藏 wsimport 输出
  -s <directory>            指定放置生成的源文件的位置
  -target <version>         按给定的 JAXWS 规范版本生成代码
                            默认为 2.2, 接受的值为 2.0, 2.1 和 2.2
                            例如, 2.0 将为 JAXWS 2.0 规范生成兼容的代码
  -verbose                  有关编译器在执行什么操作的输出消息
  -version                  输出版本信息
  -wsdllocation <location>  @WebServiceClient.wsdlLocation 值
  -clientjar <jarfile>      创建生成的 Artifact 的 jar 文件以及
                            调用 Web 服务所需的 WSDL 元数据。
  -generateJWS              生成存根 JWS 实现文件
  -implDestDir <directory>  指定生成 JWS 实现文件的位置
  -implServiceName <name>   生成的 JWS 实现的服务名的本地部分
  -implPortName <name>      生成的 JWS 实现的端口名的本地部分

\扩展:
  -XadditionalHeaders              映射标头不绑定到请求或响应消息不绑定到
                                   Java 方法参数
  -Xauthfile                       用于传送以下格式的授权信息的文件:
                                   http://username:password@example.org/stock?wsdl
  -Xdebug                          输出调试信息
  -Xno-addressing-databinding      允许 W3C EndpointReferenceType 到 Java 的绑定
  -Xnocompile                      不编译生成的 Java 文件
  -XdisableAuthenticator           禁用由 JAX-WS RI 使用的验证程序,
                                   将忽略 -Xauthfile 选项 (如果设置)
  -XdisableSSLHostnameVerification 在提取 wsdl 时禁用 SSL 主机名
                                   验证

\示例:
  wsimport stock.wsdl -b stock.xml -b stock.xjb
  wsimport -d generated http://example.org/stock?wsdl

C:\Users\Administrator.SC-201707281232>

常用命令如下:

wsimport -keep -d D:\temp\d -s D:\temp\s -p com.map -verbose http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
-keep:是否生成java源文件,即在生成 .class 文件的同时也会生成 .java 源文件
-d:指定.class文件的输出目录,此目录必须存在。
-s:指定.java文件的输出目录,不指定时,默认与 -d 设置的路径一致
-p:定义生成类的包名,不指定时保持与原来一致
-verbose:在控制台显示输出信息
-b:指定jaxws/jaxb绑定文件或额外的schemas
-extension:使用扩展来支持SOAP1.2

wsimport 根据 wsdl 文件生成类文件

1、《JWS(Java Web Service) 第一个案例入门》中的 webService 客户端是直接写的与服务端一样的接口,对于公司内部,或者很要好的合作伙伴找人家开发人员直接获取 webservice 提供的接口源码也不是不行,看起来是 low 了一点,但也是一个办法。

服务端

1、现在就开始使用 Java JDK 提供的 wsimport 工具来根据服务端提供的 wsdl 文件直接生成类文件,只要服务商提供了 wsdl 地址,自己就可以默默的生成类文件然后调用。

2、这个示例仍然以《JWS(Java Web Service) 第一个案例入门》中的 "ws 服务端"作为 webservice 的服务端,就不再反复粘贴代码了。

3、启动 webService 服务端如下:

客户端

1、仍然以《JWS(Java Web Service) 第一个案例入门》中"客户端"项目进行改写,先删除其中的 CalculatorService 文件,改用 wsimport.exe 进行生成。

2、使用命令如下,其中的 E:/wmx/webservice 目录用于存放生成好的文件,必须事先创建好:

wsimport -d E:/wmx/webservice -keep -verbose http://192.168.1.20:3333/web_server/calculator?wsdl

2、命令执行成功后,生成文件内容如下:

下面虽然也生成了接口的实现类 CalculatorServiceImplService.java (名称上比服务端上多加了后面的 Service),但是其中的内容和 webService 服务端是完全不一样的,不用担心源码泄露。

生成的 CalculatorService.java 接口中的内容大致与服务器上一致,接口中的方法名称肯定是一样的,也有其它很大内容不一致。


3、如上所示,服务端只对外提供了一个接口 CalculatorService 与其实现类 CalculatorServiceImpl,而 wsimport.exe 命令却生成了这么多文件。

4、仔细看可以发现:Addition 、Multiplication 分别是服务端 CalculatorService  接口中定义加法函数、乘法函数。

5、所以客户端需要使用的就是其中的 Addition.java、AdditionResponse.java、Multiplication.java、MultiplicationResponse.java、CalculatorService.java,以及 ObjectFactory.java 文件。接口的实现类以及其它类可以不用导入,当然全部导入也不会出错。

6、补充一句:部署阶段,直接使用上面的 .class 文件也是可以的。

7、导入生成好的文件如上,其中 Web_service 类用于调用 webservice 服务,与 《JWS(Java Web Service) 第一个案例入门》中的代码完全一致,这里再次粘贴一次,内容如下:

import com.lct.web_service.CalculatorService;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
/**
 * Created by Administrator on 2019/1/25 0025.
 */
public class Web_service {
    //日志记录器
    public static final Logger logger = Logger.getGlobal();

    public static void main(String[] args) {
        try {
            /** url:webservice 服务端提供的服务地址,结尾必须加 "?wsdl"*/
            URL url = new URL("http://192.168.1.20:3333/web_server/calculator?wsdl");

            /** QName 表示 XML 规范中定义的限定名称,QName 的值包含名称空间 URI、本地部分和前缀。
             * QName(final String namespaceURI, final String localPart):指定名称空间 URI 和本地部分的 QName 构造方法。
             * 如下所示的两个数据都可以浏览器访问服务端时返回 xml 中第一行找到,如:
             * <definitions xmlns:wsu=xxxxxxx targetNamespace="http://web_service.lct.com/" name="CalculatorServiceImplService">
             */
            QName qName = new QName("http://web_service.lct.com/", "CalculatorServiceImplService");

            /**
             * Service 对象提供 Web 服务的客户端视图
             * Service 作为以下内容的工厂:1、目标服务端点的代理,2、用于远程操作的动态面向消息调用的 javax.xml.ws.Dispatch 实例。
             * create(java.net.URL wsdlDocumentLocation,QName serviceName):创建 Service 实例。
             * wsdlDocumentLocation : 服务 WSDL 文档位置的 URL
             * serviceName : 服务的 QName
             */
            Service service = Service.create(url, qName);

            /**
             * 使用 getPorts 方法可以对服务上可用的端口/接口进行枚举
             * getPort(Class<T> serviceEndpointInterface):获取支持指定服务端点接口的对象实例
             * serviceEndpointInterface:指定返回的代理所支持的服务端点接口
             */
            CalculatorService calculatorService = service.getPort(CalculatorService.class);
            float added = calculatorService.addition(100, 80);
            float multied = calculatorService.multiplication(2.5F, 100);

            logger.info("added:" + added);
            logger.info("multied:" + multied);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

调用测试

与《JWS(Java Web Service) 第一个案例入门》完全一致,调用成功。

特别说明

如果客户端将 wsimport.exe 生成的类全部导入,主要指服务端接口的实现类,也就是上的 CalculatorServiceImplService.java,这样客户端调用服务端方法时,也可以采用如下的方式:

CalculatorServiceImplService calculatorServiceImplService = new CalculatorServiceImplService();
CalculatorService calculatorService = calculatorServiceImplService.getCalculatorServiceImplPort();
float added = calculatorService.addition(100,80);
float multied = calculatorService.multiplication(2.5F,100);

WSDL 文件结构剖析

WebService WSDL 文件结构

WSDL(Web Services Description Language) 是基于 XML web服务描述语言,用于描述 Web Service 及其函数、参数和返回值等,这样客户端才能方便调用。一些开发工具既能根据 Web service 生成 WSDL 文档,又能导入 WSDL 文档,生成调用相应 WebService 的代理类代码。

WSDL 文件保存在Web服务器上,通过一个 url 地址即可访问。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址,WebService 服务提供商通常通过两种方式来暴露它的 WSDL 文件地址:1、注册到UDDI服务器,以便被人查找;2、直接告诉给客户端调用者。

1、WSDL 文件作为一个 XML 文件,顶部必须用 <?xml version="1.0" encoding="UTF-8"?> 声明。

2、WSDL 文档的根元素是 definitions 元素,WSDL 文档包含5部分:types, message, portType, binding,service 。

1)definitions 元素

A、WSDL 文档的根元素都是 definition 元素,其中主要的是最后的两个属性,targetNameSpace 与 name。

B、targetNameSpace 属性 对应 @WebService 注解的 targetNameSpace属性,name 属性对应 @WebService 注解的 serviceName 属性。

C、可以在 webService 服务端的接口实现类中的 @WebService 注解中通过修改属性,从而修改 wsdl 文件的definition 元素的属性值,否则 targetNameSpace 为 "http://" 加 "包名的反写",name 为 "实现类名称"+"Service"。

2)types 元素:定义访问的类型,如请求的方法名,参数,以及返回值等。

可以浏览器访问 schemaLocation 属性的值,看到详细信息。

3)message:SOAP 协议消息传递的参数,同样包括请求与返回两部分。

message 的元素会和 types 中的元素进行对应。

4)portType:指明服务器的接口,并且通过 operation 绑定相应的 input、ouput 消息。

5)binding:指定消息传到所使用的格式

6)service:指定服务所发布的名称

服务方法数据类型说明

1、Java 默认提供的 JWS API 开发 webService 时,支持自己的 8 种基本类型: boolean、byte、short、int、long、float、double 和 char、也支持引用类型 List、Set、Array,以及自定义的 POJO 对象 等,但唯独不支持 Map 类型。

2、如果服务接口方法的参数或者返回值是 Map 类型,则 Endpoint.publish 发布时直接报错失败,如下所示为方法的返回值使用 Map 类型时,启动服务时报错:

Exception in thread "main" javax.xml.ws.WebServiceException:
class com.lct.web_service.jaxws.GetStudentMapResponse do not have a property of the name return

3、所以要么就服务接口中的方法参数以及返回值尽量不要使用 Map 类型,换成其它类型,如 List 等,如果一定要用 Map 类型,则只能导入 CXF 等第三方框架的 Jar 包,不用改变任何代码,即可正常发布成功。客户端仍然使用 JWS 的 API 即可,可以不用导入 CXF 的 包。

@WebResult 与 @WebParam

1、上面 types 元素定义访问的类型,如请求的方法名,参数,以及返回值等,使用的都是默认值,如果想要进行修改,则可以使用 这两个注解。

 @WebResult :定义 wsdl 文件中,服务端方法返回值名称
 @WebParam :定义 wsdl 文件中,客户端请求的方法参数名称

定义在接口中的方法上即可,如下所示进行修改,其余内容不变。

import javax.jws.*;
/**
 * Created by Administrator on 2019/1/25 0025.
 * 计算器接口
 * SEI(Service Endpoint Interface):服务终端接口,即webService提供的服务接口
 * SIB(Service Implemention Bean):服务实现类,即webService提供的服务接口的实现类
 *
 * @javax.jws.WebService : 将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口
 * 不过是服务端还是客户端,接口上都必须写上此注解
 */
@WebService
public interface CalculatorService {
    /**
     * @WebResult :定义 wsdl 文件中,服务端方法返回值名称
     * @WebParam :定义 wsdl 文件中,客户端请求的方法参数名称
     */
    //加法
    @WebResult(name = "additionResult")
    public float addition(@WebParam(name = "a") float a, @WebParam(name = "b") float b);

    //乘法
    @WebResult(name = "multiplicationResult")
    public float multiplication(@WebParam(name = "a") float a, @WebParam(name = "b") float b);
}

学生实体验证示例

1、这里提供两个服务,一是查询学生在校是否有惩罚的服务(如警告、记过等),二是查询学生的缴费状态。

服务端

服务端内容结构如上。

Student:学生实体类、StudentService:提供的学生服务接口、StudentServiceImpl:服务接口的实现

Web_Service:用于启动 webService 服务

import java.util.Date;
/**
 * Created by Administrator on 2019/2/13 0013.
 * Student 实体
 */
public class Student {
    /**
     * sID:学生学号
     * sName:学生姓名
     * sex:性別,true 表示男生、false 表示女生
     * birthday:学生生日
     * punishStatus:在校是否被惩罚过,未惩罚(0)、警告(1)、记过(2)、记大过(3)、留校察看(4)、开除学籍(5)
     */
    private Integer sID;
    private String sName;
    private Boolean sex;
    private Date birthday;
    private Integer punishStatus;

   //省略 getter、setter、toString 方法未粘贴
}
import com.lct.domain.Student;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
/**
 * Created by Administrator on 2019/2/13 0013.
 * 用户登录校验服务接口
 *
 * @javax.jws.WebService : 将 Java 类/接口标记为 Web Service(web服务)
 * 服务端的 web service 接口与其实现类都必须写 @WebService 注解
 */
@WebService
public interface StudentService {
    /**
     * 根据学生学号获取学生 "奖惩信息"
     *
     * @param sId :学生学号
     * @return 返回整个学生的简要实体数据, 主要是演示返回值为实体
     */
    @WebResult(name = "getStudentById")
    public Student getStudentById(@WebParam(name = "sId") Integer sId);

    /**
     * 学生是否支付全部学费
     *
     * @param student
     * @return
     * @WebParam 的作用是 java jdk wsimport 工具生成的代理类看起来可以更直观,否则会是 arg0、arg1 ...
     * 单纯从调用上来说,写没写 @WebParam 调用都是一样的
     * @WebResult 也是同理,作用是使生成的 wsdl 文件看起来更直观,从调用上来说,写不写都是一样的
     */
    @WebResult(name = "isPayTuition")
    public boolean isPayTuition(@WebParam(name = "Student") Student student);
}
import com.lct.domain.Student;
import javax.jws.WebService;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Logger;
/**
 * Created by Administrator on 2019/2/13 0013.
 *
 * @javax.jws.WebService : 将 Java 类/接口标记为 Web Service(web服务),服务端的 web service 接口与其实现类都必须写 @WebService 注解
 * endpointInterface:终端接口,定义服务抽象 Web Service 协定的服务端点接口的完整名称,通常设置为服务实现类的全路径
 * 写了endpointInterface,@WebResult、@WebParam才会有效
 * serviceName:对应生成的 WSDL 文件中的 definitions 元素中的 name 属性值,默认以服务类名称+"Service"为值
 * 客户端连接时使用QName创建实例时需要传入此 name 属性值,以及targetNamespace属性值,都可以在 @WebService 中指定
 */
@WebService(endpointInterface = "com.lct.web_service.StudentService", serviceName = "StudentService")
public class StudentServiceImpl implements StudentService {
    /**
     * 日志记录器
     */
    public static final Logger logger = Logger.getGlobal();

    @Override
    public Student getStudentById(Integer sId) {
        /**随机生成一个学生,只做演示*/
        Student student = new Student();
        student.setsID(sId);
        student.setBirthday(new Date());
        student.setPunishStatus(new Random().nextInt(6));
        student.setsName(UUID.randomUUID().toString());
        logger.info("获取学号 " + sId + " 的学生信息结果为:" + student.toString());
        return student;
    }

    @Override
    public boolean isPayTuition(Student student) {
        /**随机生成是否已经交费,nextInt(a)生成 [0,a)直接的随机整数*/
        boolean flag = new Random().nextInt(2) == 0 ? true : false;
        logger.info(student.toString() + " 是否已经全部缴费?" + flag);
        return flag;
    }
}
import javax.xml.ws.Endpoint;
import java.util.logging.Logger;
/**
 * Created by Administrator on 2019/1/25 0025.
 * webServer 启动类
 */
public class Web_Service {
    //日志记录器
    public static final Logger logger = Logger.getGlobal();

    public static void main(String[] args) {
        /**webService服务器提供给客户端访问的地址
         * 192.168.1.20 为服务器 ip、3333为指定的端口号、web_server 为应用名称、student 为标识
         * 这个地址符合 http 地址即可,为了看起来更像是 web访问,所以才写了应用名,即使是 http://192.168.1.20:3333/xxx 也是可以的
         */
        String wsUrl = "http://192.168.1.20:3333/web_server/student";
        /**
         * javax.xml.ws.Endpoint 表示一个 web service 终端,这是一个抽象类,其中提供了静态方法可以直接调用
         * Endpoint publish(String address, Object implementor)
         * address:传输协议的 url 地址;
         * implementor(实现者):web service 终端的实现类,因为一个 ws 接口可能会有多个实现类
         */
        Endpoint.publish(wsUrl, new StudentServiceImpl());
        logger.info("webService 服务启动,等待客户端请求...");
    }
}

2、启动 webService 后,浏览器便可以进行访问,整个 wsdl 文件:http://192.168.1.20:3333/web_server/student?wsdl、数据类型地址:http://192.168.1.20:3333/web_server/student?xsd=1 (可在 types 的 schemaLocation 属性中找到)。

客户端

1、新建客户端项目,客户端使用 Java JDK wsimport.exe 工具根据服务端提供的 wsdl 文件地址生成代理类,在 cmd 窗口中操作命令如下: wsimport -d E:/wmx/webservice -keep -verbose http://192.168.1.20:3333/web_server/student?wsdl

2、其中 -d 表示输出内容存放的目录,此目录必须事先存在;最后是 wsdl 地址,结尾必须加上 ?wsdl 参数。

3、如上所需要的一共7个,2个方法输入输出一共生成4个类,加上 ObjectFactory 对象工厂类、以及 Student 实体类、StudentService 服务接口。导入到客户端项目中:

4、其中的 Web_service 用于启动应用,调用服务端方法,其内容如下:

import com.lct.web_service.Student;
import com.lct.web_service.StudentService;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
/**
 * Created by Administrator on 2019/1/25 0025.
 */
public class Web_service {
    //日志记录器
    public static final Logger logger = Logger.getGlobal();

    public static void main(String[] args) {
        try {
            /** url:webservice 服务端提供的服务地址,结尾必须加 "?wsdl"*/
            URL url = new URL("http://192.168.1.20:3333/web_server/student?wsdl");

            /** QName 表示 XML 规范中定义的限定名称,QName 的值包含名称空间 URI、本地部分和前缀。
             * QName(final String namespaceURI, final String localPart):指定名称空间 URI 和本地部分的 QName 构造方法。
             * 如下所示的两个数据都可以浏览器访问服务端时返回 xml 中第一行找到,如:
             * <definitions xmlns:wsu=xxxxxxx targetNamespace="http://web_service.lct.com/" name="StudentService">
             * namespaceURI 可以通过服务端的 @WebService 的 targetNamespace 属性指定
             * localPart 可以通过服务端的 @WebService 的 serviceName 属性指定
             */
            QName qName = new QName("http://web_service.lct.com/", "StudentService");

            /**
             * Service 对象提供 Web 服务的客户端视图
             * Service 作为以下内容的工厂:1、目标服务端点的代理,2、用于远程操作的动态面向消息调用的 javax.xml.ws.Dispatch 实例。
             * create(java.net.URL wsdlDocumentLocation,QName serviceName):创建 Service 实例。
             * wsdlDocumentLocation : 服务 WSDL 文档位置的 URL
             * serviceName : 服务的 QName
             */
            Service service = Service.create(url, qName);

            /**
             * 使用 getPorts 方法可以对服务上可用的端口/接口进行枚举
             * getPort(Class<T> serviceEndpointInterface):获取支持指定服务端点接口的对象实例
             * serviceEndpointInterface:指定返回的代理所支持的服务端点接口
             */
            StudentService studentService = service.getPort(StudentService.class);

            Student student = studentService.getStudentById(9527);
            boolean flag = studentService.isPayTuition(student);
            logger.info("获取学生信息:姓名:" + student.getSName() + ",惩罚状态:" + student.getPunishStatus() + ",生日:" + student.getBirthday());
            logger.info("此学生是否已经交完学费:" + flag);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

5、先启动服务端,然后运行客户端,结果如下:

webService 调用服务端完全没有问题。

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页