Esercizio - Creare risorse di Azure e un'applicazione Java Spring

Completato

In questa unità verrà creata un'applicazione Spring Boot di base. Per modificare il codice si useranno l'interfaccia della riga di comando di Azure e un ambiente di sviluppo integrato (IDE) di propria scelta. Usare un terminale di propria scelta per eseguire il codice.

Preparare l'ambiente di lavoro

Configurare alcune variabili di ambiente usando i comandi seguenti:

AZ_RESOURCE_GROUP=azure-spring-workshop
AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
AZ_LOCATION=<YOUR_AZURE_REGION>
AZ_MYSQL_USERNAME=spring
AZ_MYSQL_PASSWORD=<YOUR_MYSQL_PASSWORD>
AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>

Nel codice, sostituire i segnaposto con i valori riportati nella tabella seguente. Questi valori vengono usati in tutto il modulo.

Variabile Descrizione
<YOUR_DATABASE_NAME> Nome del server MySQL. Deve essere univoco in Azure.
<YOUR_AZURE_REGION> Area di Azure che verrà usata. È possibile usare eastus per impostazione predefinita, ma è consigliabile usare un'area vicina al luogo in cui si vive. Per vedere l'elenco completo delle aree disponibili, immettere az account list-locations
<YOUR_MYSQL_PASSWORD> Password del server di database MySQL. La password deve avere un minimo di otto caratteri. I caratteri devono essere compresi tra tre delle categorie seguenti: lettere maiuscole, lettere minuscole, numeri da 0 a 9 e caratteri non alfanumerici (!, $, #, %, e così via).
<YOUR_LOCAL_IP_ADDRESS> Indirizzo IP del computer locale da cui si eseguirà l'applicazione Spring Boot. Per trovare l'indirizzo IP, nel browser passare a whatismyip.akamai.com.

Successivamente, creare un gruppo di risorse:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    | jq

Nota

Questo modulo usa lo strumento jq, che è installato per impostazione predefinita in Azure Cloud Shell per visualizzare i dati JSON e renderli più leggibili.

Se non si vuole usare lo strumento jq, è possibile rimuovere senza problemi la parte | jq di tutti i comandi in questo modulo.

Creare un'istanza di Database di Azure per MySQL

A questo punto si creerà un server MySQL gestito.

Nota

Per altre informazioni su Database di Azure per MySQL, seguire il collegamento alla documentazione pertinente alla fine di questo modulo.

Eseguire lo script seguente per creare una piccola istanza di Database di Azure per MySQL. Il database ha 1 CPU e 2 GB di RAM.

az mysql server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --location $AZ_LOCATION \
    --sku-name B_Gen5_1 \
    --storage-size 5120 \
    --admin-user $AZ_MYSQL_USERNAME \
    --admin-password $AZ_MYSQL_PASSWORD \
    | jq

Questo script crea un piccolo server MySQL che usa le variabili configurate in precedenza.

Configurare una regola del firewall per il server MySQL

Database di Azure per MySQL è protetto per impostazione predefinita. Il firewall non consente connessioni in ingresso. Aggiungere quindi una regola del firewall per consentire all'indirizzo IP locale di accedere al server di database.

Eseguire il comando seguente per aprire il firewall del server:

az mysql server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME-database-allow-local-ip \
    --server-name $AZ_DATABASE_NAME \
    --start-ip-address $AZ_LOCAL_IP_ADDRESS \
    --end-ip-address $AZ_LOCAL_IP_ADDRESS \
    | jq

Eseguire il comando seguente per consentire l'accesso al firewall dalle risorse di Azure:

az mysql server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name allAzureIPs \
    --server-name $AZ_DATABASE_NAME \
    --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0 \
    | jq

Configurare un database MySQL

Il server MySQL creato in precedenza è vuoto. Non contiene alcun database che si possa usare con l'applicazione Spring Boot. Creare un nuovo database denominato demo:

az mysql db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name demo \
    --server-name $AZ_DATABASE_NAME \
    | jq

Generare l'applicazione con Spring Initializr

Spring Initializr è un'applicazione Web che genera automaticamente una struttura di progetto Spring Boot. Spring Initializr non genera il codice dell'applicazione, ma fornisce una struttura di progetto di base e una specifica di compilazione di Maven.

Si genererà lo scaffolding dell'applicazione con tre dipendenze: web, mysql e data-jpa. Non è necessario specificare le dipendenze di Azure perché si eseguirà l'applicazione in locale.

Al prompt dei comandi, generare l'applicazione:

curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=web,data-jpa,mysql -d baseDir=azure-spring-workshop -d bootVersion=3.1.5.RELEASE -d javaVersion=17 | tar -xzvf -

Configurare Spring Boot per l'uso di Database di Azure per MySQL

Aprire il file src/main/resources/application.properties e aggiungere alcune proprietà. Assicurarsi di sostituire le due variabili $AZ_DATABASE_NAME e la variabile $AZ_MYSQL_PASSWORD con i valori configurati in precedenza.

logging.level.org.hibernate.SQL=DEBUG

spring.datasource.url=jdbc:mysql://$AZ_DATABASE_NAME.mysql.database.azure.com:3306/demo?serverTimezone=UTC
spring.datasource.username=spring@$AZ_DATABASE_NAME
spring.datasource.password=$AZ_MYSQL_PASSWORD

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop

Avviso

La proprietà di configurazione spring.jpa.hibernate.ddl-auto=create-drop indica che Spring Boot creerà automaticamente uno schema del database all'avvio dell'applicazione e proverà ad eliminarlo all'arresto dell'applicazione. Questa proprietà è ideale per i test, ma non va assolutamente usata nell'ambiente di produzione.

Nota

Si accoda ?serverTimezone=UTC alla proprietà di configurazione spring.datasource.url. Questa configurazione indica al driver JDBC (Java Database Connectivity) di usare il formato di data UTC (Coordinated Universal Time) quando ci si connette al database. In caso contrario, il server Java non userà lo stesso formato di data del database, causando un errore.

Avviare ora l'applicazione usando il wrapper Maven fornito:

./mvnw spring-boot:run

Questo screenshot mostra l'applicazione in esecuzione per la prima volta:

Screenshot showing the running application.

Codice dell'applicazione

A questo punto, aggiungere il codice Java seguente. Il codice usa Java Persistence API (JPA) per archiviare e recuperare dati dal server MySQL.

Si userà una classe di entità JPA per eseguire il mapping di un oggetto Todo Java direttamente alla tabella Todo MySQL.

Accanto alla classe DemoApplication creare una nuova classe di entità Todo. Aggiungere quindi il codice seguente:

package com.example.demo;

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

@Entity
public class Todo {

    public Todo() {
    }

    public Todo(String description, String details, boolean done) {
        this.description = description;
        this.details = details;
        this.done = done;
    }

    @Id
    @GeneratedValue
    private Long id;

    private String description;

    private String details;

    private boolean done;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Todo)) {
            return false;
        }
        return id != null && id.equals(((Todo) o).id);
    }

    @Override
    public int hashCode() {
        return 31;
    }
}

Questa classe è un modello di dominio con mapping alla tabella Todo. Verrà creata automaticamente da JPA.

Per gestire questa classe è necessario un repository. Definire una nuova interfaccia TodoRepository nello stesso pacchetto:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface TodoRepository extends JpaRepository<Todo, Long> {
}

Questo è un repository JPA gestito da Spring Data JPA. Estendendo JpaRepository si ottengono diversi metodi generici di creazione, lettura, aggiornamento ed eliminazione (CRUD, Create, Read, Update, Delete) per il tipo. In questo modo è possibile eseguire operazioni come il salvataggio e l'eliminazione di oggetti Todo.

Per completare l'applicazione, creare un elemento RestController in grado di pubblicare le interfacce REST per archiviare e recuperare i dati tramite HTTP. Implementare una classe TodoController nello stesso pacchetto. Aggiungere quindi il codice seguente:

package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/")
public class TodoController {

    private final TodoRepository todoRepository;

    public TodoController(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    @PostMapping("/")
    @ResponseStatus(HttpStatus.CREATED)
    public Todo createTodo(@RequestBody Todo todo) {
        return todoRepository.save(todo);
    }

    @GetMapping("/")
    public Iterable<Todo> getTodos() {
        return todoRepository.findAll();
    }
}

Infine, arrestare l'applicazione e riavviarla usando il comando seguente:

./mvnw spring-boot:run

L'applicazione Spring Boot verrà avviata e connessa al database.

Questo screenshot mostra l'applicazione che si connette al database:

Screenshot showing the running application connecting to database.

Testare l'applicazione

Per testare l'applicazione si può usare cURL.

Per prima cosa, creare una nuova attività nel database:

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"configuration","details":"congratulations, you have set up your Spring Boot application correctly!","done": "true"}' \
    http://127.0.0.1:8080

Questo comando restituirà l'elemento creato:

{"id":1,"description":"configuration","details":"congratulations, you have set up your Spring Boot application correctly!","done":true}

Recuperare quindi i dati usando una nuova richiesta cURL:

curl http://127.0.0.1:8080

Questo comando restituisce l'elenco delle attività, inclusa quella appena creata:

[{"id":1,"description":"configuration","details":"congratulations, you have set up your Spring Boot application correctly!","done":true}]