[JAVA] Exemple de configuration d'API RESTful minimum avec Jersey + Spring Framework

Ceci est une suite de cet article.

Configuration multi-modules avec Maven (Jersey RESTful) https://qiita.com/kasa_le/items/db0d84e3e868ff14bc2b

Objectif

Implémentez l'API RESTful avec ** Jersey ** et ** Spring Framework ** (pas Boot).

Si vous regardez Java Spring, il n'y a que des exemples de ** Spring Boot **, et il est peut-être plus facile d'utiliser Boot, mais il peut ne pas être utilisable en raison de circonstances adultes, donc ** Spring Framework ** est recommandé. Visez l'échantillon utilisé.

objectif

Hello World-like fonctionne avec le programme de configuration minimum de Jersey + Spring Framework.

Environnement etc.

Outils etc. Version etc.
MacbookPro macOS Mojave 10.14.5
IntelliJ IDEA Ultimate 2019.3.3
Java AdoptOpenJDK 11
apache maven 3.6.3
Jersey 2.30.1
JUnit 5.6.0
Tomcat apache-tomcat-8.5.51
Postman 7.19.1
Spring Framework 5.2.4-RELEASE

Site de référence

Ajouté à mon propre projet Jersey et projet Spring MVC Hello World J'ai essayé, mais quand j'ai cherché des informations, beaucoup d'entre eux utilisaient Spring Boot, donc c'était assez difficile.

J'ai enfin trouvé ce site.

Jersey + Spring integration example https://mkyong.com/webservices/jax-rs/jersey-spring-integration-example/

Ce sont des informations il y a environ 10 ans, et elles sont assez anciennes, mais le projet en cours vient de fonctionner. (* Cependant, dans l'environnement JDK9 ou version ultérieure, il est nécessaire d'ajouter des dépendances liées à JAXB) Donc, j'ai eu l'intention de passer de là à la dernière version et j'ai réussi, donc je vais prendre note du formulaire final.

Procédure de paramétrage du projet

1. Créez un nouveau projet Maven

Créez un nouveau projet Maven dans IntelliJ IDEA. Veuillez consulter ici pour la procédure.

2. Définissez les dépendances

Le pom.xml ressemble à ceci: Ce qui est différent du site de référence, c'est que chaque version est la dernière version et que le package a été déplacé en conséquence. De plus, étant donné que JAXB a été supprimé depuis JDK9, sa dépendance est également ajoutée.

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>my.example.jerseyspring</groupId>
    <artifactId>RESTfulExample</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>RESTfulExample Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <dependencies>

        <!-- Jersey -->
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <!-- Spring 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>

        <!-- Jersey + Spring -->
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.ext/jersey-spring5 -->
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-spring5</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <!--JAXB supprimé de JDK9-->
        <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.activation/activation -->
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.2</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>RESTfulExample</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <inherited>true</inherited>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <spring.version>5.2.4.RELEASE</spring.version>
        <jersey.version>2.30.1</jersey.version>
        <junit.jupiter.version>5.6.0</junit.jupiter.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

3. Créez une classe de transaction

C'est une classe à injecter par Bean. Cela semble être une méthode pour créer une interface et l'implémenter, mais il n'y a aucun problème même si ce n'est pas le cas. L'un des arguments de vente de Spring est ** DI ** (injection de dépendances), donc si vous pensez à vous moquer lors des tests ultérieurs, vous devriez le faire depuis le début.

Classe d'interface

transaction/TransactionBo.java


public interface TransactionBo {
    String save();
}

Classe d'implémentation

transaction/impl/TransactionBoImpl.java


public class TransactionBoImpl implements TransactionBo {
    public String save() {
        return "Jersey + Spring example";
    }
}

4. Créez une classe de service

Demandez à Spring DI le TransactionBoImpl, mais n'utilisez pas l'annotation @ Autowired. Utilisez l'injection de constructeur. (L'injection du constructeur semble recommandée. Pour plus de détails, voir le site de référence à la fin)

rest/PaymentService.java


import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

import org.springframework.stereotype.Component;
import my.example.jerseyspring.transaction.TransactionBo;

@Component
@Path("/payment")
public class PaymentService {

    final TransactionBo transactionBo;

    public PaymentService(TransactionBo transactionBo) {
        this.transactionBo = transactionBo;
    }

    @GET
    @Path("/mkyong")
    public Response savePayment() {
        String result = transactionBo.save();
        return Response.status(200).entity(result).build();
    }
}

5.applicationContext.xml

Il s'agit d'un fichier pour définir la classe de bean à injecter. Placez-le sous le dossier src / main / resources. Remplacez le nom du package et la classe du bean par ceux que vous avez créés.

applicationContext.xml


<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
	<context:component-scan base-package="my.example.jerseyspring" />
	
	<bean id="transactionBo" class="my.example.jerseyspring.transaction.impl.TransactionBoImpl" />
 
</beans>
  1. web.xml

Créez web.xml sous` src / main / webapp / WEB-INF / ʻet procédez comme suit.

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
		 version="2.4">
	<display-name>Restful 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>jersey.config.server.provider.packages</param-name>
			<param-value>my.example.jerseyspring</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>jersey-serlvet</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

</web-app>

La seule différence avec le site de référence est que «» est une classe Jersey. En outre, remplacez le nom du package par celui que vous avez créé.

6.index.jsp

Placez-le sous le dossier webapp. Vous n'êtes pas obligé, mais si vous ne le faites pas, lorsque vous déployez sur Tomcat et que vous le démarrez, la page 404 sera affichée et ce sera désagréable (^^;

index.jsp


<html>
<body>
    <h2>Jersey + Spring RESTful Web Application!</h2>
    <p><a href="rest/payment/mkyong">Jersey resource</a>
</body>
</html>

Courir

Si vous définissez les paramètres d'exécution dans Tomcat et que vous le démarrez, vous devriez voir l'écran suivant.

jersey_spring_1.png

Cliquez sur le lien «Jersey Resource» pour accéder à la méthode «GET» de «rest / payment / mkyong» et afficher la valeur de retour.

jersery_spring_2.png

curl et Postman devraient également réussir.

tester

J'écrirai un test car c'est un gros problème.

1. Test simple

(1) Ajouter une dépendance

Ajoutez une dépendance pour les tests. Je l'ai fait de la même manière que lorsque cet article.

Tout d'abord, ajoutez des plugins sous <build> / <plugins>.

pom.xml


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <additionalClasspathElements>
                        <additionalClasspathElement>src/test/java/</additionalClasspathElement>
                    </additionalClasspathElements>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>3.0.0-M4</version>
            </plugin>

Ensuite, ajoutez-le à ` ''.

pom.xml


       <!--tester-->
        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.test-framework.providers/jersey-test-framework-provider-grizzly2 -->
        <dependency>
            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
            <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
            <version>2.30.1</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.15.0</version>
            <scope>test</scope>
        </dependency>

(2) Implémentation de la classe de test

En gros, suivez simplement ce que vous avez fait dans Jersey Basic Sample.

src/test/java/my/example/jerseysample/PaymentServiceTest.java


package my.example.jerseyspring.rest;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;

import static org.assertj.core.api.Assertions.assertThat;

class PaymentServiceTest extends JerseyTest {

    @Override
    protected Application configure() {
        return new ResourceConfig(PaymentService.class);
    }

    @BeforeEach
    @Override
    public void setUp() throws Exception {
        super.setUp();
    }

    @AfterEach
    @Override
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    public void get(){
        final Response response = target("/payment/mkyong").request().get();

        String content = response.readEntity(String.class);
        assertThat(content).isEqualTo("Jersey + Spring example");
    }
}

2. Essayez de modifier l'implémentation de TransactionBo

Comme c'est un gros problème, j'ai essayé d'utiliser Spring DI pour voir s'il pouvait être remplacé par un simulacre.

(1) Ajouter une dépendance

Afin d'exécuter la DI de Spring, nous inclurons le framework de test de Spring.

pom.xml


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

(2) Créer une classe de haricots fictifs

Créez la classe suivante sous src / test / java / my / example / transaction / impl.

TransactionBoMock.java


public class TransactionBoMock implements TransactionBo {
    public String save() {
        return "This is mock.";
    }
}

Nous définirons cela comme un bean, mais comme il s'agit d'un test, nous créerons ʻapplicationContext.xmlpour le test. Placez-le soussrc / test / resources`.

src/test/resources/applicationContext.xml


<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="my.example.jerseyspring"/>

    <bean id="transactionBo" class="my.example.jerseyspring.transaction.impl.TransactionBoMock"/>

</beans>

Je change la classe d'implémentation en TransactionBoMock.

(3) Modification de la classe d'essai

Le style d'écriture correspond à «Junit5».

PaymentServiceTest.java


@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:/applicationContext.xml")
class PaymentServiceTest extends JerseyTest {

Ajoutez simplement deux annotations! Si vous le faites, vous obtiendrez une erreur car vous n'avez pas encore modifié la chaîne de comparaison.

org.opentest4j.AssertionFailedError: 
Expecting:
 <"This is mock.">
to be equal to:
 <"Jersey + Spring example">
but was not.
Expected :Jersey + Spring example
Actual   :This is mock.
assertThat(content).isEqualTo("Jersey + Spring example");

Changez la chaîne ci-dessus en "" Ceci est simulé ". Et vous avez terminé.

Impressions

Il faut beaucoup de temps pour arriver ici, mais ...

Quand c'est fait, c'est relativement simple. Si cela devient si simple, il sera plus facile de comprendre qu'il est nécessaire de définir dans ʻapplicationContext.xml` pour obtenir DI.

En ce qui concerne l'installation de Spring MVC, la configuration du contrôleur et du répartiteur semble à nouveau être difficile, mais comme cela n'est prévu que pour l'API RESTful, cela convient une fois. (Je n'ai pas tellement envie d'étudier Spring MVC)

Ensuite, je voudrais créer une API plus décente et, si possible, la fusionner avec Projet multi-modulaire avec Jersey uniquement.

Les projets à ce jour sont téléchargés ci-dessous.

https://github.com/le-kamba/spring-jersey-sample/tree/simple_base

Autres sites de référence

Les informations étaient obsolètes et pour Boot, donc ce n'était pas une référence directe, mais c'est un site qui m'a donné divers indices en détail.

REST API with Jersey and Spring https://www.baeldung.com/jersey-rest-api-with-spring

Programmers: Jersey with a Side of Spring http://pilotprogrammer.com/archive/2019/01/programmers-jersey-with-a-side-of-spring/

Pourquoi l'injection de constructeur est recommandée par rapport à l'injection de champ au printemps http://pppurple.hatenablog.com/entry/2016/12/29/233141

Comment faire fonctionner DI lors du test avec JUnit https://wikiwiki.jp/webapp/Spring/JUnit

JUnit5 @RunWith https://www.baeldung.com/junit-5-runwith

Recommended Posts

Exemple de configuration d'API RESTful minimum avec Jersey + Spring Framework
Exemple multi-module d'API RESTful avec IntelliJ + Jersey + Spring Framework
Spring Boot: exemple de projet d'API Restful
Mettez le fichier dans les propriétés de string avec la configuration spring xml
Comment définir et utiliser un profil avec une configuration basée sur des annotations dans le framework Spring
Spring Framework 5.0 Résumé des principaux changements
API RESTful d'autorisation d'accès au démarrage de printemps
Implémenter l'API REST avec Spring Boot
Paramètres lors de l'appel de l'API à l'aide des mesures CSRF de Spring Security dans JMeter
À propos de l'affichage initial de Spring Framework
Changements majeurs dans la fonctionnalité de base de Spring Framework 5.0
Fonctionnalités du framework Spring pour les développeurs Java
Problème de configuration Maven avec Spring pom.xml dans Eclipse
Exemple de code pour appeler l'API Yahoo! Shopping Product Search (v3) avec Spring RestTemplate