NEWS LETTER

Web笔记

Scroll down

学习路线

image-20250426222504727

Web

web:全球广域网

一、maven

1、maven介绍

maven是apache旗下的一个开源的项目,是一款用于管理和构建java项目的工具

apache开源项目官网:https://www.apache.org/index.html#projects-list

2、maven的作用

  1. 依赖管理:方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
  2. 统一项目结构:提供标准、统一的项目结构
  3. 项目构建:标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式

细节

1、配置信息(jar包消息)可以在配置文件里面改

2、统一的项目结构
image-20250426224716886

3、maven的概念

maven是基于项目对象模型(POM)的概念,通过一小段的描述信息来管理项目的构建

image-20250426225918445

4、maven的安装

安装步骤

  1. 解压apache-maven-3.6.1-bin.zip。

  2. 配置本地仓库:修改conf/settings.xml中的为一个指定目录。

    1
    <localRepository>E:\develop\apache-maven-3.6.1\mvn_repo</localRepository>
  3. 配置阿里云私服:修改conf/settings.xml中的标签,为其添加如下子标签:

    1
    2
    3
    4
    5
    6
    <mirror>
    <id>alimaven</id>
    <name>aliyunmaven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorof>
    </mirror>
  4. 配置环境变量:MAVENHOME为maVen的解压目录,并将其bin目录加入PATH环境变量。

5、IDEA集成Maven

  • 配置Maven环境

image-20250427193836062

  • IDEA创建Maven项目

image-20250427202158195

  • Maven坐标

Maven坐标是资源的唯一标识,通过该坐标可以唯一定位资源的位置。

通过坐标来定义项目或引入项目中需要的依赖。

  • 什么是坐标?
    • Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置。
    • 使用坐标来定义项目或引入项目中需要的依赖。
  • Maven坐标主要组成
    • groupld:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.itheima)
    • artifactld:定义当前Maven项目名称(通常是模块名称,例如order-service、goods-service)
    • version:定义当前项目版本号
1
2
3
4
5
6
7
8
9
<groupld>com.itheima</groupld>
<artifactld>maven-project01</artifactld>
<version>1.0-SNAPSHOT</version>

<dependency>
<groupld>ch.qos.logback</groupld>
<artifactld>logback-classic</artifactld>
<version>1.2.3</version>
</dependency>
  • 导入Maven项目

image-20250427210347787

image-20250427211202307

6、Maven依赖管理

6.1 依赖配置

  • 依赖:指当前项目运行所需要的jar包,一个项目中可以引入多个依赖。
  • 配置:
  1. 在pom.xml中编写标签
  2. 标签中使用引入坐标
  3. 定义坐标的groupld,artifactld,version
  4. 点击刷新按钮,引入最新加入的坐标
1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupld>ch.qos.logback</groupld>
<artifactld>logback-classic</artifactld>
<version>1.2.3</version>
</dependency>
</dependencies>

添加依赖的时候,要记得刷新一下

注意

  • 如果引入的依赖,在本地仓库不存在,将会连接远程仓库/中央仓库,然后下载依赖。。(这个过程会比较耗时,耐心等待)
  • 如果不知道依赖的坐标信息,可以到https://mvnrepository.com/中搜索。

6.2 依赖传递

依赖具有传递性

image-20250427221753809

依赖关系可以在idea里面以图表的形式看到

排除依赖

image-20250427222237533

如果不需要依赖关系带来的包可以主动断开,通过标签

6.3 依赖范围

image-20250427222844798

6.4 生命周期

Maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一。

Maven中有3套相互独立的生命周期:

  • clean:清理工作。
  • default:核心工作,如:编译、测试、打包、安装、部署等。
  • site:生成报告、发布站点等。

每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。

clean

  • pre-clean
  • clean
  • post-clean

default

  • validate
  • initialize
  • generate-sources
  • process-sources
  • generate-resources
  • process-resources
  • compile
  • process-classes
  • generate-test-sources
  • process-test-sources
  • generate-test-resources
  • process-test-resources
  • test-compile
  • process-test-classes
  • test
  • prepare-package
  • package
  • verify
  • install
  • deploy

site

  • pre-site
  • site
  • post-site
  • site-deploy

生命周期阶段

  • clean:移除上一次构建生成的文件
  • compile:编译项目源代码
  • test:使用合适的单元测试框架运行测试(junit))
  • package:将编译后的文件打包,如:jar、war等
  • install:安装项目到本地仓库

注意

在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行。

使用方法:

第一种在idea里面双击就行,第二种在里面cmd输入mvn clean

二、SpringBoot Web基础

1、Spring:

  • 官网:spring.io
  • Spring发展到现在已经形成了一种开发生态圈,Spring提供了若干个子项目,每个项目用于完成特定的功能
  • Spring家族:

image-20250428203921000

  • Springboot

image-20250428204331797

Springboot可以帮助我们非常快的构建应用程序、简化开发、提高效率。

2、创建Springboot工程

image-20250428205207447

3、HTTP协议

3.1 HTTP概述

image-20250428212407516

3.2 请求协议

请求数据格式

image-20250428213744443

常见的请求数据关键

1
2
3
4
5
6
7
8
9
10
11
POST /brand HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Content-Length: 161
Content-Type: application/json;charset=UTF-8
Cookie: Idea-829e6b32-841b16f0-0cfe-495a-9cc9-d5aa71501a6; JSESSIONID=0FDE4E430876BD9C5C955F061207386F
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/...

{"status":1,"brandName":"黑马","companyName":"黑马程序员","id":"","description":"黑马程序员"}
字段名 说明
Host 请求的主机名(如 localhost:8080
User-Agent 浏览器版本标识(如 Chrome 的 Mozilla/5.0 ... Chrome/79,IE 的 Mozilla/5.0 (Windows NT ...) like Gecko
Accept 浏览器可接收的资源类型(如 text/*image/**/* 表示所有类型)
Accept-Language 浏览器偏好的语言(如 zh-CN,zh;q=0.9),服务器可据此返回多语言内容
Accept-Encoding 浏览器支持的压缩类型(如 gzipdeflatebr
Content-Type 请求主体的数据类型(如 application/json;charset=UTF-8 表示JSON格式)
Content-Length 请求主体的大小(单位:字节)

3.3 响应协议

HTTP响应格式

响应数据结构

HTTP响应由三部分组成:响应行响应头响应体,示例如下:

1
2
3
4
5
6
7
8
HttpHTTP/1.1 200 OK  // 响应行  
Content-Type: application/json // 响应头(键值对格式)
Transfer-Encoding: chunked
Date: Tue, 10 May 2022 07:51:07 GMT
Keep-Alive: timeout=60
Connection: keep-alive
// 空行分隔响应头和响应体
[{"id": 1, "brandName": "阿里巴巴", "companyName": "腾讯计算机系统有限公司", "description": "玩玩玩"}] // 响应体

各部分说明

组成部分 位置 说明
响应行 响应数据第1行 包含 协议版本(HTTP/1.1)、状态码(200)、状态描述(OK)。例如:HTTP/1.1 200 OK 表示请求成功。
响应头 第2行开始,空行结束 键值对格式(Key: Value),描述响应的附加信息。常见响应头:- Content-Type:响应体数据类型(如application/json表示JSON格式);- Date:服务器响应时间。
响应体 空行之后的部分 服务器返回的具体数据(如JSON、HTML、图片等),是客户端真正需要的业务数据。

HTTP响应介绍

HTTP状态码分类

状态码分类 说明
1xx 临时状态码,表示请求已接收,客户端应继续请求或忽略(如 100 Continue
2xx 成功,表示请求已被接收并处理完成(如 200 OK201 Created
3xx 重定向,需客户端再次请求完成处理(如 301 Moved Permanently302 Found
4xx 客户端错误,责任在客户端(如 404 Not Found403 Forbidden
5xx 服务器错误,责任在服务端(如 500 Internal Server Error503 Service Unavailable

响应头字段说明

字段名 说明
Content-Type 响应内容的类型(如 text/htmlapplication/json;charset=UTF-8
Content-Length 响应内容的长度(单位:字节)
Content-Encoding 响应内容的压缩算法(如 gzipdeflate
Cache-Control 客户端缓存策略(如 max-age=300 表示缓存300秒)
Set-Cookie 服务器向客户端设置Cookie(如 sessionId=abc123; Path=/

常见状态码

状态码 英文描述 解释
200 OK 客户端请求成功,即处理成功,这是我们最想看到的状态码
302 Found 指示所请求的资源已移动到由Location响应头给定的URL,浏览器会自动重新访问到这个页面
304 Not Modified 告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
403 Forbidden 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源
404 Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了
405 Method Not Allowed 请求方式有误,比如应该用GET请求方式的资源,用了POST
428 Precondition Required 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头
429 Too Many Requests 指示用户在给定时间内发送了太多请求(“限速”),配合Retry-After(多长时间后可以请求)响应头一起使用
431 Request Header Fields Too Large 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。
500 Internal Server Error 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧
503 Service Unavailable 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好

状态码大全:https://cloud.tencent.com/developer/chapter/13553

3.4 HTTP协议解析

image-20250506214449156

http的协议解析因为比较复杂,所以已经有好多公司写好了,我们直接用就行

4、Tomcat

image-20250506214829516

Springboot内置Tomcat

  • JavaSEjava标准版
  • JavaME:java小型版
  • JavaEE: java企业版

Tomcat

  • 概念:Tomcat是Apache软件基金会一个核心项目,是一个开源免费的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范。
  • JavaEE:Java Enterprise Edition,Java企业版。指Java企业级开发的技术规范总和。包含13项技术规范:JDBC、JNDl、EJB、
  • RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF
  • Tomcat也被称为Web容器、Servlet容器。Servlet程序需要依赖于Tomcat才能运行
  • 官网:https://tomcat.apache.org/
  1. Web服务器
    1. 对HTTP协议操作进行封装,简化web程序开发。
    2. 部署web项目,对外提供网上信息浏览服务。
  2. Tomcat
    1. 一个轻量级的web服务器,支持servlet、jsp等少量javaEE规范。
    2. 也被称为web容器、servlet容器。

Tomcat的基本使用

image-20250507192059309

闪退说明:Java配置有问题,或者端口被占用了

Tomcat-基本使用

配置Tomcat端口号(conf/server.xml)

1
2
3
<Connector port="8080protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/>

注意事项
HTTP协议默认端口号为80,如果将Tomcat端口号改为80,则将来访问Tomcat时,将不用输入端口号。

基本使用

  • 安装
  • 卸载
  • 启动:bin/startup.bat
  • 停止:bin/shutdown.bat
  • 部署:应用复制到webapps目录

入门程序解析

image-20250507205442933

5、请求响应

image-20250507211213858

5.1 请求

Postman(或者apipost)(ApiFox更好一点)

学会使用即可

简单参数

接收简单参数

image-20250507220001937

如果参数名与请求参数名称不匹配,可以用@RequestParam来完成映射。

1
2
3
public String simpleParam(@RequestParam(name="name")String username,Integer age){

}

注意事项

@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。

实体参数

项目结构

image-20250507222758283

实体参数概述

image-20250507222849099

复杂实体对象

image-20250507223050881

数组集合参数

image-20250508155040713

image-20250508155307598

数组:请求参数名与形参中数组变量名相同,可以字节使用数组封装,

集合:请求参数名与形参中数组变量名相同,通过@RequestParam绑定参数关系

日期参数

image-20250508155916610

后端要指定前端要发送的日期格式

Json参数

JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用**@RequestBody**标识

1
2
3
4
5
6
7
8
{
"name":"Tom”,
"age":10,
"address":{
"province":"beijing",
"city":"beijing"
}
}

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,主要用于不同系统之间的数据传输和存储。

  • 定义:JSON 是一种基于文本的、独立于编程语言的数据格式,由键值对组成,结构类似于 JavaScript 对象。它最初由 Douglas Crockford 提出,现已成为 ECMA 国际标准
  • 特点:语法简洁、易读、解析速度快,支持嵌套和复杂数据结构(如对象和数组),广泛用于 Web 应用、移动端和 API 交互

Json参数要写到请求体中,是要用post。

image-20250508161353971

路径参数

image-20250508163607387

5.2 响应

image-20250508164114961

统一响应结果

image-20250508165208657

响应数据案例

image-20250508170934554

5.3 分层解构

问题的出现

代码都写在controller中会导致复用性太差。耦合太高

image-20250509220028035

三层架构

image-20250509220209504

Dao(对数据库的操作一般在mapper软件包里):接口,impl软件包里为实现类。

service:接口,impl里是对应实现类

整个运行过程:controller调用service里的实现类,service里的实现类通过调用Dao的实现类来获取数据。

image-20250509221810211

分成解耦

image-20250509223212105

IOC和DI

添加注解

image-20250509223543401

@Autowired注解:在运行时,IOC容器会提供该类型的bean对象,并赋值给该变量–依赖注入

@Component注解:在Service层和Dao层的实现类里使用,是把实现类交给IOC容器去管理

切换:将@Component注解给注释掉就行,给要切换的类添加@Component注解。

IOC详解

Bean的声明

要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注解 说明 位置
@Component 声明bean的基础注解 不属于以下三类时,用此注解(工具类)
@Controller @Component的衍生注解 标注在控制器类上
@Service @Component的衍生注解 标注在业务类上
@Repository @Component的衍生注解 标注在数据访问类上(由于与MyBatis整合,用的少)

注意事项

  • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

Bean组件扫描

image-20250509230253573

DI详解

设置优先级

Bean注入(@Autowired 冲突解决)

@Autowired 注解的默认行为

  • 注入方式:默认按类型(Type) 注入Bean。
  • 冲突场景:当Spring容器中存在多个同类型Bean时,会抛出如下错误:
1
2
3
4
5
 Field empService in com.itheima.controller.EmpController required a single bean, but 2 were found:  
- empServiceA: defined in file [E:\...\EmpServiceA.class]
- empServiceB: defined in file [E:\...\EmpServiceB.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean

冲突解决方法

1. @Primary:指定默认Bean

  • 作用:在多个同类型Bean中,标记优先注入的Bean。
  • 使用位置:在Bean的类上添加 @Primary 注解。
1
2
3
4
5
Java  @Service  
@Primary // 当存在多个 EmpService 类型Bean时,优先注入此类
public class EmpServiceA implements EmpService {
// ...
}

2. @Qualifier:按名称注入

  • 作用:结合 @Autowired,按Bean名称指定注入的Bean(需与 @Autowired 搭配使用)。
  • 使用方式:在注入字段上添加 @Qualifier("bean名称")
1
2
3
4
5
6
Java  @RestController  
public class EmpController {
@Autowired
@Qualifier("empServiceA") // 明确指定注入名称为 "empServiceA" 的Bean
private EmpService empService;
}

3. @Resource:按名称或类型注入(JDK注解)

  • 作用:自带按名称注入功能,无需搭配其他注解(属于JDK的 javax.annotation.Resource,非Spring注解)。
  • 使用方式:通过 name 属性指定Bean名称。
1
2
3
4
5
Java  @RestController  
public class EmpController {
@Resource(name = "empServiceB") // 直接指定Bean名称
private EmpService empService;
}

三种方案对比

方案 所属框架 注入方式 特点
@Primary Spring 类型优先,指定默认Bean 适合全局默认场景,无需修改注入处代码
@Autowired + @Qualifier Spring 类型+名称(需显式指定名称) 灵活,可在注入处精确控制Bean
@Resource JDK 默认按名称,支持按类型 非Spring原生,无需依赖Spring注解

三、Mybatis

1、Mybatis入门

image-20250510001702800

1.1 Mybatis介绍

Mybatis的数据操作

image-20250510005037242

在配置文件里写上mysql的配置信息,之后在mapper软件包中只需要写功能接口就行,框架会自动生成对应的实现类。

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootTest
class SpringbootMybatisQuickstart1ApplicationTests {

@Autowired
private UserMapper userMapper;

@Test
public void test1() {
List<User> userList = userMapper.list();
userList.stream().forEach(user -> {
System.out.println(user);
});
}

}

配置SQL提示

image-20250510145112511

image-20250510145214541

1.2 JDBC

JDBC介绍

image-20250510145623709

Jdbc代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 2. 获取连接对象
String url = "jdbc:mysql://localhost:3306/mybatis";
String username = "root";
String password = "1234";
Connection connection = DriverManager.getConnection(url, username, password);

// 3. 获取执行SQL的对象Statement,执行SQL,返回结果
String sql = "select * from user";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

// 4. 封装结果数据(封装的结果需要一个字段一个字段来解析)
List<User> userList = new ArrayList<>();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
short age = resultSet.getShort("age");
short gender = resultSet.getShort("gender");
String phone = resultSet.getString("phone");

User user = new User(id, name, age, gender, phone);
userList.add(user);
}

MybatisVsJDBC

image-20250510150157239

1.3 数据库连接池

数据库连接池概述

image-20250510151513688

连接池产品

  • 定义:由Sun官方提供的数据库连接池标准接口(javax.sql.DataSource),第三方连接池产品需实现此接口。
  • 核心功能:通过 getConnection() 方法获取数据库连接,简化连接获取流程:
1
Connection getConnection() throws SQLException; // 获取连接
常见连接池产品
产品名称 特点 应用场景
C3P0 老牌连接池,稳定性好,但性能中等,配置较复杂 早期项目(如老版Hibernate默认)
DBCP Apache开源,性能一般,依赖Commons组件 传统Java Web项目
Druid 阿里巴巴开源,功能强大(监控、防SQL注入、性能优秀),Java语言最好的连接池之一 企业级项目、分布式系统
Hikari 轻量级,性能极致优化,Spring Boot默认连接池 Spring Boot项目(推荐)
重点产品:Druid(德鲁伊)
  • 开发商:阿里巴巴(开源项目)。
  • 核心优势:
    1. 性能优秀:高效的连接池管理,响应速度快。
    2. 功能全面:内置监控(Druid Monitor)、SQL注入防护、日志记录等。
    3. 稳定性强:经过阿里内部大规模场景验证,支持高并发。
  • 适用场景:对性能和监控有较高要求的企业级应用。

切换连接池

只需要引入要切换的连接池的依赖,springboot会自动切换。

1
2
3
4
5
6
#pom.xml
<dependency>
<groupld>com.alibaba</groupld>
<artifactld>druid-spring-boot-starter</artifactld>
<version>1.2.8</version>
</dependency>
1
2
3
4
5
#application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.username=root
spring.datasource.password=1234

或者在datasource后面加个名字

1
2
3
4
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=1234

1.4 Lombok

Lombok的作用

image-20250510152957483

Lombok的使用

一、简介

Lombok 是一个实用的 Java 类库,通过注解自动生成 Java 类的常用方法(如 getter/setter、构造器、toStringequals/hashCode 等),并支持自动化日志变量,简化代码编写,提高开发效率

二、依赖配置(Maven)

pom.xml 中添加 Lombok 依赖:

1
2
3
4
XML<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

三、常用注解及作用

注解 作用
@Getter/@Setter 为类的所有非静态属性自动生成 getter/setter 方法
@ToString 生成易阅读的 toString() 方法(默认包含所有非静态属性)
@EqualsAndHashCode 根据非静态字段自动重写 equals()hashCode() 方法
@Data 综合注解:等价于 @Getter + @Setter + @ToString + @EqualsAndHashCode
@NoArgsConstructor 生成无参数的构造器(实体类常用)
@AllArgsConstructor 生成包含所有非静态字段的全参构造器(不含静态字段)

注意事项
Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)。

Lombok代码的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//@Getter
//@setter
//@ToString
//@EqualsAndHashCode
@Data
@NoArgsConstructor//无参构造
@AllArgsConstructorr//全参构造
public class User{
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
}

2、Mybatis基础操作

准备工作

image-20250510160208996

字段对应

image-20250510160456877

删除操作

具体操作

后端会接收要删除的数据,所以要用到动态参数#{}。

1
2
3
4
5
6
7
@Mapper
public interface EmpMapper{
//根据ID册除数据
@Delete("delete from emp where id = #{id)")
public void delete(Integer id);
}

因为是删除功能,所以直接返回一个方法就行。

也可以返回删除的条数(MySQL操作影响的条数)

1
public int delete(Integer id);

注意事项

如果mapper接口方法形参只有一个普通类型的参数,#[..}里面的属性名可以随便写,如:#{id]、#{value}。

日志输出和预编译SQL

解释

image-20250510162256572

预编译SQL优势

image-20250510162713584

SQL注入

image-20250510163353310

参数占位符

占位符格式 执行逻辑 安全性 使用时机
#{...} 替换为 ?,生成预编译 SQL,自动设置参数值 安全(防SQL注入) 参数传递(所有常规参数场景,推荐优先使用)
${...} 直接将参数拼接在 SQL 语句中,不经过预编译 不安全(存在SQL注入风险) 动态设置表名、列名等(非用户输入的固定值场景)

新增操作

image-20250510164339469

主键返回

一般用于多对多

image-20250510192337355

更新(修改)

image-20250510192951751

查询(根据ID)

id是主键,所以只会有一个结果,用对象封装就行

接口方法

1
2
@Select("select *from emp where id = #{id)")
public Emp getByld(Integer id);

如果代码里变量名与mysql里的字段名不一样,可以起别名;

也可以用注解,最好使用第三种方法—开启mybatis的驼峰命名自动映射

一、起别名(SQL 层面映射)

原理:在 SQL 语句中为表字段指定别名,使其与实体类属性名一致,MyBatis 自动将查询结果映射到实体类。

示例

1
2
3
4
Java@Select("select id, username, password, name, gender, image, job, entrydate, " +
"dept_id deptId, create_time createTime, update_time updateTime " + // 字段别名与属性名一致
"from emp where id = #{id}")
public Emp getById(Integer id);

说明

  • 数据库字段 dept_id → 别名 deptId(对应实体类属性 deptId)。
  • 适用于字段名与属性名差异较小的场景,简单直观。

二、手动结果映射(注解层面映射)

原理:通过 @Results@Result 注解,手动指定数据库字段与实体类属性的映射关系(忽略字段名与属性名的一致性)。

示例

1
2
3
4
5
6
7
Java@Select("select * from emp where id = #{id}")  // 查询所有字段
@Results({
@Result(column = "dept_id", property = "deptId"), // 字段dept_id → 属性deptId
@Result(column = "create_time", property = "createTime"), // 字段create_time → 属性createTime
@Result(column = "update_time", property = "updateTime") // 字段update_time → 属性updateTime
})
public Emp getById(Integer id);

说明

  • @Results 用于定义映射规则,@Result 单个字段映射(column 为数据库字段,property 为实体类属性)。
  • 适用于字段名与属性名差异较大,或多表联查时的复杂映射。

三、开启驼峰命名(全局配置映射)

原理:通过 MyBatis 全局配置,自动将数据库下划线命名(如 dept_id)转换为 Java 驼峰命名(如 deptId),无需手动映射。

配置方式: 在 application.propertiesapplication.yml 中添加:

1
2
Properties# 开启驼峰命名自动映射(推荐)
mybatis.configuration.map-underscore-to-camel-case=true

说明

  • 推荐方案:一劳永逸解决下划线与驼峰命名的映射问题,减少重复代码。
  • 要求数据库字段遵循下划线命名(如 user_name),实体类属性遵循驼峰命名(如 userName)。

查询(根据条件)

SQL语句

1
select * from emp where name like '%张%' and gender = 1 entrydate between '2010-01-01' and '2020-01-01' order by update_time desc;

查询要注意%#{}%是不能用的

(性能低、不安全、存在SQL注入问题)

1
2
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

(推荐)

1
2
3
4
5
@Select("select * from emp where name like concat('%', #{name}, '%') " +  // 使用 concat 拼接 %
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

参数说明

变量名要相同

● 在springBoot的2.x版本

1
2
3
4
5
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

@Select(("select * from emp where name like concat('%',#{name},'%') and gender = #{gender}")
List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

● 在springBoot的1.x版本/单独使用mybatis

1
2
3
4
5
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);

@Select(("select * from emp where name like concat('%',#{name},'%') and gender = #{gender}")
List<Emp> list(String var1, Short var2, LocalDate var3, LocalDate var4);

3、XML映射文件

概述

image-20250510201155348

XML映射文件的插件

image-20250510201353150

什么时候使用

使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。

官方说明:https://mybatis.net.cn/getting-started.html

动态SQL要用到XML

4、动态SQL

快捷键:alt+ctrl+L格式化SQL语句

< if >

用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL

1
2
3
<if test="name!=null">
name like concat('%',#{name},'%')
</if>

< where > selectSQL

where元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND或OR。

1
2
3
4
5
<where>
<if>

</if>
</where>

< set > updateSQL

动态地在行首插入SET关键字,并会删掉额外的逗号。(用在update语句中)

1
2
3
4
5
<set>
<if>

</if>
</set>

< foreach >

image-20250510205107244

< sql > 和< include >

image-20250510205801259

四、SpringBoot Web 开发

tlias智能学习辅助系统

部门信息功能

需求说明

image-20250510220704808

环境搭建

image-20250510221143384

开发规范

image-20250510235815138

开发规范-Restful

REST(REpresentationalStateTransfer),表述性状态转换,它是一种软件架构风格

1
2
3
4
5
//传统风格
http://localhost:8080/user/getById?id=1GET:查询id为1的用户
http://localhost:8080/user/saveUserPOST:新增用户
http://localhost:8080/user/updateUserPOST:修改用户
http://localhost:8080/user/deleteUser?id=1GET:删除id为1的用户
1
2
3
4
5
6
7
//REST风格
//1.URL 定位资源
//2.HTTP动词描述操作
http://localhost:8080/users/1GET:查询id为1的用户
http://localhost:8080/usersPOST:新增用户
http://localhost:8080/usersPUT:修改用户
http://localhost:8080/users/1DELETE:删除id为1的用户

注意事项
REST是风格,是约定方式,约定不是规定,可以打破。
描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books…

开发规范-统一响应信息

前后端交互统一响应结果Result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code; // 响应码,1 代表成功;0 代表失败
private String msg; // 响应信息,描述字符串
private Object data; // 返回的数据

// 增删改 成功响应(无返回数据)
public static Result success() {
return new Result(1, "success", null);
}

// 查询 成功响应(有返回数据)
public static Result success(Object data) {
return new Result(1, "success", data);
}

// 失败响应(返回错误信息)
public static Result error(String msg) {
return new Result(0, msg, null);
}
}

开发流程

1
2
查看页面原型——>阅读接口文档——>思路分析——>接口开发——>接口测试——>前后端联调
明确需求

查询部门

部门管理-需求说明

部门管理页面,管理员可以对部门信息进行管理,包括新增、修改、删除部门信息等。

页面开发规则

1.部门查询

1.1查询全部数据(由于部门数据比较少,不考虑分页)。

2.新增部门

1.1点击新增部门,会打开新增部门的页面。
1.2部门名称,必填,唯一,长度为2-10位。

3.删除部门

弹出确认框,提示“您确定要删除该部门的信息吗?”如果选择确定,则删除该部门,删除成功后,重新刷新列表页面。如果选择了取消,则不执行任何操作。

查询部门思路

image-20250511155645380

记录日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.gzgs.controller;

import com.gzgs.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class DeptController {

// private static Logger log = LoggerFactory.getLogger(DeptController.class);
// 可以直接用slf4j这个注解来输出日志

@RequestMapping("/depts")
public Result list(){
log.info("查询全部部门");
return Result.success();
}
}

报错修改:log报错解决方法:设置->构建、执行、部署->注解处理器->仅选启用注解和从项目类路径获取处理器->点击应用并确定即可

指定请求方式

1
2
3
4
@RequestMapping(value = "/depts",method = RequestMethod.GET)

//现在可以用
@GetMapping("/depts")

确保 Jackson 支持 Java 8 时间类型

pom.xml 中添加以下依赖以支持 LocalDateTime 的序列化:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.3</version>
</dependency>

前后端联调

  • 将资料中提供的“前端工程”文件夹中的压缩包,拷贝到一个没有中文不带空格的目录下,解压。18nginx-1.22.0-tlias.zip
  • 启动nginx,访问测试:http://localhost:90

删除部门

基本信息
请求路径:/depts/{id}
请求方式:DELETE
接口描述:该接口用于根据ID删除部门数据

参数格式

参数名 类型 是否必须 备注
id number 必须 部门ID
1
/depts/1

响应数据

参数格式
1
application/json
参数说明
参数名 类型 是否必须 备注
code number 必须 响应码,1 代表成功,0 代表失败
msg string 非必须 提示信息
data object 非必须 返回的业务数据(成功时可能为空)
响应数据样例
1
2
3
4
5
{
"code": 1,
"msg": "success",
"data": null
}

思路

image-20250511172524626

1
2
3
4
5
6
7
@DeleteMapping("/depts/{id}")
public Result delete(@PathVariable Integer id){
log.info("删除对应id的部门:{}",id);
//调用方法
deptService.delete(id);
return Result.success();
}

新增部门

请求参数

格式
1
application/json
参数说明
参数名 类型 是否必须 备注
name string 必须 部门名称
请求参数样例
1
2
3
{
"name": "教研部"
}

响应数据

参数格式
1
application/json
参数说明
参数名 类型 是否必须 备注
code number 必须 响应码,1 代表成功,0 代表失败
msg string 非必须 提示信息
data object 非必须 返回的业务数据(成功时可能为空)
响应数据样例
1
2
3
4
5
{
"code": 1,
"msg": "操作成功",
"data": { ... } // 业务数据对象(根据接口实际返回填充)
}

思路

image-20250511175248316

路径抽取

image-20250511180646438

修改部门

首先要严格按照接口文档的来写代码,一般有疑惑,在写完就会解决。

修改部门,一般要会写要修改的数据,所以要先把按照id查询的结果返回给前端,在根据前端返回修改信息来进行修改。

员工信息功能

分页查询

Mysql分页查询语句:

1
2
3
4
5
6
7
#参数1:起始索引(页码-1)—*每页展示的记录数
#参数2:查询返回的记录数
select * from emp limit 0,5;


#获取总数据
select count(*) from emp;

分析

image-20250512222517724

基本信息

参数格式

1
application/json

参数说明

参数名 类型 是否必须 备注
code number 必须 响应码,1 代表成功,0 代表失败
msg string 非必须 提示信息
data object 非必须 返回的业务数据(成功时可能为空)

响应数据样例

(注:原图片中样例未完整显示,以下为标准格式参考)

1
2
3
4
5
Json{
"code": 1,
"msg": "操作成功",
"data": { ... } // 业务数据对象(根据接口实际返回填充)
}

2.1 员工列表查询

2.1.1 基本信息

项目 内容
请求路径 /emps
请求方式 GET
接口描述 该接口用于员工列表数据的条件分页查询(支持按条件筛选并分页返回员工信息)

请求参数

参数格式

queryString(URL查询字符串,如 ?name=张&page=1&pageSize=10

参数说明

参数名称 是否必须 示例 备注
name 姓名(模糊匹配,支持部分输入)
gender 1 性别(1=男,2=女)
begin 2010-01-01 入职日期范围匹配的开始时间(格式:YYYY-MM-DD)
end 2020-01-01 入职日期范围匹配的结束时间(格式:YYYY-MM-DD)
page 1 分页查询的页码(未指定时默认值为1)
pageSize 10 每页记录数(未指定时默认值为10)

响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
"code": 1,
"msg": "success",
"data": {
"total": 2,
"rows": [
{
"id": 1,
"username": "jinyong",
"password": "123456",
"name": "金庸",
"gender": 1,
"image": "https://web-framework.oss-cn-xxx.aliyuncs.com/2023/08/01/xxx.jpg",
"job": 2,
"entrydate": "2010-01-01",
"deptId": 2,
"createTime": "2023-08-01 10:00:00",
"updateTime": "2023-08-01 10:00:00"
},
{
"id": 2,
"username": "langxiong",
"password": "123456",
"name": "朗雄",
"gender": 1,
"image": "https://web-framework.oss-cn-xxx.aliyuncs.com/2023/08/01/yyy.jpg",
"job": 3,
"entrydate": "2015-03-15",
"deptId": 1,
"createTime": "2023-08-01 11:00:00",
"updateTime": "2023-08-01 11:00:00"
}
]
}
}

思路

image-20250512223002378

代码细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {

@Autowired
private EmpService empService;

// @RequestParam(defaultValue = "1")设置默认值
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize) {
log.info("分页查询, {}, {}", page, pageSize);
PageBean pageBean = empService.page(page, pageSize);
return Result.success(pageBean);
}
}

分页插件PageHelper

image-20250513172238575

image-20250513172346591

条件分页查询

需求

image-20250513212647221

思路

image-20250513213124178

实现

image-20250513220430973

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xxx.mapper.EmpMapper">

<!-- 条件查询 -->
<select id="list" resultType="com.xxx.pojo.Emp">
select * from emp
<where>
<if test="name != null and name != ''">
and name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>

</mapper>

删除员工

请求参数

参数格式

路径参数(通过 URL 路径传递数组参数)

参数说明

参数名 类型 示例 是否必须 备注
ids 数组 array 1,2,3 必须 员工的id数组(需删除的员工ID集合)

请求参数样例

1
/emps/1,2,3  

响应数据

1
2
3
4
5
{
"code":1,
"msg":"success",
"data":null,
}

思路

image-20250514211142273

代码

1
2
3
4
5
6
7
<delete id="delete">
delete from emp
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")"
#{id}
</foreach>
</delete>

新增员工

基本信息

项目 内容
请求路径 /emps
请求方式 POST
接口描述 该接口用于添加员工的信息(接收员工信息参数,保存到数据库并返回结果)

请求参数

1
2
3
4
5
6
7
8
9
{
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}

响应数据

1
2
3
4
5
{
"code":1,
"msg":"success",
"data":null,
}

思路

image-20250516151958574

代码

1
2
3
4
5
6
//EmpController
@PostMapping
public Result save(@RequestBody Emp emp) {
empService.save(emp);
return Result.success();
}
1
2
3
4
5
6
7
8
//EmpService
@Override
public void save(Emp emp) {
// 设置创建时间和更新时间为当前时间
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.save(emp); // 调用Mapper层保存数据
}
1
2
3
4
5
6
7
8
9
//EmpMapper
/**
* 保存员工信息
*/
@Insert("insert into emp " +
"(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
"values " +
"(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
void save(Emp emp);

文件上传

介绍

  • 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
  • 文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

前端三要素

1
2
3
4
5
6
<form action="/upload"method="post"enctype="multipart/form-data"
姓名:<input type="text”name="username"><br>
年龄:<input type="text" name="age"><br>
头像:<input type="file"name="image"><br>
<input type="submit"value="提交">
</form>

前端如果没设置enctype,就只是上传文件名而已

有设置就会上传内容

服务端代码

image-20250517115259043

文件上传后会形成临时文件,连接结束后会自动删除,所以还需要在本地把它保存

本地存储

image-20250517122940677

异常

1
2
3
4
5
6
7
8
9
10
apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field image exceeds its maximum permitted size of 1048576 bytes.
at java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:1.8.0_171]
<5 internal lines>
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:122) ~[spring-web-5.3.22.jar:5.3.22]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
<1 internal line>
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
<33 internal lines>

在SpringBoot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以进行如下配置:

1
2
3
4
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
1
2
3
4
5
String getOriginalFilename(); //获取原始文件名
voidtransferTo(Filedest);//将接收的文件转存到磁盘文件中
long getSize();//获取文件的大小,单位:字节
byte[] getBytes();//获取文件内容的字节数组
InputStream getlnputStream();//获取接收到的文件内容的输入流

阿里云OSS

  • 阿里云对象存储OSS(ObjectStorageService),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
  • 类似于网盘,但是网盘是私人的,而OSS是有公开API和URL的

第三方服务-通用思路

准备工作——>参照官方SDK——>集成使用
编写入门程序

**SDK:**SoftwareDevelopmentKit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。

阿里云OSS-使用步骤

注册阿里云——>充值——>开通对象存储——>创建bucket——>获取Accesskey(秘钥)——>参照官方SDK——>案例集成OSS
(实名认证) 服务(OSS) 编写入门程序

**Bucket:**存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。

集成阿里云OSS

image-20250518104536133

文件上传基本信息

项目 内容
请求路径 /upload
请求方式 POST
接口描述 上传图片接口(接收客户端上传的图片文件并保存)

文件上传请求参数

参数格式:multipart/form-data

参数说明:

参数名称 参数类型 是否必须 示例 备注
image file

文件上传响应数据

1
2
3
4
5
{
"code": 1,
"msg": "success",
"data": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-0400.jpg"
}

文件上传代码

1
2
3
4
5
6
7
8
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
Log.info("上传的文件为: {}", image.getOriginalFilename());
// 调用工具类上传文件到OSS
String url = aliOssUtils.upload(image);
Log.info("文件上传成功: {}", image.getOriginalFilename());
return Result.success(url);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String upload(MultipartFile file) throws IOException { // IDE提示“0个用法”,可忽略
// 获取上传文件的输入流(用于读取文件内容)
InputStream inputStream = file.getInputStream();

// 避免文件覆盖(生成唯一文件名)
String originalFilename = file.getOriginalFilename(); // 获取原文件名(如:test.jpg)
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf(".")); // 唯一文件名(如:550e8400-e29b-41d4-a716-446655440000.jpg)

// 上传文件到OSS(创建客户端→执行上传)
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 初始化OSS客户端(需配置端点、AccessKey)
ossClient.putObject(bucketName, fileName, inputStream); // 上传文件(存储桶名称→文件名→输入流)

// 构造文件访问URL(OSS标准访问格式)
String[] endpointParts = endpoint.split("://"); // 拆分端点(如:https://oss-cn-hangzhou.aliyuncs.com → ["https", "oss-cn-hangzhou.aliyuncs.com"])
String url = endpointParts[0] + "://" + bucketName + "." + endpointParts[1] + "/" + fileName; // 拼接URL(如:https://my-bucket.oss-cn-hangzhou.aliyuncs.com/550e8400-e29b-41d4-a716-446655440000.jpg)

// 关闭OSS客户端(释放资源,避免泄漏)
ossClient.shutdown();

return url; // 返回上传后的文件访问路径
}

修改员工

查询回显(根据ID查询员工)

根据ID查询员工基本信息

  • 请求路径:/emps/{id}
  • 请求方式:GET
  • 接口描述:该接口用于根据主键ID查询员工的信息

根据ID查询员工请求参数

请求参数样例

参数名 类型 是否必须 备注
id number 必须 员工ID
1
/emps/1

根据ID查询员工响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"code": 1,
"msg": "success",
"data": [
{
"id": 2,
"username": "zhangwuji",
"password": "123456",
"name": "张无忌",
"gender": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg"
}
]
}

根据ID查询员工思路

image-20250518111210916

根据ID查询员工代码

1
2
3
4
5
6
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
Log.info("根据ID查询员工,ID: {}", id); // 日志记录查询的员工ID
Emp emp = empService.getById(id); // 调用服务层方法查询员工数据
return Result.success(emp); // 返回成功响应,包含查询到的员工信息
}

修改员工

修改员工基本信息

  • 请求路径:/emps
  • 请求方式:PUT
  • 接口描述:该接口用于修改员工的数据信息

修改员工请求参数

1
2
3
4
5
6
7
8
9
10
{
"id": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}

修改员工响应数据

1
2
3
4
5
{
"code":1,
"msg" :"success",
"data":null
}

修改员工思路

image-20250518112427939

修改员工代码

image-20250518114014729

配置文件

问题分析与解决

image-20250518115300585

image-20250518115449610

参数配置化

image-20250518120159792

yml配置文件

image-20250518120600695

配置文件优先使用.yaml,因为YAML官方推荐后缀,Kubernetes等云原生生态强制要求.yaml混合项目优先用.yaml

yml基本语法
  • 大小写敏感
  • 数值前边必须有空格,作为分隔符
  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • #表示注释,从这个字符一直到行尾,都会被解析器忽略
1
2
3
server:
port: 8080
address: 127.0.0.1
yml数据格式
  • 对象/Map集合:

    1
    2
    3
    4
    user:
    name: zhangsan
    age: 18
    password: 123456
  • 数组/List/Set集合:

    1
    2
    3
    4
    hobby:
    -java
    -game
    -sport
将properties转化为yml

image-20250518121918556

注解@ConfigurationProperties

问题分析

image-20250518122502628

注解

image-20250518122605920

引入依赖

image-20250518123439930

@ConfigurationProperties与@Value区别

相同点:

  • 都是用来注入外部配置的属性的。

不同点:

  • @Value注解只能一个一个的进行外部属性的注入。
  • @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中。

登陆认证

登录功能

登录功能基本信息

  • 请求路径:/login
  • 请求方式:POST
  • 接口描述:该接口用于员工登录Tlias智能学习辅助系统,登录完毕后,系统下发JWT令牌。

登录功能请求参数

1
2
3
4
{
"username": "jinyong",
"password": "123456"
}

登录功能响应数据

1
2
3
4
5
{
"code": 1,
"msg": "success",
"data": "eyJhbgciOiJIUzI1NiJ9.eyJuYw1lIjoi6YeR5bq4IiwiaWQiOjEsInVzzZXJuYw1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H90jfrr6XMJ-vYzaWCVZZCo"
}

登录功能思路

image-20250519202045308

登录功能代码

1
2
3
4
5
6
@PostMapping
public Result login(@RequestBody Emp emp) {
Log.info("登录的员工为: {}", emp); // 记录登录员工的信息(用户名、密码等)
Emp loginEmp = empService.login(emp); // 调用服务层验证登录
return loginEmp != null ? Result.success(loginEmp) : Result.error("用户名或密码错误"); // 根据验证结果返回响应
}

登录校验

image-20250519224908207

会话技术

image-20250519225424804

三种会话跟踪方案对比

Cookie

image-20250520193356262

Session

image-20250520194422638

image-20250520195226219

JWT令牌

简介

image-20250520195935475

使用场景

image-20250520200107493

生成

image-20250521180213642

校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void parseJwt() {
// 1. 创建JWT解析器,指定签名密钥(必须与生成令牌时的密钥一致)
Claims claims = Jwts.parser()
.setSigningKey("itheima") // 签名密钥(需与生成令牌时的密钥完全一致)
// 2. 解析JWT令牌(参数为待校验的JWT字符串)
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0bGlhcyIsImV4cCI6MTY1OTkxNTE3Mywic3ViIjoi6YeR5bq4In0.EUTfeqPkGslekdkBeczcCe7a7xbcllwB1MXllccTMwo")
// 3. 获取令牌中的Payload( claims )
.getBody();

// 打印解析后的claims(包含令牌中的自定义信息,如用户ID、角色等)
System.out.println(claims);
// 示例输出:{iss=tlias, exp=1659915173, sub=管理员, id=1, username=jinyong}
}

注意事项

密钥一致性:JWT校验时使用的签名密钥,必须与生成JWT令牌时使用的密钥完全一致(若密钥不匹配,解析会抛出SignatureException,提示签名无效)。 ● 令牌合法性:若解析校验时抛出以下异常,说明令牌非法,需拒绝请求:

  • SignatureException:签名无效(令牌被篡改);
  • ExpiredJwtException:令牌已过期(exp字段指定的时间已过);
  • MalformedJwtException:令牌格式错误(如缺失部分、结构损坏);
  • InvalidClaimException:令牌中的声明(claim)无效(如iss issuer 不匹配)。
备注说明
  • 用户登录成功后,系统会自动下发JWT令牌。后续每次请求时,需在**请求头(Header)**中携带该令牌至服务端,请求头的名称为token,值为登录时下发的JWT令牌(例如:token: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIERvZSIsImV4cCI6MTYxMDAwMDAwMH0.5eK5eK5eK5eK5eK5eK5eK5eK5eK5eK5eK5eK5eK)。
  • 若检测到用户未登录(如未携带tokentoken无效或过期),系统会返回固定错误信息(例如未登录提示,具体格式需参考接口文档的错误响应规范)。

image-20250521180557556

过滤器Filter

image-20250521211248737

快速入门

image-20250521211629085

详解

执行流程

image-20250521212622533

拦截路径

Filter 可以根据需求,配置不同的拦截资源路径(通过 @WebFilter 注解的 urlPatterns 属性指定):

1
2
3
4
Java@WebFilter(urlPatterns = "/*") // 拦截所有资源
public class DemoFilter implements Filter {
// 过滤器业务逻辑(如登录校验、权限检查等)
}

拦截路径配置说明

拦截类型 urlPatterns 含义描述
拦截具体路径 /login 仅当访问 /login 路径时,过滤器才会拦截请求
目录拦截 /emps/* 访问 /emps 目录下的所有资源(如 /emps/1/emps/list)时,都会被拦截
拦截所有资源 /* 访问应用中所有资源(任何路径)时,过滤器都会拦截请求

过滤器链

image-20250521213405134

登录校验过滤器

前提

image-20250521213632551

思路

image-20250521213837702

拦截器Interceptor

image-20250521220744322

快速入门

image-20250521221007725

详解

拦截路径

1. 路径配置方式

拦截器通过 InterceptorRegistry 配置拦截路径,支持包含addPathPatterns)和排除excludePathPatterns)两种规则:

1
2
3
4
5
6
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor) // 注册登录校验拦截器
.addPathPatterns("/**") // **需要拦截的资源**:所有路径(任意级)
.excludePathPatterns("/login"); // **不需要拦截的资源**:登录路径(放行登录请求)
}

2. 拦截路径规则说明

拦截路径 含义 举例
/* 一级路径 仅匹配单级目录的路径(如/depts/emps/login),不匹配子目录(如/depts/1
/** 任意级路径 匹配所有层级目录的路径(如/depts/depts/1/depts/1/2
/depts/* /depts下的一级路径 仅匹配/depts目录下的单级资源(如/depts/1),不匹配/depts本身子目录(如/depts/1/2
/depts/** /depts下的任意级路径 匹配/depts目录下的所有资源(如/depts/depts/1/depts/1/2),不匹配其他目录(如/emps/1

执行流程

image-20250521222543390

登录校验拦截器

思路

image-20250521222612296

异常处理

image-20250518123842843

全局异常处理器

image-20250518124016298

image-20250518124446575

事务管理

📚 概念

事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败(原子性)。

✏️ 核心操作

  • 开启事务:在一组操作开始前启动事务(标记事务的起点),关键字:start transaction / begin
  • 提交事务:当所有操作都成功完成时,将事务中的修改永久保存到数据库,关键字:commit
  • 回滚事务:若中间任何一个操作出现异常(如数据库错误、业务逻辑失败),则撤销事务中的所有修改,恢复到事务开始前的状态,关键字:rollback

完善删除部门

解散部门:删除部门,同时删除该部门下的员工

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class DeptServiceImpl implements DeptService {

@Autowired
private DeptMapper deptMapper; // 注入部门Mapper,用于操作部门表
@Autowired
private EmpMapper empMapper; // 注入员工Mapper,用于操作员工表

@Override
public void delete(Integer id) {
// 1. 删除部门(根据部门ID删除部门表中的记录)
deptMapper.delete(id);
// 2. 删除部门下的员工(根据部门ID删除员工表中的关联记录)
empMapper.deleteByDeptId(id);
}
}
1
2
3
4
5
6
7
8
public interface EmpMapper {
/**
* 根据部门ID,删除该部门下的所有员工数据
* @param deptId 部门ID
*/
@Delete("delete from emp where dept_id = #{deptId}")
void deleteByDeptId(Integer deptId);
}

Springboot事务管理

完善删除部门功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class DeptServiceImpl implements DeptService {

@Autowired
private DeptMapper deptMapper; // 注入部门Mapper(操作部门表)
@Autowired
private EmpMapper empMapper; // 注入员工Mapper(操作员工表)

@Override
public void delete(Integer id) {
// 1. 删除部门(第一步:删除部门表中的记录)
deptMapper.delete(id);

// 模拟异常(测试数据一致性问题):此处会抛出ArithmeticException
int i = 1 / 0;

// 2. 删除部门下的员工(第二步:根据部门ID删除员工表中的关联记录)
empMapper.deleteByDeptId(id);
}
}
1
2
3
4
5
6
7
8
9
public interface EmpMapper {

/**
* 根据部门ID删除该部门下的所有员工
* @param deptId 部门ID
*/
@Delete("delete from emp where dept_id = #{deptId}")
void deleteByDeptId(Integer deptId);
}

问题分析(数据一致性隐患)

问题现象: 当执行delete方法时,若在删除部门之后、删除员工之前抛出异常(如上述1/0模拟的异常),会导致:

  • 部门表中的记录已被删除(第一步成功);
  • 员工表中的关联记录未被删除(第二步未执行);
  • 最终数据不一致(部门不存在,但仍有员工属于该部门)。

原因: Spring默认不自动开启事务,因此两步操作是独立的,没有原子性(要么都成功,要么都失败)。

@Transactional注解说明

@Transactional是Spring中用于声明式事务管理的核心注解,通过它可以将事务逻辑与业务代码分离,简化事务管理。

属性 说明
注解名称 @Transactional
适用位置 业务(Service)层的方法接口(推荐在方法上使用)
核心作用 将目标方法/类的所有操作纳入事务管理,具体行为如下:
- 方法执行:自动开启事务(start transaction);
- 方法执行成功:自动提交事务(commit);
- 方法执行异常:自动回滚事务(rollback,默认回滚RuntimeException及其子类)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Service
public class DeptServiceImpl implements DeptService {

@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;

/**
* 删除部门及下属员工(事务管理:方法上的@Transactional
* 说明:该方法的所有操作(删除部门、删除员工)将作为一个事务处理
*/
@Override
@Transactional // 方法上添加@Transactional,控制该方法的事务!!!!!
public void delete(Integer id) {
// 1. 删除部门(第一步:成功执行)
deptMapper.delete(id);

// 模拟异常(第二步:抛出ArithmeticException)
int i = 1 / 0; // 此处异常会触发事务回滚

// 2. 删除部门下的员工(第三步:不会执行)
empMapper.deleteByDeptId(id);
}
}

配置信息

1
2
3
4
#spring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug

rollbackFor

1
2
3
4
5
6
7
8
9
10
11
12
@Transactional // Spring事务管理(默认仅回滚RuntimeException)
@Override
public void delete(Integer id) throws Exception {
deptMapper.deleteById(id); // 1. 删除部门数据(成功执行)

// 模拟业务异常(抛出Checked Exception)
if (true) {
throw new Exception("出错啦..."); // 2. 抛出Exception(Checked异常,默认不回滚)
}

empMapper.deleteByDeptId(id); // 3. 删除部门下的员工(未执行)
}

配置

  • 默认情况下,只有出现RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务。
1
2
3
4
5
6
7
8
9
@Transactional(rollbackFor = Exception.class) // 回滚所有异常(包括Checked Exception)
@Override
public void delete(Integer id) throws Exception {
deptMapper.deleteById(id); // 1. 删除部门
if (true) {
throw new Exception("出错啦..."); // 2. 抛出异常(触发回滚)
}
empMapper.deleteByDeptId(id); // 3. 未执行
}

propagation

image-20250518143241857

加强解散部门

插件

日志筛选

GrepConsole

需求

解散部门时(删除部门及下属员工),无论操作成功还是失败,都必须记录操作日志到数据库(确保日志的完整性)。

实现步骤
  1. 解散部门:删除部门表数据 + 删除该部门下的员工数据(两步操作需在同一事务中);
  2. 记录日志:无论解散部门成功或失败,都要将操作日志(如操作时间、部门ID、描述)插入到日志表中。
核心问题

若将“解散部门”和“记录日志”放在同一个事务中:

  • 若解散部门失败(事务回滚),日志记录也会回滚,导致日志丢失
  • 若日志记录失败(如日志表异常),会导致解散部门的事务回滚,影响主业务。

解决方案:使用事务传播行为,让日志记录在独立事务中执行(与主事务隔离)。

代码实现

1. 主业务:解散部门(DeptServiceImpl)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Java@Service
public class DeptServiceImpl implements DeptService {

@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;
@Autowired
private DeptLogService deptLogService; // 注入日志服务

@Override
@Transactional // 主事务(解散部门)
public void delete(Integer id) {
try {
// 1. 删除部门
deptMapper.deleteById(id);
// 模拟异常(测试事务回滚)
int i = 1 / 0;
// 2. 删除部门下的员工
empMapper.deleteByDeptId(id);
} finally {
// 3. 记录日志(无论try中是否异常,finally都会执行)
DeptLog log = new DeptLog();
log.setCreateTime(LocalDateTime.now()); // 操作时间
log.setDescription("执行了解散部门操作,此次解散的是" + id + "号部门"); // 日志描述
deptLogService.insert(log); // 调用日志服务的插入方法(独立事务)
}
}
}

2. 日志服务:记录日志(DeptLogServiceImpl)

1
2
3
4
5
6
7
8
9
10
11
12
Java@Service
public class DeptLogServiceImpl implements DeptLogService {

@Autowired
private DeptLogMapper deptLogMapper;

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW) // 事务传播行为:创建新事务
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog); // 插入日志到数据库
}
}
关键技术:事务传播行为
  • Propagation.REQUIRES_NEW: 无论当前是否存在事务,都会创建新的独立事务。新事务与主事务完全隔离(主事务回滚不影响新事务,新事务异常也不会导致主事务回滚)。
  • 作用:确保日志记录操作在独立事务中执行,即使主事务(解散部门)回滚,日志依然会被提交
效果验证
  1. 主事务成功:解散部门和删除员工成功,日志事务也成功(日志记录);
  2. 主事务失败(如抛出异常):解散部门和员工的操作回滚,但日志事务独立提交(日志仍记录);
  3. 日志事务失败(如日志表插入异常):日志事务回滚(日志未记录),但主事务不受影响(解散部门操作正常执行或回滚)。
传播行为

场景

  • REQUIRED:大部分情况下都是用该传播行为即可。
  • REQUIRESNEW:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。

AOP

AOP基础

image-20250518172618423

步骤

image-20250518172826781

使用场景

AOP 用于将横切关注点(与业务逻辑无关但多个模块都需要的功能)从业务逻辑中分离,典型场景包括:

  • 记录操作日志:跟踪用户操作行为(如新增、删除、修改);
  • 权限控制:验证用户是否有访问接口的权限;
  • 事务管理:控制方法的事务开启、提交、回滚;
  • 性能监控:统计接口执行时间、资源占用;
  • 异常处理:全局捕获并处理异常;
  • 缓存:对热点数据进行缓存读写等。

AOP 的核心优势

  • 代码无侵入:横切功能(如日志、事务)不嵌入业务逻辑代码,保持业务代码纯净;
  • 减少重复代码:避免在多个业务方法中编写相同的横切逻辑(如每个接口都写日志);
  • 提高开发效率:只需专注于核心业务逻辑,横切功能统一通过 AOP 实现;
  • 维护方便:横切功能集中管理,修改时无需改动多个业务模块。

AOP核心概念

image-20250518210556364

AOP执行流程

image-20250518210857326

AOP进阶

通知类型

注解 通知类型 执行时机
@Around 环绕通知 目标方法前、后都执行(需手动调用 proceed() 执行目标方法,可控制目标方法是否执行)
@Before 前置通知 目标方法执行前执行(如权限校验、参数打印)
@After 后置通知 目标方法执行后执行(无论是否有异常都会执行,如资源释放)
@AfterReturning 返回后通知 目标方法成功执行后执行(有异常时不执行,可获取目标方法返回值)
@AfterThrowing 异常后通知 目标方法抛出异常后执行(可捕获异常信息,如异常日志记录)

注意事项

  • @Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行
  • @Around环绕通知方法的返回值,必须指定为object,来接收原始方法的返回值。

抽取

image-20250518212620789通知顺序

image-20250518213715858

切入点表达式

  • 切入点表达式:描述切入点方法的一种表达式
  • 作用:主要用来决定项目中的哪些方法需要加入通知
  • 常见形式:
    • execution(…):根据方法的签名来匹配
    • @annotation(.):根据注解匹配
1
2
@Before("execution(public void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))
public void before(JoinPoint joinPoint)
1
2
@Before("@annotation(com.itheima.anno.Log)
public void before()

execution语法

image-20250518213946787

execution通配符

image-20250518214446439

execution同时匹配两个方法用“||”
1
2
3
@Pointcut("execution(* com.itheima.service.DeptService.list()) || " +
"execution(* com.itheima.service.DeptService.delete(java.lang.Integer)) ")
private void pt(){}

注意事项

根据业务需要,可以使用且(&&)、或()、非(!)来组合比较复杂的切入点表达式。

execution书写建议
  • 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是find开头,更新类方法都是update开头。
  • 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
  • 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用.,使用*匹配单个包。

annotation语法(常用)

要自定义一个注解类

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {

}

切入点表达式-@annotaton

@annotation切入点表达式,用于匹配标识有特定注解的方法。

1
@annotation(com.itheima.anno.Log)
1
2
3
4
@Before("@annotation(com.itheima.anno.Log)")
public void before(){
log.info("before ...);
}

连接点

image-20250518215832978

获取目标信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Around("pt()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("MyAspect8 around before ...");

// 1. 获取目标对象的类名
String className = joinPoint.getTarget().getClass().getName();
log.info("目标对象的类名:{}", className);

// 2. 获取目标方法的方法名
String methodName = joinPoint.getSignature().getName();
log.info("目标方法的方法名:{}", methodName);

// 3. 获取目标方法运行时传入的参数
Object[] args = joinPoint.getArgs();
log.info("目标方法运行时传入的参数:{}", Arrays.toString(args));

// 4. 放行目标方法执行
Object result = joinPoint.proceed();

// 5. 获取目标方法运行的返回值
log.info("目标方法运行的返回值:{}", result);

log.info("MyAspect8 around after ...");
return null;
}

AOP案例-记录日志操作

实现思路

image-20250518220749927

步骤

● 准备:

​ ● 在案例工程中引入AOP的起步依赖

​ ● 导入资料中准备好的数据库表结构,并引入对应的实体类

● 编码:

​ ● 自定义注解@Log

​ ● 定义切面类,完成记录操作日志的逻辑

获取当前登录用户

● 获取request对象,从请求头中获取到jwt令牌,解析令牌获取出当前用户的id。

五、SpringBoot Web 进阶

原理

配置优先

image-20250528172322917

image-20250528173023243

image-20250528173212440

image-20250528174137534

Bean类

bean的获取

默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:

  • 根据name获取bean:Object getBean(String name)
  • 根据类型获取bean:<T> T getBean(Class<T> requiredType)
  • 根据name获取bean(带类型转换):<T> T getBean(String name, Class<T> requiredType)

注意事项

上述所说的【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

1
2
3
4
5
6
7
8
9
10
11
// 根据Bean的名称("deptController")获取,需手动类型转换  
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
System.out.println(bean1);

// 根据Bean的类型(DeptController.class)获取,自动类型转换
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);

// 根据Bean的名称("deptController")和类型(DeptController.class)获取,无需手动转换
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);

bean的作用域

Spring支持五种作用域,后三种在web环境才生效:

作用域 说明
singleton 容器内同名称的bean只有一个实例(单例)(默认)
prototype 每次使用该bean时会创建新的实例(非单例)
request 每个请求范围内会创建新的实例(web环境中,了解)
session 每个会话范围内会创建新的实例(web环境中,了解)
application 每个应用范围内会创建新的实例(web环境中,了解)

可以通过@Scope注解来进行配置作用域:

1
2
3
4
5
6
@Scope("prototype")  
@RestController
@RequestMapping("/depts")
public class DeptController {

}

注意事项

  • 默认 singleton 的bean,在容器启动时被创建,可以使用 @Lazy 注解来延迟初始化(延迟到第一次使用时)。
  • prototype 的bean,每一次使用该bean的时候都会创建一个新的实例。
  • 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。

第三方bean

第三方bean的注册是为了能够引入bean对象直接使用

1
2
@Autowired
private SAXReader saxReader;

image-20250528180834946

起步依赖

Springboot的两大特征:起步依赖,自动配置

起步依赖:用的是Maven的依赖传递,即A依赖B,B依赖C;引入A,就会同时引入B,C

自动配置

概述

image-20250528204136868

方案

image-20250528204759374

image-20250528205349717

原理分析

image-20250528210956836

image-20250528211123648

所以spring规定第三方提供jar包时一定要有一个特定的文件夹META-INF

而通过一系列注解套娃,ImportSelector里的方法套娃

实现自动配置

在这个文件夹里有两个视频里提到过的文件,里面写好了这个jar包提供的依赖

去扫描每个jar包的该文件夹的这两个文件获取配置信息,交给IOC管理

原理分析-@condition注解

image-20250528212918801

@Conditional

1. @ConditionalOnClass

1
2
3
@Bean  
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") // 当前环境存在指定类时,才声明该bean
public HeaderParser headerParser(){...}

2. @ConditionalOnMissingBean

1
2
3
@Bean  
@ConditionalOnMissingBean // 当不存在当前类型的bean时,才声明该bean
public HeaderParser headerParser(){...}

3. @ConditionalOnProperty

1
2
3
@Bean  
@ConditionalOnProperty(name = "name", havingValue = "itheima") // 配置文件中存在对应属性和值时,才注册bean
public HeaderParser headerParser(){...}

image-20250528213134768

案例(自定义starter)

概述

image-20250528213539615

image-20250528213732090

代码

Web总结

image-20250528220520974

image-20250528220747448

项目中用到的容易忘记注解

1.Lombok 相关注解

注解 作用
@Data 自动生成 getter/settertoString()equals()hashCode() 等方法。
@NoArgsConstructor 自动生成无参构造方法。
@AllArgsConstructor 自动生成包含所有字段的构造方法。
@Slf4j 为类自动注入日志对象 log(如 log.info()),无需手动创建。
@Log 类似 @Slf4j,但使用 Java 自带的 java.util.logging.Logger

2. Spring 核心注解

注解 作用
@Component 将类标记为 Spring 管理的 Bean(组件扫描时自动实例化)。
@Configuration 标记类为配置类,用于定义 Bean(常配合 @Bean 使用)。
@Autowired 自动注入依赖(如将其他 Bean 赋值给当前字段/构造器/方法)。
@Override Java 原生注解,表示方法重写父类/接口的方法(编译时校验)。

3. Spring Boot 配置注解

注解 作用
@ConfigurationProperties(prefix = "ailyuan.oss") 将配置文件(如 application.yml)中 ailyuan.oss 开头的属性绑定到类的字段。

4. Spring MVC 控制器注解

注解 作用
@RestController 组合注解:@Controller + @ResponseBody,表示该类是控制器且返回值直接作为响应体(如 JSON)。
@RequestMapping("/depts") 映射 HTTP 请求路径(如 GET /depts 到指定方法)。
@RequestParam 获取 HTTP 请求参数(如 ?name=Alice → 方法参数 name)。
@PathVariable 获取 URL 路径中的变量(如 /user/{id} → 方法参数 id)。
@RequestBody 将 HTTP 请求体(如 JSON)解析为 Java 对象。

5. Spring AOP 注解

注解 作用
@Aspect 标记类为切面(定义切入点、通知等)。
@Retention(RetentionPolicy.RUNTIME)``@Target(ElementType.METHOD) Java 原生元注解:- @Retention:注解保留到运行时(供反射读取)。- @Target:注解仅能用于方法。

6. 异常处理注解

注解 作用
@ExceptionHandler 在控制器中定义处理特定异常的方法(如处理 NullPointerException)。
@RestControllerAdvice 全局异常处理(组合 @ControllerAdvice + @ResponseBody)。

7. Servlet 相关注解

注解 作用
@WebFilter Java EE 注解,声明类为 Servlet 过滤器(需配合 @ServletComponentScan)。
@ServletComponentScan 在 Spring Boot 中启用扫描 @WebFilter@WebServlet 等组件。

使用场景示例

  • 实体类@Data + @NoArgsConstructor + @AllArgsConstructor
  • 配置类@Configuration + @ConfigurationProperties
  • 控制器@RestController + @RequestMapping + @RequestParam
  • 全局配置@RestControllerAdvice + @ExceptionHandler
  • 日志@Slf4j + log.info("...")
  • AOP@Aspect + @Component + 定义通知方法
  • 过滤器@WebFilter + @ServletComponentScan(在启动类)

Maven高级

分模块设计与开发

为什么

image-20250519195158041

分模块设计

image-20250519195608277

image-20250519200033982

image-20250519200228393

  1. 什么是分模块设计?
    将项目按照功能拆分成若干个子模块
  2. 为什么要分模块设计?
    方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享
  3. 注意事项
    分模块设计需要先针对模块功能进行设计,再进行编码。不会先将
    工程开发完毕,然后进行拆分

继承

继承关系

Maven继承的概念

image-20250527215129244

Maven打包方式
  • jar:普通模块打包,springboot项目基本都是jar包(内嵌tomcat运行)
  • war:普通web程序打包,需要部署在外部的tomcat服务器中运行
  • pom:父工程或聚合工程,该模块不写代码,仅进行依赖管理
步骤

image-20250527215527971

image-20250527220506638

注意事项

  • 若父子工程都配置了同一个依赖的不同版本,以子工程的为准。

image-20250527220639402

版本锁定

image-20250527220944054

image-20250527222433897

< dependencyManagement >与< dependencies >的区别是什么?

  • <dependencies》是直接依赖,在父工程配置了依赖,子工程会直接继承下来。
  • <dependencyManagement》是统一管理依赖版本,不会直接依赖,还需要在子工程中引入所需依赖(无需指定版本)

聚合

image-20250527222730146

image-20250527222813109

继承和聚合的总结

  • 作用
    • 聚合用于快速构建项目
    • 继承用于简化依赖配置、统一管理依赖
  • 相同点:
    • 聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
    • 聚合与继承均属于设计型模块,并无实际的模块内容
  • 不同点:
    • 聚合是在聚合工程中配置关系,聚合可以感知到参与聚合的模块有哪些
    • 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己

私服

介绍

image-20250527223416253

资源上传与下载

image-20250527223705056

image-20250527223814593

image-20250527223824309

image-20250527223943198

image-20250527224151707

启动本地私服

  1. 解压:apache-maven-nexus.zip
  2. 进入目录::apache-maven-nexus\nexus-3.39.0-01\bin
  3. 启动服务:双击 start.bat
  4. 访问服务:localhost:8081
  5. 私服配置说明:将上述配置私服信息的192.168.150.101改为locallhost
其他文章
cover
苍穹外卖
  • 25/05/29
  • 17:48
  • 10.2k
  • 43
cover
Java笔记
  • 24/09/29
  • 17:48
  • 21.7k
  • 85
目录导航 置顶
  1. 1. 学习路线
  2. 2. Web
  3. 3. 一、maven
    1. 3.1. 1、maven介绍
    2. 3.2. 2、maven的作用
    3. 3.3. 3、maven的概念
    4. 3.4. 4、maven的安装
    5. 3.5. 5、IDEA集成Maven
      1. 3.5.1. 配置Maven环境
      2. 3.5.2. IDEA创建Maven项目
      3. 3.5.3. Maven坐标
      4. 3.5.4. 导入Maven项目
    6. 3.6. 6、Maven依赖管理
      1. 3.6.1. 6.1 依赖配置
      2. 3.6.2. 6.2 依赖传递
      3. 3.6.3. 6.3 依赖范围
      4. 3.6.4. 6.4 生命周期
  4. 4. 二、SpringBoot Web基础
    1. 4.1. 1、Spring:
    2. 4.2. 2、创建Springboot工程
    3. 4.3. 3、HTTP协议
      1. 4.3.1. 3.1 HTTP概述
      2. 4.3.2. 3.2 请求协议
      3. 4.3.3. 3.3 响应协议
      4. 4.3.4. 3.4 HTTP协议解析
    4. 4.4. 4、Tomcat
      1. 4.4.1. Springboot内置Tomcat
      2. 4.4.2. Tomcat的基本使用
      3. 4.4.3. 入门程序解析
    5. 4.5. 5、请求响应
      1. 4.5.1. 5.1 请求
      2. 4.5.2. 5.2 响应
      3. 4.5.3. 5.3 分层解构
  5. 5. 三、Mybatis
    1. 5.1. 1、Mybatis入门
      1. 5.1.1. 1.1 Mybatis介绍
      2. 5.1.2. 1.2 JDBC
      3. 5.1.3. 1.3 数据库连接池
      4. 5.1.4. 1.4 Lombok
    2. 5.2. 2、Mybatis基础操作
      1. 5.2.1. 准备工作
      2. 5.2.2. 删除操作
      3. 5.2.3. 日志输出和预编译SQL
      4. 5.2.4. 新增操作
      5. 5.2.5. 主键返回
      6. 5.2.6. 更新(修改)
      7. 5.2.7. 查询(根据ID)
      8. 5.2.8. 查询(根据条件)
    3. 5.3. 3、XML映射文件
    4. 5.4. 4、动态SQL
  6. 6. 四、SpringBoot Web 开发
    1. 6.1. tlias智能学习辅助系统
    2. 6.2. 部门信息功能
      1. 6.2.1. 环境搭建
      2. 6.2.2. 查询部门
      3. 6.2.3. 确保 Jackson 支持 Java 8 时间类型
      4. 6.2.4. 前后端联调
      5. 6.2.5. 删除部门
      6. 6.2.6. 新增部门
      7. 6.2.7. 修改部门
    3. 6.3. 员工信息功能
      1. 6.3.1. 分页查询
      2. 6.3.2. 分析
      3. 6.3.3. 基本信息
      4. 6.3.4. 2.1 员工列表查询
      5. 6.3.5. 请求参数
      6. 6.3.6. 响应数据
      7. 6.3.7. 思路
      8. 6.3.8. 代码细节
      9. 6.3.9. 分页插件PageHelper
      10. 6.3.10. 条件分页查询
      11. 6.3.11. 删除员工
      12. 6.3.12. 新增员工
      13. 6.3.13. 文件上传
      14. 6.3.14. 阿里云OSS
      15. 6.3.15. 修改员工
      16. 6.3.16. 请求参数样例
    4. 6.4. 配置文件
      1. 6.4.1. 问题分析与解决
      2. 6.4.2. 参数配置化
    5. 6.5. 登陆认证
      1. 6.5.1. 登录功能
      2. 6.5.2. 登录校验
      3. 6.5.3. 拦截路径配置说明
      4. 6.5.4. 1. 路径配置方式
      5. 6.5.5. 2. 拦截路径规则说明
    6. 6.6. 异常处理
      1. 6.6.1. 全局异常处理器
    7. 6.7. 事务管理
      1. 6.7.1. 📚 概念
      2. 6.7.2. ✏️ 核心操作
      3. 6.7.3. 完善删除部门
      4. 6.7.4. Springboot事务管理
      5. 6.7.5. 配置信息
      6. 6.7.6. rollbackFor
      7. 6.7.7. propagation
    8. 6.8. AOP
      1. 6.8.1. AOP基础
      2. 6.8.2. 使用场景
      3. 6.8.3. AOP 的核心优势
      4. 6.8.4. AOP核心概念
      5. 6.8.5. AOP执行流程
      6. 6.8.6. AOP进阶
      7. 6.8.7. 切入点表达式
      8. 6.8.8. 连接点
      9. 6.8.9. AOP案例-记录日志操作
  7. 7. 五、SpringBoot Web 进阶
    1. 7.1. 原理
      1. 7.1.1. 配置优先
      2. 7.1.2. Bean类
      3. 7.1.3. 起步依赖
      4. 7.1.4. 自动配置
      5. 7.1.5. 1. @ConditionalOnClass
      6. 7.1.6. 2. @ConditionalOnMissingBean
      7. 7.1.7. 3. @ConditionalOnProperty
  8. 8. Web总结
  9. 9. 项目中用到的容易忘记注解
    1. 9.0.1. 1.Lombok 相关注解
    2. 9.0.2. 2. Spring 核心注解
    3. 9.0.3. 3. Spring Boot 配置注解
    4. 9.0.4. 4. Spring MVC 控制器注解
    5. 9.0.5. 5. Spring AOP 注解
    6. 9.0.6. 6. 异常处理注解
    7. 9.0.7. 7. Servlet 相关注解
    8. 9.0.8. 使用场景示例
  • 10. Maven高级
    1. 10.0.1. 分模块设计与开发
    2. 10.0.2. 继承
    3. 10.0.3. 聚合
    4. 10.0.4. 继承和聚合的总结
    5. 10.0.5. 私服
  • 请输入关键词进行搜索