练习 - 创建 Azure 资源和 Java Spring 应用程序

已完成

在此单元中,你将创建一个基本的 Spring Boot 应用程序。 你将使用 Azure CLI 和所选的集成开发环境 (IDE) 来编辑代码。 使用自己所选的终端来运行代码。

准备工作环境

使用以下命令设置某些环境变量:

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>

在你的代码中,将占位符替换为下表中的值。 这些值将在整个模块中使用。

变量 说明
YOUR_DATABASE_NAME<> 你的 MySQL 服务器的名称。 它在 Azure 中应是唯一的。
YOUR_AZURE_REGION<> 你将使用的 Azure 区域。 默认情况下,你可以使用 eastus,但建议你使用靠近你居住位置的区域。 若要查看可用区域的完整列表,请输入 az account list-locations
YOUR_MYSQL_PASSWORD<> MySQL 数据库服务器的密码。 密码应至少包含八个字符。 字符应该来自以下三个类别:英文大写字母、英文小写字母、数字(0 到 9)及非字母数字字符(!、$、#、% 等)。
YOUR_LOCAL_IP_ADDRESS<> 本地计算机的 IP 地址,你将在其中运行 Spring Boot 应用程序。 若要找到此 IP 地址,请将浏览器指向 whatismyip.akamai.com

接下来,创建一个资源组:

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

注意

本模块使用 jq 工具,该工具默认安装在 Azure Cloud Shell 上,用于显示 JSON 数据并使其更具可读性。

如果不想使用 jq 工具,则可以安全地删除此模块中所有命令的 | jq 部分。

创建 Azure Database for MySQL 的实例

现在,你将创建托管 MySQL 服务器。

注意

要了解有关 Azure Database for MySQL 的详细信息,请在本模块的末尾,访问相关文档的链接。

运行以下脚本,创建一个 Azure Database for MySQL 的小型实例。 此数据库具有 1 个 CPU 和 2 GB 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

此脚本创建一个使用你先前设置的变量的小型 MySQL 服务器。

为 MySQL 服务器配置防火墙规则

默认情况下,Azure Database for MySQL 受到保护。 其防火墙不允许传入连接。 因此请添加一个防火墙规则,以允许本地 IP 地址访问数据库服务器。

运行以下命令,打开服务器的防火墙:

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

运行以下命令以允许从 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

配置 MySQL 数据库

之前创建的 MySQL 服务器为空。 它没有可用于 Spring Boot 应用程序的数据库。 创建一个名为 demo的新数据库:

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

使用 Spring Initializr 生成应用程序

Spring Initializr 是一个 Web 应用程序,用于生成 Spring Boot 项目结构。 Spring Initializr 不会生成任何应用程序代码,但为你提供一个基本的项目结构和一个 Maven 生成规范。

你将生成具有以下三个依赖项的应用程序基架:webmysqldata-jpa。 无需指定 Azure 依赖项,因为你将在本地运行应用程序。

在命令提示符处,生成应用程序:

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 -

将 Spring Boot 配置为使用 Azure Database for MySQL

打开 src/main/resources/application.properties 文件,并添加一些属性。 请确保将 $AZ_DATABASE_NAME$AZ_MYSQL_PASSWORD 这两个变量替换为先前设置的值。

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

警告

配置属性 spring.jpa.hibernate.ddl-auto=create-drop 意味着 Spring Boot 将在应用程序启动时自动创建数据库架构,并在应用程序关闭时尝试删除该数据库架构。 此属性非常适合测试,但不应在生产中使用!

注意

?serverTimezone=UTC 追加到配置属性 spring.datasource.url。 此设置会告知 Java Database Connectivity (JDBC) 驱动程序在你连接到数据库时使用协调世界时 (UTC) 日期格式。 否则,Java 服务器将不会使用与数据库相同的日期格式,这将导致错误。

现在,使用提供的 Maven 包装器启动应用程序:

./mvnw spring-boot:run

此屏幕截图显示首次运行的应用程序:

显示正在运行的应用程序的屏幕截图。

编写应用程序代码

接下来,添加以下 Java 代码。 它使用 Java 持久性 API (JPA) 来存储和检索 MySQL 服务器中的数据。

你将使用 JPA 实体类将 Java Todo 对象直接映射到 MySQL Todo 表。

DemoApplication 类旁,创建新的 Todo 实体类。 然后,添加以下代码:

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;
    }
}

此类是映射到 Todo 表上的域模型。 它将由 JPA 自动创建。

若要管理该类,需要一个存储库。 在同一包中定义一个新的 TodoRepository 接口:

package com.example.demo;

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

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

此存储库是一个由 Spring Data JPA 管理的 JPA 存储库。 通过扩展 JpaRepository,你可获得一组针对你的类型的通用 create、read、update 和 delete (CRUD) 方法。 因此,你可以执行一些操作,例如保存和删除 Todo 对象。

通过创建可发布 REST 接口的 RestController 来完成应用程序,以便通过 HTTP 存储和检索数据。 在同一包中实现 TodoController 类。 然后,添加以下代码:

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();
    }
}

最后,请停止该应用程序,然后使用以下命令再次启动它:

./mvnw spring-boot:run

Spring Boot 应用程序应启动并连接到数据库。

此屏幕截图显示应用程序正连接到数据库:

屏幕截图显示正在连接到数据库的运行中的应用程序。

测试应用程序

若要测试应用程序,可以使用 cURL

首先,在数据库中创建新的待办事项:

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

此命令应返回创建的项:

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

接下来,使用新的 cURL 请求检索数据:

curl http://127.0.0.1:8080

此命令返回待办事项列表,包括已创建的项目:

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