一、spring boot初始化

这些文件是借助 Spring Initializr 初始化项目时,官方自动生成的脚手架配套内容,用于适配 Maven、Git 版本管理等通用开发场景;其中一部分是刚需文件,一部分属于可选文件。
一、文件夹类
.mvn
- 作用:存放 Maven Wrapper 的配套配置。Maven Wrapper(也就是下文的
mvnw)可以让项目自带一套 Maven 版本,即便你的电脑本地没有安装 Maven、或者本地 Maven 版本不一致,其他人拿到项目也能依靠项目内置的 Maven 完成构建,规避本地环境差异引发的报错。 - 删除建议:可选删除。如果你本机已经配置好了适配的 Maven 环境,日常只会使用本地 Maven 进行构建,这个文件夹就可以删掉;团队成员本地 Maven 环境参差不齐的话,建议保留。
src
- 作用:项目代码主目录,是绝对不能删除 的核心目录
src/main/java:存放 Java 业务代码、Controller、实体类等;src/main/resources:存放配置文件、静态资源;src/test/java:单元测试代码。
二、Git 相关文件
.gitattributes
- 作用:Git 的配置文件,用来规范不同操作系统的换行符格式(Windows、Mac 换行标准不一样),避免跨系统提交代码出现大量无意义的换行改动,也可以设置不同文件的差异化处理规则。
- 删除建议:可选删除。如果你的项目压根不打算使用 Git 做版本控制,可以删掉;后续要用 Git 管理代码就建议保留。
.gitignore
- 作用:告诉 Git 哪些文件、文件夹不需要提交到代码仓库,典型过滤对象:
.idea(IDEA 专属配置)、编译产出 target 文件夹、本地配置、系统缓存文件等,避免 IDE 个性化配置、编译垃圾文件上传远程仓库。 - 删除建议:推荐保留,只有彻底不用 Git 的时候才删。
三、文档文件
HELP.md
- 作用:初始化自动生成的说明文档,里面记录 Spring Boot 入门帮助、常用参考链接,仅起到新手引导作用,运行项目完全不会读取这个文件。
- 删除建议:可以放心删除,绝大多数开发者建好项目之后就会删掉它,日常开发不会用到。
四、Maven Wrapper 脚本
mvnw(Linux/Mac 系统执行脚本)、mvnw.cmd(Windows 系统执行脚本)
- 作用:二者是 Maven Wrapper 的启动脚本:
mvnw适配 macOS、Linux;mvnw.cmd适配 Windows; 运行这两个脚本就会调用.mvn目录内置的 Maven 来打包、编译项目。
- 删除建议:跟随
.mvn一同取舍,本地自备 Maven 就可以一起删掉。
五、最核心不可删文件
pom.xml
- 作用:Maven 的核心配置文件,所有 Maven 依赖、插件、项目构建规则全部写在这里,之前配置的 web、lombok 等依赖都存放于此。
- 删除建议:严禁删除,删掉之后 Maven 就失去了项目依赖管理的能力,项目无法正常构建。
二、代码讲解
java
private Integer id;
选用Integer而非int的原因
1.先理清二者基础区别
(1)int是 Java 的基本数据类型,属于原生类型,默认初始值固定是0;
(2)Integer是int对应的包装类,属于引用类型,它可以赋值为null。
2.业务场景下选择 Integer 的核心理由(后端开发主流习惯):可以表达「字段不存在 / 数据库值为空」的情况(最关键)
数据库表里面的 id 字段允许设置NULL。
如果使用int id:数据库 id 为空时,Java 强制把初始值填充成0,你无法区分两种截然不同的业务情况:
① 用户真实 id 就是 0;② 数据库压根没有填入 id(空缺),会产生数据歧义;
如果使用Integer id:数据库为空时实体的 id 就接收null,可以精准识别出字段是空的状态,不会出现歧义。
java
private LocalDateTime time;
1. LocalDate
只保存年月日 ,例如 2025-11-20,不包含小时、分钟、秒这些时分秒细节。 适用场景:生日、入职日期、下单日期(只需要记录哪一天即可)。
2. LocalTime
只保存时分秒 ,例如 14:32:50,没有年、月、日信息。 适用场景:门店早晚上下班时刻、每日固定打卡时点。
3. LocalDateTime(正是代码要选用的)
二者进行组合,同时拥有年月日 + 时分秒,形如 2024-07-16 11:03:28,和你 txt 文件里2024-07-16 11:03:28这种完整时间格式完美匹配。
java
@Data
@NoArgsConstructor
@AllArgsConstructor
1. @Data(综合型注解,日常最常用)
它相当于批量一次性整合了好几类常用代码:
- 自动生成所有成员字段的
getter、setter方法; - 重写
toString(),打印实体对象时能够输出所有字段的取值,调试查看数据很便捷; - 重写
equals()与hashCode(),方便完成两个实体对象之间的相等判断; - 还会生成字段对应的 canGet/canSet 布尔方法适配部分框架。
适用场景:绝大多数普通实体类(比如你正在编写的 User 实体),打上这一个注解就省去手写一大堆 get、set、toString 代码的工作量。
2. @NoArgsConstructor:生成无参构造方法
- 作用:自动创建没有任何入参的构造函数:
public User(){} - 刚需原因:大量框架强制实体配备无参构造: ① MyBatis 从数据库查询封装实体、Spring 做反射实例化对象时,底层默认调用无参构造; ② JSON 序列化 / 反序列化(Jackson 等工具)解析前端 JSON 数据转为 Java 实体,同样离不开无参构造; 如果只写了全参构造,默认的无参构造会被 Java 自动抹除,运行阶段就容易抛出实例化报错。
3. @AllArgsConstructor:生成全参构造方法
- 作用:自动创建包含实体全部成员属性 的构造方法,可以一次性传入所有字段完成对象初始化 示例:你的 User 实体拥有 id、username、password、name、age、updateTime 一共 6 个字段,注解就自动生成接收这 6 个参数的构造器,写代码时可以直接
new User(参数1,参数2......)快速完成对象创建,适配你之前读取 txt、批量 new User 封装数据的写法。
java
@RestController
@RestController详细讲解
1. 本质来源
@RestController是 Spring MVC 提供的复合注解,等价于 @Controller + @ResponseBody 两个注解合并的效果,后端 Web 开发日常高频使用。
2. 拆分两层理解作用
(1)具备@Controller的能力:把类注册成控制器
Spring 扫描该注解之后,会将这个类纳入 Spring 容器进行管理,专门用来接收前端发来的 HTTP 请求,类内部可以编写各类接口方法(也就是 Controller 层),承接浏览器、前端页面、Postman 发出的请求。
(2)具备@ResponseBody的能力:返回 JSON 格式数据
这是它和普通@Controller最关键的区别:
- 单用
@Controller的时候,方法返回字符串会被 Spring 当成网页视图名称,会尝试跳转对应的 html 页面; - 叠加了
@ResponseBody之后,方法返回的对象、集合会自动借助 Jackson 序列化为JSON 字符串,直接把 JSON 响应给到前端,不会进行页面跳转,前后端分离开发基本都需要这种效果。
java
@RestController
public class UserController {
@RequestMapping("/list")
public List<user> list() throws Exception{
//1.加载并读取user.txt文件,获取用户数据
InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");
ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>());
//2.遍历lines集合,解析用户信息,封装为user对象 -> list集合
List<user> userList = lines.stream().map(line -> {
String[] parts = line.split(",");
Integer id = Integer.parseInt(parts[0]);
String username = parts[1];
String password = parts[2];
String name = parts[3];
Integer age = Integer.parseInt(parts[4]);
LocalDateTime updataTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return new user(id,username,password,name,age,updataTime);
}).toList();
//3.返回json格式数据
return userList;
}
}
浏览器访问 http://localhost:8080/list,程序读取 resources/user.txt 文本文件,把文件里每一行用户文字,转成 user 实体对象,打包成列表返回给前端网页展示。
第 1 行:@RestController
- 这是 SpringBoot 的注解,相当于给这个类贴标签。
- 作用:
- 告诉 Spring:这个类是接口控制器,专门用来接收浏览器的网络请求;
Rest代表:方法返回集合 / 对象时,自动转换成 JSON 字符串给前端,不用我们手动转字符串。
- 对比基础语法:注解是框架专属标记,没有对应的基础 Java 语法,记住固定作用即可。
第 2 行:public class UserController {
public:公共访问权限,Spring 框架能随便调用这个类;class UserController:我们新建的类,专门放用户相关接口代码;{}:类的代码范围,所有写接口的代码都放这里面。
第 3 行:@RequestMapping("/list")
- 又是注解,绑定网址
/list和下面这个list()方法; - 大白话:只要浏览器地址末尾是
/list,Spring 就自动执行下面的 list 函数。
第 4 行:public List<user> list() throws Exception{
拆成 5 小块,全是你学过的基础语法:
public:公共方法,Spring 能调用;List<user>:方法返回值类型,代表最后要返回一个装着 user 对象的动态数组集合(就是你学的 ArrayList 父接口,长度自动变长);list():方法名字,空括号 = 调用这个方法不用传任何参数;throws Exception:抛出所有异常- 读取文件、转数字、解析日期都可能出错(文件找不到、文字转数字失败、日期格式不对);
- 初学简化写法:告诉系统 "所有出错我暂时不写 if 判断捕获,出错直接交给服务器处理",不用写一堆 try-catch;
{}:方法内部代码全部写在大括号里。
第 5 行:InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");
分步拆开,比喻讲解
InputStream inInputStream:Java 自带字节读取管道,相当于一根吸管,用来吸文件里的文字;in:自定义变量名,后面代码用in代表这根吸管。
this:代表当前UserController这个类运行出来的对象;.getClass():拿到当前类的底层信息(类对象);.getClassLoader():类加载器,专门负责找到项目里resources文件夹下的文件;.getResourceAsStream("user.txt"):- 参数是文件名,加载器找到这个 txt 文件,打开 "吸管" 读取文件,返回 InputStream 吸管对象;
=赋值:把打开文件后的吸管,存到变量in里,后面读文件全靠这个变量。
第 6 行:ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>());
逐段拆解,用基础循环类比
ArrayList<String> linesArrayList:你学过的动态数组集合;<String>约束集合里只能存字符串;lines:变量名,用来存 txt 里每一行文字,一行就是一个 String。
IoUtil.readLines(参数1,参数2,参数3)- IoUtil 是 Hutool 工具类,别人提前写好的工具方法,底层本质就是你熟悉的
while循环一行一行读文件,帮你省去几十行重复代码; 参数 1in:我们刚才打开的文件吸管,告诉工具读哪个文件; 参数 2StandardCharsets.UTF_8:读取编码,防止中文乱码; 参数 3new ArrayList<>():新建一个空集合,工具读完所有行后,自动把每行文字放进这个集合;
- IoUtil 是 Hutool 工具类,别人提前写好的工具方法,底层本质就是你熟悉的
=赋值:装满所有行文字的集合,存入变量lines。
第 7 行:List<user> userList = lines.stream().map(line -> { ... }).toList();
逐段拆解原代码每一部分
List<user> userList:定义集合,专门存放组装好的 user 对象;lines.stream():把集合 lines 转换成 "流",只是 Java 简化循环的写法,作用 = 开启循环遍历 lines 里每一个字符串;.map(参数):翻译:遍历循环里,对每一行 line 做统一转换(把字符串一行,转换成 user 对象);line -> { ... }:Lambda 表达式,相当于 for 循环里的循环体;line:循环里临时变量,代表当前遍历到的单行文字,和 for (String line : lines) 里的 line 完全一样;{}:转换逻辑,里面全是你能看懂的数组、类型转换语法;
.toList():循环全部结束后,把所有转换好的 user 收集成一个新 List 集合,赋值给左边userList。
大括号内部循环体逐行讲解
① String[] parts = line.split(",");
③ String username = parts[1];
直接取出数组下标 1 的字符串,存用户名,基础数组取值。
④ String password = parts[2];
数组下标 2,取密码字符串。
⑤ String name = parts[3];
数组下标 3,取真实姓名。
⑥ Integer age = Integer.parseInt(parts[4]);
数组下标 4 的文字是 "20",转成数字年龄。
-
split(","):字符串分割方法,按逗号,把一行文字切成字符串数组; -
举例:一行文字
1,zhangsan,123,张三,20,2024-07-15 15:05:45,分割后数组parts:javaparts[0] = "1" parts[1] = "zhangsan" parts[2] = "123" parts[3] = "张三" parts[4] = "20" parts[5] = "2024-07-15 15:05:45" -
String[] parts:字符串数组,你基础语法学过的数组。
② Integer id = Integer.parseInt(parts[0]);
parts[0]是字符串"1",不能直接存进数字变量;Integer.parseInt():把数字字符串转换成整数,基础类型转换语法;Integer id:数字变量,存用户编号。
⑦ LocalDateTime updataTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
parts[5]:数组最后一位,是日期字符串2024-07-15 15:05:45; DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"):定义日期格式模板,告诉程序文字的年月日时分秒怎么排列;
yyyy4 位年份、MM两位月份、dd日期、HH24 小时制小时、mm分钟、ss秒;
LocalDateTime.parse(文字,模板):按照模板,把日期字符串转成 Java 日期对象,专门存时间; LocalDateTime updataTime:日期变量,存放解析完成的时间。
⑧ return new user(id,username,password,name,age,updataTime);
new user(参数):创建 user 实体类对象,把刚才拆分好的 id、用户名、密码、姓名、年龄、时间全部传入;return:把新建好的 user 对象返回给 map 流,存入最终集合 userList; 对应 for 循环里userList.add(u);这一步。
倒数第二行:return userList;
方法结束,把装满 user 对象的集合返回出去;因为类上加了@RestController,Spring 自动把这个集合转换成 JSON 文本,浏览器就能拿到表格数据渲染页面。