REST API with Jersey and Spring – 使用Jersey和Spring的REST API

最后修改: 2017年 2月 4日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Jersey is an open source framework for developing RESTful Web Services. It serves as a reference implementation of JAX-RS.

Jersey是一个用于开发RESTful Web服务的开源框架。它可以作为JAX-RS的参考实现。

In this article, we’ll explore the creation of a RESTful Web Service using Jersey 2. Also, we’ll use Spring’s Dependency Injection (DI) with Java configuration.

在这篇文章中,我们将探讨如何使用Jersey 2创建一个RESTful Web Service。同时,我们将使用Spring的依赖注入(DI)与Java配置。

2. Maven Dependencies

2.Maven的依赖性

Let’s begin by adding dependencies to the pom.xml:

让我们开始在pom.xml中添加依赖项。

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.26</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.26</version>
</dependency>

Also, for Spring integration we have to add the jersey-spring4 dependency:

另外,为了实现Spring集成,我们必须添加jersey-spring4依赖。

<dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-spring4</artifactId>
    <version>2.26</version>
</dependency>

The latest version of these dependencies is available at jersey-container-servlet, jersey-media-json-jackson and jersey-spring4.

这些依赖项的最新版本可在jersey-container-servletjersey-media-jon-jacksonjersey-spring4获得。

3. Web Configuration

3.网络配置

Next, we need to set up a web project to do Servlet configuration. For this, we’ll use Spring’s WebApplicationInitializer:

接下来,我们需要设置一个Web项目来进行Servlet配置。为此,我们将使用Spring的WebApplicationInitializer

@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationInitializer 
  implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) 
      throws ServletException {
 
        AnnotationConfigWebApplicationContext context 
          = new AnnotationConfigWebApplicationContext();
 
        servletContext.addListener(new ContextLoaderListener(context));
        servletContext.setInitParameter(
          "contextConfigLocation", "com.baeldung.server");
    }
}

Here, we’re adding the @Order(Ordered.HIGHEST_PRECEDENCE) annotation to ensure that our initializer is executed before the Jersey-Spring default initializer.

在这里,我们添加了@Order(Ordered.HIGHEST_PRECEDENCE)注解,以确保我们的初始化器在Jersey-Spring默认初始化器之前执行。

4. A Service Using Jersey JAX-RS

4.一个使用Jersey JAX-RS的服务

4.1. Resource Representation Class

4.1.资源代表类

Let’s use a sample resource representation class:

让我们使用一个资源表示类的样本。

@XmlRootElement
public class Employee {
    private int id;
    private String firstName;

    // standard getters and setters
}

Note that JAXB annotations like @XmlRootElement are required only if XML support is needed (in addition to JSON).

请注意,像@XmlRootElement这样的JAXB注解只有在需要XML支持时才需要(除JSON外)。

4.2. Service Implementation

4.2.服务的实施

Let’s now look at how we can use JAX-RS annotations to create RESTful web services:

现在让我们来看看我们如何使用JAX-RS注解来创建RESTful Web服务。

@Path("/employees")
public class EmployeeResource {
 
    @Autowired
    private EmployeeRepository employeeRepository;

    @GET
    @Path("/{id}")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Employee getEmployee(@PathParam("id") int id) {
        return employeeRepository.getEmployee(id);
    }

    @POST
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addEmployee(
      Employee employee, @Context UriInfo uriInfo) {
 
        employeeRepository.addEmployee(new Employee(employee.getId(), 
          employee.getFirstName(), employee.getLastName(), 
          employee.getAge()));
 
        return Response.status(Response.Status.CREATED.getStatusCode())
          .header(
            "Location", 
            String.format("%s/%s",uriInfo.getAbsolutePath().toString(), 
            employee.getId())).build();
    }
}

The @Path annotation provides the relative URI path to the service. We can also embed variables within the URI syntax, as the {id} variable shows. Then, the variables will be substituted at runtime. To obtain, the value of the variable we can use the @PathParam annotation.

@Path注解提供了通往服务的相对URI路径。我们还可以在URI语法中嵌入变量,正如{id}变量所示。变量所示。然后,这些变量将在运行时被替换。为了获得,变量的值,我们可以使用@PathParam注解。

@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, which will be processed by annotated methods.

@GET, @PUT, @POST, @DELETE@HEAD定义了请求的HTTP方法,该方法将被注释的方法处理。

The @Produces annotation defines the endpoint’s response type (MIME media type). In our example, we’ve configured it to return either JSON or XML depending on the value of HTTP header Accept (application/json or application/xml).

@Produces注解定义了端点的响应类型(MIME媒体类型)。在我们的例子中,我们将其配置为返回JSON或XML,这取决于HTTP头Accept的值(application/jsonapplication/xml)。

On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. In our example, the service can consume either JSON or XML depending on the HTTP header Content-Type (application/json or application/xml).

另一方面,@Consumes注解定义了服务可以消费的MIME媒体类型。在我们的例子中,服务可以消费JSON或XML,这取决于HTTP头Content-Typeapplication/jsonapplication/xml)。

The @Context annotation is used to inject information into a class field, bean property or method parameter. In our example, we’re using it to inject UriInfo. We can also use it to inject ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse.

@Context 注解被用来将信息注入类的字段、bean 的属性或方法参数。在我们的例子中,我们用它来注入UriInfo。我们还可以用它来注入ServletConfigServletContextHttpServletRequestHttpServletResponse。

5. Using ExceptionMapper

5.使用ExceptionMapper

ExceptionMapper allows us to intercept the exceptions and return appropriate HTTP response code to the client. In the following example, HTTP response code 404 is returned if EmployeeNotFound exception is thrown:

ExceptionMapper允许我们拦截异常并返回适当的HTTP响应代码给客户端。在下面的例子中,如果抛出了EmployeeNotFound异常,则返回HTTP响应代码404。

@Provider
public class NotFoundExceptionHandler 
  implements ExceptionMapper<EmployeeNotFound> {
 
    public Response toResponse(EmployeeNotFound ex) {
        return Response.status(Response.Status.NOT_FOUND).build();
    }
}

6. Managing Resource Classes

6.管理资源类

Finally, let’s wire up all service implementation classes and exception mappers against an application path:

最后,让我们把所有的服务实现类和异常映射器与应用程序路径连接起来:

@ApplicationPath("/resources")
public class RestConfig extends Application {
    public Set<Class<?>> getClasses() {
        return new HashSet<Class<?>>(
          Arrays.asList(
            EmployeeResource.class, 
            NotFoundExceptionHandler.class, 
            AlreadyExistsExceptionHandler.class));
    }
}

7. API Testing

7.API测试

Let’s now test the APIs with some live tests:

现在让我们用一些实时测试来测试这些API。

public class JerseyApiLiveTest {

    private static final String SERVICE_URL
      = "http://localhost:8082/spring-jersey/resources/employees";

    @Test
    public void givenGetAllEmployees_whenCorrectRequest_thenResponseCodeSuccess() 
      throws ClientProtocolException, IOException {
 
        HttpUriRequest request = new HttpGet(SERVICE_URL);

        HttpResponse httpResponse = HttpClientBuilder
          .create()
          .build()
          .execute(request);

        assertEquals(httpResponse
          .getStatusLine()
          .getStatusCode(), HttpStatus.SC_OK);
    }
}

8. Conclusion

8.结论

In this article, we’ve introduced the Jersey framework and developed a simple API. We’ve used Spring for Dependency Injection features. We have also seen the use of ExceptionMapper.

在这篇文章中,我们介绍了Jersey框架并开发了一个简单的API。我们使用了Spring的依赖注入功能。我们还看到了ExceptionMapper的使用。

As always, the full source code is available in this Github project.

一如既往,完整的源代码可在这个Github项目中获得。