Exemple de recherche Spring Boot Hibernate

Nous allons ici créer un exemple d’application Web Spring Boot avec le moteur de gabarit Hibernate Search Thymeleaf et le déployer en tant que WAR pour Wildfly 10.1.

Technologies utilisées:

  1. Spring Boot 1.5.6.LELEASE

  2. Java 8

  3. Recherche Hibernate 5.6.1.Final

  4. Tomcat intégré, Wildfly 8.1 Final

1. Structure du projet

Une structure de projet Maven standard

image

1. Dépendances du projet

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.techfou</groupId>
    <artifactId>spring-boot-web-wildfly-search</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>
    <name>techfou-wildfly-spring-boot</name>
    <description>Spring Boot Web Hibernate Search Example</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <logback.version>1.1.9</logback.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--
            Comment out if deploy as WAR file
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
            -->
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-search-engine -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-search-engine</artifactId>
            <version>5.6.1.Final</version>
            <exclusions>
                <exclusion>
                    <groupId>org.jboss.logging</groupId>
                    <artifactId>jboss-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-search-orm -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-search-orm</artifactId>
            <version>5.6.1.Final</version>
            <exclusions>
                <exclusion>
                    <groupId>org.jboss.logging</groupId>
                    <artifactId>jboss-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.3.0.Final</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.9</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layout>WAR</layout>
                    <executable>true</executable>
                    <mainClass>com.mkyong.WildflySpringBootApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2. Modèle

Pour cet exemple d’application, nous créons un site Web qui vous permet de rechercher des cartes de baseball rares. Nous faisons donc de notre modèle la carte de baseball et annotons les champs interrogeables.

BaseballCard.java

package com.mkyong.model;

import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Indexed
@Entity
public class BaseballCard {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Field
    private String name;
    @Field
    private String rarityLevel;
    @Field
    private int year;

   //getters n setters

}

3. Référentiel

Nous avons ici un CrudRepository de Spring Data pour le modèle BaseballCard qui nous permettra d’effectuer les fonctions de création et de lecture nécessaires.

BaseballCardRepository.java

package com.mkyong.dao;

import org.springframework.data.repository.CrudRepository;

import com.mkyong.model.BaseballCard;

public interface BaseballCardRepository extends CrudRepository<BaseballCard,Long> {
}

4. Recherche Hibernate

HibernateSearchService.java

package com.mkyong.service;

import com.mkyong.model.BaseballCard;
import org.apache.lucene.search.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import java.util.List;

@Service
public class HibernateSearchService {


    @Autowired
    private final EntityManager centityManager;


    @Autowired
    public HibernateSearchService(EntityManager entityManager) {
        super();
        this.centityManager = entityManager;
    }


    public void initializeHibernateSearch() {

        try {
            FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(centityManager);
            fullTextEntityManager.createIndexer().startAndWait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Transactional
    public List<BaseballCard> fuzzySearch(String searchTerm) {

        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(centityManager);
        QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(BaseballCard.class).get();
        Query luceneQuery = qb.keyword().fuzzy().withEditDistanceUpTo(1).withPrefixLength(1).onFields("name")
                .matching(searchTerm).createQuery();

        javax.persistence.Query jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, BaseballCard.class);

       //execute search

        List<BaseballCard> BaseballCardList = null;
        try {
            BaseballCardList = jpaQuery.getResultList();
        } catch (NoResultException nre) {
            ;//do nothing

        }

        return BaseballCardList;


    }
}

Ceci configure le HibernateSearchService pour qu’il soit accessible.

HibernateSearchConfiguration.java

package com.mkyong;

import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.mkyong.service.HibernateSearchService;
@EnableAutoConfiguration
@Configuration
public class HibernateSearchConfiguration {

    @Autowired
    private EntityManager bentityManager;

    @Bean
    HibernateSearchService hibernateSearchService() {
        HibernateSearchService hibernateSearchService = new HibernateSearchService(bentityManager);
        hibernateSearchService.initializeHibernateSearch();
        return hibernateSearchService;
    }
}

5. Service pour le modèle

C’est un service simple qui ajoute trois cartes au référentiel pour notre exemple. Pour une démonstration des principes de programmation SOLID, il existe une interface distincte pour le service.

CardService.java

package com.mkyong.service;

public interface CardService {

    void addCards();

}

CardServiceImpl.java

package com.mkyong.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mkyong.dao.BaseballCardRepository;
import com.mkyong.model.BaseballCard;

@Service
public class CardServiceImpl implements CardService {

    @Autowired
    BaseballCardRepository cardrepository;

    BaseballCard TedWilliams = new BaseballCard();
    BaseballCard BobGibson = new BaseballCard();
    BaseballCard HonusWagner = new BaseballCard();

    public void addCards() {
        TedWilliams.setName("Ted Williams");
        TedWilliams.setYear(1954);
        TedWilliams.setRarityLevel("Very Rare");

        cardrepository.save(TedWilliams);

        BobGibson.setName("Bob Gibson");
        BobGibson.setYear(1959);
        BobGibson.setRarityLevel("Very Rare");

        cardrepository.save(BobGibson);

        HonusWagner.setName("Honus Wagner");
        HonusWagner.setYear(1909);
        HonusWagner.setRarityLevel("Rarest");

        cardrepository.save(HonusWagner);

        System.out.println("Cards have been added : " + cardrepository.findAll());

    }
}

6. Contrôleur

Le contrôleur est responsable de la connexion des services principaux à notre modèle Thymeleaf frontal.

CardController.java

package com.mkyong.controller;

import com.mkyong.model.BaseballCard;
import com.mkyong.service.CardService;
import com.mkyong.service.HibernateSearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
public class CardController {

    @Autowired
    private HibernateSearchService searchservice;

    @Autowired
    private CardService cardservice;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String search(@RequestParam(value = "search", required = false) String q, Model model) {
        List<BaseballCard> searchResults = null;
        try {
            cardservice.addCards();
            searchResults = searchservice.fuzzySearch(q);

        } catch (Exception ex) {
           //here you should handle unexpected errors
           //...
           //throw ex;
        }
        model.addAttribute("search", searchResults);
        return "index";

    }

}

7. Configuration

Nous devons maintenant configurer notre recherche Thymeleaf et Hibernate.

application.properties

#==================================
# = Thymeleaf configurations
#==================================
spring.thymeleaf.check-template-location=true
spring.thymeleaf.prefix=classpath:/templates/spring.thymeleaf.suffix=.html
spring.thymeleaf.content-type=text/html
spring.thymeleaf.cache=false
server.contextPath=/#===================================
#=
# Specify the Lucene Directory
spring.jpa.properties.hibernate.search.default.directory__provider = filesystem

# Using the filesystem DirectoryProvider you also have to specify the default
# base directory for all indexes
spring.jpa.properties.hibernate.search.default.indexBase = indexpath

8. Modèle Thymeleaf

Pour notre modèle Thymeleaf, nous avons deux objectifs: permettre à l’utilisateur de rechercher et d’afficher les résultats de recherche une fois la recherche terminée.

Heureusement, Thymeleaf a des instructions conditionnelles nous permettant d’afficher les résultats si la recherche d’un utilisateur renvoie des éléments.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- META SECTION -->
    <title>Mkyong Wildfly Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <!-- END META SECTION -->
    <!--  BEGIN STYLE -->
    <style>
        table, th, td {
            border: 1px solid black;
            padding: 1px;
        }
    </style>
    <!--  END STYLE -->

</head>
<body>
<form action="#" th:action="@{/}" th:object="${search}">
    <label for="search__input">Search:</label> <input name="search"
                                                     id="search">
    </input>
    <div th:if="${not #lists.isEmpty(search)}">
        <h2>Search Results</h2>
        <table>
            <thead>
            <tr>
                <th>ID</th>
                <th>name</th>
                <th>rarity level</th>
                <th>year</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="search : ${search}">
                <td th:text="${search.id}">Text ...</td>
                <td th:text="${search.name}">Text ...</td>
                <td th:text="${search.rarityLevel}">Text ...</td>
                <td th:text="${search.year}">Text...</td>
            </tr>
            </tbody>
        </table>
    </div>
</form>
</body>
</html>

9. SpringBootApplication

WildflySpringBootApplication.java

package com.mkyong;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WildflySpringBootApplication {

    public static void main(String[]args) {
        SpringApplication.run(WildflySpringBootApplication.class, args);
    }

}

10. Démo

Démarrez Spring Boot Application avec le conteneur Tomcat intégré par défaut.

$ mvn spring-boot:run

Accédez à http://localhost : 8080/

image

J’ai cherché «Ted» et les résultats sont affichés dans le tableau, http://localhost : 8080/? Search = ted

image://wp-content/uploads/1717/fr

11. Déployer le fichier WAR sur Wildfly

Wildfly est un serveur d’applications open source JBoss. Wildfly peut être téléchargé à partir de leur% E2% 80% 9Chttp://wildfly.org/downloads/%E2%80%9C[site web officiel]

11.1 Exclure le conteneur Tomcat intégré.

pom.xml

    <dependency>
           <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

11.2 étend SpringBootServletInitializer

WildflySpringBootApplication.java

package com.mkyong;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class WildflySpringBootApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WildflySpringBootApplication.class);
    }

    public static void main(String[]args) {
        SpringApplication.run(WildflySpringBootApplication.class, args);
    }

}

11.3 Maven crée et copie le fichier WAR dans JBoss Wildfly et le démarre.

Terminal

$ mvn package

11.4 Considérations pour Wildfly 10

Pour Wildfly 10, nous devons apporter des modifications supplémentaires à cause des technologies fournies avec son emballage. Dans notre cas, nous utilisons Hibernate Search et cela est fourni dans Wildfly 10.

Pour les utilisateurs de Wildfly 10, vous devez créer un fichier persistence.xml et entrer:

persistence.xml

wildfly.jpa.hibernate.search.module = none

Terminé.

Télécharger le code source

Téléchargez le - lien://wp-content/uploads/2017/09/spring-boot-hibernate-search-example.zip[spring-boot-hibernate-search-example.zip](24 KB)

Références

Applications d’amorçage de printemps]. http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html [Thymeleaf

Printemps]. lien://printemps-boot/printemps-boot-deploy-war-fichier-à-tomcat/[Spring Boot

  • Déployer un fichier WAR sur Tomcat]

recherche hibernate lien://tag/spring-boot/[botte de printemps]lien://tag/wildfly/[wildfly]