mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6mobile wallpaper 7mobile wallpaper 8mobile wallpaper 9mobile wallpaper 10mobile wallpaper 11mobile wallpaper 12mobile wallpaper 13mobile wallpaper 14mobile wallpaper 15
4186 字
12 分钟
SSM-MyBatis
2026-04-27

MyBatis#

1.初认识#

MyBatis 是轻量级持久层(数据库)框架,通过 SQL 映射简化 JDBC 操作,解耦 SQL 与 Java 代码,自动完成数据库与 JavaBean 的映射,支持动态 SQL,兼顾灵活性与开发效率。他是一种半自动化框架 只保留关键的sql语句自己编写

2.Mybatis的HelloWorld#

1. 基础环境准备#

  • 导入 MyBatis 核心依赖(及数据库驱动依赖)
  • 配置数据源信息(数据库地址、用户名、密码等)

2. 数据模型映射#

编写 JavaBean 实体类,属性与数据库表字段一一对应(支持驼峰命名自动映射)

3. 数据访问层实现#

实现方式流程核心注解
传统 Dao 方式Dao 接口 → 编写 Dao 实现类@Repository(将实现类交给 Spring 管理)
现代 Mapper 方式Mapper 接口 → 编写 Mapper.xml(配置 SQL)@Mapper(标记为 MyBatis 映射接口)

CRUD几个部分比较相同 这里给出一个查询select

<?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="org.springdata.mybatis01helloworld.mapper.EmpMapper">
<select id="selectById" resultType="org.springdata.mybatis01helloworld.bean.Emp">
select id,emp_name as empName,age,emp_salary as empSalary from t_emp
where id = #{id}
<!-- #{}是用来提取变量的 -->
</select>
</mapper>

效率优化:安装 MyBatisX 插件,可一键为 Mapper 接口生成 Mapper.xml 文件,无需手动创建

4. 配置文件扫描#

在 application.properties 中配置 Mapper.xml 扫描路径:

mybatis.mapper-locations=classpath:mapper/**.xml

5. 编写单元测试#

@Autowired
private EmpMapper empMapper;
@Test
void testSelectById() {
Emp emp = empMapper.selectById(1);
System.out.println(emp);
}

接口都没有实现类竟然能注入进容器

这说明Mybatis在底层给接口生成了一个代理对象Proxy 然后注入容器进行调用

在配置文件中设置包的级别为debug,这样可以查看Mybatis发出的sql语句(日志)

logging.level.org.springdata.mybatis01helloworld.mapper=debug

6.自增id回填机制#

注意: id是自增的, 如果添加了一个用户,想知道自己添加用户的id是多少应该怎么办呢

<insert id="addEmp" useGeneratedKeys="true" keyProperty="id">
<!-- useGeneratedKeys告诉mybatis,这个sql会使用自动生成的id,
keyProperty指定自动生成的id对应的属性,把自动生成的id封装到Emp对象的id属性-->
insert into t_emp(emp_name,age,emp_salary) values (#{empName},#{age},#{salary})
</insert>

这样填写数据的时候,只需要再加一句获取id并输出即可 emp.getId();

7.查询所有员工#

mapper接口

List<Emp> getAllEmp();

xml

<!--返回的是集合,resultType类型也就写对象的类型就行-->
<select id="getAllEmp" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp
</select>

注意:可以在配置文件里开启驼峰下划线映射, 这样数据库里带下划线的列名可以和JavaBean中的驼峰命名的属性名互相映射

mybatis.configuration.map-underscore-to-camel-case=true

比如 empName -> emp_name

那么 Mybatis的HelloWorld项目就算完成了 还是很简单的

3.Mybatis-参数传递#

1. #{ } 与 ${ }#

常用有两种传递方式:

  • #{ } sql语句是占位符 是动态的

  • ${ } 是以拼接参数进sql的形式 目前只有一个使用场景 也就是要指定查询的表名的时候 因为sql原生语法不支持不指定表名进行操作 而且其用于sql注入问题

总结: 参数传递,大部分地方都用#{ }, 少部分用不了#{ }的用${ }

用${ }传参可以做一个sql防注入的校验,用的时候直接ai找相应的代码即可

2. 单/多参数#

单个参数的情况下,直接#{参数名}就可以取到值,

如果参数是Map或者JavaBean,用#{ key 或者 JavaBean中的属性名} 取值

多个参数时用@Param指定参数名 也推荐我们都加上@Param

Emp getEmployByIdAndName(@Param("id")Long id,@Param("name") String name)

需求: 按传入的id,和map里的name,list里的第三个索引是年龄,以及e中的salary来查询一个用户

Emp getEmploy(@Param("id") Long id, //首先要写@Param,有mybatisx插件可以用
@Param("m") Map<String,Object> m,
@Param("ids") List<Long> ids,
@Param("e") Employ e)// params.put("age",12)
}

alt+enter 可以自动生成@Param

<select id="getEmploy" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp where id = #{id} and emp_name=#{m.name} and age=#{ids[2]}and emp_salary=#{e.empSalary}
</select>

只要mapper的方法中参数多于一个,Map JavaBean就要用xx.xx的方式指定到具体的数值进行传递

4.MyBatis-结果封装#

resultType默认封装#

返回基本类型和集合

返回基本类型、普通对象 都只需要在 resultType 中声明返回值类型全类名即可

演示: 返回基本类型的演示

Mapper

Long countEmp(); //查询一共有多少条数据

xml

<select id="countEmp" resultType="java.lang.Long">
select count(*) from t_emp
</select>

如果返回的是List集合,resultType 写集合中元素类型的全类名即可(上面已经用过了)

如果返回Map集合,应该在mapper接口的方法上标注 @MapKey(“id”)

代表指定了id是key,resultType 写集合中元素的全类名,此时控制台输出的时候, key就是id值 注意:自动生成的resultType 可能是map类型,需要自己手动改一下

自定义结果集resultMap#

用法#

数据库的字段名 如果和javaBean的属性名 不能一一对应,此时数据会封装不上,有三种办法

•1、如果符合驼峰命名,则开启驼峰命名规则

•2、编写自定义结果集(ResultMap) 进行封装

还有可以起别名,让名字对应上(别用)

标签里的resultType代表的是默认规则, 可以写resultMap(自定义规则),具体如下

<resultMap id="EmpResultMap" type="com.atguigu.mybatis01helloworld.bean.Emp">
<id column="id" property="id"></id> column代表数据库的类,property代表JavaBean的属性
    <id>标签是用来声明主键映射规则的
<result column="emp_name" property="empName"></result> result标签用来声明其他属性的映射
</resultMap>
<select id="countEmp" resultType="EmpResultMap"> 这里面写resultType等于EmpResultMap(resultMap的id)
select count(*) from t_emp
</select>

最佳做法:

首先开启驼峰命名规则, 如果还有数据传不进去,就用自定义结果集方式

关联查询#

  • 1-1:一对一;多表联查产生一对一关系,比如一个订单对应唯一一个下单客户;此时需要保存关系键到某个表中都可

  • 1-N:一对多;多表联查产生一对多关系,比如一个客户产生了多个订单记录;此时多的一端需要保存关系键

  • N-N:多对多:无论从哪端出发看,都是对多关系,这就是一个多对多的关系,比如 一个学生有多个老师、一个老师又教了多个学生;此时需要一个中间表记录学生和老师的关联关系

collection标签:指定自定义集合封装规则, 对多关系, 可以关联多个

association标签:指定自定义对象封装规则, 对一关系, 一对一,唯一关联一个

一对一关联封装演示:#

根据id查询订单,并且查询下单的客户信息

首先导入ppt中的sql

写JavaBean

@Data
public class Order {
private Long id;
private String address;
private BigDecimal amount;
private Long customerId;
//订单对应的客户
private Customer customer;
}

mapper

@Mapper
public interface OrderMapper {
Order getOrderByIdWithCustomer(Integer id); //根据id查询订单,并且查询下单的客户信息
}

xml

<select id="getOrderByIdWithCustomer" resultType="com.atguigu.mybatis01helloworld.bean.Order">
select o.* , c.* from t_order as o left join t_customer as c on o.customer_id= c.id where o.id =#{id}
</select>

注意: 此时测试的话, c表的信息传不进去

因为 resultType是默认规则, 这里只表明了Order类

所以此时应该写自定义结果集

让Mybatis知道把c表的信息封装到o表的customer中

<!-- 自定义结果集 -->
<resultMap id="OrderRM" type="com.atguigu.mybatis.bean.Order">
    <id column="id" property="id"/> <!-- id标签代表主键,列id和JavaBean的id映射-->
    <result column="address" property="address"/><!--result标签代表普通列-->
    <result column="amount" property="amount"/>
    <result column="customer_id" property="customerId"/>
    <!-- 一对一关联封装 -->
    <association property="customer" javaType="com.atguigu.mybatis.bean.Customer"> <!--指定 javaType的类型        是customer -->
        <id column="c_id" property="id"/>
        <result column="customer_name" property="customerName"/>
        <result column="phone" property="phone"/>
    </association>
</resultMap>
<select id="getOrderByIdWithCustomer" resultMap="OrderRM">
select o.*,
    c.id c_id,
    c.customer_name,
    c.phone from t_order o left join t_customer c
    on o.customer_id = c.id
    where o.id = #{id}
</select>
</mapper>
一对多关联封装演示:#

按照id查询客户,以及他下的所有订单

JavaBean

@Data
public class Customer {
private Long id;
private String customerName;
private String phone;
private List<Order> orders;//保存所有订单的集合
}

mapper接口

@Mapper
public interface CustomerMapper {
Customer getCustomerByIdWithOrders (Integer id);
}

xml

<?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.atguigu.mybatis01helloworld.mapper.CustomerMapper">
<resultMap id="CutomerRM" type="com.atguigu.mybatis01helloworld.bean.Customer">
<id column="c_id" property="id"/>
<result column="customer_name" property="customerName"/>
<result column="phone" property="phone"/>
<!-- 集合的封装用collection来说明一对多的封装规则-->
<!-- 单个对象要说明javaType, 集合要说明ofType,说明了集合里是多个Order对象-->
<collection property="orders" ofType="com.atguigu.mybatis01helloworld.bean.Order">
<id column="id" property="id"/>
<result column="address" property="address"/>
<result column="amount" property="amount"/>
<result column="c_id" property="customerId"/>
</collection>
</resultMap>
<select id="getCustomerByIdWithOrders" resultMap="CutomerRM"> select c.id c_id, c.customer_name, c.phone, o.* from t_customer c left join t_order o on c.id = o.customer_id where c.id = #{id} </select>
</mapper>
多对多#

也是使用collection 原理和一对多一样

就可以理解为一对多 然后”多”里面逐一一对多

TIP

跨mapper也可以使用别人的结果集,方法调用也可以跨mapper使用

分布查询#

分布查询就是按两步进行查询先按照id查客户,再根据客户id查订单

association和collection除了javaType和ofType外还有两个属性,select发sql 和column指定传参

原生写法#

mapper

@Mapper
public interface OrderCustomerStepMapper {
//需求:按照id查询客户 以及他下的所有订单
//1. 查询客户
Customer getCustomerById(Long id);
//2. 按照客户的id查询所有订单
List<Order> getOrdersByCustomerId(Long cId);
}

xml

<mapper namespace="com.atguigu.mybatis.mapper.OrderCustomerStepMapper">
<!-- 按照id查询客户 -->
<select id="getCustomerById" resultMap="CustomerOrdersStepRM">
select * from t_customer where id = #{id} </select>
<!-- 按照客户id查询他的所有订单 -->
<select id="getOrdersByCustomerId" resultType="com.atguigu.mybatis.bean.Order">
select * from t_order where customer_id = #{cId}
</select>

测试代码

@Autowire
OrderCustomerStepMapper orderCustomerStepMapper;
@Test
void test(){
Customer c= orderCustomerStepMapper.getCustomerById(1L);
List<Order> orders = orderCustomerStepMapper.getOrdersByCustomerId(c.getId()); //测试也是分两步
c.setOrders(orders); //把订单数据也赋值给查询到的用户头上
}

借助Mybatis的自动分布查询机制进行分布查询

需求1: 按照id 查询客户 + 查询客户下的订单#

mapper

//分步查询:自动做两步 = 查询客户 + 查询客户下的订单
Customer getCustomerByIdAndOrdersStep(Long id);

xml

<!-- 分步查询的自定义结果集: -->
<resultMap id="CustomerOrdersStepRM" type="com.atguigu.mybatis.bean.Customer">
    <id column="id" property="id"/>
    <result column="customer_name" property="customerName"/>
    <result column="phone" property="phone"/>
    <collection property="orders"         select="com.atguigu.mybatis.mapper.OrderCustomerStepMapper.getOrdersByCustomerId" column="id"> </collection>
<!-- 告诉MyBatis,封装 orders 属性的时候,是一个集合,
    使用collection的select属性,来指定我们要调用的另一个方法
column:来指定我们要调用方法时,把哪一列的值作为传递的参数,交给这个方法
    column="id": 单传参: 这个id就是下面sql语句中传过来的id,把这个id传到getOrdersByCustomerId
注意:如果select指定的方法参数位置有多个参数,需要用@Param来取别名
如果select指定的方法需要传多个参数按这种格式写,column="{cid=id,name=customer_name}"
cid=id:cid参数位置上的别名,id是下面sql传进来的 -->
</resultMap>
<select id="getCustomerByIdAndOrdersStep" resultMap="CustomerOrdersStepRM">
select * from t_customer where id = #{id}
</select>

此时调用接口方法,直接可以发送两条sql,实现分布查询

需求2: 按照id查询订单 + 查询下单的客户#

mapper

//分步查询:自动做两步 = 按照id查询订单 + 查询下单的客户
Order getOrderByIdAndCustomerStep(Long id);

xml

<!-- 分步查询:自定义结果集;封装订单的分步查询 -->
<resultMap id="OrderCustomerStepRM" type="com.atguigu.mybatis.bean.Order">
<id column="id" property="id"/>
<result column="address" property="address"/>
<result column="amount" property="amount"/>
<result column="customer_id" property="customerId"/>
<!-- 一对一查询这个对象,使用association,使用select来绑定方法,使用column来传id -->
<association property="customer" select="com.atguigu.mybatis.mapper.OrderCustomerStepMapper.getCustomerById" column="customer_id"> </association>
</resultMap>
<select id="getOrderByIdAndCustomerStep" resultMap="OrderCustomerStepRM"> select * from t_order where id = #{id} </select>
需求3:按照id查询订单 以及 下单的客户 以及 此客户的所有订单#

mapper

Order getOrderByIdAndCustomerAndOtherOrdersStep(Long id);

xml

一层套一层的调用,只需要小心循环了会栈溢出(Stack OverFlow)

开启延迟加载(懒加载)#

全局配置中添加这两项

mybatis.configuration.lazy-loading-enabled=true
mybatis.configuration.aggressive-lazy-loading=false

用到某个信息,才会发送某个信息的sql, 以前是立即发送全部sql

5.MyBatis-动态SQL#

简介

•动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

•使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

例如之前restful的update方法,很多if判断,有信息则覆盖那一段,实际上很麻烦,可以用动态sql解决

if,where标签#

if标签的使用#

需求:按照 empName 和 empSalary 查询员工,如果只传了一个,带name就按name查,带salary就按salary查

以前的做法

mapper

@Mapper
public interface EmpDynamicSQLMapper {
// 按照 empName 和 empSalary 查询员工,如果只传了一个,带name就按name查,带salary就按salary查
List<Emp> queryEmpByNameAndSalary(@Param("name") String name,
@Param("salary") BigDecimal salary);
}

xml

<mapper namespace="com.atguigu.mybatis01helloworld.mapper.EmpDynamicSQLMapper">
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp where emp_name =#{name} and emp_salary=#{salary}
</select><!--问题是别人传来的name和salary可能是为空的 -->
</mapper>

测试

@Autowired
EmpDynamicSQLMapper d;
@Test
void contextLoads() throws SQLException {
d.queryEmpByNameAndSalary("l",null);
}

注意: 此时的问题是,这样做,最后系统发出的sql是按名字是l,并且薪资是null的查询, 这和我们的需求并不相同了, 而且按照薪资为空查询在sql里也是用is null不是= null, 所以此时需要动态的sql来拼装这个条件

xml修改成

<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp where
<if test="name!=null">
emp_name =#{name}
</if>
<if test="salary!=null"> test属性用来判断条件
and emp_salary=#{salary}
</if>
</select>

此时,Mybatis写的sql语句就只会按名字为l的查了,薪资为空,也不会按薪资=null来查询

where标签的使用#

注意: 上面的做法如果传的name是空,salary有值,直接会报错, 因为按照上面if标签的拼接,第一个if里的语句没有,则此时Mybatis生成的sql是

select * from t_emp where and emp_salary=? 此时多了一个and

如果name和salary都是null, 那输出的sql就是where后面啥也没有, 一样也会报错

解决方式:用where标签来代替where, 他会自动解决sql拼接的问题

<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp
<where>
<if test="name!=null">
emp_name =#{name}
</if>
<if test="salary!=null"> test属性用来判断条件
and emp_salary=#{salary}
</if>
</where>
</select>

set标签的使用#

需求: 更新员工信息,带了什么信息就更新哪个,不带的信息保持不变

mapper

void updateEmp(Emp emp);

xml

<update id="updateEmp">
update t_emp set emp_name=#{empName},emp_salary=#{empSalary},emp_age=#{age} where id=#{id}
</update>

测试

@Autowired
EmpDynamicSQLMapper d;
@Test
void contextLoads() throws SQLException {
Emp emp = new Emp();
emp.setId(4);
emp.setEmpName("hhhhhh");
emp.setAge(14);
emp.setEmpSalary(11111.0);
d.updateEmp(emp);
}

注意: 正常可以进行数据的更新,但是如果更新的时候, 有字段没传,也会正常运行,更新数据库表的信息, 没传的数据修改为空,这和需求不符,需求是不传的数据保持不变

此时我们可以使用if标签

<update id="updateEmp">
update t_emp set
<if test="empName!=null">emp_name=#{empName},</if>
<if test="empSalary!=null"> emp_salary=#{empSalary},</if>
<if test="age!=null">age=#{age}</if>
where id=#{id}
</update>

注意:此时如果最后一句为空, 会因为逗号,

存在sql拼接异常

此时可以使where前面写1=1 每个if里的语句都写逗号, 或者使用set标签来代替set

<update id="updateEmp">
update t_emp <set>
<if test="empName!=null">emp_name=#{empName},</if>
<if test="empSalary!=null"> emp_salary=#{empSalary},</if>
<if test="age!=null">age=#{age}</if>
</set>
where id=#{id}
</update>

trim标签#

是一个功能比where set强大的标签 支持自定义

trim标签代替where

<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis01helloworld.bean.Emp">
select * from t_emp
<trim prefix = "where" suffix ="" prefixOverrides="" suffixOverrides=""> prefix代表前缀,suffix代表后缀,意思是标签体里面有东西,就自动拼上这个前缀和后缀,prefixOverrides前缀覆盖:标签体中最终生成的字符串,如果以指定前缀开始,就覆盖成空串,比如下面第一个条件空,第二个条件成立,prefixOverrides应该写="and"
<if test="name!=null">
emp_name =#{name}
</if>
<if test="salary!=null"> test属性用来判断条件
and emp_salary=#{salary}
</if>
</trim>
</select>

trim代替set

<update id="updateEmp">
update t_emp
<trim prefix="set" suffixOverrides=",">
<if test="empName!=null">emp_name=#{empName},</if>
<if test="empSalary!=null"> emp_salary=#{empSalary},</if>
<if test="age!=null">age=#{age}</if>
</trim>
where id=#{id}
</update>

choose/when/otherwise标签#

select * from t_emp
<where>
    <choose>
        <when test="name!=null"> 符合此条件就走下面的语句
            emp_name=#{name}
        </when>
        <when test="salary>3000"> 符合此条件就走下面的语句
            emp_salary=#{salary}
        </when>
        <otherwise> 都不符合就走这下面的语句
            id=1
        </otherwise>
    </choose>
</where>

注意:如果上面两个条件都满足,那就走第一个

sql-foreach批量操作#

需求:查询指定id集合中的员工

mapper

List<Emp> getEmpsByIdIn(List<Long> ids); //查询指定id集合中的员工

xml

<select id="getEmpsByIdIn"
resultType="com.atguigu.mybatis01helloworld.bean.Emp"> <!--foreach遍历集合和数组, item指定的id就是遍历出来的数据,separator指定了每次遍历元素之间拼接的分隔符,还可以 写open(遍历开始的前缀)="(",以及close=")"那样包裹foreach标签的小括号也不用写了-->
select * from t_emp
<if test="ids!=null"> <!--注意:如果传的集合是空会报错,所以写if,这样如果为空就是查所有了,不会报错 -->
<foreach collection="ids" item="id" separator="," open="where id IN(" close=")">
#{id}
</foreach>
</if>
</select>

注意:如果传过来的集合没有元素,这样不会报错,因为如果没有数据就不会走foreach遍历,也就不会走open的语句

需求2:批量插入一批员工

mapper

void addEmp(List<Emp> emps);

xml

<insert id="addEmp">
insert into t_emp(emp_name,age,emp_salary) values
        <foreach collection="emps" item="emp" separator=",">
        (#{emp.empName},#{emp.age},#{emp.empSalary}) <!--注意,这要写对象点属性,因为要具体确定是集合中哪一个对象的属性 -->
    </foreach>
</insert>

这样就可以批量插入两个元素

需求3: 批量删除(基本和批量插入一样,所以不演示)

需求4: 批量修改

mappper

void updateBatchEmp(List<Emp> emps);

xml

<update id="updateBatchEmp">
<foreach collection="emps" item="e" separator=";">
update t_emp
<set>
<if test="e.empName!=null">
emp_name=#{e.empName}
</if>
<if test="e.empsalary!=null">
emp_salary=#{e.empSalary}
</if>
<if test="e.age!=null">
age=#{e.age}
</if>
</set>
where id =#{e.id}
</foreach>
</update>

注意:用Mybatis发送sql, 数据库默认不支持一个长sql里包含多个短sql

可以在配置文件里写上

jdbc:mysql://mybatis-example?allowMultiQueries=true

allowMultiQueries:允许多个SQL用;隔开,批量发送给数据库执行

由于一口气操纵数据库的代码很多,可以开启事务, 在主类上标注@EnableTransactionManagement, 在mapper上标注@Transactional

这样遇到异常数据库内容就可以回滚了,

注意:分布式项目下,很多不支持sql批量操作的回滚

抽取可复用的sql片段#

<sql id = "column_names">
id,emp_name empName,age,emp_salary empSalary
</sql>
在别的标签的sql语句位置直接写就可以拼接上
select
<include refid ="column_names"></include>
form t_emp ............................

特殊字符#

注意:正常都是写大于号> 写小于号的话 xml会识别成尖括号的一部分< 所以需要写转义字符

原始字符转义字符
&&
<<
>>
""
''

6.MyBatis-扩展内容#

PageHelper分页插件(前后端配合)#

前端需要的数据

1 总页码或者总记录数

2 当前是第几页的数据

3 本页的数据

4 后端收到前端传来的页码,响应前端需要的数据

第四步的实现只需要使用PageInfo方法

@Autowired
EmpMapper d;
@Test
void contextLoads() throws SQLException {
PageHelper.startPage(1, 2);//页码和每页大小
List<Emp> allEmp = d.getAllEmp();
PageInfo<Emp> empPageInfo = new PageInfo<>(allEmp);
System.out.println(empPageInfo.getPageNum()); //获取当前页码
System.out.println(empPageInfo.getPages()); //获取总页码
System.out.println(empPageInfo.getTotal()); //获取总记录数
System.out.println(empPageInfo.isHasNextPage()); //是否有下一页
}
}

实际使用的时候controller层的写法

//查询所有员工分页显示
@GetMapping("/emps")
@Operation(summary = "查询所有员工", description = "分页查询所有员工信息")
public R<List<Employee>> getEmps(){
PageHelper.startPage(1,5);
List<Employee> list = empService.getAllEmp();
//int i = 1/0; 检查全局异常处理是否生效
R<List<Employee>> R = new R<>();
R.setData(list);
return R.ok(list);
}

逆向生成#

Mybatis有一个好用的功能 只需要先连接上数据库 右键数据库选择 MybatisX-generator

配置好相关参数 即可自动生成你数据库里的那些表的增删改查(也是很很偷懒上了好吧)

最终作业#

写一个完整的SSM项目 项目总结在下面

员工管理系统项目总结#

1. 项目基本信息#

1.1 技术栈#

  • Spring Boot 4.0.6:基础框架
  • MyBatis 4.0.1:ORM框架
  • MySQL:数据库
  • Lombok:简化代码
  • Knife4j:接口文档
  • Spring Validation:数据校验

1.2 主要功能#

  • 员工CRUD操作
  • 分页查询
  • 数据校验
  • 全局异常处理
  • RESTful风格接口
  • 跨域支持
  • 接口文档

2. 项目结构#

mybatis-02-crud/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── springdata/
│ │ │ └── mybatis02crud/
│ │ │ ├── bean/ # 实体类
│ │ │ │ └── Employee.java
│ │ │ ├── common/ # 通用类
│ │ │ │ ├── R.java # 统一返回类型
│ │ │ │ └── ResultCode.java # 错误码枚举
│ │ │ ├── controller/ # 控制器
│ │ │ │ └── EmpController.java
│ │ │ ├── mapper/ # MyBatis映射接口
│ │ │ │ └── EmployeeMapper.java
│ │ │ ├── service/ # 服务层
│ │ │ │ ├── EmpService.java
│ │ │ │ └── impl/
│ │ │ │ └── EmpServiceImpl.java
│ │ │ ├── util/ # 工具类
│ │ │ │ └── VoConvertUtil.java # VO转换工具
│ │ │ ├── vo/ # 视图对象
│ │ │ │ ├── req/ # 请求VO
│ │ │ │ │ └── AddEmpVo.java
│ │ │ │ └── resp/ # 响应VO
│ │ │ │ └── EmpRespVo.java
│ │ │ └── advice/ # 全局异常处理
│ │ │ └── GlobalExceptionHandler.java
│ │ └── resources/
│ │ ├── org/
│ │ │ └── springdata/
│ │ │ └── mybatis02crud/
│ │ │ └── mapper/ # MyBatis XML映射文件
│ │ │ └── EmployeeMapper.xml
│ │ ├── application.yaml # 配置文件
│ │ └── messages.properties # 校验错误信息
│ └── test/
│ └── java/
│ └── org/
│ └── springdata/
│ └── mybatis02crud/
│ └── Mybatis02CrudApplicationTests.java
└── pom.xml # Maven依赖配置

3. 核心功能实现#

3.1 统一返回类型(R类)#

  • 功能:封装API响应格式,包含状态码、消息和数据
  • 关键方法
    • ok():成功响应(无数据)
    • ok(T data):成功响应(带数据)
    • error():错误响应(默认错误)
    • error(ResultCode resultCode):错误响应(指定错误码)
    • error(ResultCode resultCode, String message):错误响应(指定错误码和消息)

3.2 错误码枚举(ResultCode)#

  • 功能:集中管理错误码和消息,确保类型安全和代码清晰
  • 主要枚举值
    • SUCCESS:成功
    • SYSTEM_ERROR:系统错误
    • PARAM_ERROR:参数错误
    • DATA_NOT_FOUND:数据未找到
    • BUSINESS_ERROR:业务错误

3.3 员工CRUD操作#

  • 查询所有员工:GET /emps(分页查询)
  • 根据ID查询员工:GET /emps/{id}
  • 添加员工:POST /emp(接收JSON格式数据)(requestbody)
  • 更新员工:PUT /emp(接收JSON格式数据)
  • 删除员工:DELETE /emp/{id}

3.4 数据校验#

  • 使用注解:@NotBlank、@Email等
  • 校验错误处理:通过GlobalExceptionHandler捕获并返回统一格式的错误响应
  • 错误信息国际化:通过messages.properties配置错误消息

3.5 VO层设计#

  • AddEmpVo:添加员工请求VO,包含必要字段和校验规则
  • EmpRespVo:员工响应VO,用于返回员工信息
  • VoConvertUtil:工具类,用于VO与实体类之间的转换

3.6 接口文档#

  • 使用Knife4j:基于OpenAPI的增强型接口文档工具
  • 配置:在application.yaml中配置springdoc和knife4j
  • 注解:使用@Tag、@Operation、@Schema等注解描述接口和参数

4. 注意事项和要点#

4.1 技术要点#

  • @RequestBody注解:用于接收JSON格式的请求数据,必须添加在方法参数前
  • @PathVariable注解:用于接收URL路径中的参数,必须添加在方法参数前
  • @Valid注解:用于启用数据校验,必须添加在需要校验的参数前
  • @CrossOrigin注解:用于解决跨域问题,可添加在控制器类或方法上
  • Lombok的@Data注解:自动生成getter、setter、equals、hashCode和toString方法,简化代码

4.2 最佳实践#

  • 分层设计:遵循MVC架构,分离控制层、服务层和数据访问层
  • 统一返回格式:使用R类封装所有API响应,确保格式一致
  • 错误处理:使用全局异常处理器统一处理异常,返回标准化的错误响应
  • 代码复用:将重复代码抽取为工具类,如VoConvertUtil
  • 文档化:使用Knife4j生成接口文档,方便前端开发和测试

5. 总结#

本项目是一个基于Spring Boot和MyBatis的员工管理系统,实现了员工的CRUD操作、分页查询、数据校验、全局异常处理和接口文档等功能。通过合理的分层设计和代码组织,提高了代码的可维护性和可读性。同时,通过使用Knife4j生成接口文档,方便了前端开发和测试。

项目中使用的技术栈和实现方式都是目前企业开发中的主流实践,具有一定的参考价值。通过本项目的开发,可以掌握Spring Boot、MyBatis、数据校验、全局异常处理等核心技术的使用方法,为后续的企业级应用开发打下基础。