Maven

生命周期

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

Springboot

Springboot原理

起步依赖:依赖传递
自动配置

分层解耦

三层架构

controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
service:业务逻辑层,处理具体的业务逻辑。
dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。

分层解耦

控制反转:Inversion Of Control,简称IOC.对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean

Spring Framework的StringUtils

StringUtils常用方法

空值检查

// 检查字符串是否有内容(不为null且长度>0)
StringUtils.hasLength(str)

// 检查字符串是否有实际文本(不为null且包含非空白字符)
StringUtils.hasText(str)

// 检查字符串是否为空(null或空字符串)
StringUtils.isEmpty(str)

字符串处理

// 去除前后空白
StringUtils.trimWhitespace(str)

// 去除所有空白(包括中间的)
StringUtils.trimAllWhitespace(str)

// 将字符串数组用分隔符连接
StringUtils.collectionToDelimitedString(list, ",")

// 将逗号分隔的字符串转为数组
StringUtils.commaDelimitedListToStringArray(str)

// 首字母大写
StringUtils.capitalize(str)

// 首字母小写
StringUtils.uncapitalize(str)

Apache Commons Lang的StringUtils

空值检查

// 检查是否为空(null或空字符串)
StringUtils.isEmpty(str)

// 检查是否为空白(null、空字符串或纯空白字符)
StringUtils.isBlank(str)

// 对应的非空检查
StringUtils.isNotEmpty(str)
StringUtils.isNotBlank(str)

字符串比较

// 安全的字符串比较(处理null值)
StringUtils.equals(str1, str2)

// 忽略大小写比较
StringUtils.equalsIgnoreCase(str1, str2)

字符串处理

// 截取子字符串(安全处理null和越界)
StringUtils.substring(str, start, end)

// 左侧填充
StringUtils.leftPad(str, size, padChar)

// 右侧填充
StringUtils.rightPad(str, size, padChar)

// 去除空白
StringUtils.trim(str)
StringUtils.strip(str) // 更强大的去除空白

// 重复字符串
StringUtils.repeat(str, count)

字符串转换

// 大小写转换
StringUtils.upperCase(str)
StringUtils.lowerCase(str)

// 缩写处理
StringUtils.abbreviate(str, maxWidth)

// 反转字符串
StringUtils.reverse(str)

集合操作

// 用分隔符连接字符串数组/集合
StringUtils.join(array, separator)

// 拆分字符串
StringUtils.split(str, separator)

Bean管理

获取bean

默认情况下,Spring项目启动时,会把bean都创建好放在I0C容器中,通过@Autowired自动注入来获取bean对象。如果想要主动获取这些bean,可以通过如下方式:
在这里插入图片描述

bean的作用域

@Lazy: 延迟bean的初始化。
@Scope:设置bean的作用域。如:@Scope(“prototype”)
在这里插入图片描述

第三方bean

@Bean注解:将方法返回值交给I0C容器管理,成为I0C容器的beap对象。
如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component及衍生注解声明bean的,就需要用到 @Bean注解,一般在配置类中定义。如:

@SpringBootApplication
@MapperScan("com.myproject.*.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    /**
     * 密码加密工具类
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        System.out.println("是否自动运行Bean:true");
        return  new BCryptPasswordEncoder();
    }
}

MySQL

DDL:数据定义语言,用来定义数据库对象(数据库,表,字段)
DML:数据操作语言,用来对数据库表中的数据进行增删改
DQL:数据查询语言,用来查询数据库中表的记录
DCL:数据控制语言,用来创建数据库用户、控制数据库的访问权限

函数

now():获取当前系统时间。
if(条件表达式,true取值,false取值)
case 表达式 when 值l then 结果1 when 值2 then 结果2 …else … end

数学函数

函数 说明 示例
ABS(x) 绝对值 ABS(-5)=5
ROUND(x,d) 四舍五入 ROUND(3.1415,2)=3.14
TRUNCATE(x,d) 截断 TRUNCATE(3.1415,2)=3.14
CEIL(x) / CEILING(x) 向上取整 CEIL(3.1)=4
FLOOR(x) 向下取整 FLOOR(3.9)=3
MOD(x,y) 取余 MOD(10,3)=1
POWER(x,y) 幂运算 POWER(2,3)=8
SQRT(x) 平方根 SQRT(9)=3
RAND() 随机数(0-1) RAND()

字符串函数

函数 说明 示例
LENGTH(s) 字节长度 中文 3 字节
CHAR_LENGTH(s)LENGTH(s) 字符长度 中文 1 字符
CONCAT(a,b,...) 拼接 CONCAT('a','b')='ab'
CONCAT_WS(sep,a,b) 带分隔符拼接 CONCAT_WS('-',1,2)=1-2
SUBSTRING(s,start,len) 截取 SUBSTRING('abc',2,2)='bc'
LEFT(s,n) 左截取 LEFT('abc',2)='ab'
RIGHT(s,n) 右截取 RIGHT('abc',2)='bc'
UPPER(s) 大写
LOWER(s) 小写
REPLACE(s,a,b) 替换 REPLACE('a-b','-','_')
TRIM(s) 去空格
LTRIM(s) 去左空格
RTRIM(s) 去右空格
LOCATE(substr,str) 查找位置 LOCATE('b','abc')=2
INSTR(str,substr) 同上

日期时间函数

函数 说明 示例
NOW() 当前日期时间 2025-11-20 09:33:00
CURDATE() 当前日期
CURTIME() 当前时间
DATE_ADD(date,INTERVAL x UNIT) 日期加减 DATE_ADD(NOW(),INTERVAL 1 DAY)
DATE_SUB(date,INTERVAL x UNIT) 日期减
DATEDIFF(a,b) 天数差
TIMESTAMPDIFF(unit,a,b) 精确差 TIMESTAMPDIFF(MINUTE,a,b)
YEAR(date) 提取年份
MONTH(date)
DAY(date)
HOUR(date)
MINUTE(date)
SECOND(date)
DATE_FORMAT(date,format) 格式化 DATE_FORMAT(NOW(),'%Y-%m-%d')
STR_TO_DATE(str,format) 字符串转日期

聚合函数

函数 说明
COUNT(*) 统计行数
COUNT(column) 统计非 NULL 数量
SUM(column) 求和
AVG(column) 平均值
MAX(column) 最大值
MIN(column) 最小值

条件函数

函数 说明
IF(condition, a, b) 类似三元表达式
IFNULL(a, b) NULL 返回默认值
NULLIF(a, b) 相等返回 NULL

类型转换函数

函数 说明
CAST(x AS type) 转换类型
CONVERT(x, type) 同上
BINARY 强制按字节比较
SELECT CAST('123' AS UNSIGNED);   -- 123
SELECT CAST(3.14 AS DECIMAL(5,2));

JSON 相关函数(常用)

函数 说明
JSON_EXTRACT(json, path) 获取字段
JSON_SET(json, path, val) 设置字段
JSON_REMOVE(json, path) 删除字段
JSON_ARRAY() 创建数组
JSON_OBJECT(k,v,...) 创建对象
SELECT JSON_EXTRACT('{"a":1}','$.a');

DDL(表操作)

语法结构

在这里插入图片描述

create table 表名(
   字段1 字段类型[约束][comment 字段1注释],
   ...
   字段n 字段类型[约束][comment 字段n注释]
)[comment 表注释];

在这里插入图片描述

实例

// 创建表
create TABLE test(
  id INT COMMENT 'ID',
	user_name VARCHAR(20) comment '用户名',
	name VARCHAR(20) comment '姓名',
	age INT COMMENT '年龄',
	gender VARCHAR(2) COMMENT '性别'
) COMMENT '用户表'
//查看表的当前结构
DESCRIBE test;
// 添加主键约束
ALTER TABLE test 
MODIFY COLUMN id INT AUTO_INCREMENT,
ADD CONSTRAINT primary_key PRIMARY KEY (id)
// 添加唯一约束和非空约束
ALTER TABLE test
MODIFY user_name VARCHAR(20) NOT NULL,
ADD CONSTRAINT uq_users_username UNIQUE (user_name)
// 添加默认约束
ALTER TABLE test ALTER gender SET DEFAULT('男')

DML(数据操作)

语法结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例

// 新增--单条
INSERT into test(user_name) VALUES('caiw2'); 
// 新增--批量
INSERT INTO test(user_name) VALUES ('caiw3'),('caiw4');
// 修改
UPDATE test SET name='蔡旺',age=18 WHERE id=1;
//修改--批量
UPDATE test SET name='蔡旺',age=18
// 删除
DELETE FROM test WHERE id = 2;

DQL(查询操作)

语法结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
where与having区别

  1. 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤
  2. 判断条件不同:where不能对聚合函数进行判断,而having可以。

在这里插入图片描述
在这里插入图片描述

实例

// 基本查询
select * from test;
// 去除重复记录
SELECT DISTINCT user_name, name, age FROM test
// 条件查询
SELECT * FROM test WHERE (user_name in('caiw2','caiw3') and age = 18 and id> 2 ) || id=5

// 聚合函数
SELECT count(id) from test
SELECT count(1) from test
SELECT count(*) from test
SELECT min(age) FROM test
SELECT max(age) from test
SELECT avg(age) from test
SELECT sum(age) from test

// 分组查询--只能返回分组字段和聚合函数
select age,count(*) as '数量' from test
GROUP BY age
HAVING count(*) > 1

// 排序查询
SELECT * FROM test ORDER BY age;
SELECT * FROM test ORDER BY age desc,id DESC;

// 分页查询
SELECT * FROM test LIMIT 0 ,5

// 条件表达式--if
select IF(gender='男','男生','女生') as 性别,count(*) as 数量 FROM test GROUP BY gender;

// 条件表达式-case
select 
(CASE gender
	WHEN '男' THEN '男生'
	WHEN '女' THEN '女生'
	ELSE '太监'
END)
as 性别,
count(*) as 数量 FROM test GROUP BY gender

数据类型

数值类型

在这里插入图片描述

字符串类型

在这里插入图片描述

CHAR 和 VARCHAR的区别
CHAR 是 定长 的。你定义一个 CHAR(10),无论你存入什么字符串,它都会固定占用 10个字符 的存储空间。速度快。浪费空间
VARCHAR 是 变长 的。你定义一个 VARCHAR(10),它占用的空间是 实际字符串长度 + 1个或2个额外字节。速度慢,节省空间。

日期类型

在这里插入图片描述

多表设计

物理外键–不推荐使用,一般使用逻辑外键(代码实现)在这里插入图片描述

1对多:在多的表里增加字段;
多对多:增加中间表来关联

多表查询 ★

连接查询

内连接:相当于查询A、B交集部分数据。
在这里插入图片描述

// 隐式内连接
SELECT a.*,b.category_name from test_dish as a,test_category as b WHERE  b.id = a.category_id AND a.id=1
// 显示内连接
SELECT a.*,b.category_name FROM test_dish as a JOIN test_category as b ON b.id = a.category_id AND a.id=1

外连接
左外连接:查询左表所有数据(包括两张表交集部分数据);
右外连接:查询右表所有数据(包括两张表交集部分数据);

在这里插入图片描述

// 左外连接
SELECT a.*,b.category_name from test_dish as a LEFT JOIN test_category as b ON b.id = a.category_id AND b.category_name='菜品品类'
SELECT a.*,b.category_name from test_dish as a LEFT JOIN test_category as b ON b.id = a.category_id WHERE b.category_name='菜品品类'
// 右外连接
SELECT a.*,b.category_name from test_dish as a RIGHT JOIN test_category as b ON b.id = a.category_id 

子查询

在这里插入图片描述

// 标量子查询--查询所有品类为'菜品品类'的所有菜品,先获取菜品品类的id,根据id来获取菜品
SELECT * FROM test_dish as a WHERE a.category_id = (SELECT b.id FROM test_category b WHERE b.category_name='菜品品类')

// 列子查询--查询所有品类为'菜品品类、水果品类'的所有菜品,先获取菜品品类的id,根据id来获取菜品
SELECT * FROM test_dish as a WHERE a.category_id  in(SELECT b.id FROM test_category b WHERE b.category_name in('菜品品类','水果品类'))

// 行子查询--查询品类为'菜品品类'并且状态一致的所有菜品
SELECT * FROM test_dish as a WHERE a.category_id =  (SELECT b.id FROM test_category b WHERE b.category_name='菜品品类') and a.STATUS = (SELECT b.STATUS FROM test_category b WHERE b.category_name='菜品品类')
SELECT * FROM test_dish as a WHERE (a.category_id,a.STATUS) =  (SELECT b.id,b.STATUS FROM test_category b WHERE b.category_name='菜品品类') 

事务

事务:是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。
在这里插入图片描述

// 事务
BEGIN;
INSERT INTO test_category(category_name,create_time,update_time)VALUES('ax41',now(),now());
INSERT INTO test_dish(dish_name,price,category_id,create_time,update_time) VALUES('aaa1',200,5,now(),now());
COMMIT;
ROLLBACK;

四大特性

原子性:事务是不可分割的最小单元,要么全部成功,要么全部失败。
一致性:事务完成时,必须使所有的数据都保持一致状态。
隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

索引

索引(index):是帮助数据库 高效获取数据 的 数据结构。B+Tree(多路平衡搜索树)

优点:

  1. 提高数据查询的效率,降低数据库的I0成本。
  2. 通过索引列对数据进行排序,降低数据排序的成本降低CPU消耗。

缺点
3. 索引会占用存储空间。
4. 索引大大提高了查询效率,同时却也降低了insert、update、delete的效率。

在这里插入图片描述

MybatisPlus

BaseMapper 与 IService 方法对比

在这里插入图片描述

条件构造器LambdaQueryWrapper

在这里插入图片描述
在这里插入图片描述
实例

// SELECT * FROM user
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// WHERE username = 'zhangsan'
wrapper.eq(User::getUsername, user.getUsername());
// 执行查询并获取结果
User loginUser = this.baseMapper.selectOne(wrapper);

在Mybatis中的参数#{参数}和${参数}的区别

  1. #是预编译sql,效率更高,防止sql注入。

LambdaQueryWrapper 与lambdaQuery()区别

对比项 LambdaQueryWrapper lambdaQuery()(返回 LambdaQueryChainWrapper)
本质 条件构造器 链式查询器(包含 wrapper + mapper)
是否需要自己 new ✔ 需要 new ✘ 不需要
是否需要自己调用 mapper ✔ 需要 mapper.selectList ✘ 不需要,直接 list() 执行
能否自动识别实体类型 ❌ 不能,需要 <User> 泛型 ✔ 能,基于 ServiceImpl 泛型
使用场景 Mapper 或 Service 都可 Service 层(IService/ServiceImpl 内)
代码复杂度 较多 最简洁
内部存在关系 是 λ 链式查询器内部使用的对象 包含了 LambdaQueryWrapper

JSON 处理器

数据库字段为json类型

项目 说明
JSON 处理器 TypeHandler 机制自动转换 JSON
常用处理器 JacksonTypeHandler(推荐)、FastjsonTypeHandler
注解使用 @TableField(typeHandler = JacksonTypeHandler.class)
XML 场景 @TableName(autoResultMap = true) 必须开启
数据库类型 推荐 JSON 类型
用途 自动序列化/反序列化 List/Map/对象
@Data
public class User {

    private Long id;

    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<String> hobbies;

    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> configs;

    @TableField(typeHandler = JacksonTypeHandler.class)
    private Address address;
}

XML映射文件

  1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
  2. XML映射文件的namespace属性为Mapper接口全限定名一致。
  3. XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

官方文档

在这里插入图片描述

<!-- 定义 resultMap -->
<resultMap id="userResultMap" type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <result property="email" column="user_email"/>
    <result property="createTime" column="create_time"/>
</resultMap>

<!-- 使用 resultMap -->
<select id="getUser" resultMap="userResultMap">
    SELECT user_id, user_name, user_email, create_time 
    FROM users 
    WHERE user_id = #{id}
</select>

动态SQL

if、where、set

<select id="getAll" resultType="com.myproject.demo.entity.TestCategory" parameterType="com.myproject.demo.entity.vo.VCategory">
        select * from test_category
        <where>
            <if test="categoryName != null">
                and category_name like CONCAT('%',#{categoryName},'%')
            </if>
        </where>
    </select>

foreach批量操作

     <!--
     collection:遍历的集台
     item:遍历出来的元素
     separator:分隔符
     open:遍历开始前拼接的SQL片段
     close:遍历结束后拼接的sql片段
     -->
    <delete id="deleteByIds">
          delete from test_category where id in
          <foreach collection="ids" item="id" separator="," open="(" close=")">
              #{id}
          </foreach>
    </delete>

sql、include

<sql id="list" >
        select id,category_name,category_type,status,create_time,update_time from test_category
    </sql>
    <select id="getAll" resultType="com.myproject.demo.entity.TestCategory"
            parameterType="com.myproject.demo.entity.vo.VCategory">
        <include refid="list"></include>
        <where>
            <if test="categoryName != null">
                and category_name like CONCAT('%',#{categoryName},'%')
            </if>
        </where>
    </select>

文件上传

接收文件 – MultipartFile

@PostMapping(value="/upload")
    public Result upload(@RequestPart("file") MultipartFile file) {
        log.info("文件上传--------》",file);
        return Result.success();
 }

本地存储

使用transferTo方法转存到指定目录中

public Result upload(@RequestPart("file") MultipartFile file) throws IOException {
        log.info("文件上传--------》",file);
        // 转存到本地指定目录
        file.transferTo(new File("D:\\logs\\"+file.getOriginalFilename()));
        return Result.success();
    }

存储到OSS

存储到minio


过滤器Filter

Filter(过滤器) 是 Java Web 开发中的一个重要概念,它类似于一个"安检站",在请求到达目标资源(如 Servlet、Controller)之前和响应返回给客户端之前进行拦截和处理。

public interface Filter {
    // 初始化方法
    void init(FilterConfig filterConfig);
    
    // 核心过滤方法
    void doFilter(ServletRequest request, ServletResponse response, 
                 FilterChain chain);
    
    // 销毁方法
    void destroy();
}
  1. 更底层的请求/响应处理
  2. 与具体业务逻辑无关的通用设置
  3. 需要在Spring MVC框架之前执行

拦截器Interceptor

作用:Spring框架提供。类似过滤器。拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
常用于业务逻辑层面的拦截。

过滤器和拦截器同时存在时,过滤器先执行,放行后,再执行拦截器。
过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源

全局异常处理器

/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result ex(Exception ex){
       ex.printStackTrace();
       return Result.fail("操作失败!");
    }
}

事务回滚

@Transactional(rollbackFor = Exception.class)
默认只有运行异常RuntimeException才会回滚异常。rollbackFor属性控制回滚任何异常。
@Transactional(propagation = Propagation.REQUIRED)
根据propagation 来控制事务的传播行为。
REQUIRED:【默认值】需要事务,有则加入,无则创建新事务。
REQUIRES_NEW:需要新事务,无论有无,总是创建新事务。


AOP面向切面编程

AOP: Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程
实现: 动态代理是面向切面编程最主流的实现。

通知类型

@Aroupd:环绕通知,此注解标注的通知方法在目标方法前、后都被执行。如:@Around(“execution(* com.myproject.demo.service..(…))”)
@Before:前置通知,此注解标注的通知方法在目标方法前被执行。
@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行。
@AfterReturning :返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行。
@AfterThrowing :异常后通知,此注解标注的通知方法发生异常后执行

切入点

  1. execution(.):根据方法的签名来匹配。
    在这里插入图片描述

  2. @annotation(.):根据注解匹配。

    // 定义切入点
    // @Pointcut("execution(* com.myproject.demo.service.*.*(..))")
    // 拦截带有@OperLogAnnotation注解的方法
    @Pointcut("@annotation(com.myproject.myAnnotation.OperLogAnnotation)")
    public void operLogPointCut() {}

    // 引入切入点
    @Around("operLogPointCut()") 
    public Object addLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object proceed = proceedingJoinPoint.proceed();
        OperateLog operateLog = new OperateLog();
        operateLog.setClassName(proceedingJoinPoint.getTarget().getClass().getName());
        operateLog.setCreateId("admin");
        iOperateLogService.save(operateLog);

        return proceed;

    }

配置优先级

高到低:命令行参数->java系统属性->application.properties->application.yml。

java系统属性和命令行参数

// jar包运行
java -jar demo-0.0.1-SNAPSHOT.jar
// 配置端口号
java -Dserver.port=10000 -jar demo-0.0.1-SNAPSHOT.jar  // java系统属性
java -jar demo-0.0.1-SNAPSHOT.jar --server.port=10000  // 命令行属性,优先级高于系统属性

更多推荐