WebService


WSDL

definitions 为根节点,属性为

name:WS 名称,默认为“实现类 + Service”

targetNamespace:WS 目标命名空间,默认为“WS 实现类对应包名倒排后构成的地址”

definitions的5个子节点

types:描述了 WS 中所涉及的数据类型

portType:定义了 WS 接口名称portType.nameendpointInterface默认为“WS 实现类所实现的接口”),及其操作名称,以及每个操作的输入与输出消息

message:对相关消息进行了定义(供 types 与 portType 使用)

binding:提供了对 WS 的数据绑定方式

service:WS 名称及其端口名称service_port.nameportName默认为“WS 实现类 + Port”),以及对应的 WSDL 地址

SOAP

header

body


、产品

soap风格 (JAX-WS规范JSR-224)

JAX-WS RI:https://jax-ws.java.net/ Oracle 官方提供的实现

Axis:http://axis.apache.org/

CXF:http://cxf.apache.org/

rest风格 (JAX-RS规范JSR-339)

Jersey:https://jersey.java.net/ Oracle 官方提供的实现

Restlet:http://restlet.com/

RESTEasy:http://resteasy.jboss.org/

CXF:http://cxf.apache.org/

、JDK发布与调用

1.发布

定义接口

//此注解必须
@WebService
public interface HelloService {
    String say();
}

实现接口

@WebService(serviceName = "HelloService",
        portName = "HelloServicePort",
        endpointInterface = "org.sllx.practice.jdkws.HelloService")
public class HelloServiceImpl implements HelloService {
    @Override
    public String say() {
        return "helloWorld";
    }
}

发布服务

public class Server {
    public static void main(String[] args){
        String address = "http://localhost:8081/ws/soap/hello";
        HelloService helloService = new HelloServiceImpl();
        Endpoint.publish(address, helloService);
        System.out.println("ws is published [" + address + "?wsdl]");
    }
}

访问http://localhost:8081/ws/soap/hello?wsdl即可查看详情

2.调用

静态客户端

wsimport http://localhost:8080/ws/soap/hello?wsdl//通过 WSDL 地址生成 class 文件

jar -cf client.jar . //通过 jar 命令将若干 class 文件压缩为一个 jar 包

rmdir /s/q demo //删除生成的 class 文件(删除根目录即可)

public static void main(String[] args){
     HelloService_Service hss = new HelloService_Service();
     HelloService hs = hss.getHelloServicePort();
     System.out.println(hs.say());
}

动态代理客户端

只需提供HelloService接口,无需jar

public static void main(String[] args){
    try {
        URL wsdl = new URL("http://localhost:8081/ws/soap/hello?wsdl");
        QName serviceName = new QName("http://jdkws.practice.sllx.org/", "HelloService");
        QName portName = new QName("http://jdkws.practice.sllx.org/", "HelloServicePort");
        Service service = Service.create(wsdl, serviceName);
        HelloService helloService = service.getPort(portName, HelloService.class);
        String result = helloService.say();
        System.out.println(result);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

、CXF

User为自定义的POJO类

web发布示例集成spring

1.SOAP风格

定义接口

package top.rainynight.sitews.user.ws;

import top.rainynight.sitews.user.entity.User;
import javax.jws.WebService;

@WebService
public interface UserWS {

    User lookOver(int id);
}

实现接口

package top.rainynight.sitews.user.ws;

import top.rainynight.sitews.user.entity.User;
import org.springframework.stereotype.Component;

@Component("userWS")
public class UserWSImpl implements UserWS {

    @Override
    public User lookOver(int id) {
        return new User();
    }
}

发布服务

①Jetty发布

配置依赖

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cxf.version>3.0.0</cxf.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>${cxf.version}</version>
    </dependency>
</dependencies>

发布

public class JaxWsServer {
    public static void main(String[] args) {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setAddress("http://localhost:8080/ws/user");
        factory.setServiceClass(UserWS.class);
        factory.setServiceBean(new UserWSImpl());
        factory.create();
        System.out.println("soap ws is published");
    }
}

访问http://localhost:8080/ws/user?wsdl

②Web发布

配置依赖

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.0.5.RELEASE</spring.version>
        <cxf.version>3.0.0</cxf.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
    </dependencies>

配置web.xml

 <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
         classpath:spring.xml
     </param-value>
 </context-param>

 <servlet>
     <servlet-name>cxf</servlet-name>
     <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
 </servlet>
 <servlet-mapping>
     <servlet-name>cxf</servlet-name>
     <url-pattern>/*</url-pattern>
 </servlet-mapping>

发布

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://cxf.apache.org/jaxws
       http://cxf.apache.org/schemas/jaxws.xsd">

    <context:component-scan base-package="top.rainynight.sitews.user.ws" />

    <!-- 下面的方法更简单
    <jaxws:server address="/ws/user">
        <jaxws:serviceBean>
            <ref bean="userWS"/>
        </jaxws:serviceBean>
    </jaxws:server>
    -->

    <jaxws:endpoint implementor="# userWS" address="/ws/user" />
</beans>

访问http://localhost:8080/ws/user?wsdl

调用服务

①静态客户端

public class JaxWsClient {

    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setAddress("http://localhost:8080/ws/user");
        factory.setServiceClass(UserWS .class);

        UserWS userWS = factory.create(UserWS .class);
        User result = userWS .lookOver(1);
        System.out.println(result);
    }
}

②动态代理客户端

public class JaxWsDynamicClient {

    public static void main(String[] args) {
        JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
        Client client = factory.createClient("http://localhost:8080/ws/user?wsdl");

        try {
            Object[] results = client.invoke("lookOver", 1);
            System.out.println(results[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

③通用动态代理客户端

既可调用 JAX-WS 服务,也可调用 Simple 服务

public class DynamicClient {

    public static void main(String[] args) {
        DynamicClientFactory factory = DynamicClientFactory.newInstance();
        Client client = factory.createClient("http://localhost:8080/ws/user?wsdl");

        try {
            Object[] results = client.invoke("lookOver", 1);
            System.out.println(results[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

④Spring客户端

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://cxf.apache.org/jaxws
       http://cxf.apache.org/schemas/jaxws.xsd">

    <jaxws:client id="userWSClient"
                  serviceClass="top.rainynight.sitews.user.ws.UserWS"
                  address="http://localhost:8080/ws/user"/>

</beans>
public class UserWSClient{

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml");

        UserWS userWS= context.getBean("userWSClient", UserWS.class);
        User result = userWS.lookOver(1);
        System.out.println(result);
    }
}

2.REST风格

定义接口

!REST 规范允许资源类没有接口

请求方式注解,包括:@GET、@POST、@PUT、@DELETE

请求路径注解,包括:@Path ,其中包括一个路径参数

数据格式注解,包括:@Consumes(输入)、@Produces(输出),可使用 MediaType 常量

相关参数注解,包括:@PathParam(路径参数)、@FormParam(表单参数),此外还有 @QueryParam(请求参数)

package top.rainynight.sitews.user.ws;

import top.rainynight.sitews.user.entity.User;
import javax.jws.WebService;

@WebService
@Path("/")
public interface UserWS {

    @GET
    @Path("{id:[1-9]{1,9}}")
    @Produces(MediaType.APPLICATION_JSON)
    User lookOver(@PathParam("id") int id);
}

实现接口

package top.rainynight.sitews.user.ws;

import top.rainynight.sitews.user.entity.User;
import org.springframework.stereotype.Component;

@Component("userWS")
public class UserWSImpl implements UserWS {

    @Override
    public User lookOver(int id) {
        return new User();
    }
}

发布服务

①jetty发布

配置依赖

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cxf.version>3.0.0</cxf.version>
    <jackson.version>2.4.1</jackson.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxrs</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>

发布

public class Server {

    public static void main(String[] args) {
        // 添加 ResourceClass
        List<Class<?>> resourceClassList = new ArrayList<Class<?>>();
        resourceClassList.add(UserWSImpl .class);

        // 添加 ResourceProvider
        List<ResourceProvider> resourceProviderList = new ArrayList<ResourceProvider>();
        resourceProviderList.add(new SingletonResourceProvider(new ProductServiceImpl()));

        // 添加 Provider
        List<Object> providerList = new ArrayList<Object>();
        providerList.add(new JacksonJsonProvider());

        // 发布 REST 服务
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
        factory.setAddress("http://localhost:8080/rs/user");
        factory.setResourceClasses(resourceClassList);
        factory.setResourceProviders(resourceProviderList);
        factory.setProviders(providerList);
        factory.create();
        System.out.println("rest ws is published");
    }
}

访问http://localhost:8080/rs/user?_wadl

②web发布

配置依赖

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.0.6.RELEASE</spring.version>
        <cxf.version>3.0.0</cxf.version>
        <jackson.version>2.4.1</jackson.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    </dependencies>

配置web.xml

 <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>
         classpath:spring.xml
     </param-value>
 </context-param>

 <servlet>
     <servlet-name>cxf</servlet-name>
     <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
 </servlet>
 <servlet-mapping>
     <servlet-name>cxf</servlet-name>
     <url-pattern>/*</url-pattern>
 </servlet-mapping>

发布

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

    <context:component-scan base-package="top.rainynight.sitews.user.ws" />

    <jaxrs:server address="/rs/user">
        <jaxrs:serviceBeans>
            <ref bean="userWS"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
        </jaxrs:providers>
    </jaxrs:server>
</beans>

访问http://localhost:8080/rs/user?_wadl

调用服务

①JAX-RS 1.0 客户端

public class JAXRSClient {

    public static void main(String[] args) {
        String baseAddress = "http://localhost:8080/rs/user";

        List<Object> providerList = new ArrayList<Object>();
        providerList.add(new JacksonJsonProvider());

        UserWS userWS = JAXRSClientFactory.create(baseAddress, UserWS.class, providerList);

    }
}

②JAX-RS 2.0 客户端

public class JAXRS20Client {

    public static void main(String[] args) {
        String baseAddress = "http://localhost:8080/rs/user";

        JacksonJsonProvider jsonProvider = new JacksonJsonProvider();

        List<User> userList = ClientBuilder.newClient()
            .register(jsonProvider)
            .target(baseAddress)
            .path("/1")
            .request(MediaType.APPLICATION_JSON)
            .get(new GenericType<List<User>>() {});
    }
}

③WebClient 客户端

public class CXFWebClient {

    public static void main(String[] args) {
        String baseAddress = "http://localhost:8080/rs/user";

        List<Object> providerList = new ArrayList<Object>();
        providerList.add(new JacksonJsonProvider());

        List<User> userList = WebClient.create(baseAddress, providerList)
            .path("/1")
            .accept(MediaType.APPLICATION_JSON)
            .get(new GenericType<List<User>>() {});

    }
}

④AJAX客户端

$.ajax({
  type: 'get',
  url: 'http://localhost:8080/rs/user/1',
  dataType: 'json',
  success: function(data) {
//...
  }
});

跨域方案1:jsonp

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-extension-providers</artifactId>
    <version>${cxf.version}</version>
</dependency>
<jaxrs:server address="/rs/user">
    <jaxrs:serviceBeans>
        <ref bean="userWS"/>
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPreStreamInterceptor"/>
    </jaxrs:providers>
    <jaxrs:inInterceptors>
        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpInInterceptor"/>
    </jaxrs:inInterceptors>
    <jaxrs:outInterceptors>
        <bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPostStreamInterceptor"/>
    </jaxrs:outInterceptors>
</jaxrs:server>
$.ajax({
    type: 'get',
    url: 'http://localhost:8080/rs/user/1',
    dataType: 'jsonp',
    jsonp: '_jsonp',
    jsonpCallback: 'callback',
    success: function(data) {
        //...
    }
});

跨域方案2:cors

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-security-cors</artifactId>
    <version>${cxf.version}</version>
</dependency>
<jaxrs:server address="/rs/user">
    <jaxrs:serviceBeans>
        <ref bean="userWS"/>
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
        <bean class="org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter">
            <property name="allowOrigins" value="http://localhost"/>
        </bean>
    </jaxrs:providers>
</jaxrs:server>

allowOrigins 设置客户端域名

IE8 中使用 jQuery 发送 AJAX 请求时,需要配置 $.support.cors = true

~~警告~~

!warning 极重要,cxf在wsdl中发布的targetNamespace是实现类路径,而被调用时却只接受接口路径。所以,请将接口与实现类放在同一路径下,或者在实现类中指定targetNamespace为接口的路径;否则客户端将抛出 ..common.i18n.UncheckedException: No operation was found with the name … 异常