很多个系统,进行分布的部署,分布的系统数据通信 解决技术就是 WebService。
CXF 是目前最主流 WebService 开发框架
CXF主要分为两种服务
JAX-WS 传输数据,就是 XML 格式,基于 SOAP 协议
JAX-RS 传输数据,传输 XML 格式或者 JSON 格式,基于 HTTP 协议
JAX-WS独立服务使用
导入CXFjar包支持 Maven坐标
<dependencies>
<!-- 进行jaxes 服务开发 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 内置jetty web服务器 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 日志实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
编写服务端的代码
-
实体类
Carprivate Integer id; private String carName; private Double price;
User
private Integer id; private String carName; private Double price;
-
服务端程序
IUserService接口@WebService //用来标记类是WebService服务提供对象 public interface IUserService { @WebMethod //用来标记方法是WebService提供的方法 public String sayHello(String name); @WebMethod public List<Car> findCarsByUser(User user); }
UserServiceImpl
@WebService(endpointInterface = "cn.lzh.cxf.service.IUserService", serviceName = "userService") //endpointInterface接口服务完整全类名 //serviceName服务名称 public class UserServiceImpl implements IUserService { //简单参数传递 public String sayHello(String name) { return "Hello," + name; } //复杂参数 传递 public List<Car> findCarsByUser(User user) { // 这里本应该查询数据库的,为了演示,做一些假数据 if ("xiaoming".equals(user.getUsername())) { List<Car> cars = new ArrayList<Car>(); Car car1 = new Car(); car1.setId(1); car1.setCarName("大众途观"); car1.setPrice(200000d); cars.add(car1); Car car2 = new Car(); car2.setId(2); car2.setCarName("现代ix35"); car2.setPrice(170000d); cars.add(car2); return cars; } else { return null; } } }
-
将userService注册到网上
//将CXY 将 UserServer注册到网络上 //1.服务实现对象 IUserService userService = new UserServiceImpl(); //2发布服务地址 String address = "http://localhost:8888/userService"; //3发布服务 Endpoint.publish(address, userService); System.out.println("服务已经启动...");
成功界面
-
客户端
//ws客户端 public class WS_Client { public static void main(String[] args) { //编写客户端 调用发布WebService服务 JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean(); jaxWsProxyFactoryBean.setServiceClass(IUserService.class); jaxWsProxyFactoryBean.setAddress("http://localhost:9999/userService"); //调用远程服务代理对象 IUserService proxy = (IUserService) jaxWsProxyFactoryBean.create(); //调用代理对象任何一个方法,都将网络调用web服务 System.out.println(proxy.sayHello("你好")); } }
服务启动成功 可以用网络调用该服务
注意
可以通过
jaxWsProxyFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
jaxWsProxyFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
开启日志信息
JAX-WS和Spring整合开发WebService
导入CXF_WS的Maven坐标 与tomcat插件
<dependencies>
<!-- CSF WS开发核心 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<port>9800</port>
</configuration>
</plugin>
</plugins>
</build>
配置web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- spring核心监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- CXF WS基于web访问的servlet -->
<servlet>
<servlet-name>CXFService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFService</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
application的配置
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!--
address 客户端访问服务器路径
serviceClass 配置接口
serviceBean 配置实现
-->
<jaxws:server id="userService" address="/userService" serviceClass="cn.lzh.cxf.service.IUserService">
<jaxws:serviceBean>
<bean class="cn.lzh.cxf.service.UserServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
客户端的测试
application-test的配置
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!--
serviceClass :服务接口
address 服务访问地址
-->
<jaxws:client id="userServiceClient" serviceClass="cn.lzh.cxf.service.IUserService"
address="http://localhost:9800/cxf_ws_spring/services/userService" >
<!-- 来源消息拦截器 -->
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
</jaxws:inInterceptors>
<!-- 输出消息拦截器 -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxws:outInterceptors>
</jaxws:client>
</beans>
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
public class WS_spring_test {
@Autowired
private IUserService proxy;
@Test
public void testCXF(){
System.out.println(proxy.sayHello("你好"));
}
}
结果:
服务访问成功
JAX-RS独立使用
重点
要先了解restful风格:
在我认为restful是通过资源进行定位或进行操作的,不是什么标准,也不是什么协议,互联网的任何事物都是
资源,比如说网络上有张图片,我只需要知道那张图片的名字,通过图片名字的url来定位到这张图片,
资源操作 我们用数据库的crud 对应htpp方法,比如put修改 post保存 get查询,delete删除,这样我们能创建
统一的接口,减少代码的开发,提升开发效率 而且基于http协议,支持多种消息格式,比如xml jason 更容
易实现缓存机制,tomcat有缓存机制,第一次访问资源,第二次访问资源,返回304客户端调用本地
- 添加Maven依赖
<dependencies>
<!-- 使用CXF RS开发 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 内置jetty web服务器 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
- 编写实体类
car
@XmlRootElement(name = "Car")
//指定序列化时(转换xml json)对象名字
public class Car {
private Integer id;
private String carName;
private Double price;
public Integer getId() {
return id;
}
注意要写@XMLRootElement注解
User
@XmlRootElement(name = "User")
public class User {
private Integer id;
private String username;
private String city;
private List<Car> cars = new ArrayList<Car>();
- 编写服务端程序
IUserService
@Path("/userService")
//服务访问资源路径
@Produces("*/*")
//生成(返回值) 指定能够生成哪种格式数据返回给客户端
public interface IUserService {
@POST
//请求http协议的 增加
@Path("/user")
@Consumes({ "application/xml", "application/json" })
//方法的参数 指定能够处理客户端传递过来的数据格式
public void saveUser(User user);
@PUT
@Path("/user")
//请求http协议的 修改
@Consumes({ "application/xml", "application/json" })
public void updateUser(User user);
@GET
@Path("/user")
//请求http协议的 查询
@Produces({ "application/xml", "application/json" })
public List<User> findAllUsers();
//生成(返回值) 指定能够生成哪种格式数据返回给客户端
@GET
@Path("/user/{id}")
@Consumes("application/xml")
@Produces({ "application/xml", "application/json" })
public User finUserById(@PathParam("id") Integer id);
@DELETE
@Path("/user/{id}")
//请求http协议的 删除
@Consumes("application/xml")
public void deleteUser(@PathParam("id") Integer id);
}
注意 如果要返回数据要加@Produces注解 参数为可以处理的数据格式
注意 如果要接受参数要加@Consumes注解 参数为可以处理的数据格式
将服务发布到网络
//创建业务接口实现类对象
IUserService userService = new UserServiceImpl();
//服务器FactoryBean创建服务
JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean();
//将那些实体转换成xml、json发送
restServer.setResourceClasses(User.class,Car.class);
//设置服务的bean
restServer.setServiceBean(userService);
//设置地址
restServer.setAddress("http://localhost:9999");
//打印日志
restServer.getInInterceptors().add(new LoggingInInterceptor());
restServer.getOutInterceptors().add(new LoggingOutInterceptor());
//发布服务
restServer.create();
客户端代码
首先要在maven添加WebClient依赖
<!-- 使用rs客户端 里面有个工具包为rs client -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.1</version>
</dependency>
public static void main(String[] args) {
//create 建立与调用服务资源路径链接
//type 发送给服务器数据格式--@Consume
//accept接受服务器传输数据格式--@Produces
Collection<? extends User> collection = WebClient.create("http://localhost:9999/userService/user").accept(MediaType.APPLICATION_XML).getCollection(User.class);
System.out.println(collection);
//添加用户
User user = new User();
WebClient.create("http://localhost:9999/userService/user").type(MediaType.APPLICATION_XML).post(user);
}
成功:
注意
put为修改 post为添加 delete为删除 get为查找
传输json
错误:Caused by: javax.ws.rs.ProcessingException: No message body writer has been found
for class cn.itcast.cxf.domain.User, ContentType: application/json
解决:添加json转换器
<!-- 在CXF扩展原提供者,提供转换JSON接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.1</version>
</dependency>
<!-- CXF默认的扩展提供者 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.7</version>
</dependency>
JAX-RS 整合Spring
导入Maven坐标
<dependencies>
<!-- CXF_rs开发必须要的jar -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- 客户端程序坐标 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 扩展json提供者 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 转换json包依赖 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.7</version>
</dependency>
<!-- spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- springweb包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- spring -juite -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- junit的依赖包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<!-- tomcat插件 -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<port>9800</port>
</configuration>
</plugin>
</plugins>
</build>
web.xml配置
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- spring核心监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- CXF service的Servlet -->
<servlet>
<servlet-name>CXFService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFService</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
applicationContext.xml配置
<!--
address 发布服务地址
servicesBeaan 服务实现类
-->
<jaxrs:server id="userService" address="/userService" >
<jaxrs:serviceBeans>
<bean class="cn.lzh.cxf.service.UserServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxrs:outInterceptors>
</jaxrs:server>
注意
最终访问资源服务路径
服务器根目录地址+web.xml配置+applicationContext.xml address配置,类 @Path+方法@Path