REST Service 开发 - JAXRS 基础
【摘要】本文介绍 JAXRS 常用语法与语义,案例则使用 Maven 多模块构建,集成 spring boot,
并使用 swagger 可视化工具测试服务。最终,给出同时支持 JSON 和 XML 的服务配置。
1、准备项目
1. 下载 CXF 案例
计算机学习看文档,找教程固然重要。运行官方案例 + 模仿编程才是最佳的学习方法。
编程学习总是满足“一万行定律”,即编写相关代码足够,自然理解编程的要领。
用教学学术语叫“程序性知识”,也如同学习驾驶汽车,开一万公里就学会了。
CXF 提供的案例可在官方下载获取,请下载最新二进制发行版:
http://cxf.apache.org/download.html
解压 samples 目录,作为参考
2. 创建项目
- 建立项目目录, 例如:my-samples
- 在项目中创建 maven 构建文件 pom.xml,内容:
<?xml version="1.0" encoding="UTF-8"?>
<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>com.me.test</groupId>
<artifactId>my-samples</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>My REST Service Samples</name>
<description>My REST Service Samples</description>
<url>http://blog.csdn.net/pmlpml</url>
<properties>
<!-- don't deploy the samples, kind of pointless -->
<maven.deploy.skip>true</maven.deploy.skip>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>1.3.6.RELEASE</spring.boot.version>
<spring.cloud.version>1.1.3.RELEASE</spring.cloud.version>
<cxf.version>3.1.10</cxf.version>
<feign.version>8.18.0</feign.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
</dependencies>
<modules>
</modules>
</project>这里,我们定义了父项目,包括第三方组件的版本与公共依赖声明。
3. 创建 Spring Boot 模块
1.创建新模块
- 使用 IDEA 导入项目
- 创建模块 File –> New –> Module…
- 设置父项目,项目坐标,位置
- 最终产生模块的 pom.xml 如下:
<parent>
<artifactId>my-samples</artifactId>
<groupId>com.me.test</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.me.test.springboot</groupId>
<artifactId>springboot-test</artifactId>
<version>1.0-SNAPSHOT</version>- 按惯例在 java root 下创建包 com.me.test.springboot
2.导入 cxf 官方案例 spring_boot
- 将 spring_boot 的 /src/main.java/samples/rs/service 目录下内容(全选中)拖入项目包 com.me.test.springboot
- 参考 spring_boot 的 pom.xml 修改模块 pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description-swagger</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<scope>test</scope>
</dependency>
</dependencies>3.修改 java 文件
- 打开所有(4)个类
- 如果有因为包名修改导致导入错误,修改 import 的位置
4.在 IDEA 直接运行 SampleRestApplication 类
在运行输出的 INFO 中仔细查看 服务器端口 和 服务绑定的根
...
...Tomcat initialized with port(s): 8080 (http)
...
...Mapping servlet: 'CXFServlet' to [/services/*]
...然后,根据JAX-RS映射,在浏览器中分别输入以下 url:
http://localhost:8080/services/sayHello/cxf1
http://localhost:8080/services/sayHello2/cxf2
http://localhost:8080/services/swagger.json
http://localhost:8080/services/services这个案例展示了服务api映射与实现的关系,以及服务可视化工具 swagger 的使用
2、JAX-RS 基础
2.1 JAX-RS2.0 标准概述
The Java API for RESTful Web Services provides portable APIs for developing, exposing and accessing Web applications designed and implemented in compliance with principles of REST architectural style.
https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/index.html
它由一组软件包构成,最常用的就是高层包 javax.ws.rs ,它是 High-level interfaces and annotations used to create RESTful service resources
2.2 资源(Web Resource)
一个 Java POJO 类,使用 申明式 的javax.ws.rs 注释标记技术,成为能被暴露访问的 Web 资源。
主资源(Root Resource),它字少有 @Path 注释,且被注册发布。
例如:创建一个主资源对象的接口 CustomerService
@Path("/customer")
public interface CustomerService {
@GET
@Path("/id/{id}")
@Produces(MediaType.TEXT_PLAIN)
String GetCustomerName(@PathParam("id") String id);
}添加它的实现类 CustomerServiceImpl , 注意 @api(“\customer”)
就可以使用 swagger 调试服务了!!!
@Api("/customer")
public class CustomerServiceImpl implements CustomerService {
public String GetCustomerName(String id) {
return "hello" + id;
}
}然后,修改发布代码:
endpoint.setServiceBeans(Arrays.<Object>asList(new HelloServiceImpl1(), new HelloServiceImpl2()
, new CustomerServiceImpl()));运行!
浏览 http://localhost:8080/services/customer/id/123,或者
使用 swagger http://localhost:8080/services/services
2.3 常用注释
@Path: 用于类型和方法的注释,用于识别资源的 URI
例如:调用 GetCustomerName 方法的 URI 是 \customer\id\{id}
@PathParam : 用于方法参数的注释,绑定 URI 路径的模板
例如:请求 /customer/id/123 对应的模板{id},则 123 作为参数输入。
@GET : 用于主资源方法的注释,用于指定该方法处理 HTTP 请求的方法
例如:调用 GetCustomerName 方法的请求是 GET 方法
注:
- HTTP 方法 JAX-RS2.0 直接支持 @GET @POST @PUT @DELETE @HEAD @OPTIONS 方法
- @GET = @HttpMethod(“GET”)
@Produces : 定义 HTTP 响应 消息体 类型。javax.ws.rs.core.MediaType 给出了常用的枚举
例如:MediaType.TEXT_PLAIN = “text/plain” 的结果:
$ curl -v http://localhost:8080/services/customer/id/123
...
< Content-Type: text/plain;charset=UTF-8
...@Consumes : 定义请求消息体的类型。
2.4 常用参数注释
参数注释就是将 HTTP 的请求行、header行、body体的内容映射到函数输入之中。
除了 @PathParam 外:
2.4.1 使用 PUT 修改对象
@QueryParam : 将 URL 中 QueryString 作为参数。
例如:我们希望修改客户信息,因此添加服务接口方法:
@PUT
@Path("/update")
public Response updateCustomer(@DefaultValue("123") @QueryParam("id") Long id, @QueryParam("name") String name);@PUT :修改一个对象;
@DefaultValue :参数不存在时的默认值;
服务实现中代码:
public Response updateCustomer(Long id, String name){
System.out.println("----invoking updateCustomer, Customer name is: " + name);
Response r;
//if modify OK!
if (id == 123) {
r = Response.ok().build();
} else {
r = Response.notModified().build();
}
return r;
}其中,Response 是 javax.ws.rs.core.Response
用 swagger 测试。
2.4.2 使用 POST 提交表单
@FormParam : 从输入 body 中提取参数。
例如:我们希望添加客户信息,因此添加服务接口方法:
@POST
@Path("/add/")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public Response addCustomer(@DefaultValue("123") @FormParam("id") Long id, @FormParam("name") String name);@Consumes 必须是 MediaType.APPLICATION_FORM_URLENCODED
服务实现中代码:
public Response addCustomer(Long id, String name){
System.out.println("----invoking updateCustomer, Customer name is: " + name);
Response r;
r = Response.ok().build();
return r;
}2.4.3 使用 DELETE 删除内容
略
2.4.4 更多参数映射
@BeanParam : 将一个对象与 HTTP 请求映射
@Context,@MatrixParam, @HeaderParam, @CookieParam 的使用,建议看文档:
https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e2225
3 消息实体对象读写
3.1 使用 XML 从 MessageBody 中读写对象
添加 Customer 对象
- 直接从
samples/jax_rs/basic/src/main/java/demo/jaxrs/server/中将 Customer 类拖入项目 - 检查语法是否有错误
- 直接从
添加服务接口方法:
@POST
@Path("/addObj/")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.TEXT_PLAIN)
public Response addCustomer(Customer customer);- 添加实现代码:
public Response addCustomer(Customer customer) {
System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
Response r;
r = Response.ok().build();
return r;
}用 swagger 测试 服务!
如果,返回的也是 Customer 对象,应该如何修改?
3.2 让服务自动选择 JSON 和 XML
- 添加项目依赖
<!-- 支持 json -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>- 修改服务发布程序,添加代码:
endpoint.setProviders(Arrays.<Object>asList(
new JacksonJsonProvider(),
new JAXBElementProvider()
));它为 endpoint 配置了两种读写 body 的方法处理
- 修改服务接口定义
@POST
@Path("/addObj/")
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Customer addCustomer(Customer customer);运行!
- 在 swagger-ui 中可以自由选择 JSON XML 格式,结果自动与出入对应
- 这是满足生产要求的服务
4. 子资源
https://jersey.java.net/documentation/latest/user-guide.html#d0e2495
附件:curl 使用简易指南
使用curl指令測試REST服務 http://ju.outofmemory.cn/entry/84875