当前位置 : 首页 » 文章分类 :  开发  »  Java-JWS

Java-JWS

[TOC]


WebService概述

一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

WebService与Socket对比

(1)Socket是基于TCP/IP的传输层协议。
Webservice是基于HTTP协议传输数据,http是基于tcp的应用层协议。
Webservice采用了基于http的soap协议传输数据。
(2)Socket接口通过流传输,不支持面向对象。
Webservice 接口支持面向对象,最终webservice将对象进行序列化后通过流传输。
Webservice采用soap协议进行通信,不需专门针对数据流的发送和接收进行处理,是一种跨平台的面向对象远程调用技术。
(3)Socket适用于高性能大数据的传输,传输的数据需要手动处理,socket通信的接口协议需要自定义。
比如:自定义一种字符串拼接的格式,比如自定义的xml数据,自定义麻烦之处在接口调用方和接口服务端需要互相讨论确定接口的协议内容,不方便。
缺点:程序员需要自己去解析输入、输出流,解析发送和接收的数据。数据传输的格式不固定,需要程序员开发socket接口时自定义接口协议。
优点:如果要传输大数据量,socket可以满足,如果存在大并发使用socket也可以实现,程序用socket灵活性更大,比如可以socket的高并发框架mina开发。
Webservcie由于是遵循标准的soap协议,soap 协议的内容格式固定,soap协议传递的内容是xml数据,由于webservice是基于http的,所以简单理解为soap=http+xml,适用于没有性能要求情况下且数据传输量小,推荐在公开接口上使用webservice,因为soap协议的标准的。
优点:jaxws可以通过面向对象开发webservice,程序员不需要解析输入、输出流。 由于webservice传输数据使用标准的soap协议(基于http传输xml),soap协议已经被w3c管理了。
缺点:如果传输大数据量,webservice不适用。如果webservice开发大并发的应用,webservice依靠web容器提高并发数。

WebService三要素

  • SOAP: 服务调用协议。基于HTTP协议,采用XML格式,用来传递信息的格式。
  • WSDL: 服务描述协议。用来描述如何访问具体的服务。
  • UDDI: 服务发现/集成协议。用户自己可以按UDDI标准搭建UDDI服务器,用来管理,分发,查询WebService。

一般来说,为了实现一个具有跨平台调用和接口可机器识别特性的web服务,必需使用WSDL和SOAP协议,但并不是必须使用UDDI。


JAX-WS简介

JAX-WS的全称为Java API for XML-Based Webservices ,早期基于SOAP的JAVA Web服务规范JAX-RPC(Java API For XML-Remote Procedure Call)目前已经被JAX-WS规范取代。从java5开始支持JAX-WS2.0版本,Jdk1.6.0_13以后的版本支持2.1版本,jdk1.7支持2.2版本。

JAX-WS采用标准SOAP(Simple Object Access Protocol) 协议传输,SOAP属于W3C标准。SOAP协议是基于http的应用层协议,SOAP协议传输的是xml数据。
JAX-WS采用WSDL(Web Services Description Language) 作为描述语言即webservice使用说明书,wsdl属w3c标准。
XML是webservice的跨平台的基础,XML主要的优点在于它既与平台无关,又与厂商无关。
XSD,W3C为webservice制定了一套传输数据类型,使用xml进行描述,即XSD(XML Schema Datatypes),任何编程语言写的webservice接口在发送数据时都要转换成webservice标准的XSD发送。

在 JAX-WS中,一个远程调用可以转换为一个基于XML的协议例如SOAP。在使用JAX-WS过程中,开发者不需要编写任何生成和处理SOAP消息的代码。JAX-WS的运行时实现会将这些API的调用转换成为对于SOAP消息。
在服务器端,用户只需要通过Java语言定义远程调用所需要实现的接口SEI (service endpoint interface),并提供相关的实现,通过调用JAX-WS的服务发布接口就可以将其发布为WebService接口。
在客户端,用户可以通过JAX-WS的API创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。
通过web service所提供的互操作环境,我们可以用JAX-WS轻松实现JAVA平台与其他编程环境(.net等)的互操作。

JAX-RS 简介

JAX-RS——Java API for RESTful Web Services,是为 Java 程序员提供的一套固定的接口(Java API),用于开发表述性状态转移(REST)架构风格的 WEB 服务应用,避免了依赖第三方框架。同时,JAX-RS 使用 POJO 编程模型和基于标注(标签)的配置,并集成了 JAXB,从而可以有效缩短 REST 应用的开发周期。REST 作为一种轻量级的 Web 服务架构被原来越多的开发者所使用,JAX-RS 的发布则规范了 REST 应用开发的接口。

常见的 JAX-RS 实现方法有:

  • Jersey——伴随 JSR311的发布,SUN 公司发布的 JSR311的参考实现;
  • CXF——XFire 与 Celtix 的合并;
  • RESTEasy——JBoss 的 JAX-RS 项目。

其中,Jersey 是由 SUN 公司开发的产品级质量的 JSR-311的实现,Jersey 实现了 JSR-311中对标注的支持,使得开发人员使用 Java 开发 RESTful 的 Web 服务更加容易。在 SUN 的支持下,目前 Jersey 的易用性较之其他两种方法更高,应用也更为广泛。SuperMap iServer 参考 Jersey 进行资源实现。

JAX-WS与JAX-RS

JAX-WS 全称是Java API for XML-Based WebServices
JAX-RS 全称是Java API for RESTful Web Services
JAX-WS是针对WebService。而JAX-RS是针对RESTful HTTP Service。

可以说这是两种风格的SOA架构风格:
JAX-WS以动词为中心,指定的是每次执行函数;JAX-RS以名词为中心,每次执行的时候指的是资源。
JAX-WS是面向消息的,每次请求的时候指定了请求的方法。JAX-RS是面向资源的,将网络上的东西当做一种资源,每次请求都是对该资源进行操作,比如对资源的增删查改。


WebService注解

JAX-WS通过使用注释来指定与 Web Service 实现相关联的元数据以及简化 Web Service 的开发。注解描述如何将服务器端的服务作为 Web Service 进行发布或者客户端的 Java 类如何访问 Web Service。

@WebService

该注解应用于类或者接口上面,该类便是一个可对外访问的WebService,默认情况里面所有的public方法都是可以对外提供访问,如果@WebServcie标注接口,那么该接口有一个专业名称SEI(ServiceEnpointInterface)

@WebService注解定义:

@Retention(value=RUNTIME)
@Target(value=TYPE)
public @interface WebService

@WebMethod

定制一个公开为 Web Service 操作的方法。关联方法必须是公共方法且其参数可以返回值。

@Retention(value=RUNTIME)
@Target(value=METHOD)
public @interface WebMethod

可选属性:

  • boolean exclude,指定是否从 Web Service 中排除某一方法。缺省值为 false。 方法上加@WebMentod(exclude=true)后,此方法不被发布。

@HandlerChain

将 Web Service 与外部定义的处理程序链关联。
此注释通常用于不适合将处理程序配置直接嵌入 Java 源的情况;例如,需要在多个 Web Service 之间共享处理程序配置的地方,或者处理程序链由多个传输的处理程序组成的地方。
将此注释与 @SOAPMessageHandlers 注释组合在一起是错误的。

@Retention(value=RUNTIME)
@Target(value={TYPE,METHOD,FIELD})
public @interface HandlerChain

必需属性:

  • String file,处理程序链文件的位置。
    该位置支持两种格式:
  • externalForm 形式的绝对 java.net.URL(例如:http://myhandlers.foo.com/handlerfile1.xml )。
  • 相对于源文件或类文件的相对路径(例如:bar/handlerfile1.xml)。

JAX-WS发布调用WebService

服务端发布WebService流程

1、在类上添加@WebService注解。

此注解是jdk1.6提供的,用在类上指定将此类发布成一个ws,位于javax.jws.WebService包中。
类上添加注解@WebService,类中所有非静态方法都会被发布;静态方法和final方法不能被发布;
方法上加@WebMentod(exclude=true)后(需要javax.jws.WebMethod包),此方法不被发布;
注意:只在接口上添加@WebService并不会使其实现类自动成为ws,还需要在实现类上添加@WebService

2、通过EndPoint(端点服务)发布一个WebService

EndPoint是jdk提供的一个专门用于发布服务的类,位于javax.xml.ws.Endpoint包中。其publish(String address, Object implementor)方法用于将一个已经添加了@WebService注解的对象绑定到一个地址的端口上,该方法接收两个参数,一个是本地的服务地址,二是提供服务的类。


wsimport生成客户端需要的代码

wsimport是JDK自带的可以根据WSDL文档生成客户端调用代码的工具。无论服务器端WebService使用什么语言编写的,都将在客户端生成Java代码。所以服务器用什么语言编写的并不重要。
命令语法:wsimport [options] <WSDL_URI>
注意:WSDL_URI必须含有末尾的?wsdl

wsimport常用参数

  • -d <directory>,在指定的目录生成class文件
  • -s <directory>,在指定目录生成Java源文件
  • -p <package>,指定生成代码的包目录结构,会在生成的java代码中生成包声明语句 package <package>。-p指定的包目录会接在-s目录后面,即最终客户端代码生成的位置是:-s目录/-p目录。建议-s目录为工程src目录,-p指定完全包名,这样可以保证代码中的package包声明与实际目录一致。
  • -keep,在生成class文件,或者jar包时,同时保留java源文件
  • -clientjar <jarfile>,在当前目录生成jar文件,结合-d <directory>可以在指定的目录生成jar文件

wsimport常用参数组合

  • 在当前目录生成指定包结构的class文件和java源文件

    wsimport -s . -p com.masikkk.jws.client http://localhost:8899/HelloService?wsdl
    

    等价于:

    wsimport -keep -p com.masikkk.jws.client http://localhost:8899/HelloService?wsdl
    

    会在当前目录下生成子目录com/masikkk/jws/client/,其中有class文件和java源文件

  • 在当前目录生成指定包结构的class文件,注意不带-s参数不会生成java源文件,只有class文件

    wsimport -p com.masikkk.jws.client http://localhost:8899/HelloService?wsdl
    
  • 在指定目录生成指定包结构的class文件和java源文件
    假设wsdl文档的uri为http://localhost:6666/service/interpret?wsdl ,那么在F:\temp下,生成包结构为cn.ljl.sand.jws.chapter3.client.wsimport的java源文件的命令为:

    wsimport -s F:\temp -p cn.ljl.sand.jws.chapter3.client.wsimport
    http://localhost:6666/service/interpret?wsdl
    
  • 在指定目录生成指定包结构的jar文件
    假设wsdl文档的uri为http://localhost:6666/service/interpret?wsdl ,那么在F:\temp下,生成包结构为cn.ljl.sand.jws.chapter3.client.wsimport的interpret-wsimport.jar的命令为:

    wsimport -d F:\temp -clientjar interpret-wsimport.jar -p cn.ljl.sand.jws.chapter3.client.wsimport
    http://localhost:6666/service/interpret?wsdl
    

客户端代码核心类

根据wsdl中定义的方法个数、参数类型等不同,wsimport自动生成的java源文件个数也不同,
一般来说,每个暴露的方法会对应生成2个java类,一个定义参数、一个定义返回值。
比如,HelloService包含3个暴露的方法sayHello,sayHelloName和sayHelloList,wsimport生成的HelloService的客户端代码为:

此外,如果方法的参数或返回值中有类对象,wsimport会自动生成对应参数类或返回值类的java代码。
比如,StudentService的参数为studentRequest类,返回值为StudentResponse类,wsimport生成的StudentService的客户端代码为:

wsimport生成的java源码中,有两个是我们需要直接用到的:

  • 一个是以wsdl文档的service元素的name为名的类,HelloService中是HelloServiceImplService,通过HelloServiceImplService类的getHelloServiceImplPort()方法可以获得HelloServiceImpl类的实例,然后就可以像执行本地代码一样访问HelloServiceImpl类中的方法了。
  • 一个是以wsdl文档的portType元素的name为名的接口,本例中是HelloServiceImpl,是一个和webservice发布类同名的接口,里面包含所有发布的方法,作为调用HelloServiceImpl类的方法的本地代理。

HelloService的wsdl如下:

<!--
 Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. 
-->
<!--
 Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. 
-->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://simple.server.jws.masikkk.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://simple.server.jws.masikkk.com/" name="HelloServiceImplService">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://simple.server.jws.masikkk.com/" schemaLocation="http://localhost:8899/HelloService?xsd=1"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <message name="sayHelloName">
        <part name="parameters" element="tns:sayHelloName"/>
    </message>
    <message name="sayHelloNameResponse">
        <part name="parameters" element="tns:sayHelloNameResponse"/>
    </message>
    <message name="sayHelloList">
        <part name="parameters" element="tns:sayHelloList"/>
    </message>
    <message name="sayHelloListResponse">
        <part name="parameters" element="tns:sayHelloListResponse"/>
    </message>
    <portType name="HelloServiceImpl">
        <operation name="sayHello">
            <input wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloRequest" message="tns:sayHello"/>
            <output wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloResponse" message="tns:sayHelloResponse"/>
        </operation>
        <operation name="sayHelloName">
            <input wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloNameRequest" message="tns:sayHelloName"/>
            <output wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloNameResponse" message="tns:sayHelloNameResponse"/>
        </operation>
        <operation name="sayHelloList">
            <input wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloListRequest" message="tns:sayHelloList"/>
            <output wsam:Action="http://simple.server.jws.masikkk.com/HelloServiceImpl/sayHelloListResponse" message="tns:sayHelloListResponse"/>
        </operation>
    </portType>
    <binding name="HelloServiceImplPortBinding" type="tns:HelloServiceImpl">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="sayHelloName">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="sayHelloList">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>
    <service name="HelloServiceImplService">
        <port name="HelloServiceImplPort" binding="tns:HelloServiceImplPortBinding">
            <soap:address location="http://localhost:8899/HelloService"/>
        </port>
    </service>
</definitions>

遇到的问题

http://localhost:8080/helloService 服务发布成功,浏览器能访问到服务也可以访问到wsdl文件,使用wsimport命令生成客户端代码的时候出错。

C:\Users\MaSi>wsimport http://127.0.0.1:8080/helloService?wsdl
[ERROR] Server returned HTTP response code: 503 for URL: http://127.0.0.1:8080/helloService?wsdl
Failed to read the WSDL document: http://127.0.0.1:8080/helloService?wsdl, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.
[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):
At least one WSDL with at least one service definition needs to be provided.
Failed to parse the WSDL.

原因:
1、是否设置了网络代理,如果设置了,去掉代理;
2、使用本机真实IP而不是127.0.0.1或localhost来发布webservice,例如:Endpoint.publish("http://192.168.1.123:8080/MyWebService", new TestWs());
用了两种方法都可以解决:
1、关闭公司网络代理,或将localhost加入代理“例外”中。
2、Endpoint.publish时地址修改为本机真实ip,wsimport成功。


JAX-WS发布调用WebService实例

本实例是一个maven多模块项目,简介如下:

  • jws项目:多模块maven项目的父项目,不含任何代码,只在pom中规定各子模块依赖项的版本号
  • jws-server项目:webservice服务发布端,包含3个包:
  • com.masikkk.jws.server.simple包,发布HelloService,提供最简单的参数和返回值都是字符串的方法
  • com.masikkk.jws.server.bean包,发布StudentService,参数和返回值都是类对象,参数为StudentRequest类,返回值为StudentResponse类
  • com.masikkk.jws.server.json包,发布JsonService,参数和返回值都是json字符串,对应Group类,方法中会做参数的反序列化和返回结果序列化。通过json串传参和返回是实际项目中最常用的方法。
  • jws-client项目:wsimport生成的webservice调用客户端,包含src/main/java中3个包和一个测试包:
  • com.masikkk.jws.client.simple包,HelloService服务的客户端代码
  • com.masikkk.jws.client.bean包,StudentService服务的客户端代码
  • com.masikkk.jws.client.json包,JsonService服务的客户端代码
  • com.masikkk.jws.client包,包含3个webservice的客户端代码的JUnit测试类

服务端jws-server项目

HelloService服务

接口HelloService

HelloService.java:

package com.masikkk.jws.server.simple;

import java.util.List;

public interface HelloService {
    //返回你好
    public String sayHello();
    
    //返回你好+姓名
    public String sayHelloName(String name);
    
    //返回由length个name构成的字符串数组
    public List<String> sayHelloList(String name, int length);
    
    //被隐藏的方法
    public String hideMethod();
}

实现类HelloServiceImpl

HelloServiceImpl.java:

package com.masikkk.jws.server.simple;

import java.util.ArrayList;
import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public class HelloServiceImpl implements HelloService {
    public String sayHello() {
        return "你好!";
    }

    public String sayHelloName(String name) {
        return "你好,"+name;
    }

    @WebMethod(exclude=true)
    public String hideMethod() {
        return "此方法被exclude隐藏";
    }

    //返回由length个name构成的字符串数组
    public List<String> sayHelloList(String name, int length) {
        List<String> arrayList = new ArrayList<String>();
        for (int i = 0; i < length; i++) {
            arrayList.add(name+"."+i);
        }
        return arrayList;
    }
}

服务发布类HelloServiceMain

HelloServiceMain.java:

package com.masikkk.jws.server.simple;

import javax.xml.ws.Endpoint;

public class HelloServiceMain {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8899/HelloService", new HelloServiceImpl());
        System.out.println("HelloService发布成功,WSDL地址:http://localhost:8899/HelloService?wsdl");
        System.out.println("使用JDK中的wsimport工具的如下命令生成客户端代码:");
        System.out.println("wsimport -keep -p com.masikkk.jws.client.simple http://localhost:8899/HelloService?wsdl");        
    }
}

Run As->Java Application 启动服务端,在浏览器输入 http://localhost:8899/HelloService?wsdl 查看wsdl。


StudentService服务

参数实体StudentRequest

StudentRequest.java

package com.masikkk.jws.server.bean;

//查询参数实体
public class StudentRequest {
    private int id; //学号
    private int age; //年龄
    private String name; //姓名
    private String school; //学校
    private String city; //城市
    
    public StudentRequest() {
        this.id = 0;
        this.age = 0;
        this.name = "default";
        this.school = "default";
        this.city = "default";
    }
    
    public StudentRequest(int id, int age, String name, String school, String city) {
        this.id = id;
        this.age = age;
        this.name = name;
        this.school = school;
        this.city = city;
    }
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSchool() {
        return school;
    }
    public void setSchool(String school) {
        this.school = school;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

返回结果实体StudentResponse

StudentResponse.java:

package com.masikkk.jws.server.bean;

//查询结果实体
public class StudentResponse {
    private int id; //学号
    private int age; //年龄
    private String name; //姓名
    private String school; //学校
    private String city; //城市
    private String info; //个人介绍

    public StudentResponse() {
        this.id = 0;
        this.age = 0;
        this.name = "default";
        this.school = "default";
        this.city = "default";
        this.info = "default";
    }
    
    public StudentResponse(int id, int age, String name, String school, String city, String info) {
        this.id = id;
        this.age = age;
        this.name = name;
        this.school = school;
        this.city = city;
        this.info = info;
    }
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSchool() {
        return school;
    }
    public void setSchool(String school) {
        this.school = school;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

接口StudentService

StudentService.java:

package com.masikkk.jws.server.bean;

import java.util.List;

public interface StudentService {
    //根据请求参数studentRequest和info生成1个学生实例并返回
    public StudentResponse queryStudentResponse(StudentRequest studentRequest, String info);
    
    //根据请求参数studentRequest和info生成num个学生实例并返回
    public List<StudentResponse> queryStudentResponseList(StudentRequest studentRequest, String info, int num);
}

实现类StudentServiceImpl

StudentServiceImpl.java:

package com.masikkk.jws.server.bean;

import javax.jws.WebService;

import java.util.ArrayList;
import java.util.List;

@WebService
public class StudentServiceImpl implements StudentService {
    //根据请求参数studentRequest和info生成1个学生实例并返回
    public StudentResponse queryStudentResponse(StudentRequest studentRequest, String info) {
        int id = studentRequest.getId();
        int age = studentRequest.getAge();
        String name = studentRequest.getName();
        String school = studentRequest.getSchool();
        String city = studentRequest.getCity();
        StudentResponse studentResponse = new StudentResponse(id,age,name,school,city,info);
        return studentResponse;
    }

    //根据请求参数studentRequest和info生成num个学生实例并返回
    public List<StudentResponse> queryStudentResponseList(StudentRequest studentRequest, String info, int num) {
        List<StudentResponse> studentResponsesList = new ArrayList<StudentResponse>();
        for (int i = 0; i < num; i++) {
            int id = studentRequest.getId()+i;
            int age = studentRequest.getAge()+i;
            String name = studentRequest.getName()+i;
            String school = studentRequest.getSchool()+i;
            String city = studentRequest.getCity()+i;
            StudentResponse studentResponse = new StudentResponse(id,age,name,school,city,info+i);            
            studentResponsesList.add(studentResponse);
        }
        return studentResponsesList;
    }

}

服务发布类StudentServiceMain

StudentServiceMain.java:

package com.masikkk.jws.server.bean;

import javax.xml.ws.Endpoint;

public class StudentServiceMain {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8899/StudentService", new StudentServiceImpl());
        System.out.println("HelloService发布成功,WSDL地址:http://localhost:8899/StudentService?wsdl");
        System.out.println("使用JDK中的wsimport工具的如下命令生成客户端代码:");
        System.out.println("wsimport -keep -p com.masikkk.jws.client.bean http://localhost:8899/StudentService?wsdl");
    }
}

JsonService服务

实体User

User.java:

package com.masikkk.jws.server.json;

public class User {
    private Long id;
    private String name;

    public User() {
        this.id = 0L;
        this.name = "default";
    }
    
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

实体Group

Group.java:

package com.masikkk.jws.server.json;

import java.util.ArrayList;
import java.util.List;

public class Group {
    private Long id;
    private String name;
    private List<User> users;

    public Group() {
        this.id = 0L;
        this.name = "default";
        this.users = new ArrayList<User>();
    }
    
    public Group(Long id, String name) {
        this.id = id;
        this.name = name;
        this.users = new ArrayList<User>();
    }    
    
    public Group(Long id, String name, List<User> users) {
        this.id = id;
        this.name = name;
        this.users = users;
    }
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<User> getUsers() {
        return users;
    }
    public void setUsers(List<User> users) {
        this.users = users;
    }
    public void addUser(User user) {
        users.add(user);
    }
    
    public String toString() {
        String resultString = "group id: " + id + "\n";
        resultString += "group name: " + name + "\n";
        resultString += "users: " + "\n";
        for (User user : users) {
            resultString += "     id: "+user.getId()+", name: "+user.getName()+"\n";
        }
        return resultString;
    }
    
}

接口JsonService

JsonService.java:

package com.masikkk.jws.server.json;

public interface JsonService {
    //查询方法,输入输出都是json串
    public String queryJson(String request);
}

实现类JsonServiceImpl

JsonServiceImpl.java:

package com.masikkk.jws.server.json;

import javax.jws.WebService;

import com.alibaba.fastjson.JSON;

@WebService
public class JsonServiceImpl implements JsonService {
    //查询方法,输入输出都是json串
    public String queryJson(String request) {
        System.out.println("收到的客户端请求参数: " + request);
        Group groupRequest = JSON.parseObject(request, Group.class); //解析Json串为Group对象
        System.out.println("请求参数解析为对象: ");
        System.out.println(groupRequest.toString());
        
        Group groupResponse = new Group(222L,"com.masikkk");
        User guestUser = new User(333L,"masikkk_guest");
        User rootUser = new User(444L,"masikkk_admin");
        groupResponse.addUser(guestUser);
        groupResponse.addUser(rootUser);
        
        String responseString = JSON.toJSONString(groupResponse);
        System.out.println("返回给客户端的结果: " + responseString);
        
        return responseString;
    }
}

服务发布类JsonServiceMain

JsonServiceMain.java:

package com.masikkk.jws.server.json;

import javax.xml.ws.Endpoint;

public class JsonServiceMain {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8899/JsonService", new JsonServiceImpl());
        System.out.println("JsonService发布成功,WSDL地址:http://localhost:8899/JsonService?wsdl");
        System.out.println("使用JDK中的wsimport工具的如下命令生成客户端代码:");
        System.out.println("wsimport -keep -p com.masikkk.jws.client.json http://localhost:8899/JsonService?wsdl");
    }
}

客户端jws-client项目

wsimport生成客户端代码

使用wsimport分别生成3个服务的客户端代码,放到对应的包中,其中:
由于StudentService的方法参数和返回值中有类对象,wsimport会自动生成参数类和返回值类的java代码。
但JsonService的参数和返回值都是字符串,不会自动生成对应实体类的java代码,需要将Group和User类手动拷贝到com.masikkk.jws.client.json包中。

以生成HelloService服务的客户端代码为例,先Run As -> Java Application启动服务端代码,打开windows的cmd命令窗口,使用wsimport命令生成客户端代码。wsimport命令位于jdk的bin目录中,若没有配置环境变量,可cd到此目录再执行。

$ wsimport -s . -p com.masikkk.jws.client.simple http://localhost:8899/HelloService?wsdl
parsing WSDL...
Generating code...
Compiling code...

执行完成后会在当前目录下生成子目录com/masikkk/jws/client/simple/,其中有class文件和java源文件。


客户端Junit测试类

HelloServiceTest

构造HelloServiceImplService类对象时,默认URL是wsimport生成代码时的地址,若此后发布地址发生了变动(但要调用的webservice接口不变),可使用带URL参数的WSHelloService类构造函数。
HelloServiceTest.java:

package com.masikkk.jws.client;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import org.junit.Test;

import com.masikkk.jws.client.simple.HelloServiceImpl;
import com.masikkk.jws.client.simple.HelloServiceImplService;

public class HelloServiceTest {
    @Test
    public void testHelloService(){
        System.out.println("默认URL测试:");
        HelloServiceImplService helloServiceImplService = new HelloServiceImplService();//默认URL
        HelloServiceImpl helloServiceImpl = helloServiceImplService.getHelloServiceImplPort();
        List<String> arrayList = helloServiceImpl.sayHelloList("masikkk", 5);
        System.out.println(helloServiceImpl.sayHello());
        System.out.println(helloServiceImpl.sayHelloName("masikkk"));
        System.out.println(arrayList);
    }
    
    @Test
    public void testHelloServiceURL() throws MalformedURLException{
        System.out.println("指定URL测试:");
        URL url = new URL("http://localhost:8899/HelloService?wsdl");//加不加后面的?wsdl都行
        HelloServiceImplService helloServiceImplService = new HelloServiceImplService(url);//指定URL
        HelloServiceImpl helloServiceImpl = helloServiceImplService.getHelloServiceImplPort();
        List<String> arrayList = helloServiceImpl.sayHelloList("masikkk", 5);        
        System.out.println(helloServiceImpl.sayHello());
        System.out.println(helloServiceImpl.sayHelloName("masikkk"));    
        System.out.println(arrayList);
    }
}

运行方法:首先启动服务端确保webservice是可访问的,然后Run As -> JUnit Test执行测试类,查看控制台输出结果。

StudentServiceTest

StudentServiceTest.java:

package com.masikkk.jws.client;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import com.masikkk.jws.client.bean.StudentRequest;
import com.masikkk.jws.client.bean.StudentResponse;
import com.masikkk.jws.client.bean.StudentServiceImpl;
import com.masikkk.jws.client.bean.StudentServiceImplService;

public class StudentServiceTest {
    @Test
    public void testqueryStudentResponse() {
        System.out.println("测试queryStudentResponse:");
        StudentServiceImplService studentServiceImplService = new StudentServiceImplService();
        StudentServiceImpl studentServiceImpl = studentServiceImplService.getStudentServiceImplPort();
        StudentResponse studentResponse = studentServiceImpl.queryStudentResponse(new StudentRequest(),"Java程序员");
        printStudentResponse(studentResponse);
    }

    @Test
    public void testqueryStudentResponsesList() {
        System.out.println("测试queryStudentResponsesList:");
        StudentServiceImplService studentServiceImplService = new StudentServiceImplService();
        StudentServiceImpl studentServiceImpl = studentServiceImplService.getStudentServiceImplPort();
        List<StudentResponse> studentResponseList = studentServiceImpl.queryStudentResponseList(new StudentRequest(),"Java程序员",4);
        printStudentResponse(studentResponseList);        
    }
    
    public void printStudentResponse(List<StudentResponse> studentResponsesList) {
        for (StudentResponse temp : studentResponsesList) {
            System.out.println(temp.getId()+", "+temp.getAge()+", "+temp.getName()+", "+temp.getSchool()+", "+temp.getCity()+", "+temp.getInfo());
        }
    }
    
    public void printStudentResponse(StudentResponse temp) {
        System.out.println(temp.getId()+", "+temp.getAge()+", "+temp.getName()+", "+temp.getSchool()+", "+temp.getCity()+", "+temp.getInfo());
    }    
}

JsonServiceTest

JsonServiceTest.java:

package com.masikkk.jws.client;

import org.junit.Test;

import com.alibaba.fastjson.JSON;
import com.masikkk.jws.client.json.Group;
import com.masikkk.jws.client.json.JsonServiceImpl;
import com.masikkk.jws.client.json.JsonServiceImplService;

public class JsonServiceTest {
    @Test
    public void testqueryJson() {
        JsonServiceImplService jsonServiceImplService = new JsonServiceImplService();
        JsonServiceImpl jsonServiceImpl = jsonServiceImplService.getJsonServiceImplPort();
        String request = "{\"id\":0,\"name\":\"admin\",\"users\":[{\"id\":2,\"name\":\"guest\"},{\"id\":3,\"name\":\"root\"}]}";
        System.out.println("发送给服务器的json请求参数: " + request);
        String response = jsonServiceImpl.queryJson(request);
        System.out.println("服务器返回json结果: " + response);
        Group group = JSON.parseObject(response, Group.class);
        System.out.println("服务器返回结果解析为对象:");
        System.out.println(group.toString());
    }
}

参考


GitHub项目源码

本文中所有代码已分享到GitHub,repo地址:https://github.com/masikkk/java-webservice ,是一个多模块maven项目,可导入为maven工程运行。

项目介绍

本实例是一个maven多模块项目,简介如下:

  • jws项目:多模块maven项目的父项目,不含任何代码,只在pom中规定各子模块依赖项的版本号
  • jws-server项目:webservice服务发布端,包含3个包:
    • com.masikkk.jws.server.simple包,发布HelloService,提供最简单的参数和返回值都是字符串的方法
    • com.masikkk.jws.server.bean包,发布StudentService,参数和返回值都是类对象,参数为StudentRequest类,返回值为StudentResponse类
    • com.masikkk.jws.server.json包,发布JsonService,参数和返回值都是json字符串,对应Group类,方法中会做参数的反序列化和返回结果序列化。通过json串传参和返回是实际项目中最常用的方法。
  • jws-client项目:wsimport生成的webservice调用客户端,包含src/main/java中3个包和一个测试包:
    • com.masikkk.jws.client.simple包,HelloService服务的客户端代码
    • com.masikkk.jws.client.bean包,StudentService服务的客户端代码
    • com.masikkk.jws.client.json包,JsonService服务的客户端代码
    • com.masikkk.jws.client包,包含3个webservice的客户端代码的JUnit测试类

运行方法

运行方法:以HelloService为例,首先在jws-server项目中HelloServiceMain服务发布类上Run As->Java Application启动服务端确保webservice是可访问的,然后在jws-client项目中HelloServiceTest测试类上Run As->JUnit Test执行测试类,查看控制台输出结果。

参考博文


Eclipse中使用Web Services Explorer访问webservice

Eclipse中打开Web Services Explorer窗口:主菜单Run -> Launch the Web Services Explorer,注意Java视图中没有此项,Java EE视图中才有。
输入wsdl地址,如下图所示:

点击Go后读取wsdl文件,显示具体的operation名称,点击operation,进入参数输入界面:

填写参数后点Go即可调用webservice


HandlerChain

JAX-WS的Handler和Servlet的Filter相似,可以对所有WebServicer进行拦截,在Handler中可以记录日志、权限控制、对请求的SOAP消息进行加密,解密等。JAX-WS提供两个Handler接口,LogicalHandler和SOAPHandler。LogicalHandler处理的是Message Payload,只能够访问消息单元中的SOAP消息体。SOAPHandler处理的是整个SOAP消息(包含SOAP header和SOAP body),可以访问整个SOAP消息。

参考


参考


上一篇 JDK-Tools-wsimport

下一篇 Apache-ActiveMQ

阅读
评论
7.8k
阅读预计36分钟
创建日期 2017-09-04
修改日期 2017-09-28
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论