RESTful Web 服务
REST 在 2000 年由 Roy Fielding 在博士论文中提出,他是 HTTP 规范 1.0 和 1.1 版的首席作者之一。
REST 中最重要的概念是资源(resources),使用全球 ID(通常使用 URI)标识。客户端应用程序使用 HTTP 方法(GET/ POST/ PUT/ DELETE)操作资源或资源集。RESTful Web 服务是使用 HTTP 和 REST 原理实现的 Web 服务。通常,RESTful Web 服务应该定义以下方面:
- Web 服务的基/根 URI,比如 http://hostname/{appcontext}/resources。
- 支持 MIME 类型的响应数据,包括 JSON/XML/ATOM 等等。
- 服务支持的操作集合(例如 POST、GET、PUT 或 DELETE)。
表 1. HTTP 方法操作映射表
方法 | 执行动作 | 示例:http://hostname/{appcontext}/resources/1234 |
---|---|---|
GET | 查看资源 | 查看ID为1234的资源 |
POST | 创建一个资源 | 在下面创建一个子资源 |
PUT | 创建或更新一个资源 | 创建或更新ID为1234的资源 |
DELETE | 删除资源 | 删除ID为1234的资源 |
Jersey
Jersey is Sun’s production quality reference implementation for JSR 311: JAX-RS: The Java API for RESTful Web Services. Jersey implements support for the annotations defined in JSR-311, making it easy for developers to build RESTful web services with Java and the Java JVM. Jersey also adds additional features not specified by the JSR.
开发环境
- JDK 1.7
- Jersey 2.6
- Spring 4.2.7.RELEASE
- Maven 3.3.9
- Apache Tomcat 7.0.70
配置
1、项目结构
2、pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jersey.version>2.6</jersey.version>
<jersey-spring.version>2.23.1</jersey-spring.version>
<spring.version>4.2.7.RELEASE</spring.version>
<servlet-api-version>3.1.0</servlet-api-version>
<logback.version>1.1.1</logback.version>
<jcloverslf4j.version>1.7.6</jcloverslf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey-spring.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey-spring.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey-spring.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Spring4.2 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</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-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api-version}</version>
<scope>provided</scope>
</dependency>
<!-- Logback dependencies -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${jcloverslf4j.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
3、web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ricky.codelab.jersey.RestJaxRsApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
3.1、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: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-4.1.xsd">
<context:component-scan base-package="com.ricky.codelab.jersey"></context:component-scan>
</beans>
3.2、Jersey servlet configuration
package com.ricky.codelab.jersey;
import com.ricky.codelab.jersey.resource.UserResource;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2016-07-20 14:15
*/
public class RestJaxRsApplication extends ResourceConfig {
/**
* Register JAX-RS application components.
*/
public RestJaxRsApplication() {
// register application resources
this.register(UserResource.class);
// register filters
register(RequestContextFilter.class);
//register(LoggingResponseFilter.class);
//register(CORSResponseFilter.class);
// register exception mappers
//register(GenericExceptionMapper.class);
//register(AppExceptionMapper.class);
//register(NotFoundExceptionMapper.class);
// register features
register(JacksonFeature.class);
//register(MultiPartFeature.class);
}
}
REST API设计实现
Resources
package com.ricky.codelab.jersey.resource;
import com.ricky.codelab.jersey.domain.User;
import com.ricky.codelab.jersey.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* ${DESCRIPTION}
*
* @author Ricky Fung
* @create 2016-07-20 14:28
*/
@Path("/user")
public class UserResource {
@Autowired
private IUserService userService;
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.TEXT_HTML })
public Response createUser(User user){
long id = userService.insert(user);
return Response.status(Response.Status.CREATED)// 201
.entity("A new user has been created")
.header("Location",
"http://localhost:8888/user/"
+ String.valueOf(id)).build();
}
@POST
@Consumes({ MediaType.APPLICATION_FORM_URLENCODED })
@Produces({ MediaType.TEXT_HTML })
public Response createUserApplicationFormURLencoded(
@FormParam("name") String name,
@FormParam("age") Integer age) {
User user = new User();
user.setName(name);
user.setAge(age);
long id = userService.insert(user);
return Response
.status(Response.Status.CREATED)// 201
.entity("A new user/resource has been created at /user/"
+ id)
.header("Location",
"http://localhost:8888/user/"
+ String.valueOf(id)).build();
}
//http://localhost:8080/user/1
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUserById(@PathParam("id") Long id) {
return userService.findUserById(id);
}
@GET
@Path("/list")
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUserList() {
return userService.getUserList();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public User getUserByName(@QueryParam("username") String username) {
return userService.findUserByName(username);
}
@PUT
@Path("{id}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.TEXT_HTML })
public Response putUserById(@PathParam("id") Long id, User user){
User userById = userService.findUserById(id);
if (userById == null) {
// resource not existent yet, and should be created under the specified URI
long userId = userService.insert(user);
return Response
.status(Response.Status.CREATED)
.entity("A new user has been created AT THE LOCATION you specified")
.header("Location",
"http://localhost:8888/user/"
+ String.valueOf(userId)).build();
} else {
// resource is existent and a full update should occur
userService.update(user);
return Response
.status(Response.Status.OK)
.entity("The user you specified has been fully updated created AT THE LOCATION you specified")
.header("Location",
"http://localhost:8888/user/"
+ String.valueOf(id)).build();
}
}
@DELETE
@Produces({ MediaType.APPLICATION_JSON })
public Response deleteUser() {
userService.delete();
return Response.status(Response.Status.NO_CONTENT)
.entity("All users have been successfully removed").build();
}
@DELETE
@Path("{id}")
@Produces({ MediaType.TEXT_HTML })
public Response deletePodcastById(@PathParam("id") Long id) {
userService.deleteById(id);
return Response.status(Response.Status.NO_CONTENT)
.entity("User successfully removed from database").build();
}
}
其中有几个地方需要强调:
资源类(Resource Class)
资源类是一个简单的 Java 对象 (POJO),可以实现任何接口。这增加了许多好处,比如可重用性和简单。
JAX-RS注解定义
注解 | 描述 |
---|---|
@Path | URI path |
@GET | |
@POST | |
@PUT | |
@DELETE | |
@HEAD | |
@PathParam | |
@QueryParam | |
@Consumes | |
@Produces | |
@Provider |
参考文档
Oracle RESTful Web Services Developer’s Guide:https://docs.oracle.com/cd/E19776-01/820-4867/ggnyk/index.html
资源下载
上述代码均已上传至Github,点此下载