1. REST方式的WebService概述
1.1 REST架构风格
REST是 Roy Fielding 博士在 2000 年提出的。
REST(Representational State Transfer-表现层状态转化)是一种新的软件架构风格,它以资源(resource)为核心,使用 HTTP、 URI、XML 以及 HTML 等流行协议和标准来完成对资源的操作及显示。 这些操作包括获取、创建、修改和删除资源(CRUD),分别对应于 HTTP 协议的 GET、POST、PUT 和 DELETE 方法。
RESTful架构可以总结为以下三个内容:
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。
- GET用来获取资源,
- POST用来新建资源(也可以用于更新资源),
- PUT用来更新资源,
- DELETE用来删除资源。
1.2. REST风格服务
REST (风格的)服务(RESTful Service)是一种基于 HTTP 和 REST 准则的轻量级 Web 服务。
这类服务可以看作一系列资源(resource)的集合,服务的定义可以视为以下三个切面的组合 :
- 访问 Web Service 的 URI,如:http://example.com/resources。
- Web Service 所支持的数据 MIME 类型,如:JSON, XML, YAML 等。
- Web Service 使用 HTTP 协议支持的操作,如 GET, POST, PUT, DELETE。
1.3.优点
REST风格的服务的性能,效率和易用性等方面均优于 SOAP 协议:
- 相比SOAP 和 XML-RPC, REST 服务更加简洁,
- 它可以完全通过 HTTP 协议实现,
- 支持多种消息格式,比如XML 、JSON
- 还可以利用缓存 Cache 来提高响应速度(第一次访问资源 缓存,第二次访问资源,返回304客户端调用本地)。
1.4.JAX-RS
JAX-RS (JSR 311)是Java世界中的另一套Web Service规范,用于开发RESTful Web Service。它属于Java EE 6规范中的子规范,逐步取代了JAX-WS(大WebService的规范)的地位。
基于JAX-RS规范实现的RESTful API可达到:支持资源抽象、统一接口的 “CRUD式Web服务”。
2.CXF服务端开发
CXF框架支持JAX-WS,也支持JAX-RS规范,都是远程调用。
2.1 新建maven项目,引入依赖
pom.xml
<properties>
<cxf.version>3.1.9</cxf.version>
<slf4j.version>1.7.21</slf4j.version>
</properties>
<!-- 依赖管理 -->
<dependencies>
<!-- CXF RS -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- 内置jetty Web服务器 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- CXF的rs客户端 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者:提供了转换json的接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者转换json需要默认的一个工具包 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
</dependencies>
<!-- 构建 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<!-- 编译的jdk版本 -->
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
2.2 资源-实体类编写
@XmlRootElement 指定序列化(转换XML、JSON) 对象名字。
//指定序列化(转换XML、JSON) 对象名字
//实体类:资源对应的类
//@XmlRootElement//默认情况下,该对象在传输表现的时候,表现方式xml,要转成xml,根元素:<user类名></user> name:默认类名小写
@XmlRootElement(name="users")//根元素:<users></users>
//比如查询列表:<users><user><id>123</id>....</user></users>
//如果是json:{users:[{"id":"2342",...},{...}}
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
2.3 SEI业务
第一种 @Path 服务访问资源路径
如果访问saveUser方法 /userService/user
第二种 @Produces 生成(方法返回值) @Consumes 消费 (方法参数)
@Consumes 指定能够处理客户端传递过来数据格式
@Produces 指定能否生成哪种格式数据返回给客户端
第三种 @GET 查询 @PUT 修改 @POST 增加 @DELETE 删除
第四种:
@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数
//SEI的接口:对外暴露
//加上注解path,类似于具体的服务的名字"/mobile"
@Path("/userService")//暴露出去访问资源的服务路径:http://127.0.0.1:8888//userService/users/
public interface UserService {
//定义CRUD方法
/**
* 说明:保存用户
* @param user
*/
@Path("/users")//访问的资源
@POST//新建资源动作
//配置表现:setContenttype(....)
//消费:接收客户端传过来的消息的格式
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
//没有产品
public void saveUser(User user);
/**
*
* 说明:修改用户
* @param user
*/
@Path("/users")
@PUT//更新操作
//可接收客户端传递过来的格式
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public void updateUser(User user);
/**
*
* 说明:直接根据id删除
* @param id
*/
@Path("/users/{id}")
@DELETE//删除,uri:/users/1
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})//消费
public void deleteUser(@PathParam("id")Integer id);
/**
*
* 说明:查询所有数据列表
* @return
*/
@Path("/users")
@GET
//产品(生产):返回给客户端的格式
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public List<User> findUserList();
/**
*
* 说明:根据id来查询用户
* @param id
* @return
*/
@Path("/users/{id}")
@GET
//消费者
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
//生产者:
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
//127.0.0.1:8888/cxf_jaxrs/userService/users/1
//资源后面都是参数,参数,类似于命名占位符
public User findUserById(@PathParam("id")Integer id);
/**
*
* 说明:使用参数传参:/users?id=1
* @param id
* @return
*/
@Path("/usersparam")
@GET
//消费者
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
//生产者:
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public User findUserById2(@QueryParam("id")Integer id);
}
/**
* SEI实现
*/
public class UserServiceImpl implements UserService {
@Override
public void save(User user) {
//调用dao
System.out.println("----保存:"+user);
}
@Override
public void update(User user) {
//调用dao
System.out.println("-----更新对象:"+user);
}
@Override
public void delete(Integer id) {
//调用dao
System.out.println("-----删除的id:"+id);
}
@Override
public List<User> findUserList() {
List<User> userList = new ArrayList<>();
userList.add(new User(1,"jack","123",19));
userList.add(new User(2,"rose","1234",18));
return userList;
}
@Override
public User findUserById(Integer id) {
System.out.println("----根据id查询,id是:"+id);
return new User(1,"jack","123",19);
}
@Override
public User findUserById2(Integer id) {
System.out.println("----根据id参数查询,id是:"+id);
return new User(2,"rose","1234",18);
}
}
2.4 发布服务
public class CxfJaxRsServer {
public static void main(String[] args) {
// 发布rest服务
//1.构建服务工厂对象
JAXRSServerFactoryBean jaxrsServiceFactoryBean = new JAXRSServerFactoryBean();
//2.在工厂上设置几个属性
//2.1服务地址
jaxrsServiceFactoryBean.setAddress("http://localhost:8888/cxf_jaxrs");
//2.2资源的类型
jaxrsServiceFactoryBean.setResourceClasses(User.class);
//2.3服务对象.自动反射接口
jaxrsServiceFactoryBean.setServiceBean(new UserServiceImpl());
//c创建并发布服务
jaxrsServiceFactoryBean.create();
System.out.println("rest服务发布了!");
//资源访问的方式:web地址+服务地址+资源名字
}
}
2.5 测试
浏览器测试(只能是get方法测试)
查询所有:http://localhost:8888/cxf_jaxrs/userService/users
根据id查询(路径方式):http://localhost:8888/cxf_jaxrs/userService/users/1
根据id查询(参数方式):http://localhost:8888/cxf_jaxrs/userService/users?id=1
3. CXF客户端开发
客户端编程有两种做法:
1)HttpClient工具需要自己对HTTP协议内容进行定制和解析。
2)WebClient工具类(CXF自带)(使用)。
3.1 客户端调用类
主要的方法说明:
- create:调用服务资源路径,并建立连接
- type:客户端发送给服务器的数据(资源)格式,对应服务端的@consumes的数据类型
- accept:客户端接收服务器的数据(资源)格式,对应服务端的@Produces的数据类型
- get,post,put,delete四个方法,分别是要采用HTTP协议的那种方式访问服务器。
public class CxfRsClient {
public static void main(String[] args) {
//----方法说明
//create:调用服务资源路径,并建立连接
//type:客户端发送给服务器的数据(资源)格式,对应服务端的@consumes的数据类型
//accept:客户端接收服务器的数据(资源)格式,对应服务端的@Produces的数据类型
//get,post,put,delete四个方法,分别是要采用HTTP协议的那种方式访问服务器。
// 目标:调用服务端:crud
//WebClient:客户端工具类
//保存
//new对象
// User user = new User();
// user.setId(101);
// user.setUsername("xiaohong");
// user.setPassword("666");
// user.setAge(28);
// //访问的资源http://127.0.0.1:8888/cxf_jaxrs/userService/users
// //参数:访问的服务器上的资源
// WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users")
// //消费者(对于服务端)
// .type(MediaType.APPLICATION_JSON)//设置表现形式,内容类型,怎么传数据,服务器可接收什么
// .post(user)//自动将对象转换成xml或json
// ;
//更新
// User user2 = new User();
// user2.setId(102);
// user2.setUsername("xiaohong2");
// user2.setPassword("6662");
// user2.setAge(28);
//资源uri
// WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users")
// .type(MediaType.APPLICATION_JSON)
// .put(user2);
//删除
//资源uri
// WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users/1")
//// .path("/"+id);//类似于Stringbuffer的.append("xxxx")
// .type(MediaType.APPLICATION_JSON)
// .delete();
//查询所有列表
//资源uri
// Collection<? extends User> userList = WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users")
// //生产者(针对服务器来说,客户端能接收)
// .accept(MediaType.APPLICATION_JSON)
//// .get().getEntity()//获取内容
// .getCollection(User.class);//列表对象
// System.out.println(userList);
//根据id查询一个对象
//资源uri
// User user = WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users/1")
// //消费者
// .type(MediaType.APPLICATION_JSON)
// //生产者
// .accept(MediaType.APPLICATION_JSON)
// .get(User.class);//获取一个对象
// System.out.println(user);
//有时候查询先判断有没有查询成功,还不想要结果。
int status = WebClient.create("http://127.0.0.1:8888/cxf_jaxrs/userService/users")
.accept(MediaType.APPLICATION_JSON)
.get()
.getStatus();
System.out.println(status);
System.out.println("客户端操作完成!");
}
4. CRM系统的CXF服务端构建开发(与spring整合)
4.1. SSH基础环境搭建
技术架构:
Spring + Hibernate(spring和hibernate直接整合)+CXF+Oracle
4.1.1 新建Maven项目
引入Maven坐标:
Spring、Hibernate、数据库和连接池、日志、Servlet、JSP、junit、编译版本覆盖、tomcat端口覆盖8888:
<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.aric.project</groupId>
<artifactId>crm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>crm</name>
<description>物流的客户子系统</description>
<properties>
<spring.version>3.2.12.RELEASE</spring.version>
<hibernate.version>3.6.10.Final</hibernate.version>
<slf4j.version>1.7.5</slf4j.version>
<c3p0.version>0.9.1.2</c3p0.version>
<oracle.version>10.2.0.4.0</oracle.version>
<servlet.version>2.5</servlet.version>
<jsp.version>2.0</jsp.version>
<junit.version>4.11</junit.version>
<cxf.version>3.1.9</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>${oracle.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
<!-- CXF RS -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者:提供了转换json的接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者转换json需要默认的一个工具包 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
<!-- CXF的rs客户端 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<port>8888</port>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- 编译的jdk版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
</project>
4.1.2 整合spring
配置Spring整合Hibernate(几个配置文件:applicationContext.xml、db.properties,web.xml,log4j.properties等)
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" version="2.5">
<display-name>crm</display-name>
<!-- cxf的前端控制器 -->
<servlet>
<description>Apache CXF Endpoint</description>
<display-name>cxf</display-name>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<!-- 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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
db.properties
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:xe
jdbc.user=scott
jdbc.password=tigger
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout
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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 引入外部的属性配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- spring来整合hibernate
AnnotationSessionFactoryBean:spring提供的专门来整合hibernate注解
-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- hibernate一般属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true </prop>
</props>
</property>
<!-- 映射的类
packagesToScan:扫描哪个包,会将脑门上带@Entity的类,注册为实体类
-->
<property name="packagesToScan">
<list>
<value>cn.aric.crm.domain</value>
</list>
</property>
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 开启spring的bean组件扫描(默认也会开启注解功能) -->
<context:component-scan base-package="cn.aric.crm.service,cn.aric.crm.dao"/>
<!-- 引入cxf配置 -->
<import resource="applicationContext-cxf.xml"/>
</beans>
4.2 新建实体类
@Entity
@Table(name="t_customer",schema="scott")
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)//auto代表自动
private Integer id;//OID属性
private String name;//客户名称
private String address;//住所
private String telephone;//联系电话
private String decidedZoneId;//定区编号(客户和定区关联的字段)
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public String getTelephone() {
return telephone;
}
public String getDecidedZoneId() {
return decidedZoneId;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public void setDecidedZoneId(String decidedZoneId) {
this.decidedZoneId = decidedZoneId;
}
}
测试上面的配置,启动服务,自动建表:tomcat:run
4.3 引入CXF环境 ###
<properties>
<cxf.version>3.1.9</cxf.version>
</properties>
<dependencies>
<!-- CXF RS -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者:提供了转换json的接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者转换json需要默认的一个工具包 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
<!-- CXF的rs客户端 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
4.4 Spring整合CXF-RS的服务
@Entity
@Table(name="t_customer",schema="SCOTT")
@XmlRootElement(name="customer")
public class Customer {
@Id
//如果没有给主键策略,不管oid什么类型,都需要手动主键值
//但如果有主键策略,根据主键策略来走。
@GeneratedValue(strategy=GenerationType.AUTO)//auto代表自动
//--自动:根据OID的属性的类型来自动选择
//如果String类型,主键数据库不会自动生成,要么手动赋值(对于数据库来说手动主键),要么让hibernate的uuid赋值
//如果是Integer,Long,值自增长的,会自动创建一个序列,使用序列的值作为主键值(数据库提供的序列值--hibernate调用)。
private Integer id;//OID属性
private String name;//客户名称
private String address;//住所
private String telephone;//联系电话
private String decidedZoneId;//定区编号(客户和定区关联的字段)
4.4.1 编写SEI
@Path("/customerService")//具体服务的名字路径
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public interface CustomerService {
//提供三个暴露的方法
/**
*
* 说明:查询没有关联定区的客户的列表
* @return
*/
@Path("/customers")//某个方法的操作的资源
@GET
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public List<Customer> findCustomerListNoDecidedZoneId();
/**
*
* 说明:查询关联某个定区的客户的列表
* @return
*/
@Path("/customers/{decidedZoneId}")//某个方法的操作的资源
@GET
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public List<Customer> findCustomerListByDecidedZoneId(@PathParam("decidedZoneId")String decidedZoneId);
/**
*
* 说明:批量更新定区编号,通过客户编号
* @param decidedZoneId:DQ001
* @param customerIds:用逗号分割编号:2,3
*/
@Path("/customers/{decidedZoneId}/{customerIds}")//某个方法的操作的资源
@PUT
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public void updateDecidedZoneIdByIds(@PathParam("decidedZoneId")String decidedZoneId,@PathParam("customerIds")String customerIds);
}
//SEI:客户的业务实现类
//客户操作的业务层实现
Service("customeService")
@Transactional
public class CustomerServiceImpl implements CustomerService{
//注入dao
@Autowired
private GenericDAO<Customer, Integer> customerDAO;
@Override
public List<Customer> findCustomerListNoDecidedZoneId() {
//条件构建
DetachedCriteria criteria =DetachedCriteria.forClass(Customer.class)
.add(Restrictions.isNull("decidedZoneId"));
//查询
return customerDAO.findByCriteria(criteria);
}
@Override
public List<Customer> findCustomerListByDecidedZoneId(String decidedZoneId) {
//条件构建
DetachedCriteria criteria =DetachedCriteria.forClass(Customer.class)
.add(Restrictions.eq("decidedZoneId", decidedZoneId));
//查询
return customerDAO.findByCriteria(criteria);
}
@Override
public void updateDecidedZoneIdByIds(String decidedZoneId, String customerIds) {
//快照更新
//====先去掉指定定区的所有的关联(update)
//查询出所有原来已经关的客户列表
DetachedCriteria criteria =DetachedCriteria.forClass(Customer.class)
.add(Restrictions.eq("decidedZoneId", decidedZoneId));
List<Customer> customerList = customerDAO.findByCriteria(criteria);
//快照
for (Customer customer : customerList) {
customer.setDecidedZoneId(null);
}
//====关联需要关联指定定区的客户(update)
if(!StringUtils.isEmpty(customerIds)){
String[] customerArray = customerIds.split(",");
for (String customerId : customerArray) {
Customer customer = customerDAO.findById(Customer.class, Integer.parseInt(customerId));
customer.setDecidedZoneId(decidedZoneId);
}
}
//等待flush
}
}
4.4.2 编写DAO
略
4.4.3 配置web.xml(CXF的核心控制器)
<!-- cxf的前端控制器 -->
<servlet>
<description>Apache CXF Endpoint</description>
<display-name>cxf</display-name>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
cxf配置:applicationContext-cxf.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:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:jaxrsclient="http://cxf.apache.org/jaxrs-client"
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
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/jaxrs-client
http://cxf.apache.org/schemas/jaxrs-client.xsd">
<!-- cxf服务servlet的初始化 -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- 配置REST服务 -->
<!--
jaxrs:server:JAXRSServerFactoryBean+bean
address:请求分发的具体服务地址
serviceClass:sei接口
-->
<jaxrs:server id="customerWebService" address="/CustomerWS" >
<jaxrs:serviceBeans>
<ref bean="customerService" />
</jaxrs:serviceBeans>
<!-- 输入日志拦截器 -->
<jaxrs:inInterceptors>
<ref bean="loggingInInterceptor"/>
</jaxrs:inInterceptors>
<!-- 输出日志拦截器 -->
<jaxrs:outInterceptors>
<ref bean="loggingOutInterceptor" />
</jaxrs:outInterceptors>
</jaxrs:server>
<!-- 输入日志拦截器 -->
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<!-- 输出日志拦截器 -->
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</beans>
4.4.4 测试
测试的访问路径:
web上下文+cxf前端控制器+配置的服务路径+类上的具体的服务路径
web上下文+cxf前端控制器+配置的服务路径+类上的具体的服务路径+资源路径(方法上)
使用SoapUI—webservice的调试工具,Encoding改UTF-8。
5. BOS系统的CXF客户端
5.1.项目中引入CXF开发环境
引入Maven坐标(Pom.xml):
<cxf.version>3.1.9</cxf.version>
<!-- CXF扩展提供者:提供了转换json的接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- CXF扩展提供者转换json需要默认的一个工具包 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
<!-- CXF的rs客户端 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${cxf.version}</version>
</dependency>
5.2 CXF-RS的客户端开发
5.2.1 编写Domain
//dto
@XmlRootElement(name="customer")
public class Customer {
private Integer id;//OID属性
private String name;//客户名称
private String residence;//住所
private String telephone;//联系电话
private String decidedZoneId;//定区编号(客户和定区关联的字段)
5.2.2 编写Jsp
略
5.2.3 后台代码
//列出没有关联定区的客户
@Action("decidedZone_listCustomerListNoDecidedZoneId")
public String listCustomerListNoDecidedZoneId(){
//直接调用webservice接口
//基本服务连接
WebClient webClient = WebClient.create("http://localhost:8888/crm/services");
Collection<? extends Customer> collection = webClient
.path("/crmService/customerService")//具体服务
.path("/customers")//资源路径
.accept(MediaType.APPLICATION_JSON)//客户端要接收的类型
.type(MediaType.APPLICATION_JSON)//发出去的数据类型,java对象会转换为该类型
.getCollection(Customer.class);
//压入栈顶
pushToValuestackRoot(collection);
//json数组
return JSON; //JSON在父类中配置常量
}
//列出已经关联定区的客户
@Action("decidedZone_listCustomerListHasDecidedZoneId")
public String listCustomerListHasDecidedZoneId(){
//直接调用webservice接口
//基本服务连接
WebClient webClient = WebClient.create("http://localhost:8888/crm/services");
Collection<? extends Customer> collection = webClient
.path("/crmService/customerService")//具体服务
.path("/customers")//资源路径
.path("/"+model.getId())
.accept(MediaType.APPLICATION_JSON)//客户端要接收的类型
.type(MediaType.APPLICATION_JSON)//发出去的数据类型,java对象会转换为该类型
.getCollection(Customer.class);
//压入栈顶
pushToValuestackRoot(collection);
//json数组
return JSON;