第五章 web service cxf
web service出现的目的:为了支持“异构网络”中的应用程序之间交互出现的;
web service被定义成一组模块化的api,可以通过网络进行远程调用;web service是一个跨语言、跨平台的远程调用技术;
1. 使用场景
不同的公司系统之间的数据交互,注册微信公众号的公司和腾讯之间的交互数据,或者是电商平台与物流公司交互数据等
2.三要素
- WSDl
web服务定义描述语言
- 用于描述具体服务,定义客户端和服务端之间数据交互时传递的数据格式(请求和响应的数据)
- 每一个web service对应为一个wsdl文档
- WSDL可以认为是web service说明书
- SOAP
简单对象访问协议,基于Http协议,使用XML传递消息;
它是一种轻量级的通信协议;
用于不同应用之间的通信;
使用Http协议进行通信;
独立于平台、编程语言,基于XML,简单并可扩展
3. webservice规范
- 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做为服务的描述语言;
- 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服务
- 在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>
- 创建配置文件
<?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. 错误集锦
- com.sun.xml.internal.ws.server.ServerRtException: Server Runtime
空指针异常,有可能是前端的连接写错了
Endpoint.publish("http://localhost:8000/hello", new HelloServiceImpl());