使用Docker環境和Java Spring Boot来实现最小API:MySQL

使用 Docker 环境和Java Spring Boot 实现最小 API:MySQL。

spring-boot_and_mysql_on_docker.png

的意思是什么?

我将在 Windows 11 上使用 Linux 进行云开发。

您可以在这里查看文章的列表。

 

实现

在本地环境的Ubuntu中的Docker环境中,启动了一个由Dockerfile构建的Java Spring Boot Web服务的自定义容器和MySQL数据库容器。

以JAR文件格式作为容器启动应用程序。

运行环境

要素概要terminalターミナルUbuntuOSDockerコンテナ実行環境

REST API 服务容器

要素概要api-todo-spring-bootREST API サービス カスタムコンテナJVMJava 実行環境app.jarJava アプリケーションtomcatWeb サーバー

数据库容器

要素概要mysql-todoデータベースコンテナmysqlDB サーバーdb_todoデータベース

技術主題

什么是Spring Boot?

这里可以展开查看。Spring Boot(春季引导)

Spring Boot是一个框架,旨在支持快速开发和部署Java应用程序,并提供工具和功能来减轻常见的开发工作和配置。

关键词
内容

简易设置
Spring Boot通过最小化配置并提供默认设置来简化应用程序的设置。通过使用注释和自动配置,减少了繁琐的配置工作。

适用于微服务
Spring Boot支持微服务架构,使得从单个应用程序构建多个独立服务变得更加容易。

嵌入式服务器
在构建Web应用程序时,可以将像Tomcat或Jetty这样的Web服务器嵌入到应用程序中。这样可以生成独立可执行的JAR文件。

自动配置
Spring Boot根据应用程序的类路径和使用的库自动进行配置。这减少了繁琐的配置文件的创建,并使开发人员能够集中精力编写核心代码。

生产准备
Spring Boot提供了在生产环境中运行所需的功能。它简化了应用程序的监视和管理,包括指标、健康检查和外部配置。

丰富的启动器
Spring Boot提供了汇总了常用依赖关系的”启动器”,以便于应用程序开发。这使得轻松使用特定用途的配置成为可能。

可定制化
Spring Boot提供了一些选项来定制默认行为。这使得可以根据特定需求和要求进行调整。

研发环境

    Windows 11 Home 22H2 を使用しています。
请参考macOS版本来操作WSL的Ubuntu版本。
WSL(Microsoft Store应用程序版)※请从此相关文章中查看安装方法
> wsl –version
WSL版本:1.0.3.0
内核版本:5.15.79.1
WSLg版本:1.0.47Ubuntu ※请从此相关文章中查看安装方法
$ lsb_release -a
没有可用的LSB模块。
分发商ID:Ubuntu
描述:Ubuntu 22.04.1 LTS
版本:22.04

Java JDK ※请从此相关文章中查看安装方法
$ java -version
openjdk版本”11.0.18″ 2023-01-17
OpenJDK运行时环境(构建11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64位服务器虚拟机(构建11.0.18+10-post-Ubuntu-0ubuntu122.04,混合模式,共享)

Maven ※请从此相关文章中查看安装方法
$ mvn -version
Apache Maven 3.6.3
Maven主页:/usr/share/maven
Java版本:11.0.18,供应商:Ubuntu,运行时:/usr/lib/jvm/java-11-openjdk-amd64

Docker ※请从此相关文章中查看安装方法
$ docker –version
Docker版本23.0.1,构建a5ee5b1

本文主要使用Ubuntu终端进行操作。为了初学者学习使用Vim进行复制粘贴的方法,以下文章介绍了相关步骤。请务必尝试一下。

 

创建 REST API 的规范

エンドポイントHTTPメソッド説明リクエストBodyレスポンスBody/todosGETすべての ToDo アイテムを取得します。NoneToDo アイテムの配列/todos/completeGET完了した ToDo アイテムを取得します。NoneToDo アイテムの配列/todos/{id}GETID で ToDo アイテムを取得します。NoneToDo アイテム/todosPOST新しい ToDo アイテムを追加します。ToDo アイテムToDo アイテム/todos/{id}PUT既存の ToDo アイテムを更新します。ToDo アイテムNone/todos/{id}DELETEID で ToDo アイテムを削除します。NoneNone

启动数据库容器

您可以在这篇文章中了解到如何创建一个适用于ToDo应用的RDBMS数据库,并将其作为Docker容器启动的步骤。

 

确认数据库容器已启动。

$ docker ps
CONTAINER ID   IMAGE        COMMAND                   CREATED        STATUS       PORTS                                                  NAMES
63a3acec271c   mysql-base   "docker-entrypoint.s…"   20 hours ago   Up 3 hours   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql-todo
为了进行容器之间的通信, 预先创建了一个名为 net-todo 的Docker网络。请注意。

实现REST API的步骤是什么?

创建项目

创建项目文件夹。
*将~/tmp/restapi-spring-boot指定为项目文件夹。

$ mkdir -p ~/tmp/restapi-spring-boot
$ cd ~/tmp/restapi-spring-boot

创建Model类

在这个系列的文章中,我们将在RDBMS和NoSQL两种数据库中执行相同的API操作。因此,我们将ID字段定义为字符串而不是数字类型,以保持一致性并在不同的数据存储中运行。请注意。

我要创建一个名为Todo的实体类。

$ mkdir -p src/main/java/com/example/model
$ vim src/main/java/com/example/springboot/model/Todo.java

文件的内容 de

package com.example.springboot.model;

import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import lombok.Data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

// ToDo エンティティを表すクラス
@Data
@Entity @Table(name="todos")
public class Todo {
    // RDBMS 本来の int 型のキー:API 入出力の JSON にはマッピングしない
    @JsonIgnore
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Id @Column(name="id", unique=true) Long _rdbms_id;

    // string 型の ID を定義:RDBMS 側にはマッピングしない
    @Transient String id;
    public String getId() { return Long.toString(_rdbms_id); }
    public void setId(String id) { _rdbms_id = Long.parseLong(id); }

    @JsonProperty("content")
    @Column(name="content") String content;

    @JsonProperty("created_date")
    @Column(name="created_date") 
    @Temporal(TemporalType.TIMESTAMP) Date createdDate;

    @JsonProperty("completed_date")
    @Column(name="completed_date") 
    @Temporal(TemporalType.TIMESTAMP) Date completedDate;
}
打开说明。元素 说明
@Data 是使用 Lombok 库时使用的注释。Lombok 是基于注释的库,用于减少 Java 类中冗余的代码。
@Entity 是指示类是 JPA 实体(映射到数据库表的对象)的注释。
@Table(name=”todos”) 是表示实体映射到 todos 表的注释。指定了表名。
@Id 是指示该字段是主键的注释。
@GeneratedValue(strategy=GenerationType.IDENTITY) 是指定主键值如何自动生成的注释。IDENTITY 策略表示使用数据库的自增列生成键。
@Column(name=”id”, unique=true) 是表示字段映射到数据库列的注释。unique=true 指定了列的值是唯一的。
@Transient 是指示该字段不映射到数据库列的注释。它是一个瞬态字段。
@Temporal(TemporalType.TIMESTAMP) 是指示字段具有日期和时间的注释。使用 TIMESTAMP 类型。
@JsonProperty(“content”) 是用于指定字段名称在 JSON 序列化时的注释。
@JsonIgnore 是用于在 JSON 序列化和反序列化时忽略特定字段的注释。

通过组合这些元素,Todo 类作为 JPA 实体起作用,并用作与数据库中的 todos 表相对应的对象。

创建一个TodoRepository仓库接口。

$ mkdir -p src/main/java/com/example/model
$ vim src/main/java/com/example/springboot/model/TodoRepository.java

文件的内容 de

package com.example.springboot.model;

import java.util.List;

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

// ToDo エンティティに対する Repository インタフェース
public interface TodoRepository extends JpaRepository<Todo, Long> {
    List<Todo> findByCompletedDateIsNotNull();
}
打开说明。
这是一个使用Spring Data JPA与数据库进行交互的仓库接口。通过创建该接口,您可以轻松实现基本的CRUD操作(创建、读取、更新、删除)以及根据特定条件获取数据。元素 说明
声明TodoRepository接口 TodoRepository接口扩展了JpaRepository接口。JpaRepository是Spring Data JPA提供的基本存储库接口,包含了基本的CRUD操作。

泛型类型参数 在扩展JpaRepository时,需要指定泛型类型参数为实体类的类型(Todo)和实体的主键类型(Long)。

声明findByCompletedDateIsNotNull方法 该方法用于获取completedDate字段非空(即已完成任务)的Todo实体。根据findByCompletedDateIsNotNull的命名规则,Spring Data JPA会自动生成查询并执行相应的数据库操作。

创建 Application 类和 Controller 类

创建一个Application类。

$ vim src/main/java/com/example/springboot/Application.java

文件的内容

package com.example.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;

@EntityScan("com.example.springboot.*")
@EnableJpaRepositories("com.example.springboot.*")
@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@EntityScan(“com.example.springboot.*”) 用于指定实体类的包。将扫描指定包内的实体类,并进行与数据库的映射。@EnableJpaRepositories(“com.example.springboot.*”) 用于指定Spring Data JPA Repository的包。将启用指定包内的Repository,并提供用于数据库操作的方法。

@SpringBootApplication 指定为Spring Boot应用程序的入口点。通过此注释,将进行Spring Boot应用程序的配置和组件扫描。

@EnableAsync 是用于支持Spring Framework应用程序中的异步处理的注释。

创建一个名为TodoController的类。

$ vim src/main/java/com/example/springboot/TodoController.java

文件的内容

package com.example.springboot;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.example.springboot.model.Todo;
import com.example.springboot.model.TodoRepository;

@CrossOrigin( // CORS 設定:適切に修正してください。
    origins = "*", 
    methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE }
)
@RestController
@RequestMapping("/todos")
public class TodoController {

    private final TodoRepository _todoRepository;

    public TodoController(TodoRepository todoRepository) {
        _todoRepository = todoRepository;
    }

    // すべての ToDo アイテムを取得します。
    @GetMapping
    @Async public CompletableFuture<List<Todo>> getAllTodos() {
        List<Todo> todos = _todoRepository.findAll();
        return CompletableFuture.completedFuture(todos);
    }

    // 完了した ToDo アイテムを取得します。
    @GetMapping("/complete")
    @Async public CompletableFuture<List<Todo>> getCompleteTodos() {
        List<Todo> todos = _todoRepository.findByCompletedDateIsNotNull();
        return CompletableFuture.completedFuture(todos);
    }

    // ID で ToDo アイテムを取得します。
    @GetMapping("/{id}")
    @Async public CompletableFuture<Optional<Todo>> getTodo(@PathVariable String id) {
        Optional<Todo> todo = _todoRepository.findById(Long.parseLong(id));
        return CompletableFuture.completedFuture(todo);
    }

    // 新しい ToDo アイテムを追加します。
    @PostMapping
    @Async public CompletableFuture<Todo> createTodo(@RequestBody Todo todo) {
        todo.setCreatedDate(new Date());
        return CompletableFuture.completedFuture(_todoRepository.save(todo));
    }

    // 既存の ToDo アイテムを更新します。
    @PutMapping("/{id}")
    @Async public CompletableFuture<Todo> updateTodo(@PathVariable String id, @RequestBody Todo todo) {
        Optional<Todo> exist = _todoRepository.findById(Long.parseLong(id));
        if (exist.isPresent()) {
            Todo target = exist.get();
            target.setContent(todo.getContent());
            target.setCompletedDate(todo.getCompletedDate());
            return CompletableFuture.completedFuture(_todoRepository.save(target));
        }
        return CompletableFuture.completedFuture(null);
    }

    // ID で ToDo アイテムを削除します。
    @DeleteMapping("/{id}")
    @Async public CompletableFuture<Void> deleteTodo(@PathVariable String id) {
        _todoRepository.deleteById(Long.parseLong(id));
        return CompletableFuture.completedFuture(null);
    }
}
以下是原文的中文摘要:@CrossOrigin:用于设置CORS(跨源资源共享)的配置。指定允许来自不同源的请求的源和允许的HTTP方法。
RequestMethod:用于将控制器方法映射到特定的HTTP方法。
@RestController:用于指示该类是一个控制器类。用于提供处理HTTP请求的端点。
@RequestMapping(“/todos”):指定类级别的请求映射。此控制器内的端点将映射到/todos路径。
@GetMapping:指定对HTTP GET请求的处理程序方法。当在/todos端点收到请求时,将执行getAllTodos()方法。
@PostMapping:指定对HTTP POST请求的处理程序方法。当添加新的ToDo项目时,将执行createTodo()方法。
@PutMapping:指定对HTTP PUT请求的处理程序方法。当更新现有的ToDo项目时,将执行updateTodo()方法。
@DeleteMapping:指定对HTTP DELETE请求的处理程序方法。当删除ToDo项目时,将执行deleteTodo()方法。
@RequestBody:用于将从HTTP请求的请求主体部分发送的数据映射到Java对象中。用作控制器方法的参数,将请求主体部分的数据转换为Java对象并提供。
@PathVariable:用于将URL路径中的变量部分作为方法的参数接收。例如,在类似/todos/{id}的URL中,可以使用@PathVariable注释获取{id}部分的值作为方法的参数。
@Async:用于声明异步方法。表示该方法将以异步方式执行,利用了Spring Framework提供的异步处理功能。
CompletableFuture:Java的标准库提供的一个类,用于简化异步编程和处理异步操作结果的机制。

添加Spring Boot的配置文件

创建application.properties文件。

$ mkdir -p src/main/resources
$ vim src/main/resources/application.properties

文件的内容

spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}
spring.jpa.show-sql=false
打开说明。元素
说明

spring.datasource.url
指定连接数据库的URL。使用占位符${DB_HOST}、${DB_HOST}、${DB_PORT}和${DB_NAME}等,实际值从环境变量获取。

spring.datasource.username
指定连接数据库所使用的用户名。使用占位符${DB_USER},实际值从环境变量获取。

spring.datasource.password
指定连接数据库所使用的密码。使用占位符${DB_PASSWORD},实际值从环境变量获取。

spring.jpa.show-sql
指定是否显示通过JPA执行的查询日志。在这个示例中,它被设置为false,不会显示查询日志。

创建 pom.xml

创建pom.xml文件。

$ vim pom.xml

文件的内容 de

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>restapi-spring-boot</artifactId>
    <version>1.0</version>
    <name>restapi-spring-boot</name>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>javax.persistence-api</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
打开说明。要素
说明

modelVersion
指定Maven模型的版本。通常指定为4.0.0。

parent
指定此项目的父项目。spring-boot-starter-parent是Spring Boot项目的父项目,其中包含版本信息和构建设置。

groupId、artifactId、version、name
指定项目的Maven组ID、Artifact ID、版本和项目名称。

properties
指定整个项目中使用的属性。例如,可以在此处设置Java版本和项目的编码。

dependencies
指定项目依赖的库(依赖关系)。使用每个depependency标签指定库的信息。在该项目中,指定了用于Spring Boot Web开发所需的依赖关系(spring-boot-starter-web,spring-boot-starter-data-jpa),以及与JPA相关的类和接口(javax.persistence-api),与MySQL数据库连接相关的依赖关系(mysql-connector-java),以及Lombok库(lombok)。

build
指定与构建相关的设置。其中包含项目的最终名称和构建插件的设置。在该项目中,指定了使用spring-boot-maven-plugin来构建Spring Boot应用程序的设置。

启动应用

创建环境变量。

export DB_HOST=localhost
export DB_PORT=3306
export DB_NAME=db_todo
export DB_USER=root
export DB_PASSWORD=password
请注意这个环境变量是暂时性的。

打开应用程序。
※ 停止应用程序时,请按下 ctrl + C。

在这个例子中,应用程序将监听端口号设置为5000并启动。
$ mvn spring-boot:run \
    -Dspring-boot.run.arguments="--server.port=5000"
通过这些步骤,您可以在Ubuntu上启动应用程序。

应用程序的操作确认

在终端上使用curl命令进行确认

如果需要的话,安装jq工具。
$ sudo apt update
$ sudo apt install jq

获取:/todos终点的操作确认

获取所有的待办事项。

$ curl -s http://localhost:5000/todos | jq '.'

回应

[
// 省略
  {
    "id": "3",
    "content": "運動する",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": "2023-08-23T05:15:08.000+00:00"
  },
  {
    "id": "4",
    "content": "本を読む",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": null
  },
  {
    "id": "5",
    "content": "請求書を支払う",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": null
  },
// 省略
我能够获取所有的待办事项。

确认 /todos/complete 终端点的操作

获取已完成的待办事项。

$ curl -s http://localhost:5000/todos/complete | jq '.'

响应

[
  {
    "id": "1",
    "content": "食材を買う",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": "2023-08-23T05:15:08.000+00:00"
  },
  {
    "id": "2",
    "content": "報告書を仕上げる",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": "2023-08-23T05:15:08.000+00:00"
  },
  {
    "id": "3",
    "content": "運動する",
    "created_date": "2023-08-23T05:15:08.000+00:00",
    "completed_date": "2023-08-23T05:15:08.000+00:00"
  }
]
我可以获取已完成的待办事项。

请求:/todos/{id}端点的操作确认

使用ID获取待办事项项。

$ curl -s http://localhost:5000/todos/8 | jq '.'

回复/响应

{
  "id": "8",
  "content": "コードを書く",
  "created_date": "2023-08-25T03:12:38.000+00:00",
  "completed_date": null
}
我能够使用 ID 获取 ToDo 项目。

发帖:/todos 确认端点的操作

添加新的待办事项。

$ curl -s -X POST http://localhost:5000/todos \
    -H 'Content-Type: application/json; charset=utf-8' \
    -d \
'{
    "content": "昼寝をする"
}' | jq '.'

回应

{
  "id": "9",
  "content": "昼寝をする",
  "created_date": "2023-08-31T10:47:09.657+00:00",
  "completed_date": null
}
可以添加新的待办事项。

在中国的本土化的环境下,将以下内容进行释义:
对于 /todos/{id} 这个端点,需要进行操作确认。

更新现有的待办事项。

$ curl -s -X PUT http://localhost:5000/todos/9 \
    -H 'Content-Type: application/json; charset=utf-8' \
    -d \
'{
    "content": "窓を開ける"
}' | jq '.'

回應

None (※なし)
回应为 None,但是当查看数据库表时,可以发现相应记录已经被更新了。

删除:/todos/{id} 终端点的操作验证。

使用ID来删除待办事项。

$ curl -s -X DELETE http://localhost:5000/todos/9 | jq '.'

回应

None (※なし)
回应是None,但是在检查数据库表后发现目标记录已被删除。
通过以上步骤,我们成功地在应用程序中实现了最小限的CRUD操作的REST API。

创建容器镜像

创建 Dockerfile。

$ vim Dockerfile

文件的内容 de

# build the app.
FROM openjdk:17-jdk-slim as build-env

# set the working dir.
WORKDIR /app

# install build tools and libraries.
RUN apt-get update && apt-get install -y maven

# copy source code to the working dir.
COPY . .

# build the app.
RUN mvn clean package

# set up the container.
FROM debian:12-slim

# set the working dir.
WORKDIR /app

# install the openjdk-17-jre-headless and clean up unnecessary files.
RUN apt-get update && \
    apt-get install -y --no-install-recommends openjdk-17-jre-headless && \
    apt-get autoremove -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# set environment variables.
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/jre
ENV PATH=$PATH:$JAVA_HOME/bin

# copy the built app from the build-env.
COPY --from=build-env /app/target/*.jar app.jar

# expose the port.
EXPOSE 8080

# command to run the app using java.
ENTRYPOINT ["java","-jar","app.jar"]
打开说明。元素说明

作为构建环境的基础镜像,使用OpenJDK 17的JDK版本。

将工作目录设置为/app。

使用apt-get update命令更新软件包信息,并通过apt-get install -y maven命令安装构建所需的Maven软件包。

将源代码和pom.xml文件复制到工作目录中。

使用Maven构建应用程序。mvn clean package命令将清理项目并构建软件包。

作为运行容器的基础镜像,使用debian 12的精简版本。

将工作目录设置为/app。

使用apt-get update命令更新软件包信息,并通过apt-get install -y –no-install-recommends openjdk-17-jre-headless命令安装Java 17的JRE(无头版)。通过添加–no-install-recommends选项来指定不安装推荐的软件包。然后,清理不需要的文件以减小镜像大小。

设置JAVA_HOME环境变量,指示Java的安装目录为/usr/lib/jvm/java-17-openjdk-amd64/jre。

将Java的可执行文件路径添加到PATH环境变量中。

将build-env阶段构建的JAR文件复制到运行容器的工作目录中。

指示容器向外部公开端口8080。

指定容器启动时要执行的命令。通过使用java -jar app.jar命令以Java运行JAR文件来运行应用程序。

启动Docker守护进程。

$ sudo service docker start
 * Starting Docker: docker    [ OK ]
如果您没有Docker环境,请参考下面的相关文章了解Docker Engine的安装步骤。

 

构建容器映像。

$ docker build \
    --no-cache \
    --tag api-todo-spring-boot:latest .

我会检查容器镜像。

$ docker images | grep api-todo-spring-boot
api-todo-spring-boot    latest    01ee6f4a47ac    9 seconds ago    340MB
通过以上步骤,您可以在本地环境的 Docker 上构建应用的自定义容器映像。

启动容器

在本地启动容器。
※ 停止容器时,请按下 Ctrl + C。

请事先创建名为 net-todo 的 Docker 网络以进行容器间通信。请注意。
$ docker run --rm \
    --publish 5000:8080 \
    --name api-local \
    --net net-todo \
    --env DB_HOST=mysql-todo \
    --env DB_PORT=3306 \
    --env DB_NAME=db_todo \
    --env DB_USER=root \
    --env DB_PASSWORD=password \
    api-todo-spring-boot
通过以上步骤,我们能够在本地环境中使用 Docker 启动应用程序的自定义容器。

容器操作验证

我們將從另一個終端機使用curl命令來進行確認。
* 通過ID檢索待辦事項項目。

$ curl -s http://localhost:5000/todos/8 | jq '.'

回应

{
  "id": "8",
  "content": "コードを書く",
  "created_date": "2023-08-25T03:12:38.000+00:00",
  "completed_date": null
}
在上述步骤中,终端显示了响应并成功获取了JSON数据。

我来检查一下集装箱的状态。

$ docker ps
CONTAINER ID   IMAGE                  COMMAND                   CREATED          STATUS          PORTS                                                  NAMES
3534c2e3a94f   api-todo-spring-boot   "java -jar app.jar"       35 seconds ago   Up 34 seconds   0.0.0.0:5000->8080/tcp, :::5000->8080/tcp              api-local
63a3acec271c   mysql-base             "docker-entrypoint.s…"   8 days ago       Up 51 minutes   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql-todo

连接到容器

从另一个终端连接到容器。

$ docker exec -it api-local /bin/bash

在连接到容器后,请确认目录。
※ 当退出容器时,请按下ctrl + D。

# pwd
/app
# ls -lah
total 40M
drwxr-xr-x 1 root root 4.0K Aug 31 11:23 .
drwxr-xr-x 1 root root 4.0K Aug 31 11:29 ..
-rw-r--r-- 1 root root  40M Aug 31 11:23 app.jar

使用top命令查看当前情况。

# apt update
# apt install procps
# top
top - 11:31:27 up  4:05,  0 user,  load average: 0.21, 0.17, 0.14
Tasks:   3 total,   1 running,   2 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.8 us,  0.3 sy,  0.0 ni, 98.8 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
MiB Mem :   7897.1 total,   1299.0 free,   3898.0 used,   2996.1 buff/cache
MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.   3999.1 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    1 root      20   0 6945900 345012  23520 S   0.0   4.3   0:15.19 java
   59 root      20   0    4188   3332   2820 S   0.0   0.0   0:00.02 bash
  249 root      20   0    8560   4548   2664 R   0.0   0.1   0:00.00 top

让我们来显示容器的信息。

# cat /etc/*-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
这个容器是基于Debian GNU/Linux创建的。也就是说,可以像Debian GNU/Linux一样操作它。

附赠:Swagger 装备

添加库

将 springdoc-openapi 库添加到 pom.xml 中。

$ vim pom.xml

文件的内容

<!-- 省略 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
+   <dependency>
+       <groupId>org.springdoc</groupId>
+       <artifactId>springdoc-openapi-ui</artifactId>
+       <version>1.7.0</version>
+   </dependency>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
<!-- 省略 -->

查看Swagger

在Web浏览器中确认Swagger的URL。

http://localhost:5000/swagger-ui/index.html
image.png
通过利用这些工具,可以更便捷地操作 API。

总结

在 WSL Ubuntu Docker 环境中,我成功实现了一个最小的Java Spring Boot API。

请注意,本文的实际案例仅为一种方法,并不一定是正确的方法。还有许多其他多样的方法可供选择,请综合各种信息进行考虑。

你觉得怎样?在WSL Ubuntu上,你可以轻松地启动Java Spring Boot Web应用程序。请务必试一试。我们还会继续介绍Spring的开发环境等,敬请期待。

推荐内容

 

bannerAds