Nota

Creare un'applicazione Java basata su Oracle GraalVM utilizzando Spring Boot su OKE per memorizzare i messaggi SOAP in ATP e inviare a OCI Queue

Introduzione

Molti dei nostri clienti si affidano alla messaggistica SOAP (Simple Object Access Protocol) tradizionale per consentire la comunicazione tra le loro applicazioni. Spesso devono memorizzare i dati transazionali, garantire il disaccoppiamento del servizio, ottenere il bilanciamento del carico delle richieste in entrata e abilitare la comunicazione asincrona di questi messaggi.

In questa esercitazione vedremo come creare un'applicazione Java basata su Oracle GraalVM utilizzando Spring Boot distribuito sull'infrastruttura Oracle Cloud Infrastructure Kubernetes Engine (OKE) che verrà utilizzata come integratore transazionale con i diversi servizi Oracle Cloud Infrastructure (OCI), come Oracle Autonomous Transaction Processing (ATP) e OCI Queue. Questa configurazione consente ai sistemi di interagire senza connessioni dirette, facilitando la comunicazione tra applicazioni con velocità di elaborazione diverse. Inoltre, una volta memorizzate nel database, le informazioni possono essere consultate o analizzate.

Utilizzeremo le seguenti tecnologie:

Oracle Cloud Infrastructure Services (OCI): OCI è una piattaforma cloud sicura e ad alte prestazioni che offre oltre 150 servizi cloud. È progettato per garantire scalabilità, sicurezza e prestazioni.

Tecnologia Oracle:

Altre tecnologie:

Architettura di livello superiore OCI:

Architettura OCI

Architettura caso d'uso

Nota:

Obiettivi

Prerequisiti

Task 1: provisioning e configurazione del cluster OKE

In questo task verrà eseguito il provisioning della piattaforma Kubernetes, in cui l'applicazione supporterà tutti i messaggi SOAP ad alta transazionalità da memorizzare in ATP e inviare ciascuno a OCI Queue in tempo reale.

  1. Eseguire il login a OCI Console, passare a Servizi per sviluppatori, Cluster Kubernetes (OKE) e selezionare il Compartimento desiderato.

    È possibile creare un cluster OKE in due modi:

    • Creazione rapida:
    • Creazione personalizzata.
  2. Selezionare Creazione rapida perché questo metodo è più semplice, veloce e distribuisce automaticamente tutti gli elementi richiesti da OKE per il relativo funzionamento, ad esempio:

    • Rete cloud virtuale (VCN).
    • Gateway Internet.
    • Gateway NAT (Network Address Translation).
    • Gateway del servizio.
    • Cluster Kubernetes.
    • Nodi di lavoro e pool di nodi Kubernetes.

    Nota: per gli ambienti aziendali, in cui già i clienti dispongono di servizi, rete, infrastruttura, è importante personalizzare la distribuzione OKE, in modo che sia conforme, in linea con l'architettura client, le risorse e seguendo le best practice.

    Creazione rapida

  3. Fare clic su Crea cluster e immettere le informazioni riportate di seguito.

    • Nome: immettere il nome del cluster OKE.
    • Compartimento: selezionare il compartimento creato per questo progetto.
    • Versione Kubernetes: selezionare la versione più recente di Kubernetes disponibile.
    • Endpoint API Kubernetes: in questa esercitazione selezionare Endpoint pubblico, ma è anche possibile selezionare Endpoint privato.
    • Tipo di nodo: selezionare i nodi Managed.
    • Nodi di lavoro Kubernetes: selezionare Lavoratori privati.
    • Forma e immagine: selezionare VM.Standard.E5. Flex, personalizza il numero di OCPU (2) e memoria (16 GB) e conserva l'immagine predefinita di Oracle Linux 8.
    • Conteggio nodi: immettere 2 nodi di lavoro da distribuire con il pool di nodi OKE.

    Crea cluster OKE

    Verificare che il cluster OKE funzioni.

    OKE in esecuzione

Task 2: Provisioning, configurazione e accesso a OCI Container Registry Classic

È necessario gestire le immagini del progetto in un repository. Per ottenere questo risultato, eseguirà il provisioning di OCI Container Registry Classic. Una volta memorizzate le immagini in OCI Container Registry Classic, saremo in grado di distribuirle in OKE.

  1. Andare alla console OCI, andare a Servizi sviluppatore, Container e artifact, Container Registry e fare clic su Crea repository.

  2. Immettere le informazioni riportate di seguito e fare clic su Crea.

    • Crea nel compartimento: selezionare il compartimento creato per questo progetto.
    • Accesso: selezionare Pubblico.
    • Nome repository: immettere springboot/tutorialapp.

    Crea repository

  3. Una volta creato il repository, dall'host amministratore Oracle accedervi utilizzando il comando seguente.

    docker login -u 'tenancy_namespace/domain/username' regionID.ocir.io
    
    Password: xxxxxx
    

    Autenticazione Oracle Registry

    OK

Task 3: Provisioning e configurazione del database serverless Oracle Autonomous Transaction Processing (ATP)

Nel database ATP, memorizzeremo i dati di ogni messaggio SOAP ricevuto per transazione, approssimativamente ognuno sarà nell'ordine di millisecondi, assistendo a inserzioni parallele e sequenziali.

  1. Andare alla console OCI, andare a Oracle Database e fare clic su Autonomous Transaction Processing.

  2. Fare clic su Crea Autonomous Database e immettere le informazioni seguenti.

    • Selezionare il compartimento: selezionare il compartimento creato per questo progetto.
    • Nome visualizzato: immettere il nome visualizzato.
    • Visualizza nome database: immettere il nome del database.
    • Scegliere un tipo di carico di lavoro: selezionare Elaborazione delle transazioni.
    • Scegliere un tipo di distribuzione: selezionare Serverless.
    • Configurare il database:
      • Sviluppatore: deselezionalo.
      • Scegliere la versione del database: selezionare 23ai.
      • Conteggio ECU: inserire 2.
      • Ridimensionamento automatico della computazione: selezionalo.
      • Memorizzazione: immettere 1024 GB.
    • Periodo di conservazione del backup automatico in giorni: lasciare l'opzione predefinita 60 giorni.
    • Creare credenziali amministratore:
      • Nome utente: è l'impostazione predefinita ADMIN e non può essere modificata.
      • Password: immettere la password preferita.
      • Conferma password: immettere di nuovo la password.
    • Scegliere l'accesso di rete: selezionare Solo accesso a endpoint privato, quindi scegliere la VCN e la subnet create per questo progetto. Questa impostazione limita le connessioni solo alla rete privata (VCN) specificata. Tuttavia, è possibile scegliere altre opzioni, questo dipende dalle esigenze dell'azienda.

    Crea database Oracle ATP

    Crea database Oracle ATP

    Crea database Oracle ATP

    Verificare che il database ATP sia in esecuzione.

    ATP in esecuzione

Task 4: Connetti e crea tabelle di progetto in Oracle Autonomous Transaction Processing (ATP)

Ora dobbiamo configurare, connettere e creare le tabelle di progetto nel database ATP generato nel Task 3.

  1. Andare alla console OCI, andare a Oracle Database, Autonomous Transaction Processing e fare clic su Connessione al database. Selezionare Autenticazione TLS, TLS e fare clic su Scarica wallet.

    Connessione al database

  2. Estrarre il file .zip del wallet e in tnsnames.ora è possibile ottenere l'URL dell'origine dati per ottenere la connessione a questo database. Salvare questo URL dell'origine dati.

    Ad esempio:

    tutorialoracleatp_medium = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=xxxxxxxx.adb.sa-saopaulo-1.oraclecloud.com))(connect_data=(service_name=xxxxxxxxxxxxxxx_tutorialoracleatp_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=no)))
    
  3. L'accesso al database è ora necessario. Quando è stato eseguito il provisioning di ATP, l'accesso a Oracle REST Data Services (ORDS) è stato abilitato. Per ulteriori informazioni, vedere Oracle REST Data Services.

    Andare alla pagina Dettagli di Autonomous Database e fare clic su Azioni database. Tenere presente che è possibile accedervi solo da un'istanza di computazione in esecuzione nella stessa rete cloud virtuale (VCN).

    Database Actions

  4. Incollare l'URL nel browser e accedere a ORDS utilizzando l'utente e la password immessi in precedenza nel database ATP e accedere al modulo Oracle SQL Developer Web.

    ORDS

  5. Utilizzare le query riportate di seguito per creare le tabelle USERS, CARS e HOUSES correlate ai messaggi SOAP che verranno ricevuti.

    CREATE TABLE USERS (
    username varchar(50) NOT NULL,
    userlastname varchar(50) NOT NULL,
    id int NOT NULL,
    email varchar(50) NOT NULL,
    dateuser varchar(50) NOT NULL,
    attributeuser varchar(50) NOT NULL  
    );
    
    CREATE TABLE CARS (
    userid int NOT NULL,
    brand varchar(50) NOT NULL,
    color varchar(50) NOT NULL,
    plate varchar(50) NOT NULL  
    );
    
    CREATE TABLE HOUSES (
    userid int NOT NULL,
    floors int NOT NULL,
    locationhouse varchar(50) NOT NULL,
    rooms int NOT NULL,
    bathrooms int NOT NULL
    );
    

    Tabelle create nel database

Task 5: Provisioning e configurazione di OCI Queue

In OCI Queue, memorizzeremo i messaggi altamente transazionali tramite l'API HTTP RESTful per un periodo di tempo specifico. I consumatori possono quindi leggere ed eliminare i messaggi immediatamente o a loro piacimento, garantendo il disaccoppiamento e prevenendo la perdita di dati.

  1. Andare a OCI Console, andare a Servizi per sviluppatori, Integrazione applicazioni e fare clic su Code.

  2. Fare clic su Crea coda, immettere le informazioni riportate di seguito e fare clic su Crea coda.

    • Nome: immettere il nome adeguato per la coda.
    • Compartimento: selezionare il compartimento di lavoro.
    • Impostazioni coda: in questa esercitazione verrà selezionata l'opzione Configurazione predefinita, ma se si preferisce, è possibile personalizzare più opzioni in base alle esigenze aziendali, ad esempio le impostazioni Timeout visibilità, Periodo massimo di conservazione, Consumo massimo canale e Coda di lettere morte.
    • Configura impostazioni di cifratura: selezionare Chiave gestita da Oracle, ma anche Chiave gestita dal cliente.

    Pagina Crea coda

    Verificare che OCI Queue sia in esecuzione.

    Coda OCI in esecuzione

Task 6: creare un'applicazione Java basata su Oracle GraalVM con Spring Boot e distribuirla in OKE

Ora svilupperemo e implementeremo un'applicazione Java basata su Oracle GraalVM su Spring Boot che eseguirà le seguenti attività:

Nota: prima di iniziare, è importante creare un host di amministrazione e un ambiente di sviluppo, come illustrato nelle sezioni Prerequisiti - Host di amministrazione e Prerequisiti - Ambiente di sviluppo.

Una volta configurato e pronto l'host di amministrazione e l'ambiente di sviluppo, è possibile iniziare a sviluppare il progetto Spring Boot.

  1. Vai su Spring initializr e crea il primo progetto che ci darà la struttura delle cartelle e i file di base di un progetto Spring Boot, per modificarlo in seguito in base alle nostre esigenze. Immettere le informazioni riportate di seguito e fare clic su Genera. Il progetto Spring Boot verrà scaricato automaticamente, salvato ed estratto nell'host di sviluppo.

    • Progetto: selezionare Maven.
    • Lingua: selezionare Java.
    • Boot di primavera: selezionare 3.3.6.
    • Metadati progetto:
      • Gruppo: immettere com.tutorial_springboot.
      • Artifact: immettere l'esercitazione.
      • Nome: immettere l'esercitazione.
      • Descrizione: immettere Applicazione di avvio di primavera (leggere SOAP, trasformare in JSON, inserire ATP e mettere in OCI Queue).
    • Packaging: selezionare Jar.
    • Java: selezionare 17.
    • Dipendenze: selezionare Driver Oracle, Servizi Web Spring e Web Spring.

    Nota: possiamo aggiungere alcune dipendenze nel progetto e successivamente aggiungerne altre direttamente nel file pom.xml, in base alle nostre esigenze.

    Progetto Springboot

  2. Ora abbiamo il progetto della struttura dello stivale a molla.

    Struttura Stivale a molla

    Rivedere il file pom.xml, inizieremo a lavorarci sopra.

    File POM originale

    Aggiornare il file pom.xml, in base all'ambito proposto in questa esercitazione.

    • Aggiungere la versione oci sdk e le seguenti dipendenze.

      • oci-java-sdk-common.
      • oci-java-sdk-queue.
      • oci-java-sdk-addons-oke-workload-identity.
      • oci-java-sdk-common-httpclient-jersey3.

      L'applicazione dovrà eseguire l'autenticazione con OCI, connettere e gestire i servizi OCI, come OCI Queue.

    • Il nostro file pom.xml ha già una dipendenza spring-boot-starter-web-services e dobbiamo aggiungere una dipendenza wsdl4j. Lo scopo principale è quello di ottenere i dati ricevuti dai messaggi SOAP e inserirli in oggetti Java, creando servizi Web Spring che manipolano i payload XML, ha lo scopo di facilitare lo sviluppo di servizi SOAP basati su contratto. Consente inoltre di configurare la porta, l'URI e impostare lo schema XML caricato dal file XSD (XML Schema Definition).

    • Aggiungi dipendenza JSON. Questa libreria verrà utilizzata per generare il formato JSON con i dati estratti dal messaggio SOAP.

    • Aggiungere il plugin spring-boot-maven-plugin nella sezione Build. Questo plugin ci permetterà di generare il file di progetto Spring Boot eseguibile jar.

    • Aggiungere il plugin jaxb2-maven-plugin nella sezione Build. Questo plugin utilizzerà l'API Java per l'associazione XML (JAXB), per generare classi Java dagli schemi XML e, in questo modo, possiamo passare i dati dal messaggio SOAP agli oggetti di classe Java creati da noi.

      In questa sezione del plugin, è importante inserire la configurazione che indicherà il percorso, dove il file XSD è incluso nel nostro progetto Spring Boot.

      <configuration>
         <sources>
         <source>${project.basedir}/src/main/resources/messages.xsd<source>
         </sources>
      </configuration>
      
    • Aggiungere la dipendenza jasypt-spring-boot-starter nella sezione Dipendenze e il plugin jasypt-maven-plugin nella sezione Build che ci consentirà di cifrare i parametri riservati nel file application.properties, garantendo un uso sicuro all'interno della nostra applicazione.

    Esaminare le dipendenze seguenti aggiunte nel file pom.xml.

    File POM modificato

    File POM modificato

  3. Scaricare le librerie ed eseguire i comandi seguenti.

    1. Nell'ambiente di sviluppo, eseguire il comando seguente per accedere al progetto.

      cd tutorial
      

      Cartella progetto Spring Boot

    2. Pulire il progetto e rimuovere tutti i file generati dalla build precedente.

      mvn clean
      

      Cleanup Maven

    3. Rimuovere (eliminare e, facoltativamente, risolvere di nuovo) gli artifact dal repository locale del forno.

      mvn dependency:purge-local-repository
      

    Dipendenze rimozione Maven

  4. Abbiamo già le dipendenze e il file pom.xml configurato nel nostro progetto, procederemo a controllare il file XML SOAP, in quanto rappresenta la richiesta dal lato del client, e il file XSD, che interpreta la richiesta dal lato del nostro progetto Spring Boot.

    1. Questo file XML SOAP ha due messaggi, con informazioni personali e altri tipi di attributi da due client diversi che invieremo per richiesta, come mostrato nella seguente immagine.

      File sapone

    2. Ora sul lato del progetto Spring Boot, è necessario uno schema XML per definire un dominio di servizio Web che il servizio Web Spring esporta automaticamente come WSDL, l'immagine seguente mostra il file messages.xsd definito per questa esercitazione.

      messages.xsd:

      File XSD

    3. Salvare il file messages.xsd nella cartella delle risorse del progetto Spring Boot.

      File XSD nella cartella

  5. Creare e installare i file di progetto in un file jar. Eseguire il comando seguente e assicurarsi di trovarsi nella cartella del progetto Spring Boot.

    mvn install
    

    Nota: una volta eseguito il comando di installazione del forno, la cartella di destinazione viene generata automaticamente e, allo stesso modo, le classi Java in base al file XSD creato in precedenza e al file .jar eseguibile del progetto.

    Cartella di destinazione

  6. Ora possiamo aggiungere le classi Java richieste al nostro progetto Spring Boot.

    WebServiceConfig.java Class: Questa classe Java è stata sviluppata per creare il servizio Web SOAP:

    • Imposta il servlet per gestire le richieste SOAP.
    • Genera una definizione WSDL basata su uno schema XML.
    • Definisce l'endpoint di accesso del servizio Web SOAP.
    • Utilizza il file di schema messages.xsd dal classpath.
    //Imports
    import org.springframework.boot.web.servlet.ServletRegistrationBean; //import the ServletRegistrationBean class
    import org.springframework.context.ApplicationContext; //import the ApplicationContext class
    import org.springframework.context.annotation.Bean; //import the Bean class
    import org.springframework.context.annotation.Configuration; //import the Configuration class
    import org.springframework.core.io.ClassPathResource; //import the ClassPathResource class
    import org.springframework.ws.config.annotation.EnableWs; //import the EnableWs class
    import org.springframework.ws.config.annotation.WsConfigurerAdapter; //import the WsConfigurerAdapter class
    import org.springframework.ws.transport.http.MessageDispatcherServlet; //import the MessageDispatcherServlet class
    import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; //import the DefaultWsdl11Definition class
    import org.springframework.xml.xsd.SimpleXsdSchema; //import the SimpleXsdSchema class
    import org.springframework.xml.xsd.XsdSchema; //import the XsdSchema class
    
    //Configuration class for the Web Service configuration
    @EnableWs //Enable the Web Service
    @Configuration //Define the class as a Configuration class 
    
    public class WebServiceConfig extends WsConfigurerAdapter {
    
       //Create a ServletRegistrationBean object to register the MessageDispatcherServlet object with the application context
       @Bean
       public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
          MessageDispatcherServlet servlet = new MessageDispatcherServlet(); //Create a MessageDispatcherServlet object
          servlet.setApplicationContext(applicationContext); //Set the application context for the MessageDispatcherServlet object
          servlet.setTransformWsdlLocations(true); //Set the transformWsdlLocations property to true
          return new ServletRegistrationBean<>(servlet, "/ws/*"); //Return a new ServletRegistrationBean object with the MessageDispatcherServlet object and the URL pattern
       }
    
       //Create a DefaultWsdl11Definition object to define the WSDL
       @Bean(name = "messages")
       public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema messagesSchema) {
          DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); //Create a DefaultWsdl11Definition object
          wsdl11Definition.setPortTypeName("MessagesPort"); //Set the port type name
          wsdl11Definition.setLocationUri("/ws"); //Set the location URI
          wsdl11Definition.setTargetNamespace("http://tutorial_example.com/ns0"); //Set the target namespace
          wsdl11Definition.setSchema(messagesSchema); //Set the schema
          return wsdl11Definition; //Return the DefaultWsdl11Definition object
       }
    
       //Create a XsdSchema object to define the schema
       @Bean
       public XsdSchema messagesSchema() {
          return new SimpleXsdSchema(new ClassPathResource("messages.xsd")); //Return a new SimpleXsdSchema object with the messages.xsd file
       }
    }
    

    Nota: se si desidera eseguire il test del servizio Web, è possibile eseguire il progetto Spring Boot nello stesso desktop dell'ambiente di sviluppo locale e inviare la richiesta HTTP utilizzando curl, come indicato di seguito.

    mvn spring-boot:run
    

    Esegui progetto Spring Boot

    Esegui progetto Spring Boot

    Una volta che il progetto è in esecuzione e il servizio Web è attivo, eseguire una richiesta HTTP SOAP locale utilizzando curl, come indicato di seguito.

    curl --location 'http://localhost:8080/ws/'
    

    E riceverai una risposta dal servizio web esposto nel nostro progetto Spring Boot.

    Web Service SOAP

  7. Creare una cartella denominata model e in questa cartella verranno aggiunte le seguenti classi Java.

    Cartella modello

    Nota: queste classi Java Car, House e User recupereranno le informazioni in base ai dati in ogni messaggio SOAP estratto dalla richiesta SOAP HTTP.

    • Car.java class: Questa classe Java rappresenta un oggetto Car con i relativi attributi collegati a ciascun utente.

      ```
      //Imports
      import org.springframework.stereotype.Component; // For component scanning
      import org.springframework.context.annotation.Scope; // For defining bean scope
      
      @Component // Marks a class as a Spring-managed component
      @Scope("prototype") //A new instance is created every time the bean is requested
      
      public class Car {
      
         //Attributes
      
         private String brand; 
         private String color; 
         private String plate; 
      
         //"getter" and "setter" methods to get and set the information in each object
      
         public String getBrand(){
         return brand;
         }
      
         public void setBrand(String brand){
         this.brand = brand;
         }
      
         public String getColor(){
         return color;
         }
      
         public void setColor(String color){
         this.color = color;
         }
      
         public String getPlate(){
         return plate;
         }
      
         public void setPlate(String plate){
         this.plate = plate;
         }
      
      }
      ```
      
      • House.java class: Questa classe Java rappresenta un oggetto House con i relativi attributi collegati a ciascun utente.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        public class House {
        
           //Attributes
        
           private int floors;
           private String location;
           private int rooms;
           private int bathrooms;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public int getFloors(){
              return floors;
           }
        
           public void setFloors(int floors){
              this.floors = floors;
           }
        
           public String getLocation(){
              return location;
           }
        
           public void setLocation(String location){
              this.location = location;
           }
        
           public int getRooms(){
              return rooms;
           }
        
           public void setRooms(int rooms){
              this.rooms = rooms;
           }
        
           public int getBathRooms(){
              return bathrooms;
           }
        
           public void setBathRooms(int bathrooms){
              this.bathrooms = bathrooms;
           }
        
        }
        
      • User.java class: Questa classe Java rappresenta un oggetto Utente con i relativi attributi, contenente gli oggetti Auto e Casa.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        
        public class User {
        
           //Attributes
        
           private String username; 
           private String userlastname;
           private int id;
           private String email;
           private String date;
           private String attribute;
           private Car car;
           private House house;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public String getUserName(){
           return username;
           }
        
           public void setUserName(String username){
           this.username = username;
           }
        
           public String getUserLastName(){
           return userlastname;
           }
        
           public void setUserLastName(String userlastname){
           this.userlastname = userlastname;
           }    
        
           public int getID(){
           return id;
           }
        
           public void setID(int id){
           this.id = id;
           }        
        
           public String getEmail(){
           return email;
           }
        
           public void setEmail(String email){
           this.email = email;
           }
        
           public String getDate(){
           return date;
           }
        
           public void setDate(String date){
           this.date = date;
           }
        
           public String getAttribute(){
           return attribute;
           }
        
           public void setAttribute(String attribute){
           this.attribute = attribute;
           }
        
           public Car getCar(){
           return car;
           }
        
           public void setCar(Car car){
           this.car = car;
           }
        
           public House getHouse(){
           return house;
           }
        
           public void setHouse(House house){
           this.house = house;
           }
        }
        
  8. Ora configureremo i parametri necessari nel nostro progetto Spring Boot per memorizzare i dati ottenuti nel database OCI ATP. Nella cartella resources è necessario trovare il file application.properties utilizzato per aggiungere i parametri richiesti dall'applicazione. Viene generato automaticamente e viene caricato da Spring Boot all'avvio dell'applicazione.

    Nota: è davvero importante gestire i metodi di cifratura e sicurezza che garantiscono che le informazioni riservate, come le password o i dati pertinenti, non possano essere estratte o visualizzate dagli hacker. In questa esercitazione viene utilizzata la libreria jasypt configurata nel file pom.xml. Per ulteriori informazioni, vedere Come cifrare le password in un progetto Spring Boot utilizzando Jasypt. Inoltre nelle nostre classi Java su Spring Boot è documentato dove aggiungere le annotazioni e il codice sorgente relativi a questa libreria per decifrare i parametri application.properties.

    Aggiungere i parametri appropriati richiesti dal database ATP nel file application.properties, come mostrato nella seguente immagine.

    File delle proprietà dell'applicazione

    Creare la classe Java Spring Boot per memorizzare ogni messaggio nel database, sarà nella cartella database come mostrato nella seguente immagine.

    Database Folder

    • SoapObjectRepository.java: Questa classe Java Spring Boot consente di inserire in formato transazionale in tempo reale, ogni messaggio in ATP, utilizzando il driver JDBC.

      //Java Classes USER, CAR, HOUSE Imports
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      //Spring Boot Imports
      import org.springframework.stereotype.Repository;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.beans.factory.annotation.Autowired;
      
      //Repository Class to save SOAP Messages in the Database
      @Repository
      public class SoapObjectRepository {
         private JdbcTemplate template;
         private User user;
      
         //Getters and Setters for JdbcTemplate template object
         public JdbcTemplate getTemplate(){
            return template;
         }
      
         //Autowired annotation to inject JdbcTemplate object into the template object
         @Autowired
         public void setTemplate(JdbcTemplate template){
            this.template = template;
         }
      
         //Method to save User SOAP Message in the Database
         public void saveUserSOAPMessage(User user){
            this.user = user;
            String sql = "INSERT INTO USERS (username, userlastname, id, email, dateuser, attributeuser) VALUES(?, ?, ?, ?, ?, ?)";
            template.update(sql, user.getUserName(), user.getUserLastName(), user.getID(), user.getEmail(), user.getDate(), user.getAttribute());
         }
      
         //Method to save Car SOAP Message in the Database
         public void saveCarSOAPMessage(Car car){
            String sql = "INSERT INTO CARS (userid, brand, color, plate) VALUES(?, ?, ?, ?)";
            template.update(sql, user.getID(), car.getBrand(), car.getColor(), car.getPlate());
         }
      
         //Method to save House SOAP Message in the Database
         public void saveHouseSOAPMessage(House house){
            String sql = "INSERT INTO HOUSES (userid, floors, locationhouse, rooms, bathrooms) VALUES(?, ?, ?, ?, ?)";
            template.update(sql, user.getID(), house.getFloors(), house.getLocation(), house.getRooms(), house.getBathRooms());
         }
      
      
      }
      

      Ora, aggiungi il codice software JSON, prima creando la cartella json_message e la sua classe Java Spring Boot come mostrato nella seguente immagine.

      Cartella Json

    • JsonBuilder.java: Questa classe Java Spring Boot viene convertita dal formato XML SOAP al formato JSON.

      //Imports to be used for JSON
      import org.json.JSONArray;
      import org.json.JSONObject;
      
      //Imports to be used for the User class
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      
      //Imports to be used for the ArrayList class
      import java.util.ArrayList;
      
      
      public class JsonBuilder {
      
         //The buildJsonMessage method creates a JSON object from the ArrayList of User objects
         public JSONObject buildJsonMessage(ArrayList<User> usersMessageArray) {
      
            JSONObject rootJson = new JSONObject(); //Create a new JSON object called rootJson
            JSONObject messagesJson = new JSONObject(); //Create a new JSON object called messagesJson
            JSONArray messageArray = new JSONArray(); //Create a new JSON array called messageArray
      
      
            //Iterate through the ArrayList of User objects and create a JSON object for each User object in the ArrayList
            for (User user : usersMessageArray) {
                  JSONObject messageJson = new JSONObject();
                  messageJson.put("username", user.getUserName()); //Add the username of the user to the messageJson object
                  messageJson.put("userlastname", user.getUserLastName()); //Add the userlastname of the user to the messageJson object
                  messageJson.put("id", user.getID()); //Add the id of the user to the messageJson object
                  messageJson.put("email", user.getEmail()); //Add the email of the user to the messageJson object
                  messageJson.put("date", user.getDate()); //Add the date of the user to the messageJson object
                  messageJson.put("attribute", user.getAttribute()); //Add the attribute of the user to the messageJson object
      
      
                  //
                  JSONObject bodyJson = new JSONObject(); //Create a new JSON object called bodyJson
                  JSONObject envelopeJson = new JSONObject(); //Create a new JSON object called envelopeJson
      
                  //Switch statement to check the attribute of the User object
                  switch (user.getAttribute()) {
                     case "CAR":
                              Car car = user.getCar();
                              envelopeJson.put("brand", car.getBrand()); //Add the brand of the car to the envelopeJson object
                              envelopeJson.put("color", car.getColor()); //Add the color of the car to the envelopeJson object
                              envelopeJson.put("plate", car.getPlate()); //Add the plate of the car to the envelopeJson object                       
                        break;
                     case "HOUSE":
                              House house = user.getHouse();
                              envelopeJson.put("floors", house.getFloors()); //Add the floors of the house to the envelopeJson object
                              envelopeJson.put("location", house.getLocation()); //Add the location of the house to the envelopeJson object
                              envelopeJson.put("rooms", house.getRooms()); //Add the rooms of the house to the envelopeJson object
                              envelopeJson.put("bathrooms", house.getBathRooms()); //Add the bathrooms of the house to the envelopeJson object                     
                        break;
                     default:
                        System.out.println("Unknown subject: " + user.getAttribute());
                  }
      
      
                  bodyJson.put("envelope", envelopeJson); //Add the envelopeJson object to the bodyJson object
      
                  messageJson.put("body", bodyJson); //Add the bodyJson object to the messageJson object
      
               messageArray.put(messageJson); //Add the messageJson object to the messageArray array
            }
      
            messagesJson.put("message", messageArray); //Add the messageArray array to the messagesJson object
            rootJson.put("messages", messagesJson); //Add the messagesJson object to the rootJson object
      
            return rootJson;
         }
      }
      
  9. Ora possiamo inviare i messaggi in formato JSON a OCI Queue. Creare la cartella oci_queue e la relativa classe Java Spring Boot, come illustrato nella seguente immagine.

    Cartella coda

    Nota: nella classe OCIQueue.java sarà necessario definire l'accesso da OKE a OCI Queue. Per questa esercitazione verrà utilizzato l'accesso ai carichi di lavoro per concedere l'accesso alle risorse OCI, senza dover gestire informazioni riservate quali utente, password, OCID associati alla tenancy. Per ulteriori informazioni, vedere Concessione dell'accesso dei carichi di lavoro alle risorse OCI.

    Prima di iniziare a sviluppare la classe OCIQueue.java, configureremo l'accesso ai carichi di lavoro nella nostra tenancy. In primo luogo, dobbiamo creare uno spazio di nomi da associare alla nostra applicazione Java basata su Oracle GraalVM. Assicurarsi di trovarsi nell'host amministratore.

    kubectl create ns-tutorial
    

    Quindi, creare un account di servizio Kubernetes per l'applicazione.

    kubectl create serviceaccount tutorialserviceaccount --namespace ns-tutorial
    

    Ora, definisci un criterio IAM OCI per consentire al carico di lavoro di accedere alle risorse OCI necessarie. In questa esercitazione, OCI Queue.

    Andare alla console OCI, andare a Identità e sicurezza, Criteri e fare clic su Crea criterio. Immettere le informazioni riportate di seguito e fare clic su Crea.

    • Nome: immettere il nome del criterio preferito.
    • Descrizione: immettere Accesso dalla coda OKE alla coda OCI.
    • Costruzione guidata criteri:

      Allow any-user to use queues in compartment id ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx where all {request.principal.type = 'workload', request.principal.namespace = 'ns-tutorial', request.principal.service_account = 'tutorialserviceaccount', request.principal.cluster_id = 'ocid1.cluster.oc1.sa-saopaulo-1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
      

    Criteri di accesso carichi di lavoro

    Dopo aver configurato il criterio di accesso al carico di lavoro, lo spazio di nomi e l'account del servizio, possiamo continuare.

    Nel file application.properties aggiungere i parametri di coda necessari per connettersi e gestire la coda OCI specifica creata nel task 5.

    Impostazioni OCIID

    • OCIQueue.java: Questa classe Java Spring Boot consente di accedere e inserire i messaggi in OCI Queue.

      //Imports
      import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider; //Import OkeWorkloadIdentityAuthenticationDetailsProvider to enable access and use OCI Workload Identity
      import com.oracle.bmc.queue.QueueClient; //Import QueueClient to have access and manage of OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetails; //Import PutMessagesDetails to send messages to the OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetailsEntry; //Import PutMessagesDetailsEntry to send messages to the OCI Queue
      import com.oracle.bmc.queue.requests.PutMessagesRequest; //Import PutMessagesRequest to send messages to the OCI Queue
      
      //Imports for the ArrayList and List
      import java.util.ArrayList;
      import java.util.List;
      
      public class OCIQueue {
         //Set the required parameters to access to OCI and the Queue
      
         //Variables
         private String queueId; 
         private String endPoint;
         private String region;
      
         //Constructor to initialize the OCI Queue object with the required parameters
         public OCIQueue(String queueId, String endPoint, String region){
            this.queueId = queueId;
            this.endPoint = endPoint;
            this.region = region;   
         }
      
      
         //The sendMessages method sends a message to the OCI Queue
         public void sendMessages(String jsonMessage){
            try{    
      
                  //Create an OkeWorkloadIdentityAuthenticationDetailsProvider object to authenticate the OCI Queue
                  OkeWorkloadIdentityAuthenticationDetailsProvider provider = new OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder().build();
      
                  //Create a QueueClient object to send the message to the OCI Queue
                  QueueClient queueClient = QueueClient.builder().build(provider);
                  queueClient.setRegion(region);
                  queueClient.setEndpoint(endPoint);
      
      
      
                  //Create a PutMessagesDetailsEntry object to send the message
                  PutMessagesDetailsEntry message = PutMessagesDetailsEntry.builder()
                     .content(jsonMessage)
                     .build();
      
                  //Create a List of PutMessagesDetailsEntry objects to send the message
                  List<PutMessagesDetailsEntry> messages = new ArrayList<>();
                  messages.add(message);
      
                  //Create a PutMessagesDetails object to send the message
                  PutMessagesDetails putMessagesDetails = PutMessagesDetails.builder()
                     .messages(messages)
                     .build();
      
      
                  //  Create a PutMessagesRequest object to send the message
                  PutMessagesRequest putMessagesRequest = PutMessagesRequest.builder()
                     .queueId(queueId)
                     .putMessagesDetails(putMessagesDetails)
                     .build();
      
                  // Send the request and get the response
                  queueClient.putMessages(putMessagesRequest);
      
            }catch(Exception e){
                  System.out.println("Exception sending message to OCI Queue: "+e);
            }
         }
      }
      
  10. Una volta che hai le classi Java Spring Boot per database, JSON e OCI Queue, possiamo procedere con la classe MessagesEndpoint.java.

    Per questo, creeremo una cartella chiamata endpoint e la sua classe Java Spring Boot.

    Cartella endpoint

    Nota: in MessagesEndpoint.java è necessario importare alcune classi generate automaticamente. A tale scopo, aggiungere la seguente origine nella sezione Configurazione del file pom.xml:

    <configuration>
       <sources>
       <source>${project.build.directory}/generated-sources</source>
       </sources>
    </configuration>
    

    Il file pom.xml dovrebbe avere un aspetto simile.

    Percorso origini generate

    • MessagesEndpoint.java: Lo scopo di questa classe Java Spring Boot è estrarre la richiesta HTTP SOAP e mapparne i valori agli oggetti User, Car e House Java per ogni messaggio. Memorizza quindi i dati estratti in un database ATP per ogni transazione XML SOAP, converte i dati da XML in formato JSON e inserisce i messaggi in una coda OCI. Questi messaggi possono essere successivamente recuperati ed eliminati dalla coda dai consumer.

      //Imports
      import com.oracle_springboot_tutorial.tutorial.model.*; //Import all the classes from the model package
      import com.oracle_springboot_tutorial.tutorial.oci_queue.OCIQueue; //Import the OCIQueue class from the oci_queue package
      
      
      import com.tutorial_example.ns0.Messages;//Import the Messages class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      import com.tutorial_example.ns0.MessageType; //Import the MessageType class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      
      //Import the ArrayList class from the java.util package
      import java.util.ArrayList;
      
      //Spring Boot imports to be used for the SOAP Web Service
      import org.springframework.beans.factory.annotation.Autowired; //Import the @Autowired annotation to inject the SoapObjectRepository object
      import org.springframework.beans.factory.annotation.Value; //Import the @Value annotation to inject the values from the application.properties file
      import org.springframework.stereotype.Component; //Import the @Component annotation to register the class with Spring
      
      //Spring Boot imports 
      import org.springframework.ws.server.endpoint.annotation.Endpoint; //Import the @Endpoint annotation to register the class with Spring WS
      import org.springframework.ws.server.endpoint.annotation.PayloadRoot; //Import the @PayloadRoot annotation to specify the namespace URI and local part of the request payload
      import org.springframework.ws.server.endpoint.annotation.RequestPayload; //Import the @RequestPayload annotation to map the request payload to the method parameter
      import org.springframework.ws.server.endpoint.annotation.ResponsePayload; //Import the @ResponsePayload annotation to map the returned value to the response payload
      
      //Imports to be used storing SOAP information in the database 
      import com.oracle_springboot_tutorial.tutorial.database.SoapObjectRepository; //Import the SoapObjectRepository class from the database package
      
      //Imports to be used for JSON
      import com.oracle_springboot_tutorial.tutorial.json_message.JsonBuilder; //Import the JsonBuilder class from the json_message package 
      import org.json.JSONObject; //Import the JSONObject class from the org.json package
      
      
      //The @Endpoint annotation registers the class with Spring WS.
      //The @Component annotation registers the class with Spring to be used as a Spring Bean.
      @Endpoint
      @Component
      public class MessagesEndpoint {
      
         //Inject not encrypted and decrypted values using jasypt library from the application.properties file
         @Value("${oci.queue.queueId}")
         private String queueId;
         @Value("${oci.queue.endPoint}")
         private String endPoint;
         @Value("${oci.queue.region}")   
         private String region;
         @Value("${spring.datasource.password}")
         private String datasourcePassword;
      
         //The @Autowired loads JDBC template in SoapObjectRepository.
         @Autowired
         private SoapObjectRepository soapObjectRepository = new SoapObjectRepository();
         //Create a new instance of the JsonBuilder class
         JsonBuilder jsonBuilder = new JsonBuilder();
      
      
         //The namespace URI
         private static final String NAMESPACE_URI = "http://tutorial_example.com/ns0";
      
         //The handleMessagesRequest method is annotated with @PayloadRoot, which means that it is invoked when a request with the specified namespace URI and local part is received.
         @PayloadRoot(namespace = NAMESPACE_URI, localPart = "messages")
         //The @ResponsePayload annotation makes Spring WS map the returned value to the response payload.
         @ResponsePayload
         //The handleMessagesRequest method processes the request and sends the message to the OCI Queue.
         public void handleMessagesRequest(@RequestPayload Messages request) {
            OCIQueue ociQueue = new OCIQueue(queueId, endPoint, region);
      
            //Create an ArrayList to store the users
            ArrayList<User> usersMessageArray = new ArrayList<User>();
      
            //Iterate over the messages, extracting the SOAP Messages and storing in the Java Objects (Car, House, User) 
            for (MessageType message : request.getMessage()) {
      
                  User user = new User();
                  user.setUserName(message.getUsername());
                  user.setUserLastName(message.getUserlastname());
                  user.setID(message.getId());
                  user.setEmail(message.getEmail());
                  user.setDate(message.getDate());
                  user.setAttribute(message.getAttribute());
      
                  //Insert User in Oracle ATP
                  soapObjectRepository.saveUserSOAPMessage(user);
      
                  //Process the attributes Car or House depending of the kind of User
                  processMessage(user, message);
                  //Add the user to the ArrayList
                  usersMessageArray.add(user);
            }
      
      
            //Convert to JSON format
            JSONObject jsonObject = jsonBuilder.buildJsonMessage(usersMessageArray);
      
            //Send the JSON message to OCI Queue
            ociQueue.sendMessages(jsonObject.toString());
      
         }
      
         //The processMessage method processes the message based on the user's attribute.
         private void processMessage(User user, MessageType message) {
            String subject = user.getAttribute();
            switch (subject) {
                  case "CAR":
                     handleCAR(user, message);
                     break;
                  case "HOUSE":
                     handleHouse(user, message);
                     break;
                  default:
                     System.out.println("Unknown subject: " + subject);
            }
         }
      
         //The handleCAR method processes the CAR message.
         private void handleCAR(User user, MessageType message) {
            Car car = new Car();
            car.setBrand(message.getBody().getEnvelope().getBrand());
            car.setColor(message.getBody().getEnvelope().getColor());
            car.setPlate(message.getBody().getEnvelope().getPlate());
      
            user.setCar(car);
            //Insert Car in Oracle ATP
            soapObjectRepository.saveCarSOAPMessage(user.getCar());
      
         }
      
         //The handleHouse method processes the HOUSE message.
         private void handleHouse(User user, MessageType message) {
            House house = new House();
            house.setFloors(message.getBody().getEnvelope().getFloors());
            house.setLocation(message.getBody().getEnvelope().getLocation());
            house.setRooms(message.getBody().getEnvelope().getRooms());
            house.setBathRooms(message.getBody().getEnvelope().getBathrooms());
      
            user.setHouse(house);
      
            //Insert Houses in Oracle ATP
            soapObjectRepository.saveHouseSOAPMessage(user.getHouse());
      
         }
      }
      
  11. Ora che abbiamo terminato l'intera costruzione del progetto Spring Boot, creeremo il Dockerfile nella cartella del progetto.

  1. Eseguire il comando seguente per creare ed eseguire il PUSH dell'immagine del progetto nel repository Docker locale.

    docker build . -t springbootapp:latest
    

    Crea immagine Docker

  2. Eseguire il comando seguente per verificare l'immagine nel repository Docker locale.

    docker images
    

    Repo locale immagine Docker

  3. Possiamo contrassegnare l'immagine dell'applicazione Spring Boot con il percorso completo del repository OCI Container Registry Classic.

    docker tag springbootapp:latest gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    
  4. Eseguire il comando seguente per verificare nel repository Docker locale.

    docker images
    

    Contrassegna applicazione OKE

  5. Eseguire il comando riportato di seguito per eseguire il PUSH dell'immagine in OCI Container Registry Classic.

    docker push gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    

    Applicazione OKE push

  6. Per esaminare l'applicazione immagine OKE in OCI Container Registry Classic, andare a Servizi per sviluppatori, Container e artifact e fare clic su Container Registry.

    Immagine nel registro OKE Containe

    Una volta che l'immagine si trova in OCI Container Registry Classic, possiamo andare al nostro ambiente di sviluppo e distribuire questa immagine in OKE. Per questa esercitazione, eseguire il comando seguente per creare le configurazioni richieste.

    Nota: poiché lo spazio di nomi e l'account di servizio erano stati configurati in precedenza, richiede il segreto.

    1. Eseguire il comando seguente per accedere alla cartella del progetto.

      cd tutorial/
      
    2. Eseguire il comando seguente per creare un segreto per OKE.

      kubectl create secret -n ns-tutorial generic ocir --from-file=.dockerconfigjson=../.docker/config.json --type=kubernetes.io/dockerconfigjson
      

      Crea OA secrete

  7. L'ambiente OKE è già pronto, quindi distribuire l'immagine dell'applicazione da OCI Container Registry Classic a OKE.

    Nota: per distribuire l'immagine dell'applicazione, è necessario disporre di un file manifest. In questa esercitazione il file yaml seguente è il file manifest, utilizzato per distribuire l'applicazione e creare il servizio in entrata rappresentato in un load balancer OCI in ascolto utilizzando la porta 80.

    • springboot_application.yaml:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: soap-oci-queue-app
      namespace: ns-tutorial 
      labels:
         app: soap-oci-queue-app
      spec:
      replicas: 6
      selector:
         matchLabels:
            app: soap-oci-queue-app
      template:
         metadata:
            labels:
            app: soap-oci-queue-app
         spec:
            serviceAccountName: tutorialserviceaccount
            automountServiceAccountToken: true      
            containers:
            - name: soap-oci-queue-app
            image: gru.ocir.io/xxxxxxxxxxxx/springboot/tutorialapp:latest
            ports:
            - containerPort: 8080
            imagePullSecrets:
            - name: ocir-docker-config
      ---
      
      apiVersion: v1
      kind: Service
      metadata:
      name: svc-dev-app 
      namespace: ns-tutorial 
      spec:
      selector:
         app: soap-oci-queue-app
      ports:
         - port: 80
            targetPort: 8080
      type: LoadBalancer
      
  8. Eseguire il comando kubectl nella cartella in cui è stato salvato il file manifesto.

    kubectl apply -f springboot_application.yaml
    

    Ora l'applicazione viene distribuita e il servizio load balancer in entrata viene creato in OKE.

    Applica manifesto in OKE

  9. Per convalidare il pod e il servizio creati in OKE, eseguire il comando seguente.

    kubectl get pods -A
    

    OKE PODS

    kubectl get svc -A
    

    Servizi OKE

    Nota: scaricare il progetto applicativo Java basato su Oracle GraalVM di Spring Boot da qui: tutorial.zip.

Task 7: eseguire il test dell'applicazione Oracle Graal VM Spring Boot utilizzando JMeter

Per ulteriori informazioni sull'installazione JMeter, vedere Guida introduttiva a JMeter.

Dopo aver installato e configurato JMeter, è possibile inviare richieste SOAP HTTP POST. Ad esempio, impostare il numero di thread su 2 per rappresentare 2 utenti o applicazioni simultanee e impostare Conteggio loop su 3000, ovvero ogni utente o applicazione invierà 3000 richieste, per un totale di 6000 richieste SOAP.

Messaggi SOAP

In JMeter impostare l'IP del load balancer OCI, percorso configurato nel progetto Spring Boot e XML SOAP nel corpo.

Richiesta SOAP HTTP

Eseguire JMeter con 6000 transazioni SOAP e verificare.

Nota: durante la simulazione della messaggistica SOAP delle applicazioni client, per ogni richiesta HTTP SOAP le informazioni sono uguali a quelle visualizzate nel file XML SOAP mostrato sopra e non cambiano, ma in un ambiente cliente reale le informazioni varieranno sicuramente.

Eseguire la seguente istruzione:

  1. Per visualizzare i dati totali memorizzati in ATP.

    Oracle ATP

  2. Per visualizzare i dettagli dei dati memorizzati in ogni tabella in ATP.

    • AUTO:

      AUTO

    • CASE:

      CASE

    • USERS:

      USERS

  3. Per visualizzare le richieste OCI Queue totali memorizzate in OCI Queue.

    Totale richieste OCI Queue

  4. Per visualizzare i dettagli dei messaggi in OCI Queue in formato JSON.

    Dettagli messaggi coda OCI

Conferme

Altre risorse di apprendimento

Esplora altri laboratori su docs.oracle.com/learn o accedi a più contenuti gratuiti sulla formazione su Oracle Learning YouTube channel. Inoltre, visita education.oracle.com/learning-explorer per diventare un Oracle Learning Explorer.

Per la documentazione del prodotto, visita l'Oracle Help Center.