JAX-RS 规范详解
一、什么是 JAX-RS?
JAX-RS(Java API for RESTful Web Services)是 Jakarta EE(原 Java EE)提供的一套用于构建 RESTful Web 服务的 API 规范。它定义了一套用于将 Java 类映射为 Web 资源的方法,广泛用于微服务、前后端分离架构和 API 开发。
JAX-RS 在 Jakarta EE 9 中迁移到了 jakarta.ws.rs
命名空间,之前为 javax.ws.rs
。
二、设计目标
JAX-RS 的设计目标包括:
- 简化 RESTful 服务开发
- 注解驱动的声明式编程模型
- 与 HTTP 方法和资源 URI 紧密集成
- 易于扩展(拦截器、过滤器、实体提供者)
- 支持内容协商(Content Negotiation)
- 规范与实现分离,支持多种实现(如 Jersey、RESTEasy、Apache CXF)
三、核心注解和说明
1. @Path
定义类或方法处理的 URI 路径。
1
2
3
4
5
6
7
|
@Path("/users")
public class UserResource {
@GET
public String listUsers() {
return "List of users";
}
}
|
- 支持动态路径参数
/users/{id}
。
- 类上的
@Path
是基础路径,方法上的路径会拼接。
2. HTTP 方法注解
这些注解表明方法响应特定的 HTTP 动作:
@GET
:获取资源
@POST
:创建资源
@PUT
:更新资源
@DELETE
:删除资源
@PATCH
:部分更新
@HEAD
/ @OPTIONS
:特殊用途
1
2
3
4
5
|
@GET
@Path("/{id}")
public String getUser(@PathParam("id") int id) {
return "User with ID: " + id;
}
|
3. 参数注解
用于绑定 HTTP 请求数据:
注解 |
来源 |
@PathParam |
URL 路径 |
@QueryParam |
URL 查询参数 |
@HeaderParam |
HTTP Header |
@CookieParam |
Cookie 值 |
@MatrixParam |
URL 矩阵参数 |
@FormParam |
表单字段 |
@Context |
注入上下文信息对象(如 UriInfo , HttpHeaders ) |
1
2
3
4
5
|
@GET
@Path("/search")
public String search(@QueryParam("q") String query) {
return "Searching for: " + query;
}
|
4. @Produces
与 @Consumes
用于声明处理的媒体类型(MIME types)。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser(@PathParam("id") int id) {
return userService.find(id);
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response addUser(User user) {
userService.save(user);
return Response.ok().build();
}
|
支持类型如:
MediaType.APPLICATION_JSON
MediaType.APPLICATION_XML
MediaType.TEXT_PLAIN
- 自定义类型,如
application/vnd.myapp+json
四、响应构造器 jakarta.ws.rs.core.Response
Response
是一个强类型响应类,用于定制状态码、实体、头部等。
1
2
3
4
|
return Response.status(Response.Status.CREATED)
.entity(user)
.header("Location", "/users/123")
.build();
|
常用状态码
状态码 |
含义 |
200 |
OK |
201 |
Created |
204 |
No Content |
400 |
Bad Request |
401 |
Unauthorized |
404 |
Not Found |
500 |
Internal Server Error |
五、内容协商(Content Negotiation)
通过 HTTP 的 Accept
和 Content-Type
头部,服务端可以自动处理客户端请求的内容格式。
1
2
3
4
5
|
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public User getUser() {
return new User("Tom", 25);
}
|
客户端:
1
|
curl -H "Accept: application/xml" http://localhost:8080/api/user
|
六、异常处理:ExceptionMapper
可通过实现 ExceptionMapper<T>
捕获并转换异常为 HTTP 响应。
1
2
3
4
5
6
7
8
9
|
@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
public Response toResponse(Throwable ex) {
return Response.status(500)
.entity("Error: " + ex.getMessage())
.type(MediaType.TEXT_PLAIN)
.build();
}
}
|
注册后自动生效。
七、请求过滤器与拦截器
1. 请求/响应过滤器(ContainerRequestFilter
/ ContainerResponseFilter
)
用于处理请求前后逻辑,例如日志、认证、CORS。
1
2
3
4
5
6
|
@Provider
public class LoggingFilter implements ContainerRequestFilter {
public void filter(ContainerRequestContext ctx) {
System.out.println("Request URI: " + ctx.getUriInfo().getRequestUri());
}
}
|
2. 实体拦截器(ReaderInterceptor
/ WriterInterceptor
)
拦截 HTTP 实体读写,用于加密、压缩等。
1
2
3
4
5
6
7
|
@Provider
public class GzipWriterInterceptor implements WriterInterceptor {
public void aroundWriteTo(WriterInterceptorContext ctx) throws IOException {
// wrap output stream with gzip
ctx.proceed();
}
}
|
八、实体提供者(MessageBodyReader / Writer)
可自定义如何序列化与反序列化 Java 对象与 HTTP 实体。
1
2
3
4
5
6
7
|
@Provider
@Consumes("application/myformat")
public class MyFormatReader implements MessageBodyReader<MyObject> {
public MyObject readFrom(...) {
// 读取并解析输入流
}
}
|
九、客户端 API(jakarta.ws.rs.client
)
JAX-RS 提供标准 REST 客户端:
1
2
3
|
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/api/users/1");
User user = target.request(MediaType.APPLICATION_JSON).get(User.class);
|
POST 示例:
1
2
3
4
|
User newUser = new User("Alice", 30);
Response response = client.target("http://localhost:8080/api/users")
.request()
.post(Entity.entity(newUser, MediaType.APPLICATION_JSON));
|
十、完整示例:用户资源类
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
|
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
private static Map<Integer, User> users = new HashMap<>();
private static AtomicInteger idCounter = new AtomicInteger();
@GET
public Collection<User> getAll() {
return users.values();
}
@GET
@Path("/{id}")
public Response getUser(@PathParam("id") int id) {
User user = users.get(id);
if (user == null) return Response.status(404).build();
return Response.ok(user).build();
}
@POST
public Response createUser(User user) {
int id = idCounter.incrementAndGet();
user.setId(id);
users.put(id, user);
return Response.status(201).entity(user).build();
}
@PUT
@Path("/{id}")
public Response updateUser(@PathParam("id") int id, User updated) {
if (!users.containsKey(id)) return Response.status(404).build();
updated.setId(id);
users.put(id, updated);
return Response.ok(updated).build();
}
@DELETE
@Path("/{id}")
public Response deleteUser(@PathParam("id") int id) {
users.remove(id);
return Response.noContent().build();
}
}
|
对应实体类:
1
2
3
4
5
6
7
|
public class User {
private int id;
private String name;
private int age;
// Constructors, getters, setters
}
|
十一、与 Jakarta EE 其他技术集成
- JPA:用于持久化实体对象
- CDI:用于依赖注入与生命周期管理
- Bean Validation:用于输入校验(如
@NotNull
, @Size
)
示例:
1
2
3
4
5
|
@POST
public Response addUser(@Valid User user) {
em.persist(user); // EntityManager 注入的
return Response.status(201).entity(user).build();
}
|
十二、部署方式
1. Jakarta EE 容器
将资源类打包为 .war
部署到如 GlassFish、Payara、WildFly。
2. 使用 Jersey 独立部署
1
2
3
4
5
6
7
|
public class Main {
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig().packages("com.example.api");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
URI.create("http://localhost:8080/api/"), config);
}
}
|
十三、小结
特性 |
支持情况 |
注解驱动 REST API |
✅ |
内容协商 |
✅ |
参数绑定与注入 |
✅ |
异常处理 |
✅ |
请求/响应拦截器 |
✅ |
自定义序列化/反序列化 |
✅ |
客户端访问 API |
✅ |
与 CDI / JPA / Bean Validation 集成 |
✅ |