前言

  • Mybatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费太多经历去处理,例如注册驱动。创建连接,创建statement ,手动设置参数,结果集检索等jdbc繁杂的过程代码。

  • Mybatis通过xml或注解的方式将要执行的各种statement(statement/preparedStatement/CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybaits框架执行sql并将结果映射成java对象再返回。

    架构图

架构说明

简单说一下图的内容:

  1. SqlMapConfig.xml此文件是Mybatis的核心,配置了Mybatis的运行环境等信息。

    • 而其中的mapper.xml文件就是SQL映射文件,配置了操作数据库的sql语句,此文件需要在SqlMapConfig.xml中加载。(你有几张表,就代表会有几个Mapper.xml文件)
  2. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂。(工厂需要核心配置文件和Mapper,xml原材料才能生存sqlSession)

  3. 由会话工厂创建sqlSession即会话,操作数据库就是通过sqlSession进行的。

  4. mybatis底层定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器,一个是缓存执行器。

  5. Mapped Statement 也是mybatis的一个底层封装对象,它包装了mybatis配置信息及sql映射信息等,Mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

  6. Mapped Statement 对sql执行输入参数进行定义,包括HashMap、基本类型、pojo、Executor通过Mapped Statement 在执行sql前将输入的java对象映射到sql中,输入参数映射就是jdbc中对preparedStatement设置参数。

  7. Mapped Statement 对sql执行输出结果进行定义,包括HashMap、基本类型、pojo、Executor通过Mapped Statement 在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc中对结果的解析处理过程.

逆向工程

  • mybaits 需要程序员自己编写 sql 语句,mybatis 官方提供逆向工程可以针对单表自动生成 mybatis 执行所需要的代码(mapper.java,mapper.xml、po..)
  • 企业实际开发中,常用的逆向工程方式:由数据库的表生成 java 代码
  • 逆向工程使用文档
  • 下载地址

Java 程序方式

  1. 导包

    1
    2
    3
    4
    5
    6
    <!-- mybatis逆向工程 -->
    <dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.4.0</version>
    </dependency>
  2. 生成配置文件:generatorConfig.xml

    • 多模块下Mybatis逆向工程的targetProject 目录要使用绝对路径
    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
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    <!DOCTYPE generatorConfiguration PUBLIC
    "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
    <!--
    mybatis逆向工程配置说明详见官网:http://mybatis.org/generator/running/runningWithMaven.html
    mybatis 标签属性说明:http://mybatis.org/generator/configreference/xmlconfig.html#
    -->
    <!-- targetRuntime: MyBatis3DynamicSql/MyBatis3/MyBatis3Simple -->
    <context id="mysql" defaultModelType="flat" targetRuntime="MyBatis3">
    <!-- 生成的Java文件的编码 -->
    <property name="javaFileEncoding" value="UTF-8"/>
    <!-- 格式化java代码 -->
    <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
    <!-- 格式化XML代码 -->
    <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
    <!--添加分隔符-->
    <property name="beginningDelimiter" value="'"></property>
    <property name="endingDelimiter" value="'"></property>


    <!--默认生成getter/setter方法,使用插件忽略生成getter/setter方法-->
    <!--<plugin type="com.mybatis.plugin.IngoreSetterAndGetterPlugin" />-->
    <!--用于在实体类中实现java.io.Serializable接口-->
    <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
    <!--用于重写equals 和 hashCode 方法-->
    <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
    <property name="useEqualsHashCodeFromRoot" value="true"/>
    </plugin>
    <!--用于生成 toString 方法-->
    <plugin type="org.mybatis.generator.plugins.ToStringPlugin">
    <property name="useToStringFromRoot" value="true"/>
    </plugin>

    <!--生成注释信息的配置-->
    <commentGenerator>
    <!--阻止生成注释,默认为false-->
    <property name="suppressAllComments" value="true"></property>
    <!--阻止生成的注释包含时间戳,默认为false-->
    <property name="suppressDate" value="true"></property>
    <!--注释是否添加数据库表的备注信息,默认为false-->
    <property name="addRemarkComments" value="true"></property>
    </commentGenerator>

    <!--数据库连接信息-->
    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    connectionURL="jdbc:mysql://192.168.56.101:3306/springbootstudy?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull&amp;serverTimezone=Asia/Shanghai&amp;useSSL=false"
    userId="test"
    password="123456">
    <!-- MySQL 不支持 schema 或者 catalog 所以需要添加这个,官方文档有 -->
    <property name="nullCatalogMeansCurrent" value="true"/>
    </jdbcConnection>

    <!--javaTypeResolver:节点用于指定和配置 Java 类型解析器。-->
    <javaTypeResolver>
    <!--默认的解析器可能会将数据库类型 decimal 或 numberic 解析为Short、Integer、Long等 Java 类型,-->
    <property name="forceBigDecimals" value="ture"/>
    <!--是否不强制将数据库类型 date, time 和 timestamp 解析为 Date;
    默认为false,如果为true,
    解析规则将变成:date -> LocalDate,time -> LocalTime,timestamp -> LocalDateTime-->
    <property name="useJSR310Types" value="true"/>
    </javaTypeResolver>

    <!--javaModelGenerator : 节点用于配置实体类生成器-->
    <!--targetPackage:生成实体类存放的包名 targetProject:指定目标项目路径,可以使用绝对路径或者相对路径-->
    <javaModelGenerator targetPackage="tk.fulsun.demo.model"
    targetProject="C:\Users\fulsun\IdeaProjects\springboot-study\demo-mybatis\src\main\java">
    <!-- constructorBased为true就会使用构造方法入参,为false使用setter方法入参,默认为false -->
    <!--<property name="constructorBased" value="false"></property>-->
    <!--enableSubPackages 是否在targetPackage基础上生成子包。默认为false。当为true时,会将表所在 schema 名作为子包名-->
    <!--<property name="enableSubPackages" value="false" />-->
    <!--immutable:用于配置实体类属性是否可变,如果为true,不管constructorBased设置,都会使用构造方法入参不会生成setter方法。
    如果为false实体类属性可以改变,默认为false-->
    <!--<property name="immutable" value="false"></property>-->
    <!--设置所有实体类的基类-->
    <!--<property name="rootClass" value="类的全限定名"></property>-->
    <!--在setter方法中是否对传入字符串进行 trim 操作-->
    <property name="trimStrings" value="true"/>
    </javaModelGenerator>

    <!--sqlMapGenerator : 节点用于配置 XML 生成器-->
    <sqlMapGenerator targetPackage="mybatis.mapper"
    targetProject="C:\Users\fulsun\IdeaProjects\springboot-study\demo-mybatis\src\main\resources">
    <!--enableSubPackages : 是否在targetPackage基础上生成子包。默认为false。当为true时,会将表所在 schema 名作为子包名-->
    <!--<property name="enableSubPackages" value="false" />-->
    </sqlMapGenerator>

    <!-- javaClientGenerator:最多配置一个,用于生成mapper接口
    MyBatis3:ANNOTATEDMAPPER、MIXEDMAPPER、XMLMAPPER
    MyBtais3Simple:ANNOTATEDMAPPER、XMLMAPPER
    -->
    <javaClientGenerator type="XMLMAPPER" targetPackage="tk.fulsun.demo.mapper"
    targetProject="C:\Users\fulsun\IdeaProjects\springboot-study\demo-mybatis\src\main\java">
    </javaClientGenerator>

    <!--表的配置-->
    <table schema="db_mybatis" tableName="%"></table>
    </context>
    </generatorConfiguration>
  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
    public class GeneratorSqlmap {
    public void generator() throws Exception {
    List<String> warnings = new ArrayList<String>();
    boolean overwrite = true;
    //指定 逆向工程配置文件
    // 注意:xml 文件在 src 目录下,路径为 src/generatorConfig.xml
    File configFile = ResourceUtils.getFile("classpath:db-generator/generatorConfig.xml");
    ConfigurationParser cp = new ConfigurationParser(warnings);
    Configuration config = cp.parseConfiguration(configFile);
    DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,callback, warnings);
    myBatisGenerator.generate(null);

    }
    public static void main(String[] args) throws Exception {
    try {
    GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
    generatorSqlmap.generator();
    } catch (Exception e) {
    e.printStackTrace();
    }

    }
    }

Maven 插件方式

  1. Maven 插件添加依赖

    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
    <build>
    <plugins>
    <plugin>
    <!-- MBG 插件 -->
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <!--<overwrite>true</overwrite> 覆盖生效从1.3.7开始 -->
    <version>1.4.0</version>
    <configuration>
    <configurationFile>
    ${basedir}/src/main/resources/db-generator/generatorConfig.xml
    </configurationFile>
    <overwrite>true</overwrite>
    <verbose>true</verbose>
    </configuration>
    <dependencies>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
    </dependency>
    </dependencies>
    </plugin>
    </plugins>
    </build>
  2. 找到maven的可视化界面运行即可

MBG生成文件解析

XxxExamper

  • 基本结果代码如下

    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

    import java.util.ArrayList;
    import java.util.List;

    public class UserExample {

    //升序还是降序
    //参数格式:字段+空格+asc(desc)
    protected String orderByClause;

    //去除重复
    //true是选择不重复记录
    protected boolean distinct;

    //自定义查询条件
    //Criteria的集合,集合中对象是由or连接
    protected List<Criteria> oredCriteria;

    public UserExample() {
    oredCriteria = new ArrayList<>();
    }

    public void clear() {
    oredCriteria.clear();
    orderByClause = null;
    distinct = false;
    }

    //是mybatis中逆向工程中的代码模型
    protected abstract static class GeneratedCriteria {

    protected List<Criterion> criteria;
    }

    //内部类Criteria包含一个Cretiron的集合,每一个Criteria对象内包含的Cretiron之间是由AND连接的
    public static class Criteria extends GeneratedCriteria {

    protected Criteria() {
    super();
    }
    }

    //是最基本,最底层的Where条件,用于字段级的筛选
    public static class Criterion {

    private String condition;

    private Object value;

    private Object secondValue;

    private boolean noValue;

    private boolean singleValue;

    private boolean betweenValue;

    private boolean listValue;

    private String typeHandler;
    }
    }

Criteria

  • Criteria 内部类的每个属性都包含 andXXX 方法,以及如下的标准的SQL查询方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    IS NULL - 指相关的列必须为NULL
    IS NOT NULL - 指相关的列必须不为NULL
    = (equal) - 指相关的列必须等于方法参数中的值
    <> (not equal) - 指相关的列必须不等于方法参数中的值

    > (greater than) - 指相关的列必须大于方法参数中的值
    = (greater than or equal) - 指相关的列必须大于等于方法参数中的值
    < (less than) - 指相关的列必须小于于方法参数中的值
    <= (less than or equal) - 指相关的列必须小于等于方法参数中的值
    LIKE - 指相关的列必须 “like” 方法参数中的值. 这个方法不用必须加入 ‘%’, 您必须设置方法参数中的值.
    NOT LIKE - 指相关的列必须 “not like” 方法参数中的值. 这个方法不用必须加入 ‘%’, 您必须设置方法参数中的值.
    BETWEEN - 指相关的列必须在 “between” 方法参数中的两个值之间.
    NOT BETWEEN - 指相关的列必须不在 “not between” 方法参数中的两个值之间.
    IN - 指相关的列必须在传入的方法参数的list中.
    NOT IN - 指相关的列必须不在传入的方法参数的list中.

使用

  • UserMapper属于dao层,UserMapper.xml是对应的映射文件,我们可以通过UserMapper的实例操作数据库

  • 接口中提供了基本的增删改查操作,XxxxSelective方法: 会判断字段是否为null,当不为null值的时候才更新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public interface UserMapper {
    long countByExample(UserExample example);

    int deleteByExample(UserExample example);

    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    List<User> selectByExample(UserExample example);

    User selectByPrimaryKey(Integer id);

    int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);

    int updateByExample(@Param("record") User record, @Param("example") UserExample example);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
    }
  • 查询用户数量

    1
    2
    // 类似于:select count(*) from user
    long count = UserMapper.countByExample(example);
  • where条件查询或多条件查询

    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
    // 类似于:select * from user where name={#user.name} and sex={#user.sex} order by age asc;
    example.setOrderByClause("age asc");//升序
    example.setDistinct(false);//不去重

    if(!StringUtils.isNotBlank(user.getName())){
    Criteria.andNameEqualTo(user.getName());
    }

    if(!StringUtils.isNotBlank(user.getSex())){
    Criteria.andSexEqualTo(user.getSex());
    }

    List<User> userList=userMapper.selectByExample(example);

    // 类似于:select * from user where name={#user.name} or sex={#user.sex} ;
    UserExample.Criteria criteria1 = example.createCriteria();
    UserExample.Criteria criteria2 = example.createCriteria();

    if(!StringUtils.isNotBlank(user.getName())){
    Criteria1.andNameEqualTo(user.getName());
    }

    if(!StringUtils.isNotBlank(user.getSex())){
    Criteria2.andSexEqualTo(user.getSex());
    }

    Example.or(criteria2);
    List<User> userList=userMapper.selectByExample(example);
  • 模糊查询

    1
    2
    3
    4
    5
    6
    //类似于:select * from user where name like %{#user.name}%
    if(!StringUtils.isNotBlank(user.getName())){
    criteria.andNameLike('%'+name+'%');
    }

    List<User> userList=userMapper.selectByExample(example);
  • 分页查询

    1
    2
    3
    4
    5
    6
    7
    8
    // 类似于:select * from user limit start to rows
    int start = (currentPage - 1) * rows;
    //分页查询中的一页数量
    example.setPageSize(rows);
    //开始查询的位置
    example.setStartRow(start);
    List<User> userList=userMapper.selectByExample(example);

整合MyBatis

导入依赖

  • 关于mybatis-spring-boot-starter的版本需要注意:

    • 2.1.x版本适用于:MyBatis 3.5+、Java 8+、Spring Boot 2.1+
    • 2.0.x版本适用于:MyBatis 3.5+、Java 8+、Spring Boot 2.0/2.1
    • 1.3.x版本适用于:MyBatis 3.4+、Java 6+、Spring Boot 1.5
  • 其中,目前还在维护的是2.1.x版本和1.3.x版本。

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
    </dependency>

修改配置文件

  • 配置数据库连接信息
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
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.61.45:3306/springbootStudy?characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
test-while-idle: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 30000
validation-query: select 'x'
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
filters: stat,wall
max-pool-prepared-statement-per-connection-size: 20
use-global-data-source-stat: true
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# mybatis的配置
mybatis:
# 映射实体地址
type-aliases-package: tk.fulsun.demo.model
# xml配置文件地址
mapper-locations: classpath:mybatis/mapper/*.xml
# mybatis全局配置,与configuration 不能同时存在
# config-location: classpath:mybatis/mybatis-config.xml
configuration:
# 开启驼峰命名
map-underscore-to-camel-case: true
#当传入null的时候对应的jdbctype
jdbc-type-for-null: null

测试数据库连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@SpringBootTest
public class SpringbootDataJdbcApplicationTests {
//DI注入数据源
@Autowired
DataSource dataSource;

@Test
public void contextLoads() throws SQLException {
//看一下默认数据源
System.out.println(dataSource.getClass());
//获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
//关闭连接
connection.close();
}
}

实体类

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
package top.fulsun.pojo;

import java.util.Date;

/**
* @Description: 用户实体类
*/
public class User {
private int id;
private String name;
private Date createTime;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "RoncooUser [id=" + id + ", name=" + name + ", createTime=" + createTime + "]";
}
}

创建mapper目录和Mapper 接口

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 top.fulsun.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import top.fulsun.pojo.User;

import java.util.List;

@Mapper
@Repository
//@Mapper : 表示本类是一个 MyBatis 的 Mapper
//不添加要在启动类上添加扫描 @MapperScan("top.fulsun.mapper.*")
// 接口属性默认public satic final
// 方法 public abstarct
public interface UserMapper {
public static final int age = 18;

public abstract List<User> queryList();

User queryById(int id);

int addUser(User user);

int updateUser(User user);

int deleteUser(int id);

}

编写对应的mapper.xml

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
<?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="top.fulsun.mapper.UserMapper">

<select id="queryList" resultType="User" useCache="true">
select * from user;
</select>

<select id="queryById" resultType="User" parameterType="int">
select * from user where id = #{id};
</select>

<insert id="addUser" parameterType="User">
insert into user (name, create_time) values (#{name}, #{createTime});
</insert>

<update id="updateUser" parameterType="User">
update user set name=#{name},create_time=#{createTime} where id=#{id};
</update>

<delete id="deleteUser" parameterType="int">
delete from user where id =#{id};
</delete>

</mapper>

maven配置资源过滤问题

idea默认是不编译 src\main\java下的xml文件的,所以如果是使用mybatis,需要解决这个问题。

  1. 在src\mian\resources下创建一个文件夹存放mapper文件。

    1
    2
    3
    4
    5
    6
    7
    mybatis:
    # 指定别名扫描的包:resultMap的type或者parameterType会使用自定义的pojo,
    type-aliases-package: top.fulsun.pojo
    # 多个路径用逗号分隔 classpath:mappers/2/*.xml,classpath*:/mappers/**/*.xml
    # * 必不可少,缺少*号的话后面的通配符不起作用。
    # **表示可以表示任意多级目录。
    mapper-locations: classpath:mybatis/mapper/*.xml
  2. 在pom.xml下加个配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <resources>
    <resource>
    <directory>src/main/java</directory>
    <includes>
    <include>**/*.xml</include>
    </includes>
    <filtering>true</filtering>
    </resource>
    </resources>

编写Controller测试

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
package top.fulsun.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.fulsun.dao.UserDao;
import top.fulsun.mapper.UserMapper;
import top.fulsun.pojo.User;

import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserDao userDao1;

@Autowired
private UserMapper userDao;

@GetMapping("/queryList")
public List<User> queryList() {
List<User> result = userDao.queryList();
return result;
}

@GetMapping("/query/{id}")
public User queryById(@PathVariable("id") int id) {
User result = userDao.queryById(id);
return result;
}

@GetMapping("/add/{name}")
public int addUser(@PathVariable("name") String name) {
User user = new User();
user.setName(name);
user.setCreateTime(new Date());
int result = userDao.addUser(user);
return result;
}
@GetMapping("/update/{id}/{name}")
public int updateUser(@PathVariable("id") int id ,@PathVariable("name") String name) {
User User = queryById(id);
User.setName(name);
int result = userDao.updateUser(User);
return result;
}
@GetMapping("/del/{id}")
public int deleteUser(@PathVariable("id") int id) {
int result = userDao.deleteUser(id);
return result;
}

}

测试

  • 测试代码如下

    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
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    package tk.fulsun.demo.controller;

    import com.alibaba.fastjson.JSON;
    import org.hamcrest.CoreMatchers;
    import org.junit.jupiter.api.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
    import tk.fulsun.demo.model.User;

    /**
    *
    *
    * <pre>
    * • MockMvc允许我们方便的发送 HTTP 请求。
    * • SpringBootTest方便的创建一个 Spring Boot 项目的测试程序。
    * mockMvc.perform执行一个请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理,返回一个ResultActions实例
    * MockMvcRequestBuilders.get("/student/findAll") 根据uri模板和uri变量值 构造一个GET,PUT,POST,DELETE等请求,Post请求就用.post方法
    * contentType(MediaType.APPLICATION_JSON_UTF8)代表发送端发送的数据格式是application/json;charset=UTF-8
    * accept(MediaType.APPLICATION_JSON_UTF8)代表客户端希望接受的数据类型为application/json;charset=UTF-8
    * ResultActions.andExpect添加执行完成后的断言
    * ResultActions.andExpect(MockMvcResultMatchers.status().isOk())方法看请求的状态响应码是否为200如果不是则抛异常,测试不通过
    * ResultActions.andExpect(MockMvcResultMatchers.jsonPath(“$.author”).value("username"))这里jsonPath用来获取author字段比对是否为嘟嘟MD独立博客,不是就测试不通过
    * ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息
    * </pre>
    *
    * @author fulsun
    * @title: UserControllerTest
    * @projectName springboot-study
    * @description: 接口测试
    * @date 5/26/2021 4:19 PM
    */
    // SpringBoot1.4版本之前用的是SpringJUnit4ClassRunner.class
    @RunWith(SpringRunner.class)
    // SpringBoot1.4版本之前用的是@SpringApplicationConfiguration(classes = Application.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    @AutoConfigureMockMvc
    class UserControllerTest2 {

    @Autowired private MockMvc mvc;

    @Test
    public void getAllUser() throws Exception {
    mvc.perform(MockMvcRequestBuilders.get("/user/all").accept(MediaType.APPLICATION_JSON))
    // 添加断言
    .andExpect(MockMvcResultMatchers.status().isOk())
    // .andExpect(MockMvcResultMatchers.content().string(CoreMatchers.equalTo("Hello World")));
    // 添加返回结果 一般在测试时候用
    .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void getUserByName() throws Exception {
    String name = "三";
    mvc.perform(MockMvcRequestBuilders.get("/user/" + name).accept(MediaType.APPLICATION_JSON))
    // 添加断言
    .andExpect(MockMvcResultMatchers.status().isOk())
    // .andExpect(MockMvcResultMatchers.content().string(CoreMatchers.equalTo("Hello World")));
    // 添加返回结果 一般在测试时候用
    .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void addUser() throws Exception {
    User user = new User();
    user.setName("李四");
    user.setAge(22);
    String content = JSON.toJSONString(user);
    System.out.println(content);
    // 执行一个post请求
    mvc.perform(
    MockMvcRequestBuilders.post("/user/add")
    // post请求的内容
    .content(content)
    // post请求数据类型
    .contentType(MediaType.APPLICATION_JSON))
    // 添加断言
    .andExpect(MockMvcResultMatchers.status().isOk())
    .andExpect(MockMvcResultMatchers.content().string(CoreMatchers.equalTo("成功")))
    // 添加返回结果
    .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void updateUser() throws Exception {
    User user = new User();
    user.setId(8);
    user.setName("lishi");
    user.setAge(22);
    String content = JSON.toJSONString(user);
    System.out.println(content);
    // 执行一个post请求
    mvc.perform(
    MockMvcRequestBuilders.put("/user/update")
    // post请求的内容
    .content(content)
    // post请求数据类型
    .contentType(MediaType.APPLICATION_JSON))
    // 添加断言
    .andExpect(MockMvcResultMatchers.status().isOk())
    .andExpect(MockMvcResultMatchers.content().string(CoreMatchers.equalTo("成功")))
    // 添加返回结果
    .andDo(MockMvcResultHandlers.print());
    }

    @Test
    public void delUser() throws Exception {
    User user = new User();
    user.setId(8);
    user.setName("lishi");
    user.setAge(22);
    String content = JSON.toJSONString(user);
    System.out.println(content);
    // 执行一个post请求
    mvc.perform(MockMvcRequestBuilders.delete("/user/" + user.getId()))
    // 添加断言
    .andExpect(MockMvcResultMatchers.status().isOk())
    .andExpect(MockMvcResultMatchers.content().string(CoreMatchers.equalTo("成功")))
    // 添加返回结果
    .andDo(MockMvcResultHandlers.print());
    }
    }