极简 Java 入门

极简 Java 入门

概述

语言的学习

很多人说“我要学习 Python”,但如果深入问一句:“你是想用 Python 做什么?”这时候答案往往就会变得具体起来——有人是为了做 AI,有人是为了数据处理,有人是为了 Web 开发。如果没有明确的回答,这门语言大概率无法顺利地学下去,学习外语也是这样。在具体场景中使用一门语言发挥生产力,实际上要是掌握它在各个领域的应用场景、业务流程和最佳实践。拿 Python 举例:

  • 如果是做 AI 的,重点可能在 PyTorch、JAX、Transformers 等深度学习框架;
  • 如果是搞数据分析的,可能围绕 pandas、NumPy、matplotlib、Scikit-learn;
  • 做 Web 的,会涉及 Django、Flask、FastAPI;
  • 自动化脚本、爬虫、数据处理、脚本化工具也是 Python 的强项。

当然,光去记住这些库的说明书,对于理解这个库其实也没有什么帮助,尤其是现在有了大模型的情况下,关键是要理解整个流程。在这种背景下,一种比较高效的学习路径是:

先快速建立基本图像,然后基于某个具体应用方向纵向跑通业务流程,最后在横向拓展功能的过程中,逐渐掌握更多语言细节。

Java 应用

Java 最典型的标签就是“企业级开发”。换句话说,Java 的主战场是中后台系统、Web 服务、微服务架构、大型分布式系统

Java 生态中最核心的技术栈就是:

Spring 全家桶(Spring Framework、Spring Boot、Spring MVC、Spring Cloud)

Spring 系列提供了企业开发中几乎所有需要的能力:控制反转(IoC)、依赖注入(DI)、Web 框架、数据库访问、安全认证、分布式配置、服务注册与发现、微服务通信、消息中间件等。

除了 Spring 生态,Java 在以下领域也有成熟的支持:

领域 技术栈
持久化(ORM) Hibernate、JPA、MyBatis
构建工具 Maven、Gradle
单元测试 JUnit、Mockito
Web 应用 Spring Boot、Jakarta EE、Servlet
微服务 Spring Cloud、Dubbo
安全认证 Spring Security、OAuth2
前后端接口通信 RESTful API、JSON、Jackson、Feign
云原生 Spring Cloud + Kubernetes、Spring Boot Docker 化部署
运维监控 Actuator、Micrometer、Prometheus

总之,学习 Java,最重要的不只是掌握它的语法,而是理解它在“企业级应用”这条主航道上的生态布局,尤其是围绕 Spring 为核心的一整套解决方案。所以,与其去啃厚重的语法教程,不如从一个简单的 Spring Boot 项目入手,跑通第一个接口,理解 MVC 流程,再逐步拓展数据库访问、配置管理、接口返回、安全控制等功能,然后更多地熟悉这个语言。

Java 底线知识

语言类型

按程序的执行方式划分,编程语言大致可以分为三类:

  • 🟡 解释型语言

    如 Shell、Python,这类语言不需要预先编译,源代码由解释器逐行读取并执行。因为不直接和系统底层打交道,跨平台能力很强,开发调试也很灵活。不过也因此牺牲了部分执行效率。例如运行 Python 脚本时,其实是 Python 解释器在实时翻译并执行代码。

  • 🔵 编译型语言

    如 C、C++,编写好的源码需要通过编译器编译成特定平台的机器码,生成 .exe.out 文件,才能执行。这类语言的优势是运行效率高、控制能力强,但每个平台都需要重新编译一次,跨平台不太友好。

  • 🟩 中间型语言 / 混合型语言

    代表语言有 Java 和 C#,这类语言先将源码编译为一种平台无关的“中间语言”格式(如 Java 字节码、C# 的 IL),再由虚拟机运行。这样既保持了一定的跨平台能力,又能通过虚拟机的优化(如 JIT)获得不错的执行效率。

Java 是中间型语言的典型代表,它的执行流程大致如下:

  1. 开发者编写 .java 源代码;
  2. 使用 JDK 中的 javac 命令将源码编译为 .class 文件,其中包含了 Java 的 字节码
  3. 执行 java 类名(如 java HelloWorld),由 JVM(Java 虚拟机) 加载 .class 文件,并执行其中的字节码。

Java 虚拟机会将字节码逐条解释执行,也可能通过 JIT(即时编译) 技术将热代码优化为机器码,提高性能。

这一模式让 Java 实现了它的核心口号:

Write Once, Run Anywhere(一次编写,到处运行)

只要系统中安装了 JVM,不论是 Windows、Linux 还是 macOS,都可以运行相同的 .class 文件,无需重新编译。当然,在实际开发中,我们不会每次都手动敲 javacjava。这就像我们不会在每个 Node.js 项目里手动用 node.js 文件,而是用 npm run dev 启动前端服务、用 vite 创建 Vue 项目、或者用 webpack 进行构建打包。

Java 也有类似的构建工具,常见的有 Maven 和 Gradle,它们可以帮助我们自动编译 Java 代码、管理依赖(比如引入第三方库)、打包成可运行的 .jar 文件、执行单元测试、部署、生成文档等。构建工具在实际项目中非常关键,不过我们可以先了解 Java 的语言机制和基本运行方式,后续再深入 Maven 等工具的使用。

JDK 和 JRE

在使用 Java 进行开发时,两个最常被提到的组件是 JDK(Java Development Kit)JRE(Java Runtime Environment)。它们虽然经常一起出现,但其实职责不同:

  • JRE 是“运行环境”:它包含了 Java 虚拟机(JVM)和 Java 标准类库,目的是让你能够运行 .class 文件(字节码)。
  • JDK 是“开发工具包”:它包含了 JRE,同时还额外提供了编译器 javac、调试器、打包工具等,目的是为了编写和构建 Java 程序。

比如我们写了一个最简单的 HelloWorld.java 程序(具体的语法后面再介绍):

1
2
3
4
5
6
7
// HelloWorld.java

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

这个程序的执行流程分为两步:

  1. 使用 JDK 提供的编译器,将源码编译为字节码:

    1
    javac HelloWorld.java

    这会生成一个 HelloWorld.class 文件,里面是 Java 的中间表示(字节码)。

  2. 使用 Java 虚拟机运行字节码:

    1
    java HelloWorld

    控制台就会输出:

    1
    Hello World!

所以简单来说,JRE 是“跑 Java 程序”的工具,JDK 是“写 Java 程序”的工具。由于 JDK 本身就包含了完整的 JRE,我们在安装 Java 时只需要安装 JDK 就足够了。反过来,如果只安装了 JRE,就没法编译 .java 文件(因为它没有 javac),也就无法完整开发 Java 程序。

在安装了 JDK 后,有一个非常重要的系统变量叫做 JAVA_HOME,它的作用是告诉操作系统和各种工具,JDK 安装在哪里。比如像 Maven、Gradle、IDEA、Eclipse 等工具,都会通过读取 JAVA_HOME 变量来找到正确的 javajavac 命令。我们在安装了 JDK 后,需要新建一个把这个变量设置为我们的安装目录,比如 C:\Program Files\Java\jdk-17

JAR 包

Java 程序在开发完成并编译成 .class 文件后,通常会进一步打包成一种特殊格式 —— JAR 包(Java ARchive),这是 Java 世界中最常见的打包形式。JAR 本质上是一个压缩文件(类似 .zip),它可以包含:

  • 编译好的 .class 字节码;
  • 程序依赖的资源文件(如配置文件、图片等);
  • 一个 MANIFEST.MF 文件,用于定义元信息,比如程序入口类
  • 可选的第三方依赖。

作用类似于 Python 中的 .whl 文件、Node.js 的 npm 包,用于程序分发、部署、共享。

Java 概念 类比 Python 中的概念
.class 文件 .pyc 字节码文件
.jar .whl 包(wheel),或 .pyz 可执行包
manifest setup.py 中的 entry_points__main__.py
mvn package python setup.py sdist / pip install .
第三方 jar Python 的依赖库(如 numpy.whl)

继续以上例子,我们已经有一个 HelloWorld.class 文件,现在我们希望把它打包成一个可运行的 jar 包。

步骤 1:编写 manifest 文件

新建一个 manifest.txt,写入以下内容,指定程序入口类:

1
Main-Class: HelloWorld

之所以要这个东西,是因为一个 JAR 包中可以包含多个文件和多个公共类,而每个类理论上都可以有自己的 main() 方法(入口点)。所以 JVM 并不知道我们到底想运行哪个类作为“主程序”。这个文件,会被传递给 jar 命令,在 JAR 包里生成 META-INF/MANIFEST.MF 文件,用于描述 JAR 包的入口。当然,假如我们只写了一堆工具类,别人只会 import 我们的类,而不是直接运行我们的 JAR 包,那么也就不需要这个文件了。

步骤 2:打包

使用 Java 自带的 jar 命令进行打包:

1
jar cfm HelloWorld.jar manifest.txt HelloWorld.class

解释:

  • c:create(创建)
  • f:file(输出到文件)
  • m:manifest(使用自定义 manifest)

这会生成一个 HelloWorld.jar 包。

步骤 3:运行 jar 包

1
java -jar HelloWorld.jar

输出:

1
Hello World!

JAR 包可以把项目代码打成一个独立的应用(类似 Python 的 pyz),就像 Python 的 wheel 包一样,Java 的第三方库也几乎都是以 .jar 的形式分发的。多个 jar 可以组成一个大项目,像拼装积木一样。比如我们在使用 Spring Boot、Gson、Lombok 等库时,实际上它们的核心就是 .jar 包,只是通过 Maven 自动下载和管理而已。

Java 语法常识

Java 的语法和 C、C++ 十分类似,甚至对熟悉 C++ 的人来说,Java 的基础语法几乎可以直接读懂。但对于初学 Java 的开发者来说,仍有一些看起来“神秘”但实际很有逻辑的规则,尤其是关于类、方法、文件结构等。我们通过一个最简单的 Hello World 程序来逐步分析:

1
2
3
4
5
6
7
// HelloWorld.java

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

☝️ 第一:所有代码必须写在类中

Java 是一个 “纯面向对象” 的语言。和 Python 不同,Python 中我们可以在模块的最外层直接写表达式或函数:

1
print("Hello World!")  # 顶层语句,不需要类

而 Java 中,所有代码必须写在类或接口中,包括程序的入口函数。这是 Java 语言设计的基本原则。哪怕只是输出一行文字,也必须“包裹在类里”才能编译运行。

✌️ 第二:.java 文件只能有一个 public 类,且文件名必须与其一致

在 Java 中,一个 .java 文件中可以包含多个类,但最多只能有一个 public。而且这个 public 类的名称必须与文件名完全一致(大小写敏感)。

比如:

  • 如果类名是 HelloWorld,文件名必须是 HelloWorld.java
  • 否则会报错:类 HelloWorld 是公共的,应在名为 HelloWorld.java 的文件中声明

🤟 第三:main 方法是 Java 程序的入口

1
public static void main(String[] args)

这是 Java 程序的标准入口方法,JVM 在执行一个类时,会自动从这个方法开始执行。

  • public:必须公开,JVM 才能访问;
  • static:不依赖对象就能运行(因为入口方法是在没有类实例的情况下运行的);
  • void:方法不返回任何值;
  • String[] args:命令行参数传入数组。

如果一个类中没有包含这个方法,运行它时就会报错:

1
2
错误: 在类 HelloWorld 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)

✋ 第四:Java 的包与目录结构强绑定,导入类而非文件

在实际开发中,我们不可能所有代码都写在一个类里,会有多个 .java 文件。此时,就需要引入 Java 的包机制(package)来管理代码结构。

假设我们有如下目录结构:

1
2
3
4
comac/
│── HelloWorld.java
└── submodule/
└── Person.java

此时,Java 要求:

  • HelloWorld.java 中必须指定包名为:

    1
    package comac;

  • Person.java 中必须指定包名为:

    1
    package comac.submodule;

包名必须严格匹配目录结构(以根目录为起点),否则编译会报错。

🙌 使用 import 导入类,而不是导入文件

与 Python 不同,Java 的 import 是用来导入类或整个包中的类,而不是导入文件名。

假设在 Person.java 中写了一个类:

1
2
3
4
5
6
7
8
// comac/submodule/Person.java
package comac.submodule;

public class Person {
public void sayHello() {
System.out.println("Hi, I am a Person.");
}
}

要在 HelloWorld.java 中使用这个类,需要:

1
2
3
4
5
6
7
8
9
10
11
// comac/HelloWorld.java
package comac;

import comac.submodule.Person;

public class HelloWorld {
public static void main(String[] args) {
Person p = new Person();
p.sayHello();
}
}

也可以使用通配符一次导入一个包下的所有类:

1
import comac.submodule.*;

但不能像 Python 那样 import person 或导入整个文件——Java 的 import按类名来的,不是按文件名。

🔐 Java 中的访问权限与包结构关系

Java 对“类能否被访问”有一套清晰且严格的规则。前面也提到过了,Java 强制要求:

  • 每个文件最多有一个 public 类;
  • public 的类在“包内可见”,包外隐藏。

这种设计体现了 Java 的模块化思想:每个 .java 文件就是一个明确的“编译单元”,它对外只暴露一个清晰的“公共接口”。public 类相当于模块的“入口”,是我们愿意暴露给外部使用的部分;其他 default 类,则是模块内部的“实现细节”,不鼓励外部直接依赖。这种结构帮助 Java 项目在复杂工程中保持清晰的依赖边界。

需要注意的是,默认类只能在“同一包内”访问,即使是在“子包”中也不能访问!假设我们有如下结构:

1
2
3
4
5
6
src/
└── com/
└── example/
├── HelloWorld.java // 包:com.example
└── utils/
└── Helper.java // 包:com.example.utils

文件内容如下:

1
2
3
4
5
6
7
8
9
10
// com/example/HelloWorld.java
package com.example;

import com.example.utils.Helper; // ❌ 无法访问 Helper

public class HelloWorld {
public static void main(String[] args) {
Helper h = new Helper(); // 编译失败:Helper 不是 public
}
}
1
2
3
4
5
6
7
8
// com/example/utils/Helper.java
package com.example.utils;

class Helper {
void sayHi() {
System.out.println("Hi from Helper");
}
}

虽然两个类文件目录上是“父子关系”,但包名不同 → 它们是完全不同的命名空间。default 权限只在“同一个包”里有效。

Maven

前面我们提到了,项目的包结构、用 JDK 编译、用 JRE 运行,以及管理第三方依赖等,如果每次都靠手动操作是非常繁琐且容易出错的。好在 Java 社区为此发展出了一套标准化的构建工具,最常用的就是:

工具 构建描述文件 特点说明
Maven pom.xml 最主流的构建工具,强调约定优于配置
Gradle build.gradle 语法更现代(基于 Groovy 或 Kotlin)

这两个工具可以自动生成标准的项目结构、编译项目源代码、管理和自动下载第三方依赖、运行测试用例、打包为可执行 JAR/WAR、甚至还支持部署和发布版本。相比来说,Maven 使用的更加广泛,Maven 使用 pom.xml 来配置项目的元信息以及管理依赖。如果我们之前接触过 Node 项目,可以这样理解:

npm 命令 Maven 对应
npm create vite mvn archetype:generate
npm install 自动解析 pom.xml 中依赖并下载
package.json pom.xml
node_modules(局部依赖) .m2 目录(全局依赖缓存)

不过与 npm 不同,Maven 并不是每个项目都保留一份依赖副本,而是把所有下载的依赖统一保存在用户主目录的 .m2/repository/ 目录中,所有项目共享使用。可以通过设置 .m2/settings.xml 自定义这个缓存目录:

1
2
3
<settings>
<localRepository>D:/my-maven-cache</localRepository>
</settings>

Maven 初次执行时会联网下载构建工具本身的插件和模板,比如生成项目结构需要 maven-archetype-plugin,编译代码需要 maven-compiler-plugin,它们都来自 Maven 官方中央仓库,以后构建就不需要重新下载了。这些工具基本上都是 JAR 包及其相对应的 .pom 文件:

文件类型 示例文件名 含义 用途
.jar maven-compiler-plugin-3.10.1.jar Java 的二进制包 这是插件/库的真正可执行代码
.pom maven-compiler-plugin-3.10.1.pom 项目的元信息(Project Object Model) 描述该 jar 包的依赖、作者、版本等信息

Maven 的依赖管理是基于 POM 文件构建的“依赖树”,Maven 首先读取 .pom 文件来知道这个 jar 依赖了哪些 jar(传递依赖),需要哪些插件协助编译/运行,然后才去下载 .jar 本体和它依赖的 jar。所以,没有 .pom,Maven 无法知道构建图谱,也就无法自动化下载和解析依赖。我们后面可以通过 mvn install 来让 Maven 安装我们自己的项目到全局目录中,Maven 会自动生成项目的 .pom 文件。这整个流程其实和 Python 也很类似:

Java Maven Python
my-lib-1.0.jar my_lib-1.0-py3-none.whl
my-lib-1.0.pom setup.py or pyproject.toml
mvn install pip install .(安装到 site-packages)
发布到远程 Maven 仓库 发布到 PyPI

最简单的 Maven 项目

我们可以使用 Maven 的脚手架快速生成一个 Java 项目模板:

1
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

参数说明如下表所示:

参数名 含义
groupId 包名/组织名(约定域名反写,确保包名在全球范围不冲突。如果公司官网是 www.comac.com,那么域名反写后就是 com.comac
artifactId 项目名(将成为生成 jar 的名字)
archetypeArtifactId 使用哪个模板构建(此处为最简模板)
interactiveMode=false 关闭交互式问答,直接生成

生成的目录结构大体如下所示,Maven 会默认把 src/main/java 当作项目源代码的根目录,因此 .java 文件中 package 字段都要以这个根目录节点开始算起:

1
2
3
4
5
6
7
8
9
10
11
my-app/
├── pom.xml ← Maven 配置文件
└── src/
├── main/
│ └── java/
│ └── com/mycompany/app/
│ └── App.java ← 主类
└── test/
└── java/
└── com/mycompany/app/
└── AppTest.java ← 测试类

App.java 默认是一个输出 Hello World! 的入口类,在项目根目录执行:

1
mvn compile

会将 .java 编译为 .class 文件,输出到:

1
2
target/classes/
└── com/mycompany/app/App.class

我们可以运行:

1
mvn exec:java -Dexec.mainClass=com.mycompany.app.App

来使用 Maven 的 exec 插件执行编译好的 .class 文件。如果我们没有在 pom.xml 中手动指定 exec 的插件版本,那么 Maven 会自动下载最新兼容版本的 exec 插件来执行这个命令。和之前一样,Maven 会下载相应的 JAR 包放到全局目录里。

我们也可以在 pom.xml 中进行打包相关的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version> <!-- 版本可以略有不同 -->
<configuration>
<archive>
<manifest>
<mainClass>com.mycompany.app.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

上面的配置指定了插件和入口类:

元素 作用
groupId 插件所属组织(通常是 Maven 官方)
artifactId 插件名称,这里是构建 JAR 的插件
version 插件的具体版本号
mainClass(在 manifest 中) 指定打包后 JAR 的程序入口类,用于 java -jar 启动

执行:

1
mvn package

会生成一个可执行的 JAR 文件:

1
target/my-app-1.0-SNAPSHOT.jar

用以下命令可以直接运行:

1
java -jar target/my-app-1.0-SNAPSHOT.jar

Spring Boot

有了上面的基本概念,我们就可以正式开始 Spring Boot 的开发实践了。

Spring 是一个庞大的 Java 开发生态系统,可以类比 Python 的科学计算生态。例如:

  • Python 的 NumPy 是底层基础,Pandas、Scikit-learn、Matplotlib 等都是在它上面构建的;
  • Java 的 Spring 也是底层框架,围绕它构建了众多子项目,比如 Spring Boot、Spring Security、Spring Cloud、Spring Data 等等。

Spring 本质上是一种组件式开发框架,它提供了 IoC(控制反转)容器、AOP(面向切面编程)、统一配置和资源管理机制、声明式事务管理等基础能力。在这个基础之上,Spring 团队和社区开发了大量用于特定场景的组件:

框架 用途
Spring Boot 快速构建独立、可部署的 Spring 应用
Spring Security 安全框架,处理认证、授权、加密等
Spring Data JPA 数据访问抽象,简化数据库交互
Spring Cloud 构建分布式微服务系统
Spring Batch 大批量数据处理
Spring WebSocket 实现实时通信
... ...

其中,Spring Boot 是 Spring 家族中最受欢迎的子项目之一,它的设计目标就是为了大幅简化 Spring 应用的创建、配置和部署。如果是第一次接触 Spring Boot,可以将它理解为一个“快速开发的 Web 框架”,它通过约定大于配置的方式,封装了大量 Spring 的繁琐配置,降低了开发门槛。使用 Spring Boot,有几个明显优势:

  • 可以一键启动应用,不再需要部署到外部的 Tomcat 或 WebLogic;
  • 内置了常用中间件和技术栈的整合方案(如 Web、JPA、Redis、Security 等);
  • 通过 Starter 和自动装配机制,按需添加依赖,按需激活功能
  • 提供了大量运维工具,比如应用健康检查、日志、监控接口(Actuator);
  • 支持热部署、命令行运行、Docker 化部署、Kubernetes 集成等现代开发方式。

所以说,Spring Boot 就像是为 Java 后端开发者准备的一整套后端“车间”:一旦搭好结构,就可以专注在业务逻辑本身,无需为框架拼装浪费太多时间。

我们先不考虑什么复杂的应用,假如我们就要开发一个最简单的 Web 服务,访问 / 返回 Hello World!

在 Flask 中,我们只需要写几行代码:

1
2
3
4
5
6
7
8
9
10
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

if __name__ == "__main__":
app.run()

Flask 自动帮我们完成了 HTTP 服务器的搭建、请求处理流程、路由注册等任务,非常轻量。

那使用 Spring Boot 完成相同的功能,需要做哪些工作呢?

项目初始化

首先,我们可以在 start.spring.io 网站上通过 Spring Initializr 工具初始化我们的 Spring 项目。这一步就像是为我们预先打包好一个标准化的工程骨架。在初始化页面中,我们选择语言为 Java,构建工具为 Maven,Spring Boot 版本可选择稳定的 3.x 或尝试最新的 4.0.0 M1(里程碑版本)。然后填写项目信息,例如:

  • Group:com.comac.data(推荐使用公司域名反写形式)
  • Artifact:demo
  • Package name:com.comac.data.demo
  • Java 版本:24

接着在右侧“Dependencies”中添加两个常用依赖:

  • Spring Boot DevTools:它是一种开发辅助工具,支持代码修改后自动重启应用,相当于 Flask 的 debug 模式;
  • Spring Web:提供了 Web MVC、REST API、JSON 转换等核心功能,是开发 Web 服务必备的模块。

点击 “Generate” 按钮后,即可下载生成的 Maven 项目源码包。解压后,我们可以看到一个符合 Maven 规范的标准 Java 项目结构。

项目结构

在标准的 Spring Boot Web 项目中,通常会有如下几个核心部分。当然这里的内容已经超出了这个博客的原本范围,这里也只是让我自己有一个大致了解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
src/
└── main/
├── java/
│ └── com/comac/deta/demo/
│ ├── DemoApplication.java <-- 启动类(main)
│ ├── controller/
│ │ └── HelloController.java <-- 路由类(Controller)
│ ├── service/
│ │ └── HelloService.java <-- 业务逻辑类(Service)
│ └── repository/
│ └── HelloRepository.java <-- 数据访问类(DAO)
└── resources/
├── application.yml / .properties <-- 配置文件
└── static/、templates/ <-- 静态资源 / 页面模板

启动类:DemoApplication.java

1
2
3
4
5
6
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

该类包含 main() 方法,整个应用的启动入口,执行后会启动 Spring 容器、自动扫描所在包及子包的组件、启动内嵌服务器(Tomcat)。运行这个类之后,Spring Boot 就会在默认端口 8080 启动服务,我们的应用就上线了。如果我们在 Vscode 中要启动热更新,则还要开启 Java 的自动编译。我们可以在终端里执行:

1
mvn spring-boot:run

来启动应用,也可以在 Vscode 里直接点击 Run 来运行应用,它会调用 Java 来执行 .class 文件。

控制器类(Controller):路由处理器

1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("/hello")
public class HelloController {

@GetMapping
public String hello() {
return "Hello World!";
}
}

控制器类负责处理 HTTP 请求,类似 Flask 的 @app.route

  • @RestController = @Controller + @ResponseBody,默认返回 JSON 或字符串
  • @GetMapping / @PostMapping / @PutMapping / @DeleteMapping 映射到 HTTP 方法
  • @RequestMapping 可以统一设置路由前缀

这里的 @ 都是注解(Annotation),本质上和 Python 的装饰器类似,为类或方法添加元信息,供框架在运行时读取并处理。上面的 @RestController 的作用,就像 Flask-Restful 中的一个资源类。我们可以在这个类里用 @GetMapping@PostMapping 等注解开发对应 HTTP 方法的处理函数。

服务类(Service):业务逻辑层

1
2
3
4
5
6
@Service
public class HelloService {
public String getGreeting() {
return "Hello from Service!";
}
}
  • 放业务处理逻辑(如计算、合并数据、调用第三方 API)
  • 控制器中调用服务层方法来获取/处理数据
  • 使用 @Service 注解标记为 Spring 管理的组件

大概就是 Spring 提供了某些事件管理机制,@Service 就是告诉 Spring 这个类是处理业务逻辑的,Spring 会为他提供一些管理方法。在 Flask 的开发中,虽然我们也会大致分成 路由 -> 服务 -> 数据 这么三层,但是不需要通过注解告诉框架每个类的作用,因为 Flask 很轻量没有提供这些管理功能。

数据访问类(Repository / DAO):数据层(操作数据库)

1
2
3
4
5
6
@Repository
public class HelloRepository {
public List<String> findAllUsers() {
return List.of("Alice", "Bob", "Charlie");
}
}
  • 和数据库打交道的地方
  • 一般使用 Spring Data JPA、MyBatis、JDBC 等工具
  • @Repository 是 Spring 管理的持久层组件(带异常转换)

Spring 会明确这个类是数据访问层的,执行一些自动管理操作,比如自动将底层数据库异常转换到 Spring 的统一异常体系。

配置文件:全局设置(端口、数据库、日志等)

路径:src/main/resources/application.ymlapplication.properties

1
2
3
4
5
6
7
8
server:
port: 8081

spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456

听说推荐用依赖注入的方式读取,这个后面再慢慢总结。

静态资源

  • src/main/resources/static/:放图片、JS、CSS,浏览器可以直接访问
  • src/main/resources/templates/:放模板文件(如 Thymeleaf)

Hello World!

我们开发一个最简单的 Spring 项目,提供一个简单的问候接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.comac.data.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Hello World REST Controller
* 提供简单的问候接口
*/
@RestController
public class HelloController {
@GetMapping("/")
public String hello() {
return "Hello World!";
}
}

运行入口类后,访问 127.0.0.1:8080,就可以看到 Hello World! 了。