- Home »

Учебник Jersey Java — создание RESTful веб-сервисов
Если ты разрабатываешь или планируешь разрабатывать RESTful веб-сервисы на Java, то Jersey Framework — это один из самых популярных и мощных инструментов для этой задачи. Это reference implementation стандарта JAX-RS (Java API for RESTful Web Services), который значительно упрощает создание REST API. В этой статье мы разберём Jersey от простого к сложному, покажем практические примеры настройки и деплоя, а также сравним с альтернативными решениями.
Что такое Jersey и как он работает
Jersey — это фреймворк для создания RESTful веб-сервисов на Java, который реализует спецификацию JAX-RS. Основная фишка в том, что он позволяет создавать REST API с минимальным количеством boilerplate кода, используя аннотации для определения endpoints, HTTP методов и параметров.
Архитектура Jersey построена на следующих принципах:
- Annotation-based configuration — используем аннотации вместо XML-конфигов
- Resource-oriented approach — каждый класс представляет ресурс с определённым URI
- Automatic serialization/deserialization — автоматическое преобразование объектов в JSON/XML
- Dependency injection — встроенная поддержка DI через HK2
Быстрый старт: настройка проекта пошагово
Давайте создадим простой REST API с нуля. Для начала нужен Maven проект с правильными зависимостями:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
Создаём простой ресурс:
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;
@Path("/api/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
private static Map<Integer, User> users = new HashMap<>();
@GET
public Response getAllUsers() {
return Response.ok(users.values()).build();
}
@GET
@Path("/{id}")
public Response getUser(@PathParam("id") int id) {
User user = users.get(id);
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(user).build();
}
@POST
public Response createUser(User user) {
users.put(user.getId(), user);
return Response.status(Response.Status.CREATED).entity(user).build();
}
@PUT
@Path("/{id}")
public Response updateUser(@PathParam("id") int id, User user) {
if (!users.containsKey(id)) {
return Response.status(Response.Status.NOT_FOUND).build();
}
user.setId(id);
users.put(id, user);
return Response.ok(user).build();
}
@DELETE
@Path("/{id}")
public Response deleteUser(@PathParam("id") int id) {
if (users.remove(id) == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.noContent().build();
}
}
Простой POJO для User:
public class User {
private int id;
private String name;
private String email;
// Конструкторы, геттеры и сеттеры
public User() {}
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// геттеры и сеттеры...
}
Теперь создаём Application класс:
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
@ApplicationPath("/")
public class RestApplication extends Application {
// Jersey автоматически найдёт все ресурсы с аннотациями
}
Конфигурация web.xml:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jakarta.ws.rs.Application</param-name>
<param-value>com.example.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Практические примеры и кейсы
Давайте рассмотрим несколько практических сценариев использования Jersey:
Обработка исключений
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
@Provider
public class CustomExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
ErrorResponse error = new ErrorResponse(
"INTERNAL_ERROR",
exception.getMessage()
);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(error)
.build();
}
}
Валидация данных
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Email;
public class User {
@NotNull
private String name;
@Email
private String email;
// геттеры и сеттеры
}
// В ресурсе
@POST
public Response createUser(@Valid User user) {
// Jersey автоматически валидирует объект
return Response.ok(user).build();
}
Фильтры и перехватчики
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.ext.Provider;
@Provider
public class AuthenticationFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) {
String authHeader = requestContext.getHeaderString("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED).build()
);
}
}
}
Сравнение с альтернативными решениями
Фреймворк | Производительность | Простота настройки | Экосистема | Размер JAR |
---|---|---|---|---|
Jersey | Высокая | Средняя | Богатая | ~15MB |
Spring Boot | Средняя | Очень простая | Огромная | ~20MB |
Quarkus | Очень высокая | Простая | Растущая | ~8MB |
Micronaut | Высокая | Средняя | Средняя | ~10MB |
Продвинутые возможности
Асинхронная обработка
import jakarta.ws.rs.container.AsyncResponse;
import jakarta.ws.rs.container.Suspended;
import java.util.concurrent.CompletableFuture;
@GET
@Path("/async")
public void getAsyncData(@Suspended AsyncResponse asyncResponse) {
CompletableFuture
.supplyAsync(() -> {
// Долгая операция
return heavyComputation();
})
.thenAccept(result -> asyncResponse.resume(result))
.exceptionally(ex -> {
asyncResponse.resume(Response.status(500).entity(ex.getMessage()).build());
return null;
});
}
Server-Sent Events (SSE)
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
import jakarta.ws.rs.core.Context;
@GET
@Path("/events")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void streamEvents(@Context SseEventSink eventSink, @Context Sse sse) {
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
eventSink.send(sse.newEvent("Event " + i));
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
eventSink.close();
}
}).start();
}
Деплой на сервер
Для деплоя Jersey приложения на production сервер вам понадобится VPS сервер или выделенный сервер. Рассмотрим несколько вариантов:
Tomcat
# Собираем WAR файл
mvn clean package
# Копируем в Tomcat
sudo cp target/myapp.war /opt/tomcat/webapps/
# Перезапускаем Tomcat
sudo systemctl restart tomcat
Jetty как embedded сервер
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
public class JettyServer {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jakarta.ws.rs.Application", "com.example.RestApplication");
server.setHandler(context);
server.start();
server.join();
}
}
Docker контейнер
FROM openjdk:17-jdk-slim
COPY target/myapp.war /app.war
EXPOSE 8080
CMD ["java", "-jar", "/app.war"]
Мониторинг и производительность
Jersey предоставляет встроенные возможности для мониторинга:
import org.glassfish.jersey.server.monitoring.ApplicationEvent;
import org.glassfish.jersey.server.monitoring.ApplicationEventListener;
import org.glassfish.jersey.server.monitoring.RequestEvent;
import org.glassfish.jersey.server.monitoring.RequestEventListener;
@Provider
public class MonitoringListener implements ApplicationEventListener {
@Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
System.out.println("Application initialized");
break;
}
}
@Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return new RequestEventListener() {
@Override
public void onEvent(RequestEvent event) {
switch (event.getType()) {
case RESOURCE_METHOD_START:
System.out.println("Request started: " + event.getUriInfo().getPath());
break;
case FINISHED:
System.out.println("Request finished");
break;
}
}
};
}
}
Интеграция с базами данных
Пример интеграции с JPA:
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
@Stateless
@Path("/users")
public class UserService {
@PersistenceContext
private EntityManager em;
@GET
public List<User> getAllUsers() {
return em.createQuery("SELECT u FROM User u", User.class).getResultList();
}
@POST
@Transactional
public Response createUser(User user) {
em.persist(user);
return Response.status(Response.Status.CREATED).entity(user).build();
}
}
Тестирование Jersey приложений
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.*;
public class UserResourceTest extends JerseyTest {
@Override
protected Application configure() {
return new RestApplication();
}
@Test
public void testGetAllUsers() {
Response response = target("/api/users").request().get();
assertEquals(200, response.getStatus());
}
@Test
public void testCreateUser() {
User user = new User(1, "John", "john@example.com");
Response response = target("/api/users")
.request()
.post(Entity.json(user));
assertEquals(201, response.getStatus());
}
}
Интересные факты и нестандартные применения
Jersey можно использовать не только для классических REST API:
- WebSocket endpoints — Jersey поддерживает WebSocket через Tyrus
- GraphQL интеграция — можно создать GraphQL endpoint через Jersey
- Microservices mesh — Jersey отлично работает в Service Mesh архитектуре
- Reactive programming — поддержка RxJava для реактивных приложений
Пример интеграции с RxJava:
import rx.Observable;
import rx.schedulers.Schedulers;
@GET
@Path("/reactive")
public Observable<String> getReactiveData() {
return Observable.fromCallable(() -> {
// Долгая операция
return "Reactive result";
}).subscribeOn(Schedulers.io());
}
Безопасность и аутентификация
Jersey предоставляет несколько способов реализации безопасности:
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.Context;
@Path("/secure")
public class SecureResource {
@GET
@RolesAllowed("ADMIN")
public Response getSecureData(@Context SecurityContext securityContext) {
String username = securityContext.getUserPrincipal().getName();
return Response.ok("Hello, " + username).build();
}
}
Заключение и рекомендации
Jersey — это мощный и гибкий фреймворк для создания RESTful веб-сервисов на Java. Он отлично подходит для:
- Enterprise приложений — благодаря полной поддержке JAX-RS стандарта
- Microservices — легковесность и быстрая настройка
- API Gateway — отличные возможности для маршрутизации и фильтрации
- Интеграционных решений — богатая экосистема для работы с различными форматами данных
Когда использовать Jersey:
- Нужна максимальная совместимость с JAX-RS стандартом
- Планируется интеграция с Java EE/Jakarta EE
- Требуется высокая производительность
- Нужны продвинутые возможности работы с HTTP
Когда лучше выбрать альтернативы:
- Если нужна максимальная простота настройки — Spring Boot
- Для облачных native приложений — Quarkus или Micronaut
- Для простых API без сложной логики — Spark Java
Jersey продолжает активно развиваться и остаётся одним из лучших выборов для создания RESTful веб-сервисов на Java. Официальная документация доступна на официальном сайте, а исходный код — на GitHub.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.