8 minute read


1. JavaWeb 基础

前端部分暂时跳过

1.1 web基础知识

1.1.1 SpringBoot 项目的结构

springboot-demo/
│
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       ├── DemoApplication.java        ← 程序入口(启动类)
│   │   │       ├── controller/                 ← 控制层(接收请求)
│   │   │       ├── service/                    ← 业务逻辑层
│   │   │       ├── mapper/                     ← 数据访问层(MyBatis接口)
│   │   │       └── entity/                     ← 实体类(与数据库表对应)
│   │   ├── resources/
│   │   │   ├── application.properties          ← 核心配置文件
│   │   │   ├── static/                         ← 静态资源(js、css、图片)
│   │   │   ├── templates/                      ← 页面模板(如 Thymeleaf)
│   │   │   └── mapper/                         ← MyBatis 的 XML 映射文件
│   │   └── ...
│   └── test/
│       └── java/
│           └── com/example/demo/
│               └── DemoApplicationTests.java    ←  单元测试类
│
├── pom.xml                                     ← Maven 配置文件(依赖管理)
└── README.md                                   ← 项目说明(可选)

自动生成的 Application 是整个 Spring Boot 项目的 启动入口类,作用为:

  • 项目启动时从这里执行;
  • 启动内置的 Tomcat;
  • 加载所有 Spring 配置;
  • 扫描组件(Controller、Service、Repository 等);
  • 运行你的 Web 应用或后台服务。

1.2 相关注解解释


注解 所属层 主要功能 注入方式
@RestController 控制层 定义 REST 接口,返回 JSON 数据 ——
@RequestMapping 控制层 映射请求路径 ——
@Resource 通用 按名称注入 Bean(JDK 标准) byName → byType
@Repository 数据层 标识 DAO 层组件,异常转换 ——
@Service 业务层 标识业务逻辑组件 ——
@Autowired 通用 按类型注入 Bean(Spring 特有) byType
@Component 通用 标注不属于 Controller / Service / Repository 层的通用类 ——

  • @RestController控制层(Controller) 的注解,用于定义一个 RESTful 风格的控制器。

    等价于:

      @Controller + @ResponseBody
    

    功能:

    • 表示该类负责处理 HTTP 请求;
    • 返回的数据不是页面,而是 JSON / XML 等数据格式
    • 通常用于开发前后端分离的接口。
  • @RequestMapping 用于 映射请求路径 到控制器方法或类上。

    常用位置:

    • 类上:定义公共路径前缀;
    • 方法上:定义具体的请求路径。

    Spring 提供了更细粒度的注解:

    注解 说明
    @GetMapping 处理 GET 请求
    @PostMapping 处理 POST 请求
    @PutMapping 处理 PUT 请求
    @DeleteMapping 处理 DELETE 请求
  • @ResourceJDK 提供的依赖注入注解(属于 javax.annotation 包)。用于 自动注入 Bean 对象(类似于 @Autowired)。

    特点:

    • 默认按 名称(byName) 注入;
    • 如果找不到同名 Bean,则按类型(byType)匹配;
    • 可以通过 name 属性显式指定 Bean 名称。
  • @Repository 用于标注 持久层(DAO / Mapper) 组件。

    功能:

    • 表示该类是与数据库交互的组件;
    • 使异常转换机制生效(Spring 会将数据库异常转换为统一的 Spring DataAccessException)。

    在 MyBatis 中,一般接口上不用手动加 @Repository,因为 Mapper 会被自动扫描注册为 Bean。

  • @Service 用于标注 业务逻辑层(Service 层) 的组件。

    功能:

    • 标识业务逻辑类;
    • 让 Spring 自动将其注册为 Bean;
    • 便于与 Controller、Repository 层区分。
  • @Autowired:Spring 的依赖注入(DI)注解,用于自动装配 Bean。

    特点:

    • 类型(byType) 自动注入;
    • 如果有多个同类型 Bean,可以用 @Qualifier 指定;
    • 也可以和构造方法、Setter、字段一起使用。
  • @Component 是 Spring 中最基础的 组件注解,表示一个类被 Spring 管理,成为 IOC 容器中的 Bean。

    只要类上加了 @Component,Spring 启动时就会自动创建这个类的对象,并放进容器中管理(实现依赖注入)。

    使用场景:

    一般用于标注不属于 Controller / Service / Repository 层的通用类;

1.2.1 代码案例

  • 通过前端页面来请求本地的文件中的数据,然后将数据显示在前端中
@RestController
public class UserController {
    //放在 static/user.html 下的 HTML 文件,就相当于网站的一个页面。
    //所以使用 http://localhost:8080/list 会返回原始数据,后端接口,只返回数据(JSON 格式)。
    // 使用http://localhost:8080/user.html显示前端页面,前端页面,展示 UI,并通过 JS 请求后端数据。
    @RequestMapping("/list")
    public List<Day250928_User> list(){
        // 1. 读取资源文件(user.txt),文件放在 resources/static 目录下
        //从 classpath(即 src/main/resources 下的资源目录)查找资源文件 "static/user.txt"。
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("static/user.txt");
        // 2. 用 Hutool 工具类把文件内容读成一行一行的字符串,然后把每一行作为一个 String 放到这个 ArrayList 里。
        ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());
        // 3. 把每一行字符串解析成 User 对象
        List<Day250928_User> userList = lines.stream().map(line -> {
            //stream() 把列表转换成 流,方便用函数式操作(map、filter、collect 等)。
            //map 会对流中的每一个元素执行 转换操作,这里每个元素就是 line(一行文本)。
            String[] parts = line.split(",");
            Integer id = Integer.parseInt(parts[0]);
            String username = parts[1];
            String password = parts[2];
            String name = parts[3];
            String sex = parts[4];
            Integer age = Integer.parseInt(parts[5]);
            LocalDateTime updateTime = LocalDateTime.parse(parts[6],
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            return new Day250928_User(id, username, password, name, sex, age, updateTime);
        }).collect(Collectors.toList());//collect(Collectors.toList()) 把处理后的对象流 收集成一个 List。

        //上面这是lambda表达式,下面这是完整写法,是重写了Function接口
        InputStream in2 = this.getClass().getClassLoader().getResourceAsStream("static/user.txt");
        ArrayList<String> lines2 = IoUtil.readLines(in2, StandardCharsets.UTF_8, new ArrayList<>());
        List<Day250928_User> userList2 = lines2.stream().map(new Function<String, Day250928_User>() {
            @Override
            public Day250928_User apply(String line) {
                String[] parts = line.split(",");
                Integer id = Integer.parseInt(parts[0]);
                String username = parts[1];
                String password = parts[2];
                String name = parts[3];
                String sex = parts[4];
                Integer age = Integer.parseInt(parts[5]);
                LocalDateTime updateTime = LocalDateTime.parse(parts[6],
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                return new Day250928_User(id, username, password, name, sex, age, updateTime);
            }
        }).collect(Collectors.toList());//collect(Collectors.toList()) 把处理后的对象流 收集成一个 List。

        return userList2;// 4. 返回用户列表 -> Spring Boot 自动把它转成 JSON
        // 因为类上有 @RestController,Spring Boot 会自动把这个对象序列化为 JSON,再写到 HTTP 响应里。
    }
}

上述代码将所有的处理逻辑都放在了controller方法中,为了解耦,实现三层架构:

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

将上述代码进行分开:

  • 控制层
@RestController
public class newUserController {
    //private UserServiceImpl userService =  new UserServiceImpl();
    /**
     * 必须初始化,或者在其他的地方进行初始化,不然会报错,但是这种方式,
     * NewUserController 直接依赖 UserServiceImpl 的具体实现。
     * 如果将来想换成 UserServiceV2Impl,你必须修改 Controller 的代码,才能替换:
     * private UserServiceImpl userService = new UserServiceV2Impl();
     * 同理Dao也是这个问题,
     *
     * 理想的低耦合做法
     * Controller 应该只依赖 接口(UserService),而不是具体实现(UserServiceImpl)。
     * 哪个实现类要被注入,由 Spring 容器来决定。
     * */

    //解决:在对应的实现类前加     注解
//    @Autowired // 自动注入 Spring 容器中的 NewService 实现
//    private newService userService;//如果有多个相同的bean注入时,这个会报错,有以下三种解决方案
    /**
     * 使用@Primary注解 当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
     * 使用@Qualifier注解
     * 指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称,名称首字母小写。 @Qualifier注解不能单独使用,必须配合@Autowired使用。
     * 使用@Resource注解
     * 是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。*/
//    @Qualifier("userServiceImpl2")//这里为首的字母要小写
//    @Autowired
//    private newService userService;

    @Resource(name = "userServiceImpl2")
    private newService userService;


    @RequestMapping("/newList")
    public List<Day250928_User> newList(){
        System.out.println("newList");
        return userService.findAll();
    }
}
  • 业务逻辑层
public interface newService {
    public List<Day250928_User> findAll();
}
@Service  // 告诉 Spring 这是一个业务层 Bean,要交给 IOC 容器管理 为了解耦层与层之间的耦合
public class UserServiceImpl2 implements newService{
    //private UserDaoImpl userDao = new UserDaoImpl();
    @Autowired
    private newDao userDao;

    @Override
    public List<Day250928_User> findAll() {
        List<String> lines = userDao.findAll();

        List<Day250928_User> list = lines.stream().map(
                new Function<String, Day250928_User>() {
                    @Override
                    public Day250928_User apply(String s) {
                        String[] parts = s.split(",");
                        Integer id = Integer.valueOf(parts[0]);
                        String username = parts[1];
                        String password = parts[2];
                        String name = "new" + parts[3];
                        String sex =  parts[4];
                        Integer age = Integer.valueOf(parts[5]);
                        LocalDateTime updateTime = LocalDateTime.parse(parts[6],
                                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        return new Day250928_User(id, username, password, name, sex, age, updateTime);
                    }
                }
        ).collect(Collectors.toList());

        return list;
    }
}
  • 数据访问层
public interface newDao {
    public List<String> findAll();
}
@Repository //
public class UserDaoImpl implements newDao {
    @Override
    public List<String> findAll() {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("static/user.txt");
        List<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());
        return lines;
    }
}

其中,如果利用以前的只是,就像控制层中注释中写的那样 private UserServiceImpl userService = new UserServiceImpl(); 需要什么对象,直接new一个对象,如果说我们需要更换实现类,比如由于业务的变更,UserServiceImpl 不能满足现有的业务需求,我们需要切换为 UserServiceImpl2 这套实现,就需要修改Contorller的代码,需要创建 UserServiceImpl2 的实现new UserServiceImpl2() 。这样会导致层与层之间相互关联,因此有了 @Resource@Repository@Service@Autowired 等注解, 通过使用注解来代替手动new对象,通过容器来管理要使用的对象

1.2 web后端基础(数据库)

SQL 语句

DDL(Data Definition Language)语句 — 数据定义语言

DDL 用于定义和管理数据库对象,如数据库、表、字段等。


  1. 数据库操作

    操作 SQL 示例
    查询所有数据库 SHOW DATABASES;
    查询当前数据库 SELECT DATABASE();
    创建数据库 CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET utf8mb4];
    使用数据库 USE 数据库名;
    删除数据库 DROP DATABASE [IF EXISTS] 数据库名;

  1. 表操作
  • 创建表

      CREATE TABLE 表名 (
          字段1 字段1类型 [约束] [COMMENT '字段1注释'],
          字段2 字段2类型 [约束] [COMMENT '字段2注释'],
          ...
          字段n 字段n类型 [约束] [COMMENT '字段n注释']
      ) [COMMENT '表注释'];
    
    • 常用数据类型(简要)

      类型类别 示例 说明
      整数类型 INT, BIGINT 存储整数
      小数类型 DECIMAL(10,2) 存储精确小数
      字符串类型 CHAR(10), VARCHAR(50) 存储字符串
      日期时间类型 DATE, DATETIME, TIMESTAMP 存储时间日期
      布尔类型 BOOLEAN 存储真或假(1/0)
    • 常用约束

      约束名 描述 关键字
      非空约束 限制该字段值不能为 NULL NOT NULL
      唯一约束 保证字段值唯一、不重复 UNIQUE
      主键约束 表中唯一标识每一行数据,且不能为空 PRIMARY KEY
      默认约束 未指定值时使用默认值 DEFAULT
      外键约束 建立两表之间关系,保证数据一致性 FOREIGN KEY
      主键自增 自动生成主键值 AUTO_INCREMENT

  • 表结构管理

    操作 SQL 示例
    查询当前数据库所有表 SHOW TABLES;
    查看表结构 DESC 表名;
    查看建表语句 SHOW CREATE TABLE 表名;
    添加字段 ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT '注释'] [约束];
    修改字段类型 ALTER TABLE 表名 MODIFY 字段名 新类型(长度);
    修改字段名及类型 ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT '注释'] [约束];
    删除字段 ALTER TABLE 表名 DROP 字段名;
    修改表名 RENAME TABLE 旧表名 TO 新表名;
    删除表 DROP TABLE [IF EXISTS] 表名;

DML(Data Manipulation Language)语句 — 数据操作语言

DML 用于对表中数据进行增、删、改操作。


  1. 增加数据(INSERT)

    类型 SQL 示例
    指定字段插入 INSERT INTO 表名 (字段1, 字段2) VALUES (值1, 值2);
    全字段插入 INSERT INTO 表名 VALUES (值1, 值2, ...);
    批量插入(指定字段) INSERT INTO 表名 (字段1, 字段2) VALUES (值1, 值2), (值3, 值4);
    批量插入(全字段) INSERT INTO 表名 VALUES (值1, 值2, ...), (值3, 值4, ...);

  1. 修改数据(UPDATE)

     UPDATE 表名 
     SET 字段1 = 1, 字段2 = 2, ...
     [WHERE 条件];
    

    ⚠️ 建议使用 WHERE 限定条件,否则会修改全表数据。


  1. 删除数据(DELETE)

     DELETE FROM 表名 [WHERE 条件];
    

DQL(Data Query Language)语句 — 数据查询语言

用于查询数据,是 SQL 的核心部分。


基本语法结构

SELECT
    字段列表
FROM
    表名列表
WHERE
    条件列表
GROUP BY
    分组字段列表
HAVING
    分组后条件列表
ORDER BY
    排序字段列表
LIMIT
    分页参数;

  • 基本查询

    功能 SQL 示例
    查询多个字段 SELECT 字段1, 字段2 FROM 表名;
    查询所有字段 SELECT * FROM 表名;
    设置字段别名 SELECT 字段1 AS 别名1, 字段2 AS 别名2 FROM 表名;
    去除重复记录 SELECT DISTINCT 字段名 FROM 表名;

  • 条件查询(WHERE)
SELECT 字段列表
FROM 表名
WHERE 条件列表;
  • 比较运算符

    运算符 功能
    > 大于
    >= 大于等于
    < 小于
    <= 小于等于
    = 等于
    <>!= 不等于
    BETWEEN ... AND ... 在指定范围内(含边界)
    IN (...) 在指定集合中
    LIKE 模糊匹配(_ 单个字符,% 任意字符)
    IS NULL 判断是否为空
  • 逻辑运算符

    运算符 功能
    AND / && 并且(多个条件同时成立)
    OR / ` 或者(任意一个成立)
    NOT / ! 取反(条件不成立)

  • 聚合函数(Aggregate Functions)

    函数 作用
    COUNT(字段) 统计行数(忽略 NULL)
    SUM(字段) 求和
    MAX(字段) 最大值
    MIN(字段) 最小值
    AVG(字段) 平均值

    💡 聚合函数通常与 GROUP BY 搭配使用。


  • 分组查询(GROUP BY)

      SELECT 分组字段, 聚合函数(...)
      FROM 表名
      [WHERE 条件]
      GROUP BY 分组字段
      [HAVING 分组后条件];
    

    说明:

    • WHERE 在分组前过滤;
    • HAVING 在分组后过滤;
    • 通常配合聚合函数使用。

  • 排序查询(ORDER BY)

      SELECT 字段列表
      FROM 表名
      ORDER BY 字段1 [ASC|DESC], 字段2 [ASC|DESC];
    
    排序方式 说明
    ASC 升序(默认)
    DESC 降序

  • 分页查询(LIMIT)

      SELECT 字段列表
      FROM 表名
      LIMIT 起始索引, 查询条数;
    

    示例:

      LIMIT 0, 5;   -- 从第0条开始,查询5条记录
    

    💡 常用于前端分页显示。


JDBC

package com.example;

import org.junit.jupiter.api.Test;

import java.sql.*;

public class jdbcTest {
    /**jdbc 入门程序*/
    @Test
    public void testUpdate() throws ClassNotFoundException, SQLException {
        //准备工作
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/web01";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);
        Statement stmt = conn.createStatement();

        //执行sql
        int i = stmt.executeUpdate("update user set password = '11111111' where id = 1");//静态sql
        System.out.println("sql 语句执行后 影响的 记录数:  " + i);
        //释放资源
        stmt.close();
        conn.close();
    }

    @Test
    public void testJdbc() throws SQLException {
        //获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web01", "root", "123456");
        //常见预编译的 PreparedStatement 对象
        PreparedStatement pstmt = conn.prepareStatement("select * from user where username = ? and password = ?");
        //预编译sql,更加安全,防止sql注入,性能更高
        /**
         * 静态sql
         * 使用普通的字符串拼接方式:
         * String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = '" + password + "'";
         * Statement stmt = conn.createStatement();
         * ResultSet rs = stmt.executeQuery(sql);
         *
         * 如果攻击者输入:
         * username: admin
         * password: ' OR '1'='1
         *
         * 那么拼接后的 SQL 实际是:
         * SELECT * FROM user WHERE username = 'admin' AND password = '' OR '1'='1'
         * '1'='1' 恒为真 → 查询返回所有用户 → 登录绕过。
         *
         * SQL 预编译阶段
         * 数据库在第一次接收到带问号(?)的 SQL 模板时,会先对 SQL 结构 进行编译、优化、生成执行计划。
         * 此时,SQL 的结构是固定的,? 只是参数占位符。
         *
         * 参数绑定阶段
         * 通过 setString() 等方法传入参数时,这些值会被当作数据(Data)绑定到执行计划中,而不会改变 SQL 的语法结构。*/

        //设置参数
        pstmt.setString(1, "daqiao");//第一个问号对应的参数
        pstmt.setString(2, "123456");//第二个问号对应的参数
        //执行查询
        ResultSet rs = pstmt.executeQuery();
        //处理结果集
        while(rs.next()){
            int id = rs.getInt("id");
            String username = rs.getString("username");
            String password = rs.getString("password");
            String name = rs.getString("name");
            int age = rs.getInt("age");

            System.out.println("ID: " + id + ", Username: " + username +
                    ", Password: " + password + ", Name: " + name + ", Age: " + age);
        }
        //关闭资源
        rs.close();
        pstmt.close();
        conn.close();
    }
}

mybatis

  • 创建springboot工程,并导入 mybatis的起步依赖、mysql的驱动包、lombok。项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖。
  • 数据准备:创建用户表user,并创建对应的实体类User。
  • 配置Mybatis,在 application.properties 中配置数据库的连接信息。

      # 配置查看日志
      mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    
      # 使用 druid 这个 数据库连接池
      spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
      spring.datasource.url=jdbc:mysql://localhost:3306/web01
      spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
      spring.datasource.username=root
      spring.datasource.password=123456
    
      # 指定 xml 映射配置文件的位置
      mybatis.mapper-locations=classpath:mapper/*.xml
    
  • 上一步既可以将配置代码写到上述文件中,也可以直接使用xml文件来进行配置,但要注意xml文件的位置,以及xml文件中包名要正确
      <?xml version="1.0" encoding="UTF-8"?>
      <!--<beans xmlns="http://www.springframework.org/schema/beans"-->
      <!--       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"-->
      <!--       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">-->
    
      <!--</beans>-->
    
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.example.day251007_springbootmybatisquickstart.mapper.UserMapper">
          <!-- 查询操作 -->
          <select id="findAll" resultType="com.example.day251007_springbootmybatisquickstart.pojc.User">
              select * from user
          </select>
    
      </mapper>
    
  • 编写Mybatis程序:编写Mybatis的持久层接口,定义SQL语句(注解). 在创建出来的springboot工程中,在引导类所在包下,在创建一个包 mapper 。在 mapper 包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫 XxxMapper)。

      package com.example.day251007_springbootmybatisquickstart.mapper;
    
      import com.example.day251007_springbootmybatisquickstart.pojc.User;
      import org.apache.ibatis.annotations.*;
    
      import java.util.List;
    
      // 编写mybatis 的持久层接口
      @Mapper //应用程序在运行时,会自动的为该接口创建一个实现类对象(代理对象),并且会自动地将该实现类对象存入IOC容器中
      public interface UserMapper {
    
          /**
           * 查询所有用户 注释掉注解来进行测试 xml */
          //@Select("select * from user")
          public List<User> findAll();
    
          /** 删除 的两种方式 */
          @Delete("delete from user where id = 5")
          public Integer deleteById1();
    
          //通过参数占位符号 #{...} 来占位,在调用deleteById方法时,传递的参数值,最终会替换占位符。
          @Delete("delete from user where id = #{id}")
          public Integer deleteById2(Integer id);
    
          /** 增 */
          @Insert("insert into user(username,password,name,age) values(#{username},#{password},#{name},#{age})")
          public void insert(User user);
    
          /** 改 */
          @Update("update user set username = #{username},password=#{password},name=#{name},age=#{age} where id=#{id}")
          public void update(User user);
    
          /** 查 */
          @Select("select * from user where username = #{username} and password = #{password}")
          public User findByUsernameAndPassword(String username,String password);
      }
    
  • 单元测试; 在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,并且在测试类上已经添加了注解 @SpringBootTest,代表该测试类已经与SpringBoot整合。 该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器)。我们要测试那个bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。

     package com.example.day251007_springbootmybatisquickstart;
    
     import com.example.day251007_springbootmybatisquickstart.mapper.UserMapper;
     import com.example.day251007_springbootmybatisquickstart.pojc.User;
     import org.junit.jupiter.api.Test;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.boot.test.context.SpringBootTest;
    
     import java.util.List;
    
     @SpringBootTest
     class Day251007SpringbootMybatisQuickstartApplicationTests {
    
         @Autowired
         private UserMapper userMapper;
    
         @Test
         public void testFindAll(){
             List<User> users = userMapper.findAll();
             for (User user : users) {
                 System.out.println(user);
             }
         }
    
         @Test
         public void testFindById(){
             System.out.println(userMapper.deleteById1());
             System.out.println(userMapper.deleteById2(1));
         }
    
         @Test
         public void testInsert(){
             User user = new User();
             user.setUsername("lililili");
             user.setPassword("55555555");
             user.setAge(18);
             user.setName("李莉莉");
             userMapper.insert(user);
         }
    
         @Test
         public void testUpdate(){
             User user = new User();
             user.setId(6);
             user.setUsername("lililili");
             user.setPassword("88888888");
             user.setAge(18);
             user.setName("李莉莉");
             userMapper.update(user);
         }
         @Test
         public void testSelectByUsernameAndPassword(){
             User  u = userMapper.findByUsernameAndPassword("lililili","88888888");
             System.out.println(u);
         }
    
     }