第五章 web service cxf

web service出现的目的:为了支持“异构网络”中的应用程序之间交互出现的;

web service被定义成一组模块化的api,可以通过网络进行远程调用;web service是一个跨语言、跨平台的远程调用技术;

1. 使用场景

不同的公司系统之间的数据交互,注册微信公众号的公司和腾讯之间的交互数据,或者是电商平台与物流公司交互数据等

2.三要素

  1. WSDl

web服务定义描述语言

  • 用于描述具体服务,定义客户端和服务端之间数据交互时传递的数据格式(请求和响应的数据)
  1. 每一个web service对应为一个wsdl文档
  2. WSDL可以认为是web service说明书
  1. SOAP

简单对象访问协议,基于Http协议,使用XML传递消息;
它是一种轻量级的通信协议;
用于不同应用之间的通信;
使用Http协议进行通信;
独立于平台、编程语言,基于XML,简单并可扩展

3. webservice规范

  1. JAX-WS规范

全称:Java Api For Xml-Based WebService;
早期的时候是叫JAX-RPC(Java Api For Xml-Rmote Procedure Call);
JAX-RPC目前已经被JAX-WS取代;

JDK5.0开始支持JAX-WS的2.0版本;
JDK1.6.0_13版本开始支持JAX-WS的2.1版本
JDK7支持了JAX-WS的2.2版本

采用标准的Soap协议传输数据,Soap协议是基于应用层的Http协议,传输xml数据;
采用WSDL做为服务的描述语言;

  1. JAX-RS规范

是Java针对REST风格的请求制定的一套web服务规范;
没有随着JDK1.6发布

支持JAX-RS规范的框架

  • CXF
  • RESTEasy :JBOSS的
  • RESTLet:比较早的rest框架,比JAX-RS规范还要早
  • Jersey

1.JDK自带的

1.1 创建服务提供者

import javax.jws.WebService;

// 这个@WebService需要同时写在接口和实现类上
@WebService
public interface HelloService {

    String sayHello(String name);

}
import com.etoak.service.HelloService;

import javax.jws.WebService;

@WebService
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        System.out.println("server invoke");
        return "Hello " + name;
    }

}
import com.etoak.service.impl.HelloServiceImpl;

import javax.xml.ws.Endpoint;

public class JdkServer {
    public static void main(String[] args) {
        // 参数一:服务地址
        // 参数二:要发布的服务
        Endpoint.publish("http://localhost:8000/hello",
                new HelloServiceImpl());
    }
}

1.2创建客户端

在任意文件夹使用cmd窗口执行一下命令 wsimport http://localhost:8001/hello?wsdl,创建客户端

2.cxf

3.cxf与spring整合

3.1创建服务

3.2创建客户端

3.3如何发布一个webservice服务

  1. 在web.xml中配置 cxf
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  
<!-- CXFServlet -->
<servlet>
  <servlet-name>CXF</servlet-name>
  <servlet-class>
    org.apache.cxf.transport.servlet.CXFServlet
  </servlet-class>
  <!-- 如果不配置config-location,
       默认查找/WEB-INF/cxf-servlet.xml -->
  <init-param>
    <param-name>config-location</param-name>
    <param-value>classpath:spring-cxf.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>CXF</servlet-name>
  <url-pattern>/ws/*</url-pattern>
</servlet-mapping>
  
</web-app>
  1. 创建配置文件
<?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:jaxws="http://cxf.apache.org/jaxws"
       xmlns:core="http://cxf.apache.org/core"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://cxf.apache.org/jaxws
        http://cxf.apache.org/schemas/jaxws.xsd
        http://cxf.apache.org/core
        http://cxf.apache.org/schemas/core.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <context:component-scan base-package="com.etoak" />
    <!-- 数据源
         SqlSessionFactoryBean
         MapperScannerConfigurer
     -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://127.0.0.1:3306/et1912" />
       <property name="username" value="root" />
       <property name="password" value="root" />
       <!-- 初始化连接数  -->
       <property name="initialSize" value="20" />
       <!-- 最大活跃连接数 -->
       <property name="maxActive" value="50" />
       <property name="validationQuery" value="select 1" />
    </bean>

    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.etoak.bean" />
        <property name="mapperLocations"
                  value="classpath:/mappers/*.xml" />
        <property name="plugins" >
            <list>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.etoak.mapper" />
    </bean>

<!--
    1. JaxWsServerFactoryBean
    2. wsdl地址 : http://localhost:8001/ws/user
    3. 设置服务接口
    4. 设置服务实现
    5. 创建服务并启动服务
-->
<jaxws:server address="/user"
    serviceClass="com.etoak.service.UserService">
    <jaxws:serviceBean>
        <ref bean="userServiceImpl" />
    </jaxws:serviceBean>

    <!--<!– 服务器接收请求:使用In拦截器 –>
    <jaxws:inInterceptors>
        <!– 使用官方定义的日志拦截器: 默认拦截阶段 - receive –>
        <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />

        <!– 使用自定义拦截器 –>
        <bean class="com.etoak.interceptor.AuthInInterceptor">
            <!– 执行阶段:方法执行前拦–>
            <constructor-arg name="phase" value="pre-invoke" />
        </bean>
    </jaxws:inInterceptors>-->

    <!-- 服务器响应结果:使用Out拦截器 -->
   <!-- <jaxws:outInterceptors>
        <!– 使用官方定义的日志拦截器 –>
        <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
    </jaxws:outInterceptors>-->

</jaxws:server>


<jaxws:server address="/student" serviceClass="com.etoak.service.StudentService">
    <jaxws:serviceBean>
        <ref bean="studentServiceImpl" />
    </jaxws:serviceBean>

</jaxws:server>



<core:bus>
 <core:inInterceptors>
   <!-- 使用官方定义的日志拦截器: 默认拦截阶段 -> receive -->
   <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />

   <!-- 使用自定义拦截器 -->
   <bean class="com.etoak.interceptor.AuthInInterceptor">
       <!-- 执行阶段:方法执行前拦-->
       <constructor-arg name="phase" value="pre-invoke" />
   </bean>
 </core:inInterceptors>
 <core:outInterceptors>
   <!-- 使用官方定义的日志拦截器 -->
   <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
 </core:outInterceptors>
</core:bus>
</beans>

4.配置拦截器[官方]

5.自定义拦截器

6.实例,调用外部接口

7. 发布接口

使用wsdl自带的命令发布客户端

wsimport http://localhost:8001/hello?wsdl

X. 错误集锦

  1. com.sun.xml.internal.ws.server.ServerRtException: Server Runtime

空指针异常,有可能是前端的连接写错了

Endpoint.publish("http://localhost:8000/hello", new HelloServiceImpl());