一、基本介绍
Web Services是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。Web Services更多是一种标准,而不是一种具体的技术,不同的平台、语言大都提供Web Services的开发实现。在java领域,Web Services的框架很多,例如:Axis、xfire、CXF等。
二、CXF基本介绍
Apache CXF = Celtix + XFire,Apache CXF 的前身叫 Apache CeltiXfire,现在已经正式更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。
Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。
CXF WebService 开发,主要分为两种服务提供方式 WS 、RS 。这里分别介绍这两种方式独立发布方法和与Spring整合的发布方法。
三、CXF-WS开发入门
1、JAX-WS独立服务使用
JAX-WS 传输数据,就是 XML 格式,基于 SOAP 协议。
开发步骤:
1.建立简单的Maven项目。
2.引入关键坐标依赖,具体如下配置。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.leon.maven</groupId>
<artifactId>cxf_ws_first_application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cxf_ws_first_application</name>
<description>独立发布的CXF-WS服务java项目</description>
<dependencies>
<!-- 要进行jax-ws开发,必须引入这个依赖 -->
<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>
<!-- ws开发需要的注解配置 -->
<dependency>
<groupId>javax.jws</groupId>
<artifactId>jsr181</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
- 第一个坐标是用来开发cxf应用,第二个坐标是搭建一个服务器,可以独立运行cxf应用,这个服务器类似独立的tomca插件服务器。
- 第三个坐标是日志输出的jar依赖,设置了这个依赖,就可以在项目运行期间打印出详细的数据传递的日志信息。但是不能忘记将log4j.properties配置文件拷贝至项目根目录下。
3.编写服务端程序,编写实体类。
User案例实体类:
package cn.leon.cxf.domain;
import java.util.ArrayList;
import java.util.List;
public class User {
private Integer id;
private String username;
private String city;
private List<Car> cars = new ArrayList<Car>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
}
Car案例实体类:
package cn.leon.cxf.domain;
public class Car {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
服务端程序:
服务端口接口程序,这个是对外发布的接口,必须得有,具体的代码业务实现,是它的实现类来完成。接口代码如下:
package cn.leon.cxf.service;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import cn.leoncxf.domain.Car;
import cn.leon.cxf.domain.User;
/**
* 该接口是服务端提供对外服务的接口,服务的主要代码由其实现类来完成。
* @author lemon
*
*/
@WebService // 使用在类上面,标记类是 WebService 服务提供对象
public interface IUserService {
@WebMethod // 使用在方法上面,标记方法 是 WebService 服务提供方法
String sayHello(String name);
@WebMethod
List<Car> findCarByUser(User user);
}
注解说明:
@WebService:使用在类上面,标记类是 WebService 服务提供对象;
@WebMethod:使用在方法上面,标记方法是 WebService 服务提供方法。
1) 给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。不支持静态方法,final方法。
2) 如果希望某个方法(非static,非final)不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
3) 如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
4) 服务类中不能没有方法
5) @WebMethod(exclude=true)屏蔽方法
实现类代码实现:
package cn.leon.cxf.service;
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebService;
import cn.leon.cxf.domain.Car;
import cn.leon.cxf.domain.User;
@WebService(endpointInterface = "cn.itcast.cxf.service.IUserService", serviceName = "userService")
// 注解设置 endPointInterface 接口服务完整类名, servicename 服务名称
public class UserServiceImpl implements IUserService {
// 传递简单的数据
public String sayHello(String name) {
return "Hello " + name;
}
// 传递复杂的数据
public List<Car> findCarByUser(User user) {
List<Car> list = null;
if ("tom".equals(user.getUsername())) {
list = new ArrayList<Car>();
Car car = new Car();
car.setId(1);
car.setName("QQ汽车");
car.setPrice(10000D);
list.add(car);
}
return list;
}
}
注解参数说明:
endpointInterface:接口服务的完整类名;
serviceName:服务名。
4.服务发布,编写服务发布代码。
package cn.leon.cxf.ws.server;
import javax.xml.ws.Endpoint;
import cn.itcast.cxf.service.IUserService;
import cn.itcast.cxf.service.UserServiceImpl;
/**
* 使用CXF将将UserService注册到到网络上
* @author lemon
*
*/
public class WS_Server {
public static void main(String[] args) {
// 1.服务实现类对象
IUserService userService = new UserServiceImpl();
// 2.发布服务地址
String address = "http://localhost:9999/userService";
// 3.发布服务
Endpoint.publish(address, userService);
System.out.println("服务开启了....");
}
}
服务地址:http://localhost:9999/userService?wsdl可以在浏览器*问这个地址,实现数据的访问,但是由于从浏览器没法传递参数,故无法完成对服务的方法的调用。
5.编写客户端程序代码,实现通信。
package cn.leon.cxf.ws.client;
import java.util.List;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import cn.leon.cxf.domain.Car;
import cn.leon.cxf.domain.User;
import cn.leon.cxf.service.IUserService;
public class WS_Client {
public static void main(String[] args) {
// 编写客户端,调用WebService服务
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress("http://localhost:9999/userService");
jaxWsProxyFactoryBean.setServiceClass(IUserService.class);
// 日志打印设置,是可选设置
jaxWsProxyFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
jaxWsProxyFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
// 创建调用远程服务的代理对象
IUserService proxy = (IUserService) jaxWsProxyFactoryBean.create();
// 直接调用远程服务的方法
System.out.println(proxy.sayHello("ITCAST"));
User user = new User();
user.setUsername("tom");
List<Car> cars = proxy.findCarByUser(user);
for (Car car : cars) {
System.out.println(car);
}
}
}
这就是一个独立发布的JAX-WS的一个完整流程,现总结如下:
- 配置相关依赖,也就是配置依赖的jar包;
- 编写传递数据的载体——实体类;
- 编写服务端的接口;
- 编写服务端接口的实现类;
- 编写服务发布的应用;
- 提供访问路径给第三方,由第三方编写客户端实现数据的通信。
JAX-WS原理分析:
客户端创建jaxWsProxyFactoryBean对象,它是一个服务端实现类的代理对象的创建工厂,通过create()方法可以创建服务端实现类的代理对象,这个对象可以调用一切在接口上添加了@WebMethod的方法,它的类型就是接口的类型,相当于服务端实现类对象的兄弟对象,这就完成了一个完整的Web Service应用。
2、JAX-WS与Spring整合开发Web Service
第一步:建立 maven web 项目 ,基于 tomcat 发布服务。
第二步:导入Maven坐标,建立依赖关系。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.leon.maven</groupId>
<artifactId>cxf_ws_spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>cxf_ws_spring</name>
<description>CXF的WS和Spring整合服务发布</description>
<dependencies>
<!-- CXF的WS开发的依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
</dependency>
<!-- spring开发 -->
<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>
<!-- 配置依赖的servlet api,仅仅测试的时候才配置 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 配置服务启动端口 -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<port>9998</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 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的web配置,基于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>/service/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
4.导入前面已有的实体类、接口和服务实现类。
5.在applicationContext.xml中配置服务,这个服务交给spring来管理。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" 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://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置服务 -->
<!--
address是访问路径;
serviceClass是配置接口;
serviceBean是配置实现类。
-->
<jaxws:server id="userService" address="/userService"
serviceClass="cn.leon.cxf.service.IUserService">
<jaxws:serviceBean>
<bean class="cn.leon.cxf.service.UserServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
需要注意的是:需要引入jaxws命名空间和约束。xmlns:jaxws="http://cxf.apache.org/jaxws"
6.使用tomcat插件启动maven项目,提供给第三方访问路径:http://localhost:9998/cxf_ws_spring/service/userService?wsdl。
注意:尤其要注意访问路径的拼接问题。tomcat访问路径+项目名+web.xml配置的访问路径+服务名,后面连接上参数wsdl。
7.整合spring,配置客户端,客户端交给spring来管理。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" 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://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置服务 -->
<!-- address是访问路径; serviceClass是配置接口; serviceBean是配置实现类。 -->
<jaxws:server id="userService" address="/userService"
serviceClass="cn.leon.cxf.service.IUserService">
<jaxws:serviceBean>
<bean class="cn.leon.cxf.service.UserServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
<!-- 配置客户端 -->
<jaxws:client id="userServiceClient" serviceClass="cn.leon.cxf.service.IUserService"
address="http://localhost:9998/cxf_ws_spring/service/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>
其中消息拦截器是可选设置。
8.编写测试案例。
package cn.leon.cxf.server.test;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.leon.cxf.domain.Car;
import cn.leon.cxf.domain.User;
import cn.leon.cxf.service.IUserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class CXFTest {
// 注入一个代理对象
@Autowired
private IUserService proxy;
@Test
public void testServer() {
System.out.println(proxy.sayHello("黑马程序员"));
}
@Test
public void testServer2() {
User user = new User();
user.setUsername("tom");
List<Car> cars = proxy.findCarByUser(user);
for (Car car : cars) {
System.out.println(car);
}
}
}
四、CXF-RS开发入门(重点)
1、JAX-RS独立服务使用
1.建立简单的Maven java项目。
2.导入Maven坐标。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.leon.maven</groupId>
<artifactId>cxf_rs_first_application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cxf_rs_first_application</name>
<description>独立的jax-rs应用</description>
<dependencies>
<!-- 要进行jax-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>
<!-- 客户端需要配置的依赖 -->
<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>
</dependencies>
</project>
3.编写实体类。
User类:
package cn.leon.cxf.domain;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "User")
public class User {
private Integer id;
private String username;
private String city;
private List<Car> cars = new ArrayList<Car>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", city=" + city + ", cars=" + cars + "]";
}
}
Car类:
package cn.itcast.cxf.domain;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Car")
public class Car {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
注意:@XmlRootElement(name = "Car")指定了转换成xml和json的时候对象的名称。
4.编写业务接口和业务实现类。
业务接口:
package cn.leon.cxf.service;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import cn.leon.cxf.domain.User;
@Path("/userService")
@Produces("*/*")
public interface IUserService {
@POST
@Path("/user") // 设置二级访问路径
@Consumes({ "application/xml", "application/json" }) // 设置接收参数的格式
void saveUser(User user);
@PUT
@Path("/user")
@Consumes({ "application/xml", "application/json" })
void updateUser(User user);
@GET
@Path("/user")
@Consumes({ "application/xml", "application/json" })
@Produces({ "application/xml", "application/json" }) // 指定返回数据格式
List<User> findAll();
@GET
@Path("/user/{id}")
@Consumes({ "application/xml", "application/json" })
@Produces({ "application/xml", "application/json" })
User findUserById(@PathParam("id") Integer id); // 参数指定了接收数据的名字
@DELETE
@Path("/user/{id}")
@Consumes({ "application/xml", "application/json" })
void deleteUserById(@PathParam("id") Integer id);
}
说明:
- @Path 指定了服务访问资源路径,访问路径是类上的path+方法上的path;
- @Consumes 指定能够处理客户端传递过来数据格式,也就是说指定了客户端传递过来的数据格式;
- @Produces 指定能否生成哪种格式数据返回给客户端;
- @GET 查询 @PUT 修改 @POST 增加 @DELETE 删除;
- @PathParam("id")指定了拼接在访问路径上参数。
业务实现类:
package cn.leon.cxf.service;
import java.util.ArrayList;
import java.util.List;
import cn.leon.cxf.domain.Car;
import cn.leon.cxf.domain.User;
public class UserServiceImpl implements IUserService {
public void saveUser(User user) {
System.out.println("save user:" + user);
}
public void updateUser(User user) {
System.out.println("update user:" + user);
}
public List<User> findAll() {
List<User> users = new ArrayList<User>();
User user1 = new User();
user1.setId(1);
user1.setUsername("小明");
user1.setCity("北京");
List<Car> carList1 = new ArrayList<Car>();
Car car1 = new Car();
car1.setId(101);
car1.setName("保时捷");
car1.setPrice(1000000d);
carList1.add(car1);
Car car2 = new Car();
car2.setId(102);
car2.setName("宝马");
car2.setPrice(400000d);
carList1.add(car2);
user1.setCars(carList1);
users.add(user1);
User user2 = new User();
user2.setId(2);
user2.setUsername("小丽");
user2.setCity("上海");
users.add(user2);
return users;
}
public User findUserById(Integer id) {
if (id == 1) {
System.out.println(22222);
User user1 = new User();
user1.setId(1);
user1.setUsername("小明");
user1.setCity("北京");
return user1;
}
return null;
}
public void deleteUserById(Integer id) {
System.out.println("delete user id :" + id);
}
}
5.发布服务
package cn.leon.cxf.server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import cn.leon.cxf.domain.Car;
import cn.leon..cxf.domain.User;
import cn.leon.cxf.service.IUserService;
import cn.leon.cxf.service.UserServiceImpl;
public class RSServer {
public static void main(String[] args) {
// 创建服务端业务接口实现类对象
IUserService userService = new UserServiceImpl();
// 创建服务
JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
jaxrsServerFactoryBean.setResourceClasses(User.class, Car.class); // 指定将哪些实体类转换成xml、json进行发送
jaxrsServerFactoryBean.setAddress("http://localhost:9997");
jaxrsServerFactoryBean.setServiceBean(userService);
// 发布服务
jaxrsServerFactoryBean.create();
System.out.println("服务开启了....");
}
}
现在可以通过浏览器来进行对服务端的数据访问了。
6.编写客户端。
对于客户端程序的编写 有两种做法
- 使用 http client 工具 ,需要自己对 HTTP 协议内容进行定制和解析
- WebClient 工具类使用(CXF 自带)
使用第二种,需要导入一个依赖,cxf-rt-rs-client。
依赖:
<!-- 客户端需要配置的依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.1</version>
</dependency>
客户端编写:
package cn.leon.cxf.client;
import java.util.Collection;
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
import cn.leon.cxf.domain.User;
public class RSClient {
public static void main(String[] args) {
// 参数说明:
// create是创建一个连接,给定一个访问地址
// accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
// getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
// type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
Collection<? extends User> collection = WebClient.create("http://localhost:9997/userService/user")
.accept(MediaType.APPLICATION_XML).getCollection(User.class);
System.out.println(collection);
// 保存一个对象
User user = new User();
user.setUsername("Lemon");
WebClient.create("http://localhost:9997/userService/user")
.type(MediaType.APPLICATION_XML).post(user);
}
}
方法说明:
- create是创建一个连接,给定一个访问地址
- accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
- getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
- type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
思考:
如何是要JSON数据格式进行交互?
要是要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数据格式交互的转换接口 -->
<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>
使用JSON数据进行交互的客户端:
package cn.leon.cxf.client;
import java.util.Collection;
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
import cn.leon.cxf.domain.User;
public class RSClient2 {
public static void main(String[] args) {
// 参数说明:
// create是创建一个连接,给定一个访问地址
// accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
// getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
// type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
Collection<? extends User> collection = WebClient.create("http://localhost:9997/userService/user")
.accept(MediaType.APPLICATION_JSON).getCollection(User.class);
System.out.println(collection);
// 保存一个对象
User user = new User();
user.setUsername("Lemon");
WebClient.create("http://localhost:9997/userService/user")
.type(MediaType.APPLICATION_JSON).post(user);
}
}
2、JAX-RS与Spring整合开发Web Service
1.建立Maven Web项目。
2.导入相关依赖。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.leon.maven</groupId>
<artifactId>cxf_rs_spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>cxf_rs_spring</name>
<description>CXF的rs服务发布与spring整合</description>
<dependencies>
<!-- cxf 进行rs开发 必须导入 -->
<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工具包,被extension providers 依赖 -->
<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>
<!-- spring web集成 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- spring 整合junit -->
<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>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<port>9996</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
第三步:3.导入web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 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的web配置,基于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>/service/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
4.导入上述的实体类和服务接口、服务实现类。需要注意的是:服务接口上的@Path需要删除,或者将applicationContext.xml中发访问地址设置为空。@Path与applicationContext.xml 配置重复,所以一般注释掉,但是还是建议将xml中的配置设置为空,这里的path设置不为空,因为xml中可以配置接口的多个实现类,如果在xml设置配置统一的访问路径,那么就难以区分到底是哪个实现类在工作,而在类上设置@path,那么就可以区分不同的实现类,很明了。
5.配置applicationContext.xml
<?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:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<!--
address 发布服务地址
servicesBeans 服务实现类
-->
<jaxrs:server id="userService" address="/userService" >
<jaxrs:serviceBeans>
<bean class="cn.itcast.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>
</beans>
需要注意的是:需要引入名称空间:
xmlns:jaxrs="http://cxf.apache.org/jaxrs" http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
6.启动服务,访问路径。
访问路径:服务器根目录地址(项目地址) + web.xml 配置 + applicationContext.xml address 配置 (或类 @Path )+ 方法 @Path
7.编写客户端。
package cn.leon.cxf.client;
import java.util.Collection;
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
import cn.leon.cxf.domain.User;
public class RSClient {
public static void main(String[] args) {
// 参数说明:
// create是创建一个连接,给定一个访问地址
// accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
// getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
// type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
Collection<? extends User> collection = WebClient.create("http://localhost:9996/cxf_rs_spring/service/userService/user")
.accept(MediaType.APPLICATION_XML).getCollection(User.class);
System.out.println(collection);
// 保存一个对象
User user = new User();
user.setUsername("Lemon");
WebClient.create("http://localhost:9996/cxf_rs_spring/service/userService/user")
.type(MediaType.APPLICATION_XML).post(user);
}
}
其他调用webservice的方式
4.11、 使用ajax调用
var xhr;
function invoke(){
if(window.ActiveXObject){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}else{
xhr = new XMLHttpRequest();
}
//指定请求地址
var url = "http://127.0.0.1:7777/hello?wsdl";
//定义请求类型和地址和异步
xhr.open("POST", url, true);
//设置Content-Type
xhr.setRequestHeader("Content-Type", "text/xml;charset=UTF-8");
//指定回调方法
xhr.onreadystatechange = back;
var textVal = document.getElementById("mytext").value;
//组装消息体的数据
var data = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://server.hm.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+'<soapenv:Body>'
+'<q0:sayHello>'
+'<arg0>'+textVal+'</arg0>'
+'</q0:sayHello>'
+'</soapenv:Body>'
+'</soapenv:Envelope>';
xhr.send(data);
}
function back(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var doc = xhr.responseXML;
alert(doc);
alert(xhr.responseText);
var tag = doc.getElementsByTagName("return")[0];
alert(tag)
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
4.12、通过URLConnection调用
//创建url地址
URL url = new URL("http://192.168.1.104:8080/hello");
//打开连接
URLConnection conn = url.openConnection();
//转换成HttpURL
HttpURLConnection httpConn = (HttpURLConnection) conn;
//打开输入输出的开关
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
//设置请求方式
httpConn.setRequestMethod("POST");
//设置请求的头信息
httpConn.setRequestProperty("Content-type", "text/xml;charset=UTF-8");
//拼接请求消息
String data = "<soapenv:Envelope xmlns:soapenv=" +
"\"http://schemas.xmlsoap.org/soap/envelope/\" " +
"xmlns:q0=\"http://server.rl.com/\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+"<soapenv:Body>"
+"<q0:sayHello>"
+"<arg0>renliang</arg0> "
+"</q0:sayHello>"
+"</soapenv:Body>"
+"</soapenv:Envelope>";
//获得输出流
OutputStream out = httpConn.getOutputStream();
//发送数据
out.write(data.getBytes());
//判断请求成功
if(httpConn.getResponseCode() == 200){
//获得输入流
InputStream in = httpConn.getInputStream();
//使用输入流的缓冲区
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
String line = null;
//读取输入流
while((line = reader.readLine()) != null){
sb.append(line);
}
//创建sax的读取器
SAXReader saxReader = new SAXReader();
//创建文档对象
Document doc = saxReader.read(new StringReader(sb.toString()));
//获得请求响应return元素
List<Element> eles = doc.selectNodes("//return");
for(Element ele : eles){
System.out.println(ele.getText());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
4.13、使用jquery调用cxf
$(function(){
$("#mybutton").click(function(){
var data = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://server.web.cxf.rl.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+'<soapenv:Body>'
+'<q0:sayHello>'
+' <arg0>sss</arg0>'
+' </q0:sayHello>'
+'</soapenv:Body>'
+'</soapenv:Envelope>';
$.ajax({
url:'http://localhost:8080/cxf-web-server/services/hello',
type:'post',
dataType:'xml',
contentType:'text/xml;charset=UTF-8',
data:data,
success:function(responseText){
alert($(responseText).find('return').text());
},
error:function(){
alert("error");
}
})
})
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
5、wsdl文档元素名称修改
自动生成的文档的名字有时不规范,可以手动进行修改。
@WebService(
portName=”myHelloService”,修改端口名字
serviceName=”HelloServices”,修改服务访问点集合名字
name=”HelloService”,修改服务类的名字
targetNamespace=”hello.rl.com” 修改命名空间名字
)
@WebResult(name=”sirHello”)修改返回值的元素的父标签名字
@WebParam(name=”sir”)修改传入参数的元素的父标签名字
6、CXF使用详解
说到webservice那么cxf是不得不说的一个东西
1、什么是cxf
可以理解为使用webservice的一种框架,用了cxf,可以让发布和调用更加简单并且功能丰富
2、cxf目录详解(了解)
Apache CXF = Celtix + Xfire
支持多种协议:
a) SOAP1.1,1,2
b) HTTP
c) CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)
d) 并可以与Spring进行快速无缝的整合
e) 灵活的部署:可以运行有Tomcat,Jboss,Jetty(内置),IBMWS,BeaWS上面。
bin(目录)
bin 目录中是 CXF 框架中所提供的代码生成、校验、管理控制台工具(可执行命令)
docs(目录)
CXF 所有类(class)对应的 API 文档,为开发者使用 CXF 完成应用开发提供应有的帮助。
etc(目录)
包含一个基本的 Service 暴露所需要的 web.xml 文件,及其它的配置文件。
lib(目录)
lib 目录中包含 CXF 及其运行时所需要的和可选的第三方支持类包(.jar 文件),可以根据不同项目所需的 CXF 特性选择所需要的支持类包。如果不想一一去区分的话,可
以直接在 Web 项目中包含所有的 CXF 及其运行时所需要的第三方支持类包(.jar 文件)即可。
其中 cxf-2.0.2-incubator.jar 是 CXF 框架的二进制包文件,包含了全部的模块(modules),cxf-manifest-incubator.jar 是列表清单文件 manifest jar 。
以下的 jar 包是所有 CXF 项目所必需的:
cxf.jar
commons-logging.jar
geronimo-activation.jar (Or the Sun equivalent)
geronimo-annotation.jar (Or the Sun equivalent)
geronimo-javamail.jar (Or the Sun equivalent)
neethi.jar
jaxb-api.jar
jaxb-impl.jar
stax-api.jar
XmlSchema.jar
wstx-asl.jar
xml-resolver.jar
对于 Java2WSDL 和 WSDL2Java,除了必需的之外,还需要再增加如下 jar 包:
jaxb-xjc.jar
veliocity.jar
velocity-dep.jar
为了支持 JAX-WS ,除了必需的之外,还需要再增加如下 jar 包:
jaxws-api.jar
saaj-api.jar
saaj-impl.jar
asm.jar (可选的,但是可以提升包装类型的性能)
为了支持 XML 配置,除了必需的之外,还需要再增加如下 jar 包:aopalliance.jar
spring-beans.jar
spring-context.jar
spring-core.jar
spring.web.jar
为了独立的 HTTP 服务支持,除了必需的之外,还需要再增加如下 jar 包:geronimo-servlet.jar
jetty.jar
jetty-sslengine.jar
jetty-util.jar
sl4j.jar & sl4j-jdk14.jar (可选的,但是可以提升日志 logging)
为了支持 Aegis ,除了必需的之外,还需要再增加如下 jar 包:
jaxen.jar
jdom.jar
stax-utils.jar
为了支持 WS-Security ,除了必需的之外,还需要再增加如下 jar 包:bcprov-jdk14.jar
wss4j.jar
xalan.jar
xmlsec.jar
为了支持 HTTP Binding ,除了必需的之外,还需要再增加如下 jar 包:jra.jar
jettison.jar (仅为 JSON 服务所需的)
licenses(目录)
列表了引用第三方 jar 包的相关许可协议。
modules(目录)
modules 目录中包含了 CXF 框架根据不同特性分开进行编译的二进制包文件。发布基于 CXF 框架的 Web 项目时,可以选择使用该目录下的所有 .jar 文件,也可以选择 lib 目 录中的 cxf-2.0.2-incubator.jar 文件。
samples(目录)
samples 目录中包含了所有随 CXF 二进制包发布的示例,包含这些示例的源代码和相关 Web 应用配置文件,可以方便地用 Ant 来编译运行测试这些示例,来了解 CXF 的开发和
使用的方法。可以通过 samples 目录和它各个子目录下的 README.txt 的文件来详细了解示例的编译与运行的步骤。