«1. Обзор

С ростом популярности микросервисной архитектуры и разработки облачных приложений растет потребность в быстром и легком сервере приложений.

В этом вводном руководстве мы рассмотрим платформу Open Liberty для создания и использования веб-службы RESTful. Мы также рассмотрим несколько основных функций, которые он предоставляет.

2. Open Liberty

Open Liberty — это открытая среда для экосистемы Java, позволяющая разрабатывать микросервисы с использованием функций платформ Eclipse MicroProfile и Jakarta EE.

Это гибкая, быстрая и легкая среда выполнения Java, которая кажется многообещающей для разработки облачных микросервисов.

Фреймворк позволяет нам настраивать только те функции, которые нужны нашему приложению, что приводит к меньшему объему памяти при запуске. Кроме того, его можно развернуть на любой облачной платформе с использованием таких контейнеров, как Docker и Kubernetes.

Он поддерживает быструю разработку за счет перезагрузки кода в реальном времени для быстрой итерации.

3. Сборка и запуск

Сначала мы создадим простой проект на основе Maven с именем open-liberty, а затем добавим в pom.xml новейший подключаемый модуль Liberty-maven-plugin:

<plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.3-M3</version>
</plugin>

Или мы можем добавить последнюю зависимость Maven openliberty-runtime в качестве альтернативы Liberty-maven-plugin:

<dependency>
    <groupId>io.openliberty</groupId>
    <artifactId>openliberty-runtime</artifactId>
    <version>20.0.0.1</version>
    <type>zip</type>
</dependency>

Точно так же мы можем добавить последнюю зависимость Gradle в build.gradle:

dependencies {
    libertyRuntime group: 'io.openliberty', name: 'openliberty-runtime', version: '20.0.0.1'
}

Затем мы добавим последние зависимости jakarta.jakartaee-web-api и микропрофиля Maven:

<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>8.0.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.eclipse.microprofile</groupId>
    <artifactId>microprofile</artifactId>
    <version>3.2</version>
    <type>pom</type>
    <scope>provided</scope>
</dependency>

Затем давайте добавим свойства порта HTTP по умолчанию в pom.xml:

<properties>
    <liberty.var.default.http.port>9080</liberty.var.default.http.port>
    <liberty.var.default.https.port>9443</liberty.var.default.https.port>
</properties>

Затем мы создадим файл server.xml в каталоге src/main/liberty/config:

<server description="Baeldung Open Liberty server">
    <featureManager>
        <feature>mpHealth-2.0</feature>
    </featureManager>
    <webApplication location="open-liberty.war" contextRoot="/" />
    <httpEndpoint host="*" httpPort="${default.http.port}" 
      httpsPort="${default.https.port}" id="defaultHttpEndpoint" />
</server>

Здесь мы добавили функцию mpHealth-2.0 для проверки работоспособности приложения.

Вот и все основные настройки. Давайте запустим команду Maven для первой компиляции файлов:

mvn clean package

Наконец, давайте запустим сервер с помощью предоставленной Liberty команды Maven:

mvn liberty:dev

Вуаля! Наше приложение запущено и будет доступно по адресу localhost:9080:

Кроме того, мы можем получить доступ к состоянию приложения по адресу localhost:9080/health:

{"checks":[],"status":"UP"}

Команда Liberty:dev запускает сервер Open Liberty в режим разработки, который перезагружает любые изменения, внесенные в код или конфигурацию, без перезапуска сервера.

Точно так же доступна команда Liberty:run для запуска сервера в производственном режиме.

Кроме того, мы можем использовать Liberty:Start-Server и Liberty:Stop-Server для запуска/остановки сервера в фоновом режиме.

4. Сервлет

Чтобы использовать сервлеты в приложении, мы добавим функцию servlet-4.0 в server.xml:

<featureManager>
    ...
    <feature>servlet-4.0</feature>
</featureManager>

Добавьте последнюю зависимость servlet-4.0 Maven, если используете openliberty- Зависимость Maven во время выполнения в pom.xml:

<dependency>
    <groupId>io.openliberty.features</groupId>
    <artifactId>servlet-4.0</artifactId>
    <version>20.0.0.1</version>
    <type>esa</type>
</dependency>

Однако, если мы используем подключаемый модуль Liberty-maven-plugin, в этом нет необходимости.

Затем мы создадим класс AppServlet, расширяющий класс HttpServlet:

@WebServlet(urlPatterns="/app")
public class AppServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
        String htmlOutput = "<html><h2>Hello! Welcome to Open Liberty</h2></html>";
        response.getWriter().append(htmlOutput);
    }
}

Здесь мы добавили аннотацию @WebServlet, которая сделает AppServlet доступным по указанному шаблону URL.

Давайте получим доступ к сервлету по адресу localhost:9080/app:

5. Создайте веб-службу RESTful

Сначала добавим функцию jaxrs-2.1 в server.xml:

~~ ~ Затем мы создадим класс ApiApplication, который предоставляет конечные точки веб-службе RESTful:

<featureManager>
    ...
    <feature>jaxrs-2.1</feature>
</featureManager>

Здесь мы использовали аннотацию @ApplicationPath для URL-пути.

@ApplicationPath("/api")
public class ApiApplication extends Application {
}

Затем давайте создадим класс Person, обслуживающий модель:

Затем мы создадим класс PersonResource для определения сопоставлений HTTP:

public class Person {
    private String username;
    private String email;

    // getters and setters
    // constructors
}

Здесь мы добавили getAllPersons метод сопоставления GET с конечной точкой /api/persons. Итак, веб-служба RESTful готова, и команда Liberty:dev будет загружать изменения «на лету».

@RequestScoped
@Path("persons")
public class PersonResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Person> getAllPersons() {
        return Arrays.asList(new Person(1, "normanlewis", "[email protected]"));
    }
}

Давайте получим доступ к веб-сервису /api/persons RESTful с помощью запроса curl GET:

Затем мы получим в ответ массив JSON:

curl --request GET --url http://localhost:9080/api/persons

Аналогичным образом мы можем добавить POST сопоставление путем создания метода addPerson:

[{"id":1, "username":"normanlewis", "email":"[email protected]"}]

Теперь мы можем вызвать конечную точку с помощью POST-запроса curl:

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response addPerson(Person person) {
    String respMessage = "Person " + person.getUsername() + " received successfully.";
    return Response.status(Response.Status.CREATED).entity(respMessage).build();
}

Ответ будет выглядеть так:

curl --request POST --url http://localhost:9080/api/persons \
  --header 'content-type: application/json' \
  --data '{"username": "normanlewis", "email": "[email protected]"}'

6. Постоянство

Person normanlewis received successfully.

«6.1. Конфигурация

Давайте добавим поддержку постоянства в наши веб-сервисы RESTful.

Сначала мы добавим зависимость derby Maven к pom.xml:


Затем мы добавим на сервер несколько функций, таких как jpa-2.2, jsonp-1.1 и cdi-2.0. .xml:

<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.14.2.0</version>
</dependency>

Здесь функция jsonp-1.1 предоставляет API Java для обработки JSON, а функция cdi-2.0 обрабатывает области действия и внедрение зависимостей.

<featureManager>
    ...
    <feature>jpa-2.2</feature> 
    <feature>jsonp-1.1</feature>
    <feature>cdi-2.0</feature>
</featureManager>

Далее мы создадим файл persistence.xml в каталоге src/main/resources/META-INF:

Здесь мы использовали генерацию EclipseLink DDL для автоматического создания схемы нашей базы данных. Мы также можем использовать другие альтернативы, такие как Hibernate.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="jpa-unit" transaction-type="JTA">
        <jta-data-source>jdbc/jpadatasource</jta-data-source>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables"/>
            <property name="eclipselink.ddl-generation.output-mode" value="both" />
        </properties>
    </persistence-unit>
</persistence>

Затем добавим конфигурацию dataSource в server.xml:

Обратите внимание, jndiName имеет ту же ссылку на тег jta-data-source в файле persistence.xml.

<library id="derbyJDBCLib">
    <fileset dir="${shared.resource.dir}" includes="derby*.jar"/> 
</library>
<dataSource id="jpadatasource" jndiName="jdbc/jpadatasource">
    <jdbcDriver libraryRef="derbyJDBCLib" />
    <properties.derby.embedded databaseName="libertyDB" createDatabase="create" />
</dataSource>

6.2. Entity и DAO

Затем мы добавим аннотацию @Entity и идентификатор в наш класс Person:

Далее давайте создадим класс PersonDao, который будет взаимодействовать с базой данных, используя экземпляр EntityManager: ~~ ~

@Entity
public class Person {
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private int id;
    
    private String username;
    private String email;

    // getters and setters
}

Обратите внимание, что @PersistenceContext определяет ту же ссылку на тег persistence-unit в файле persistence.xml.

@RequestScoped
public class PersonDao {
    @PersistenceContext(name = "jpa-unit")
    private EntityManager em;

    public Person createPerson(Person person) {
        em.persist(person);
        return person;
    }

    public Person readPerson(int personId) {
        return em.find(Person.class, personId);
    }
}

Теперь мы добавим зависимость PersonDao в класс PersonResource:

Здесь мы использовали аннотацию @Inject, предоставленную функцией CDI.

@RequestScoped
@Path("person")
public class PersonResource {
    @Inject
    private PersonDao personDao;

    // ...
}

Наконец, мы обновим метод addPerson класса PersonResource, чтобы сохранить объект Person:

Здесь метод addPerson снабжен аннотацией @Transactional для управления транзакциями управляемых компонентов CDI.

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
public Response addPerson(Person person) {
    personDao.createPerson(person);
    String respMessage = "Person #" + person.getId() + " created successfully.";
    return Response.status(Response.Status.CREATED).entity(respMessage).build();
}

Давайте вызовем конечную точку уже обсуждавшимся POST-запросом curl:

Затем мы получим текстовый ответ:

curl --request POST --url http://localhost:9080/api/persons \
  --header 'content-type: application/json' \
  --data '{"username": "normanlewis", "email": "[email protected]"}'

Аналогичным образом добавим метод getPerson с отображением GET для получения Объект Person:


Person #1 created successfully.

Давайте вызовем конечную точку с помощью запроса curl GET:

@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public Person getPerson(@PathParam("id") int id) {
    Person person = personDao.readPerson(id);
    return person;
}

Затем мы получим объект Person в виде ответа JSON:

curl --request GET --url http://localhost:9080/api/persons/1

7. Использование веб-службы RESTful Использование JSON-B

{"email":"[email protected]","id":1,"username":"normanlewis"}

Во-первых, мы обеспечим возможность прямой сериализации и десериализации моделей, добавив функцию jsonb-1.0 в server.xml: method:

Здесь мы использовали класс ClientBuilder для запроса конечных точек веб-службы RESTful.

<featureManager>
    ...
    <feature>jsonb-1.0</feature>
</featureManager>

Наконец, давайте напишем модульный тест для использования веб-службы RESTful /api/person и проверки ответа:

public class RestConsumer {
    public static String consumeWithJsonb(String targetUrl) {
        Client client = ClientBuilder.newClient();
        Response response = client.target(targetUrl).request().get();
        String result = response.readEntity(String.class);
        response.close();
        client.close();
        return result;
    }
}

Здесь мы использовали класс JsonbBuilder для анализа ответа String в объекте Person.

Кроме того, мы можем использовать клиент MicroProfile Rest Client, добавив функцию mpRestClient-1.3 для использования веб-сервисов RESTful. Он предоставляет интерфейс RestClientBuilder для запроса конечных точек веб-службы RESTful.

@Test
public void whenConsumeWithJsonb_thenGetPerson() {
    String url = "http://localhost:9080/api/persons/1";
    String result = RestConsumer.consumeWithJsonb(url);        
    
    Person person = JsonbBuilder.create().fromJson(result, Person.class);
    assertEquals(1, person.getId());
    assertEquals("normanlewis", person.getUsername());
    assertEquals("[email protected]", person.getEmail());
}

8. Заключение


В этой статье мы рассмотрели инфраструктуру Open Liberty — быструю и легкую среду выполнения Java, которая предоставляет все функции платформ Eclipse MicroProfile и Jakarta EE.

Для начала мы создали веб-сервис RESTful с использованием JAX-RS. Затем мы включили постоянство, используя такие функции, как JPA и CDI.

Наконец, мы использовали веб-службу RESTful с использованием JSON-B.

Как обычно, все реализации кода доступны на GitHub.

«

As usual, all the code implementations are available over on GitHub.