[JAVA] J'ai essayé le didacticiel Angular + SpringBoot + PostgreSQL

Angular + SpringBoot + PostgreSQL

introduction

Extrémité avant: angulaire (TypeScript) Backend: Spring Boot (Java) DB: PostgreSQL

En référence à cet article, j'ai essayé de faire ce que dit le titre. Tutoriel angulaire + J'ai essayé Spring Boot

Conditions préalables

Création d'un projet avec Spring Initializer Créé avec Maven Project Les dépendances incluent postgreSQL Driver et Lombok.

Le nom est approprié

environnement

Cet article est fait sur Mac, mais il fonctionne bien sur Windows. (7 a été confirmé, mais 10 ne sait pas)

% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.2
BuildVersion:   19C57

% osascript -e 'version of app "IntelliJ IDEA"'   
2019.3.1

% java --version
java 11.0.4 2019-07-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.4+10-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.4+10-LTS, mixed mode)

 % postgres --version
postgres (PostgreSQL) 12.1

% ng --version
Angular CLI: 8.3.4
Node: 11.12.0
OS: darwin x64
Angular: 
... 

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.803.4
@angular-devkit/core         8.3.4
@angular-devkit/schematics   8.3.4
@schematics/angular          8.3.4
@schematics/update           0.803.4
rxjs                         6.4.0

PostgreSQL Nous partirons du principe que PostgreSQL est déjà installé. Cette fois, j'utilise un schéma.

Création de schéma et création de table

CREATE SCHEMA tutorial
CREATE TABLE tutorial.heroes(
    id INT,
    name VARCHAR(64)
)

Insérer des données factices

INSERT INTO tutorial.heroes VALUES
(1, 'capitaine Amérique'),
(2, 'Homme de fer'),
(3, 'Ponton'),
(4, 'Alors Odinson'),
(5, 'Veuve noire'),
(6, 'Oeil de faucon'),
(7, 'Wijon'),
(8, 'Sorcière écarlate'),
(9, 'Faucon'),
(10, 'Machine de guerre'),
(11, 'Capitaine Marvel');

Maintenant, PostgreSQL est prêt.

Angular Nous partirons du principe que tout le Tutoriel angulaire a été terminé.

Classe de service

Remplacez la classe de service heroUrl par l'URL de l'API REST.

hero.service.ts


...
//Abréviation

export class HeroService {
// private heroesUrl = 'api/heroes';  //URL de l'API Web
  private heroesUrl = 'http://localhost:8080'; // <=Ajouter ici

  httpOptions = {
    headers: new HttpHeaders({ "Content-Type": "application/json" })
  };

  constructor(
    private http: HttpClient,
    private messageService: MessageService
  ) {}

//Abréviation
...

app.module.ts

Pour obtenir les données en touchant réellement l'API au lieu de se moquer Mettez en commentaire le HttpClientInMemoryWebApiModule qui se comporte comme un serveur API.

app.module.ts


@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent,
    HeroDetailComponent,
    MessagesComponent,
    DashboardComponent,
    HeroSearchComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    HttpClientModule
    // HttpClientInMemoryWebApiModule.forRoot(
    //   InMemoryDataService, { dataEncapsulation: false }
    // )
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Composant héros

heroes.component.ts


add(name: string): void {
    name = name.trim();
    //↓ Ajoutez 1 au dernier élément comme ID du nouveau héros
    let id = this.heroes.slice(-1)[0].id + 1;
    if (!name) { return; }
    //Ajouter un identifiant et passer l'argument en tant que héros
    this.heroService.addHero({ name, id } as Hero)
      .subscribe(hero => {
        this.heroes.push(hero);
      });
  }

Ceci termine les changements angulaires.

Côté backend (Java)

Hero class Créez une classe de héros pour la définition de type de héros. Depuis que j'utilise Lombok, je n'ai pas besoin de setter et de getter. (Dans Intellij, vous devez mettre lombok dans Plugin)

Hero.java


package tutorial.tutorial.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor
@Data
@NoArgsConstructor
@ToString
public class Hero {
    private Integer id;
    private String name;
}

HeroDAO class Créez une classe DAO pour accéder à la base de données. Créez tous les traitements CRUD.

HeroDAO.java


package tutorial.tutorial.model;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class HeroDAO {

    /**
     *Méthode pour établir les informations de connexion à la base de données
     *
     * @retour des informations de connexion conn
     */
    public Connection getConnection() throws ClassNotFoundException, SQLException {
        //Préparer les variables pour stocker les informations de connexion
        Connection conn = null;
        //Initialisation
        Class.forName("org.postgresql.Driver");
        //Entrez les informations de la base de données
        conn = DriverManager.getConnection("jdbc:postgresql://localhost/postgres?currentSchema=tutorial", "postgres", "postgres");
        //Désactiver l'autocommit
        conn.setAutoCommit(false);
        //Renvoie les informations de connexion
        return conn;
    }

    /**
     *Méthode pour obtenir et renvoyer tous les héros
     *
     * @retourner la liste des types de héros héros
     */
    public List<Hero> findAll() throws ClassNotFoundException, SQLException {
        //Préparer les variables pour stocker les informations de connexion
        Connection conn = null;
        //Pour stocker les instances de la classe dto
        List<Hero> heroes = new ArrayList<>();


        //Se connecter à la base de données
        try {
            conn = getConnection();
            //Création d'objets pour l'exécution d'instructions SQL
            Statement pstmt = conn.createStatement();
            //Émission de l'instruction SELECT
            String sql = "SELECT * FROM tutorial.heroes";
            //Obtenir le résultat de l'exécution de l'instruction SQL (valeur reçue de la base de données)
            ResultSet rs = pstmt.executeQuery(sql);

            //Répétez la valeur reçue de DB pour le nombre d'enregistrements
            while (rs.next()) {
                // Hero(DTO)Créer une instance de la classe
                Hero dto = new Hero();
                //Définir la valeur de l'ID de colonne
                dto.setId(rs.getInt("id"));
                //Définir la valeur du nom de la colonne
                dto.setName(rs.getString("name"));
                //Stocker l'instance dans la liste
                heroes.add(dto);
                //Passer au traitement d'enregistrement suivant avec l'instruction while(s'il y a)
            }
            //Instruction de capture d'erreur
        } catch (SQLException e) {
            e.printStackTrace();
            //Traitement à exécuter indépendamment du fait qu'une exception se produise
        } finally {
            //Si le contenu de conn est inclus, déconnectez la connexion db
            if (conn != null) {
                conn.close();
            }
        }
        //Renvoie une liste d'instances de la classe DTO
        return heroes;
    }


    /**
     *Une méthode pour obtenir et retourner Hero qui correspond à l'id reçu en argument
     *
     * @param id
     * @return selectedHero
     */
    public Hero findOneHero(int id) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        Hero selectedHero = new Hero();

        //Se connecter à la base de données
        try {
            conn = getConnection();
            //Émission de l'instruction SELECT
            String sql = "SELECT * FROM tutorial.heroes WHERE id = ?";

            //Création d'objets pour l'exécution d'instructions SQL
            PreparedStatement pstmt = conn.prepareStatement(sql);

            //Définissez l'identifiant reçu comme argument dans l'espace réservé.
            pstmt.setInt(1, id);

            //Obtenir le résultat de l'exécution de l'instruction SQL (valeur reçue de la base de données)
            ResultSet rs = pstmt.executeQuery();

            //Définissez la valeur reçue du DB sur dto.
            while (rs.next()) {
                // Hero(DTO)Créer une instance de la classe
                Hero dto = new Hero();
                //Définir la valeur de l'ID de colonne
                dto.setId(rs.getInt("id"));
                //Définir la valeur du nom de la colonne
                dto.setName(rs.getString("name"));
                //
                selectedHero = dto;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        return selectedHero;
    }

    /**
     *Une méthode pour mettre à jour Hero qui correspond à l'id reçu dans l'argument
     *
     * @param hero
     */
    public void updateHero(Hero hero) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        try {
            conn = getConnection();
            String sql = "UPDATE tutorial.heroes SET name = ? WHERE id = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, hero.getName());
            pstmt.setInt(2, hero.getId());
            pstmt.executeUpdate();
            conn.commit();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
    }

    /**
     *Une méthode pour supprimer Hero qui correspond à l'id reçu dans l'argument
     *
     * @id du paramètre id du héros que vous souhaitez effacer
     */
    public void deleteHero(int id) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        try {
            conn = getConnection();
            String sql = "DELETE FROM tutorial.heroes WHERE id = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id);
            pstmt.executeUpdate();
            conn.commit();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
    }

    /**
     *Une méthode pour insérer un nouveau héros avec l'id et le nom reçus comme arguments
     *
     * @param hero
     */
    public void createHero(Hero hero) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        try {
            conn = getConnection();
            String sql = "INSERT INTO tutorial.heroes VALUES(?, ?)";

            //Création d'objets pour l'exécution d'instructions SQL
            PreparedStatement pstmt = conn.prepareStatement(sql);

            //Définissez l'identifiant reçu comme argument dans l'espace réservé.
            pstmt.setInt(1, hero.getId());
            pstmt.setString(2, hero.getName());

            //Obtenir le résultat de l'exécution de l'instruction SQL (valeur reçue de la base de données)
            pstmt.executeUpdate();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
    }
}

HeroController class

Créez une API REST. J'ai créé les cinq suivants. --GetHeroes renvoie tous les héros --getHero pour renvoyer le héros associé à l'id

Les données reçues selon le didacticiel sont définies sur Hero.

HeroContoller.java


package tutorial.tutorial.controller;

import org.springframework.web.bind.annotation.*;
import tutorial.tutorial.model.*;
import java.sql.SQLException;
import java.util.*;

@RestController
public class HeroController {

    /**
     *Une méthode qui reçoit tous les héros de la classe DAO
     *
     * @return heroList 
     */
    @GetMapping("/")
    public List<Hero> getHeroes() throws SQLException, ClassNotFoundException {
        HeroDAO dao = new HeroDAO();
        List<Hero> heroes = dao.findAll();
        List<Hero> heroList = new ArrayList<>();
        heroList.addAll(heroes);
        return heroList;
    }

    /**
     *Une méthode qui reçoit le héros associé à l'id de la classe DAO
     *
     * @param id
     * @return hero
     */
    @GetMapping("/{id}")
    public Hero getHero(@PathVariable Integer id) throws SQLException, ClassNotFoundException {
        HeroDAO dao = new HeroDAO();
        Hero hero = dao.findOneHero(id);
        return hero;
    }

    /**
     *Une méthode à INSÉRER avec l'id et le nom reçus dans la classe DAO
     *
     * @param newHero
     * @return hero
     */
    @PostMapping("/")
    public Hero create(@RequestBody Hero newHero) throws SQLException, ClassNotFoundException {
        HeroDAO dao = new HeroDAO();
        dao.createHero(newHero);
        return newHero;
    }


    /**
     *Une méthode pour SUPPRIMER le héros associé à l'id dans la classe DAO
     *
     * @param id
     */
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Integer id) throws SQLException, ClassNotFoundException {
        HeroDAO dao = new HeroDAO();
        dao.deleteHero(id);
    }

    /**
     *Une méthode pour METTRE À JOUR le héros associé à l'id dans la classe DAO
     *
     * @param updatedHero
     */
    @PutMapping("/")
    public Hero update(@RequestBody Hero updatedHero) throws SQLException, ClassNotFoundException {
        HeroDAO dao = new HeroDAO();
        dao.updateHero(updatedHero);
        return updatedHero;
    }

}

Compatible CORS

Pour des raisons de sécurité, ajax etc. ne peut acquérir des ressources de la même origine que par SOP. Étant donné que les numéros de port sont cette fois différents entre Angular et Spring Boot, il est nécessaire d'activer CORS afin de libérer le SOP uniquement entre les origines approuvées.

WebConfig.java


package tutorial.tutorial.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*")
                //Spécifiez le numéro de port à autoriser(Côté angulaire)
                .allowedOrigins("http://localhost:3000")
                //Liste des méthodes autorisées
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                //En-tête autorisé
                .allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept")
                .allowCredentials(false).maxAge(3600);
    }
}

Exécuter

Lançons TutorialApplication et Angular. Vous pouvez confirmer que l'API est appelée et que la base de données est en cours d'utilisation.

Résumé

Afin de comprendre à quoi ressemble l'application Web, j'ai effectué un échange en utilisant Angular comme frontal, Spring Boot comme back-end et PostgreSQL comme base de données, qui sont étroitement liés à Ionic que j'utilise habituellement. ..

Recommended Posts

J'ai essayé le didacticiel Angular + SpringBoot + PostgreSQL
[J'ai essayé] Tutoriel de printemps
J'ai essayé UPSERT avec PostgreSQL.
J'ai essayé d'utiliser OnlineConverter avec SpringBoot + JODConverter
J'ai commencé Angular
J'ai essayé Spring.
J'ai essayé de mettre Tomcat
J'ai essayé youtubeDataApi.
J'ai essayé de refactoriser ①
J'ai essayé FizzBuzz.
J'ai essayé JHipster 5.1
J'ai essayé d'exécuter Autoware
J'ai essayé d'utiliser Gson
J'ai essayé QUARKUS immédiatement
J'ai essayé d'utiliser TestNG
J'ai essayé Spring Batch
J'ai essayé d'utiliser Galasa
J'ai essayé node-jt400 (Programmes)
J'ai essayé node-jt400 (exécuter)
J'ai essayé node-jt400 (Transactions)
J'ai essayé node-jt400 (Construction de l'environnement)
J'ai essayé DI avec Ruby
J'ai essayé node-jt400 (écriture IFS)
J'ai essayé node-jt400 (mise à jour SQL)
J'ai essayé d'utiliser azure cloud-init
J'ai essayé la machine Spring State
J'ai essayé Drools (Java, InputStream)
J'ai essayé Rails débutant [Chapitre 1]
J'ai essayé d'utiliser Apache Wicket
J'ai essayé node-jt400 (requête SQL)
J'ai essayé d'utiliser Java REPL
J'ai essayé l'analyse du code source
J'ai essayé le problème FizzBuzz
J'ai essayé node-jt400 (flux SQL)
J'ai essayé node-jt400 (lecture IFS)
J'ai essayé Rails débutant [Chapitre 2]
J'ai essayé BIND avec Docker
J'ai essayé de vérifier yum-cron
J'ai essayé la métaprogrammation avec Java