1.mysql

1.1基础语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查询所有数据库
show databases;
# 创建数据库
create database 数据库名;
# 使用数据库
use 数据库名
# 查询数据库的创建信息
show create database 数据库名\G
#删除数据库
drop database 数据库名
# 创建新的表格
create table 表格名(
字段名 数据类型,
字段名 数据类型
);
# 查询某个库的所有表格
show tables from 数据库名
# 查看表的创建信息
show create table 表名称\G
# 删除表格
drop table 表格名

1.2表的增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查询语句
SELECTFROM
# 别名(可忽略AS)
SELECT student AS stu, shool sho FROM employees;
# 去除重复行
SELECT DISTINCT id FROM employees;

# 添加语句
INSERT INTO persons (name, birth_date, phone)
VALUES ('Peter Wilson', '1990-07-15', '0711-020361');

# 修改语句
UPDATE employees
SET salary = 6000, dept_id = 2
WHERE emp_id = 5;

# 删除语句
DELETE FROM persons WHERE id > 3;

1.3排序与分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# order byselect语句的最后
# ASC:升序
# DESC:降序
SELECT * FROM dept ORDER BY id ASC

# 前10条记录
SELECT * FROM table LIMIT 0,10
SELECT * FROM table LIMIT 10
# 第1120条记录
SELECT * FROM table LIMIT 10,10
# 第2130条记录
SELECT * FROM table LIMIT 20,10;

# MySQL8.0中可以使用LIMIT 3 OFFSET 4,可以表示第5条记录开始后3条记录
# 分页显示公式(当前页数-1* 每页条数,每页条数
# LIMIT 必须放到最后
SELECT * FROm table
LIMIT (PageNo -1)*PageSize,PageSize;

1.4运算符IN和BETWEEN

1
2
3
4
5
6
7
8
9
10
# IN表示检查指定的值
# 获取来自table表中id为13的所有数据
SELECT * FROM table
WHERE id IN (1,3)

# BETWEEN表示检查指定范围的值
# 获取employees表中工资在70009000范围内的所有数据
SELECT * FROM employees
WHERE salary
BETWEEN 7000 AND 9000;

1.5运算符UNION和like

UNION操作符用于将两个或多个SELECT查询的结果合并到一个结果集中。

1
2
3
4
# 如果没有加ALL则表示去除重复行
SELECT column_list FROM table1_name
UNION ALL
SELECT column_list FROM table2_name;

LIKE用于模糊查询

声明 含义
WHERE name LIKE ‘Da%’ 查找以Da开头的名字
WHERE name LIKE ‘%th’ 查找以th结尾的名字
WHERE name LIKE ‘%on%’ 查找包含on的名字
WHERE name LIKE ‘Sa_’ 查找以Sa开头且最多后跟一个字符的名字
WHERE name LIKE ‘_oy’ 查找以oy结尾且最多包含一个字符的名字
WHERE name LIKE ‘an 查找包含an的名字,并以一个字符开头和结尾

1.6表的连接

code

  1. 内连接
  • 两个表中交集的数据
    1
    2
    3
    SELECT t1.emp_id, t1.emp_name, t1.hire_date, t2.dept_name
    FROM employees AS t1 INNER JOIN departments AS t2
    ON t1.dept_id = t2.dept_id ORDER BY emp_id;
    code
  1. 左连接
  • 左表和两表交集的数据
    1
    2
    3
    SELECT t1.emp_id, t1.emp_name, t1.hire_date, t2.dept_name
    FROM employees AS t1 LEFT JOIN departments AS t2
    ON t1.dept_id = t2.dept_id ORDER BY emp_id;
    code
  1. 右连接
  • 右表和两表交集的数据
    1
    2
    3
    SELECT t1.emp_id, t1.emp_name, t1.hire_date, t2.dept_name
    FROM employees AS t1 RIGHT JOIN departments AS t2
    ON t1.dept_id = t2.dept_id ORDER BY dept_name;
    code

1.7函数

1.7.1关于日期时间函数

获取日期时间函数
  1. 获取当前日期时间
    1
    SELECT NOW(); # 2022-01-06 22:37:45
  2. 获取当前日期
    1
    SELECT CURRENT_DATE(); # 2022-01-06
  3. 获取当前时间
    1
    SELECT CURRENT_TIME(); # 22:39:04
日期格式化
  1. 日期转指定格式字符串
    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
    SELECT DATE_FORMAT('2022-01-08 22:23:01', '%Y%m%d%H%i%s');# 20220108222301
    说明:
    %W 星期名字(Sunday……Saturday)
    %D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
    %Y 年, 数字, 4 位 ★★★
    %y 年, 数字, 2
    %a 缩写的星期名字(Sun……Sat)
    %d 月份中的天数, 数字(00……31) ★★★
    %e 月份中的天数, 数字(0……31)
    %m 月, 数字(01……12) ★★★ month
    %c 月, 数字(1……12)
    %b 缩写的月份名字(Jan……Dec)
    %j 一年中的天数(001……366)
    %H 小时(00……23)★★★
    %k 小时(0……23)
    %h 小时(01……12)
    %I 小时(01……12)
    %l 小时(1……12)
    %i 分钟, 数字(00……59) ★★★ minite
    %r 时间,12 小时(hh:mm:ss [AP]M)
    %T 时间,24 小时(hh:mm:ss)
    %S 秒(00……59)
    %s 秒(00……59) ★★★
    %p AM或PM
    %w 一个星期中的天数(0=Sunday ……6=Saturday )
    %U 星期(0……52), 这里星期天是星期的第一天,查询指定日期属于当前年份的第几个周 ★★★★
    %u 星期(0……52), 这里星期一是星期的第一天
    示例代码:
    1
    2
    3
    4
    5
    6
    7
    # 日期格式化
    select date_format(now(),'%Y%m%d%H%i%s');
    # 获取当前是星期几
    select date_format(now(),'%Y%m%W');
    # 查看当前属于一年中的第几个周 以周末作为一个循环
    select date_format(now(),'%Y%U');
    select date_format('20220108090109','%Y%U');
  2. 字符串转日期
    1
    2
    3
    # 日期格式与表达式格式一致即可
    SELECT STR_TO_DATE('06/01/2022', '%m/%d/%Y'); # 2022-06-01
    SELECT STR_TO_DATE('20220108090109', '%Y%m%d%H%i%s'); # 2022-01-08 09:01:09
日期间隔
  1. 增加日期间隔 ★★★
    1
    2
    3
    4
    # 间隔单位可以是DAY MONTH MINUTE WEEK YEAR SECOND HOUR
    SELECT DATE_ADD(NOW(),INTERVAL 2 DAY); # 2022-01-07 22:46:39
    SELECT DATE_ADD(NOW(),INTERVAL 2 MONTH); # 2022-02-06 22:47:17
    SELECT DATE_ADD('2022-02-06 22:47:17',INTERVAL 2 MONTH); # 2022-04-06 22:47:17
  2. 减去一个时间间隔★★★
    1
    2
    SELECT DATE_SUB(NOW(),INTERVAL 3 DAY); # 2022-01-03 22:49:24
    SELECT DATE_SUB('2022-02-06 22:47:17',INTERVAL 2 MONTH); # 2021-12-06 22:47:17
  3. 日期相差天数(天)
    1
    select datediff('2022-01-06','2021-12-28'); -- 9
  4. 相差时间(小时)
    1
    select timediff('2022-01-06 08:08:08', '2021-12-28 09:00:00'); -- 08:08:08
星期操作

返回日期date的星期索引

1
2
3
4
# 返回日期date的星期索引(1=星期天,2=星期一, ……7=星期六)。这些索引值对应于ODBC标准。
SELECT DAYOFWEEK(NOW())-1;
# 返回date的星期索引(0=星期一,1=星期二, ……6= 星期天)
SELECT WEEKDAY(NOW())+1

其它操作
1
2
3
4
5
6
7
8
# 获取日
SELECT DAYOFMONTH(NOW());# 6
# 获取月份
SELECT MONTH(NOW());# 1
# 获取星期几
SELECT DAYNAME(NOW());# Thursday
# 获取第几季度
SELECT QUARTER(NOW());# 2022/1/6 --> 1

2.mybatis

快速入门

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class DeptController {

@Autowired
private DeptService deptService;

//部门列表查询
@GetMapping("/depts")
public Result depList(){
List<Dept> depts = new ArrayList<>();
depts = deptService.selectList();
return Result.success(depts);
}
}

Service
1
2
3
public interface DeptService {
public List<Dept> selectList();
}

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

@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> selectList() {
List<Dept> depts = deptMapper.selectList();
for (Dept dept : depts) {
System.out.println(dept);// 调用对象的toString();
}
return depts;
}
}

Mapper
1
2
3
4
@Mapper
public interface DeptMapper {
List<Dept> selectList();
}

Mapper.xml
1
2
3
4
5
6
7
8
<?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.itheima.mapper.DeptMapper">
<select id="selectList" resultType="com.itheima.pojo.Dept">
SELECT * FROM dept
</select>
</mapper>

2.1mybatis动态语句

  1. if和where标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- List<Employee> selectEmployeeByCondition(Employee employee); -->
    <select id="selectEmployeeByCondition" resultType="employee">
    select emp_id,emp_name,emp_salary from t_emp
    <!-- where标签会自动去掉“标签体内前面多余的and/or” -->
    <where>
    <!-- 使用if标签,让我们可以有选择的加入SQL语句的片段。这个SQL语句片段是否要加入整个SQL语句,就看if标签判断的结果是否为true -->
    <!-- 在if标签的test属性中,可以访问实体类的属性,不可以访问数据库表的字段 -->
    <if test="empName != null">
    <!-- 在if标签内部,需要访问接口的参数时还是正常写#{} -->
    or emp_name=#{empName}
    </if>
    <if test="empSalary &gt; 2000">
    or emp_salary>#{empSalary}
    </if>
    <!--
    第一种情况:所有条件都满足 WHERE emp_name=? or emp_salary>?
    第二种情况:部分条件满足 WHERE emp_salary>?
    第三种情况:所有条件都不满足 没有where子句
    -->
    </where>
    </select>
  2. set标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- void updateEmployeeDynamic(Employee employee) -->
    <update id="updateEmployeeDynamic">
    update t_emp
    <!-- set emp_name=#{empName},emp_salary=#{empSalary} -->
    <!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 -->
    <set>
    <if test="empName != null">
    emp_name=#{empName},
    </if>
    <if test="empSalary &lt; 3000">
    emp_salary=#{empSalary},
    </if>
    </set>
    where emp_id=#{empId}
    <!--
    第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?
    第二种情况:部分条件满足 SET emp_salary=?
    第三种情况:所有条件都不满足 update t_emp where emp_id=?
    没有set子句的update语句会导致SQL语法错误
    -->
    </update>
  3. choose/when/otherwise标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
    <select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
    select emp_id,emp_name,emp_salary from t_emp
    where
    <choose>
    <when test="empName != null">emp_name=#{empName}</when>
    <when test="empSalary &lt; 3000">emp_salary &lt; 3000</when>
    <otherwise>1=1</otherwise>
    </choose>

    <!--
    第一种情况:第一个when满足条件 where emp_name=?
    第二种情况:第二个when满足条件 where emp_salary < 3000
    第三种情况:两个when都不满足 where 1=1 执行了otherwise
    -->
    </select>
  4. foreach
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--
    collection属性:要遍历的集合
    item属性:遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象
    separator属性:指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
    open属性:指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串
    close属性:指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串
    index属性:这里起一个名字,便于后面引用
    遍历List集合,这里能够得到List集合的索引值
    遍历Map集合,这里能够得到Map集合的key
    -->
    <foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
    <!-- 在foreach标签内部如果需要引用遍历得到的具体的一个对象,需要使用item属性声明的名称 -->
    (#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
    </foreach>
  5. sql片段
  • 抽取重复片段
    1
    2
    3
    4
    <!-- 使用sql标签抽取重复出现的SQL片段 -->
    <sql id="mySelectSql">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
    </sql>
  • 引用
    1
    2
    <!-- 使用include标签引用声明的SQL片段 -->
    <include refid="mySelectSql"/>

3.mybatis-plus

快速入门
  1. 依赖
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.5</version>
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>springboot-starter-mybatis-plus-06</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!-- 测试环境 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <!-- mybatis-plus -->
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
    </dependency>

    <!-- 数据库相关配置启动器 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <!-- druid启动器的依赖 -->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.18</version>
    </dependency>

    <!-- 驱动类-->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
    </dependency>

    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.28</version>
    </dependency>

    </dependencies>


    <!-- SpringBoot应用打包插件-->
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    </project>
  2. yaml
    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
    # 连接池配置
    spring:
    datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
    url: jdbc:mysql:///day01
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    mybatis-plus: # mybatis-plus的配置
    # 默认位置 private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"};
    mapper-locations: classpath:/mapper/*.xml
    configuration:
    # 配置MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    global-config:
    db-config:
    # 配置MyBatis-Plus操作表的默认前缀
    table-prefix: t_
    # 配置MyBatis-Plus的主键策略
    id-type: auto
    # 全局指定逻辑删除
    logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
    logic-delete-value: 1 # 逻辑已删除值(默认为 1)
    logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

  3. 启动类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @MapperScan("com.atguigu.mapper")
    @SpringBootApplication
    public class MainApplication {

    public static void main(String[] args) {
    SpringApplication.run(MainApplication.class,args);
    }

    }

  4. mapper接口
    1
    2
    public interface UserMapper extends BaseMapper<User> {
    }
  5. service接口
    1
    2
    public interface UserService extends IService<User> {
    }
  6. ServiceImpl
    1
    2
    3
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
    }
  7. mapper.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namespace = 接口的全限定符 -->
    <mapper namespace="com.atguigu.mapper.UserMapper">

    <select id="queryAll" resultType="user" >
    select * from user
    </select>
    </mapper>

3.1基于Mapper的CRUD

Insert方法
1
2
3
4
// 插入一条记录
// T 就是要插入的实体对象
// 默认主键生成策略为雪花算法(后面讲解)
int insert(T entity);
Delete方法
1
2
3
4
5
6
7
8
// 根据 ID 删除
int deleteById(主键id);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(自定义名称)集合idList);
// 根据 entity 条件,删除记录
int delete(wapper对象);
// 根据 columnMap 条件,删除记录
int deleteByMap(Map对象);
Update方法
1
2
3
4
5
// 根据 whereWrapper 条件,更新记录
int update(修改的实体类(可以为null), wapper对象);

// 根据 ID 修改 主键属性必须值
int updateById(T entity);
Select方法
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
// 根据 ID 查询
T selectById(主键id);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(集合idList);

// 根据 entity 条件,查询一条记录
T selectOne(queryWrapper);

// 根据 entity 条件,查询全部记录
List<T> selectList(queryWrapper);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(queryWrapper);

// 查询(根据 columnMap 条件)
List<T> selectByMap(Map条件);

// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, queryWrapper);

// 根据 Wrapper 条件,查询总记录数
Integer selectCount( queryWrapper);

3.2基于Service的CRUD

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
保存:
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);

修改或者保存:
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

移除:
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

更新:
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);

数量:
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

查询:
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

集合:
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

3.3条件构造器

Wrapper : 条件构造抽象类,最顶端父类

  • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
    • QueryWrapper : 查询/删除条件封装
    • UpdateWrapper : 修改条件封装
    • AbstractLambdaWrapper : 使用Lambda 语法
      • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
      • LambdaUpdateWrapper : Lambda 更新封装Wrapper
        UpdateWrapper 可以把字段设置为null

code

组装查询条件
1
2
3
4
5
6
7
8
9
10
11
@Test
public void test01(){
//查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("username", "a")
.between("age", 20, 30)
.isNotNull("email");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);


组装排序条件
1
2
3
4
5
6
7
8
9
10
11
@Test
public void test02(){
//按年龄降序查询用户,如果年龄相同则按id升序排列
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,id ASC
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.orderByDesc("age")
.orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}

组装删除条件
1
2
3
4
5
6
7
8
9
10
@Test
public void test03(){
//删除email为空的用户
//DELETE FROM t_user WHERE (email IS NULL)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
//条件构造器也可以构建删除语句的条件
int result = userMapper.delete(queryWrapper);
System.out.println("受影响的行数:" + result);
}

and和or关键字使用(修改)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void test04() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
//UPDATE t_user SET age=?, email=? WHERE username LIKE ? AND age > ? OR email IS NULL)
queryWrapper
.like("username", "a")
.gt("age", 20)
.or()
.isNull("email");
User user = new User();
user.setAge(18);
user.setEmail("user@atguigu.com");
int result = userMapper.update(user, queryWrapper);
System.out.println("受影响的行数:" + result);
}

指定列映射查询
1
2
3
4
5
6
7
8
9
10
@Test
public void test05() {
//查询用户信息的username和age字段
//SELECT username,age FROM t_user
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("username", "age");
//selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为null
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}

condition判断组织条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 @Test
public void testQuick3(){

String name = "root";
int age = 18;

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//判断条件拼接
//当name不为null拼接等于, age > 1 拼接等于判断
//方案1: 手动判断
if (!StringUtils.isEmpty(name)){
queryWrapper.eq("name",name);
}
if (age > 1){
queryWrapper.eq("age",age);
}

//方案2: 拼接condition判断
//每个条件拼接方法都condition参数,这是一个比较运算,为true追加当前条件!
//eq(condition,列名,值)
queryWrapper.eq(!StringUtils.isEmpty(name),"name",name)
.eq(age>1,"age",age);
}

LambdaQueryWrapper示例代码
1
2
3
4
5
6
7
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();

lambdaQueryWrapper.eq(User::getName, "John")
.ge(User::getAge, 18)
.orderByDesc(User::getCreateTime)
.last("limit 10");
List<User> userList = userMapper.selectList(lambdaQueryWrapper);

3.4注解

  • @TableName—-表名注解
  • @TableId—-主键注解
  • @TableField—-字段注解
  • @TableLogic—-逻辑删除
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @TableName("sys_user")
    public class User {
    @TableId(value="主键列名",type=主键策略)
    private Long id;
    @TableField("nickname")
    private String name;
    private Integer age;
    private String email;

    @TableLogic
    //逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1
    private Integer deleted;
    }
    全局指定逻辑删除
    1
    2
    3
    4
    5
    6
    mybatis-plus:
    global-config:
    db-config:
    logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
    logic-delete-value: 1 # 逻辑已删除值(默认为 1)
    logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

    4.SpringMVC

    4.1请求路径

    @RequestMapping
    @GetMapping
    @PostMapping
    @PutMapping 更新全部资源
    @DeleteMapping
    @PatchMapping 更新部分资源

4.2接收参数

param和JSON比较
  1. 参数编码:param是ASCII码,json是UTF-8
  2. 参数顺序:param没有限制
  3. 数据类型:param简单的数据类型
  4. 嵌套性:param不支持嵌套
  5. 可读性:param简单易读,json结构清晰
param参数接收
  1. 直接接收
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Controller
    @RequestMapping("param")
    public class ParamController {

    /**
    * 前端请求: http://localhost:8080/param/value?name=xx&age=18
    *
    * 可以利用形参列表,直接接收前端传递的param参数!
    * 要求: 参数名 = 形参名
    * 类型相同
    * 出现乱码正常,json接收具体解决!!
    * @return 返回前端数据
    */
    @GetMapping(value="/value")
    @ResponseBody
    public String setupForm(String name,int age){
    System.out.println("name = " + name + ", age = " + age);
    return name + age;
    }
    }
  2. @RequestParam注解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     /**
    * 前端请求: http://localhost:8080/param/data?name=xx&stuAge=18
    *
    * 使用@RequestParam注解标记handler方法的形参
    * 指定形参对应的请求参数@RequestParam(请求参数名称)
    */
    @GetMapping(value="/data")
    @ResponseBody
    public Object paramForm(@RequestParam("name") String name,
    @RequestParam(value = "stuAge",required = false,defaultValue = "18") int age){
    System.out.println("name = " + name + ", age = " + age);
    return name+age;
    }
  3. 特殊场景接值
  • 一名多值(多选框)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 前端请求: http://localhost:8080/param/mul?hbs=吃&hbs=喝
    *
    * 一名多值,可以使用集合接收即可!但是需要使用@RequestParam注解指定
    */
    @GetMapping(value="/mul")
    @ResponseBody
    public Object mulForm(@RequestParam List<String> hbs){
    System.out.println("hbs = " + hbs);
    return hbs;
    }
  • 实体类接收
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Controller
    @RequestMapping("param")
    public class ParamController {

    @PostMapping("/user")
    @ResponseBody
    public String addUser(User user) {
    // 在这里可以使用 user 对象的属性来接收请求参数
    System.out.println("user = " + user);
    return "success";
    }
    }
  • 路径接收
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     /**
    * 动态路径设计: /user/{动态部分}/{动态部分} 动态部分使用{}包含即可! {}内部动态标识!
    * 形参列表取值: @PathVariable Long id 如果形参名 = {动态标识} 自动赋值!
    * @PathVariable("动态标识") Long id 如果形参名 != {动态标识} 可以通过指定动态标识赋值!
    *
    * 访问测试: /param/user/1/root -> id = 1 uname = root
    */
    @GetMapping("/user/{id}/{name}")
    @ResponseBody
    public String getUser(@PathVariable Long id,
    @PathVariable("name") String uname) {
    System.out.println("id = " + id + ", uname = " + uname);
    return "user_detail";
    }
  • json参数接收
  1. 前端请求的json数据
    1
    2
    3
    4
    5
    {
    "name": "张三",
    "age": 18,
    "gender": "男"
    }
  2. 定义接收json的java类
    1
    2
    3
    4
    5
    6
    public class Person {
    private String name;
    private int age;
    private String gender;
    // getter 和 setter 略
    }
  3. Controller
    1
    2
    3
    4
    5
    6
    @PostMapping("/person")
    @ResponseBody
    public String addPerson(@RequestBody Person person) {
    // 在这里可以使用 person 对象来操作 JSON 数据中包含的属性
    return "success";
    }

4.3接收cookie数据

考虑使用以下 cookie 的请求:

1
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的示例演示如何获取 cookie 值:
1
2
3
4
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}

4.4接收请求头数据

请考虑以下带有标头的请求:

1
2
3
4
5
6
Host                    localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300

下面的示例获取 Accept-EncodingKeep-Alive 标头的值:
1
2
3
4
5
6
@GetMapping("/demo")
public void handle(
@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}

4.5校验注解

注解 规则
@Null 标注值必须为 null
@NotNull 标注值不可为 null
@AssertTrue 标注值必须为 true
@AssertFalse 标注值必须为 false
@Min(value) 标注值必须大于或等于 value
@Max(value) 标注值必须小于或等于 value
@DecimalMin(value) 标注值必须大于或等于 value
@DecimalMax(value) 标注值必须小于或等于 value
@Size(max,min) 标注值大小必须在 max 和 min 限定的范围内
@Digits(integer,fratction) 标注值值必须是一个数字,且必须在可接受的范围内
@Past 标注值只能用于日期型,且必须是过去的日期
@Future 标注值只能用于日期型,且必须是将来的日期
@Pattern(value) 标注值必须符合指定的正则表达式
@Email 标注值必须是格式正确的 Email 地址
@Length 标注值字符串大小必须在指定的范围内
@NotEmpty 标注值字符串不能是空字符串
@Range 标注值必须在指定的范围内
  1. 导入依赖(二选一)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- 校验注解 -->
    <dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>9.1.0</version>
    <scope>provided</scope>
    </dependency>

    <!-- 校验注解实现-->
    <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
    <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
    <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>8.0.0.Final</version>
    </dependency>
1
2
3
4
<dependency>  
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  1. 注解应用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class User {
    //age 1 <= age < = 150
    @Min(10)
    private int age;

    //name 3 <= name.length <= 6
    @Length(min = 3,max = 10)
    private String name;

    //email 邮箱格式
    @Email
    private String email;

    public int getAge() {
    return age;
    }
    }
  2. handler标记和绑定错误收集
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @RestController
    @RequestMapping("user")
    public class UserController {
    /**
    * @Validated 代表应用校验注解! 必须添加!
    */
    @PostMapping("save")
    public Object save(@Validated @RequestBody User user,
    //在实体类参数和 BindingResult 之间不能有任何其他参数, BindingResult可以接受错误信息,避免信息抛出!
    BindingResult result){
    //判断是否有信息绑定错误! 有可以自行处理!
    if (result.hasErrors()){
    System.out.println("错误");
    String errorMsg = result.getFieldError().toString();
    return errorMsg;
    }
    //没有,正常处理业务即可
    System.out.println("正常");
    return user;
    }
    }

5.接口文档的使用

  1. 查看请求路径和方式

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

  2. 看请求参数
    请求参数样例(路径传参) —- @PathVariable

    1
    /depts/1

    请求参数样例(json传参) —- @RequestBody 可以自己创建一个VO类传参

    1
    2
    3
    {
    "name": "教研部"
    }

    请求数据样例(Param传参) —- @RequestParam

    1
    2
    3
    4
    5
    @RequestParam(defaultValue = "1")Integer page,
    @RequestParam(defaultValue = "10") Integer pageSize,
    String name, Short gender,
    @DateTimeFormat(pattern ="yyyy-MM-dd") LocalDate begin,
    @DateTimeFormat(pattern ="yyyy-MM-dd") LocalDate end
    1
    /emps?name=张&gender=1&begin=2007-09-01&end=2022-09-01&page=1&pageSize=10
  3. 响应数据
    响应数据样例 —- 可以自己创建一个DTO进行响应 —- 数据要一一对应

    1
    2
    3
    4
    5
    6
    {
    "id": 1,
    "name": "学工部",
    "createTime": "2022-09-01T23:06:29",
    "updateTime": "2022-09-01T23:06:29"
    }

    响应数据样例 —- 创建一个List集合接收并返回

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [
    {
    "id": 1,
    "name": "学工部",
    "createTime": "2022-09-01T23:06:29",
    "updateTime": "2022-09-01T23:06:29"
    },
    {
    "id": 2,
    "name": "教研部",
    "createTime": "2022-09-01T23:06:29",
    "updateTime": "2022-09-01T23:06:29"
    }
    ]

6.登录功能

mybatis+jwt+token+拦截器+明文密码
  1. 导入依赖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
    </dependency>

    <dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
    </dependency>
  2. 编写配置类
    1
    2
    3
    4
    5
    #jwt配置
    jwt:
    token:
    tokenExpiration: 120 #有效时间,单位分钟
    tokenSignKey: headline123456 #当前程序签名秘钥 自定义
  3. 导入工具类
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    package com.atguigu.utils;

    import com.alibaba.druid.util.StringUtils;
    import io.jsonwebtoken.*;
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;

    import java.util.Date;

    @Data
    @Component
    @ConfigurationProperties(prefix = "jwt.token")
    public class JwtHelper {

    private long tokenExpiration; //有效时间,单位毫秒 1000毫秒 == 1秒
    private String tokenSignKey; //当前程序签名秘钥

    //生成token字符串
    public String createToken(Long userId) {
    System.out.println("tokenExpiration = " + tokenExpiration);
    System.out.println("tokenSignKey = " + tokenSignKey);
    String token = Jwts.builder()

    .setSubject("YYGH-USER")
    .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration*1000*60)) //单位分钟
    .claim("userId", userId)
    .signWith(SignatureAlgorithm.HS512, tokenSignKey)
    .compressWith(CompressionCodecs.GZIP)
    .compact();
    return token;
    }

    //从token字符串获取userid
    public Long getUserId(String token) {
    if(StringUtils.isEmpty(token)) return null;
    Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
    Claims claims = claimsJws.getBody();
    Integer userId = (Integer)claims.get("userId");
    return userId.longValue();
    }



    //判断token是否有效
    public boolean isExpiration(String token){
    try {
    boolean isExpire = Jwts.parser()
    .setSigningKey(tokenSignKey)
    .parseClaimsJws(token)
    .getBody()
    .getExpiration().before(new Date());
    //没有过期,有效,返回false
    return isExpire;
    }catch(Exception e) {
    //过期出现异常,返回true
    return true;
    }
    }
    }

  4. Controller
    1
    2
    3
    4
    5
    6
    7
    8
    //登录功能
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){

    Result result = empService.login(emp);
    System.out.println(result);
    return result;
    }
  5. Service
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Override
    public Result login(Emp emp) {
    //根据账号查询账号
    Emp loginUser = empMapper.selectOne(emp);
    //判断账号是否为空
    if (loginUser == null){
    return Result.error("账号不存在");
    }
    //判断密码是否为空,且密码是否正确
    if (!StringUtils.isEmpty(loginUser.getPassword())
    && loginUser.getPassword().equals(emp.getPassword())){
    //生成token
    String token = jwtHelper.createToken(Long.valueOf(loginUser.getId()));
    return Result.success(token);
    }

    return Result.error("密码错误");
    }
  6. 创建拦截器
    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
    36
    37
    38
    39
    40
    package com.itheima.interceptor;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.itheima.until.JwtHelper;
    import com.itheima.pojo.Result;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    @Component
    public class Process01Interceptor implements HandlerInterceptor {

    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    String token = request.getHeader("token");
    //判断token是否为空或过期
    if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)){
    //设置响应参数
    Result result = Result.error("NOT_LOGIN");
    //创建把参数转换为json的对象
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(result);
    response.getWriter().print(json);
    //拦截
    return false;
    }else{
    //放行
    return true;
    }
    }
    }

  7. 拦截器配置类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.itheima.config;

    import com.itheima.interceptor.Process01Interceptor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    //拦截器配置
    @Autowired
    private Process01Interceptor process01Interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    //设置拦截除了/login的所有路径
    registry.addInterceptor(process01Interceptor).excludePathPatterns("/login");
    }
    }

  8. 统一返回值类型
    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
    package com.itheima.pojo;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @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);
    }
    }

7.分页查询

mybatis+pagehelper插件
  1. 导入依赖
    1
    2
    3
    4
    5
    6
    <!--分页插件依赖-->
    <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.2</version>
    </dependency>
  2. 实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Override
    public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
    //设置分页参数
    PageHelper.startPage(page,pageSize);
    //进行模糊查询
    List<Emp> emplist = empMapper.list(name, gender, begin,end);
    //Page是插件提供的
    Page<Emp> p=(Page<Emp>)emplist;
    //封装返回值
    PageBean pageBean=new PageBean(p.getTotal(),p.getResult());
    return pageBean;
    }
mybatis-plus+分页插件
  • 分页插件的原理

    首先分页参数放到 ThreadLocal 中,拦截执行的 sql,根据数据库类型添加对应的分页语句重写 sql,例如:(select from table where a) 转换为 (select count (※) from table where a) 和 (select from table where a limit ,)
    计算出了 total 总条数、pageNum 当前第几页、pageSize 每页大小和当前页的数据,是否为首页,是否为尾页,总页数等。

  1. 配置分页插件的配置类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.xuecheng.content.config;  
    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    @MapperScan("com.xuecheng.content.mapper")
    public class MybatisPlusConfig {
    /**
    * 定义分页拦截器
    */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    return interceptor;
    }
    }
  2. 测试类
    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
    36
    37
    38
    39
    40
    41
    42
    @Slf4j  
    @Service
    public class CourseBaseInfoServiceImpl implements CourseBaseInfoService {
    @Autowired
    CourseBaseMapper courseBaseMapper;

    //课程分页查询和条件查询
    @Override
    public PageResult<CourseBase> queryCourseBaseList(PageParams pageParams, QueryCourseParamsDto courseParamsDto) {
    //拼装查询条件
    LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
    //根据名称模糊查询,在sql中拼接 course_base.name like '%值%'
    queryWrapper.like(StringUtils.isNotEmpty(courseParamsDto.getCourseName())
    ,CourseBase::getName
    ,courseParamsDto.getCourseName());
    //根据课程审核状态查询,在sql中拼接 course_base.audit_status = ? queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getAuditStatus())
    ,CourseBase::getAuditStatus
    ,courseParamsDto.getAuditStatus());
    //根据课程状态查询
    queryWrapper.eq(StringUtils.isNotEmpty(courseParamsDto.getPublishStatus())
    ,CourseBase::getStatus
    ,courseParamsDto.getPublishStatus());


    //创建Page分页参数对象 ,参数:页码和每页记录数
    Page<CourseBase> Page = new Page<>(pageParams.getPageNo(),pageParams.getPageSize());
    //开始进行分页查询
    Page<CourseBase> pageResult = courseBaseMapper.selectPage(Page, queryWrapper);
    //数据列表
    List<CourseBase> items = pageResult.getRecords();
    //总记录数
    long total = pageResult.getTotal();

    //List<T> items , Long counts , Long page , Long ,pageSize
    //封装返回参数
    PageResult<CourseBase> courseBasePageResult =
    new PageResult<CourseBase>(items,total,pageParams.getPageNo()
    ,pageParams.getPageSize());
    System.out.println(courseBasePageResult);
    return courseBasePageResult;
    }
    }

8.全局异常处理和自定义异常处理

  1. 设置通用信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public enum CommonError {  
    //定义枚举类
    UNKOWN_ERROR("执行过程异常,请重试。"),
    PARAMS_ERROR("非法参数"),
    OBJECT_NULL("对象为空"),
    QUERY_NULL("查询结果为空"),
    REQUEST_NULL("请求参数为空");

    private String errMessage;

    public String getErrMessage() {
    return errMessage;
    }
    //有参构造
    private CommonError( String errMessage) {
    this.errMessage = errMessage;
    }
    }
  2. 自定义异常处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class XueChengPlusException extends RuntimeException {  
    private String errMessage;
    //无参构造
    public XueChengPlusException() {
    super();
    }
    //有参构造
    public XueChengPlusException(String errMessage) {
    super(errMessage);
    this.errMessage = errMessage;
    }
    //get方法
    public String getErrMessage() {
    return errMessage;
    }
    //抛异常直接调用 XueChengPlusException(参数)
    public static void cast(CommonError commonError){
    throw new XueChengPlusException(commonError.getErrMessage());
    }
    public static void cast(String errMessage){
    throw new XueChengPlusException(errMessage);
    }
    }
  3. 响应用户的统一类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.io.Serializable;  
    //和前端约定返回的异常信息模型
    public class RestErrorResponse implements Serializable {
    private String errMessage;
    public RestErrorResponse(String errMessage){
    this.errMessage= errMessage;
    }
    public String getErrMessage() {
    return errMessage;
    }
    public void setErrMessage(String errMessage) {
    this.errMessage = errMessage;
    }
    }
  4. 全局异常处理
    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
    import lombok.extern.slf4j.Slf4j;  
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.*;
    @Slf4j
    @ControllerAdvice
    //@RestControllerAdvice
    public class GlobalExceptionHandler {

    //全局异常处理
    @ResponseBody
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestErrorResponse exception(Exception e){
    //记录异常
    log.error("系统异常{}",e.getMessage(),e);
    //解析出异常信息
    RestErrorResponse restErrorResponse = new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());
    return restErrorResponse;
    }

    //自定义异常处理
    @ResponseBody
    @ExceptionHandler(XueChengPlusException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RestErrorResponse customException(XueChengPlusException e){
    //记录异常
    log.error("系统异常{}",e.getErrMessage(),e);
    //..
    //解析出异常信息
    String errMessage = e.getErrMessage();
    RestErrorResponse restErrorResponse = new RestErrorResponse(errMessage);
    return restErrorResponse;
    }
    }