master a665d5a94c50 cached
46 files
49.8 KB
16.4k tokens
52 symbols
1 requests
Download .txt
Repository: fengwenyi/MyBatis-Plus-Example
Branch: master
Commit: a665d5a94c50
Files: 46
Total size: 49.8 KB

Directory structure:
gitextract_ke3bd0xo/

├── .gitignore
├── README.md
├── doc/
│   ├── 00-mybatis-plus知识点.md
│   ├── 01-SpringBoot整合MyBatis-Plus.md
│   ├── 02-mybatis-plus-example.sql
│   ├── 03-MyBatis-Plus代码生成器的使用.md
│   ├── 04-CRUD.md
│   ├── 05-mybatis知识点.md
│   ├── 06-MyBatis-Plus条件查询.md
│   ├── 07-MyBatis-Plus分页查询.md
│   ├── 08-MyBatis-Plus数据库枚举实现.md
│   ├── 09-MyBatis-Plus乐观锁.md
│   ├── 10-MyBatis-Plus多数据源(动态).md
│   ├── 11-MyBatis-Plus连表查询.md
│   ├── 12-使用p6spy-SQL打印和性能分析.md
│   ├── 13-MyBatis-Plus逻辑删除.md
│   ├── 14-MyBatis-Plus数据安全保护.md
│   ├── 15-MyBatis-Plus字段填充.md
│   └── version/
│       └── 3.2.1.md
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── fengwenyi/
    │   │           └── mybatisplusexample/
    │   │               ├── MybatisPlusExampleApplication.java
    │   │               ├── config/
    │   │               │   └── MyBatisPlusConfiguration.java
    │   │               ├── entity/
    │   │               │   ├── CategoryEntity.java
    │   │               │   ├── GoodsEntity.java
    │   │               │   └── enums/
    │   │               │       └── GoodsFlagEnum.java
    │   │               ├── handler/
    │   │               │   └── MyBatisPlusAutoFillMetaObjectHandler.java
    │   │               ├── mapper/
    │   │               │   ├── ICategoryMapper.java
    │   │               │   └── IGoodsMapper.java
    │   │               └── repository/
    │   │                   ├── MPCategoryRepository.java
    │   │                   ├── MPGoodsRepository.java
    │   │                   └── impl/
    │   │                       ├── CategoryRepositoryImpl.java
    │   │                       └── GoodsRepositoryImpl.java
    │   └── resources/
    │       ├── application-dev.yml
    │       ├── application-prod.yml
    │       ├── application-test.yml
    │       ├── application.yml
    │       ├── logback-spring.xml
    │       ├── mapper/
    │       │   ├── CategoryMapper.xml
    │       │   └── GoodsMapper.xml
    │       └── spy.properties
    └── test/
        └── java/
            └── com/
                └── fengwenyi/
                    └── mybatisplusexample/
                        ├── CategoryMapperTests.java
                        ├── CategoryModelTests.java
                        ├── CategoryRepositoryTests.java
                        ├── GoodsRepositoryTests.java
                        ├── MPWTests.java
                        └── MybatisPlusExampleApplicationTests.java

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
HELP.md
/target/
.mvn/
mvnw
mvnw.cmd

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/

### VS Code ###
.vscode/
/log/
.gradle
gradle
gradlew
gradlew.bat
*.log


================================================
FILE: README.md
================================================
# MyBatis-Plus-Example

Spring Boot 整合 MyBatis Plus 实例,持续更新!!!

## 代码生成器

[请点击此处的传送门](https://github.com/fengwenyi/mybatis-plus-code-generator)

## 不再维护

作者尽力有限,此项目不再维护,后续会全部迁移到这里

[demo-spring-boot-mybatis-plus](https://github.com/fengwenyi/spring-boot-demo/tree/main/demo-spring-boot-mybatis-plus)

## 三方框架版本总览

| 名称 | 版本 | 更新时间 |
| --- | --- | --- |
| Spring Boot | 2.4.2 |  2021.02.02 |
| MyBatis-Plus | 3.4.2 |  2021.02.02 |
| JavaLib | 2.1.1 |  2021.07.06 |
| api-result | 2.3.1 |  2021.02.02 |
| swagger | 2.9.2 |  2019.08.27 |

## 项目版本标识说明

BUILD
开发版本:用于标识该版本正在构建或者开发中。

SNAPSHOT
预览版本:开发已经完成,开始进入测试阶段。

RELEASE
稳定版本:已发布到中央仓库。

## 数据库设计

### 商品类别表-category
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | bigint(20) | 主键ID |
| name | varchar(50) | 类别名称 |

### 商品表-goods
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | bigint(20) | 主键ID |
| name | varchar(255) | 商品名称 |
| category_id | bigint(20) | 类别ID |
| stock_num | bigint(20) | 库存数量 |
| price | decimal(9, 4) | 单价 |
| flag | tinyint(1) | 上下架。0:下架;1:上架。默认0。 |
| delete_status | tinyint(1) | 逻辑删除状态。0:正常;1:删除。默认0。 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
| create_by | varchar(64) | 创建人 |
| update_by | varchar(64) | 修改人 |
| version | int(11) | 版本。默认:0。 |

## 常见问题

### 1、LocalDateTime无法使用的问题

#### 描述

用代码生成器生成的时间类型默认为 `LocalDateTime`, 但是在项目中使用报错。今天在项目上遇到了这个问题,什么原因呢?

#### 分析

首先要明确,如果你的项目都和示例项目配置、依赖、版本都一样,那说明本身是没有问题的。肯定是其他问题导致的。

经过排查,项目引入了 `druid`, 版本比较老,所以无法转换导致的。

#### 解决

升级 `druid` 版本


================================================
FILE: doc/00-mybatis-plus知识点.md
================================================
# MyBatis-Plus知识点

## Spring Boot整合MyBatis-Plus

第一步:pom.xml引入MyBatis-Plus依赖,注意,不需要再引入MyBatis的包,因为我这里使用Spring Boot搭建的工程,所有因为方式见下:

```xml
<dependencies>
    ...
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.1</version>
    </dependency>
    ...
</dependencies>
```

第二步:将生成的代码,拷贝到相应的包下

![代码目录结构](https://upload-images.jianshu.io/upload_images/5805596-368a8af54fe639b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

第三步:在配置文件中进行相应的配置

具体配置可参考官网,这里需要注意这样几个地方:

```yaml
mybatis-plus:
  # xml
  mapper-locations: classpath:mapper/*Mapper.xml
  # 实体扫描,多个package用逗号或者分号分隔
  type-aliases-package: com.fengwenyi.mp3demo.model
  configuration:
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
```
![日志:分页查询](https://upload-images.jianshu.io/upload_images/5805596-f5b314a660a48844.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



第四步:在启动类上添加下面的注解

```java
@EnableTransactionManagement
@MapperScan("com.fengwenyi.mp3demo.dao")
```

## 增删改

**Service**

我们一起去看源码 `com.baomidou.mybatisplus.extension.service.IService<T>`

增加:

```
    /**
     * <p>
     * 插入一条记录(选择字段,策略插入)
     * </p>
     *
     * @param entity 实体对象
     */
    boolean save(T entity);
```

修改:

```java
    /**
     * <p>
     * 根据 ID 选择修改
     * </p>
     *
     * @param entity 实体对象
     */
    boolean updateById(T entity);

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 
     * {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    boolean update(T entity, Wrapper<T> updateWrapper);
```

删除:

```java
    /**
     * <p>
     * 根据 ID 删除
     * </p>
     *
     * @param id 主键ID
     */
    boolean removeById(Serializable id);

    /**
     * <p>
     * 根据 entity 条件,删除记录
     * </p>
     *
     * @param queryWrapper 实体包装类 
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    boolean remove(Wrapper<T> queryWrapper);
```

**Mapper**

`com.baomidou.mybatisplus.core.mapper.BaseMapper<T>`

增加:

```java
    /**
     * <p>
     * 插入一条记录
     * </p>
     *
     * @param entity 实体对象
     */
    int insert(T entity);
```

修改:

```java
    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象 (set 条件值,不能为 null)
     * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
     */
    int update(@Param(Constants.ENTITY) T entity, 
               @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * <p>
     * 根据 ID 修改
     * </p>
     *
     * @param entity 实体对象
     */
    int updateById(@Param(Constants.ENTITY) T entity);
```

删除:

```java
    /**
     * <p>
     * 根据 entity 条件,删除记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 ID 删除
     * </p>
     *
     * @param id 主键ID
     */
    int deleteById(Serializable id);
```

以上相当于是常用API了,我们去看看,他是怎么实现的。毫无疑问,Mapper是底层,Service调用Mapper去执行sql,完成相关操作,所以,你完全可以直接调用Mapper完成相关操作,就跟使用MyBatis一样。下面我们去看看,他帮我们写的Service是什么样子,这里只看一个修改操作吧。

接口:

```java
    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类
     * {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    boolean update(T entity, Wrapper<T> updateWrapper);
```

实现:

```java
    @Override
    public boolean update(T entity, Wrapper<T> updateWrapper) {
        return ServiceImpl.retBool(baseMapper.update(entity, updateWrapper));
    }

    /**
     * <p>
     * 判断数据库操作是否成功
     * </p>
     * <p>
     * 注意!! 该方法为 Integer 判断,不可传入 int 基本类型
     * </p>
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    protected static boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    /**
     * <p>
     * 判断数据库操作是否成功
     * </p>
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    public static boolean retBool(Integer result) {
        return null != result && result >= 1;
    }
```

哈哈,是不是我们自己也会这样写啊!

## 查询

接下来,我们一起讨论下查询吧。

MP 3.x,查询接口发生了很大的变化,反正我是不喜欢的,你就弄一个什么开头啊,到时候,我一点就知道有哪些方法了,他这里有 `list*`, `get*`,反正就是一个字——没必要。

先看下接口说明:

```java
    /**
     * <p>
     * 查询列表
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类 
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    List<T> list(Wrapper<T> queryWrapper);

      /**
     * <p>
     * 根据 ID 查询
     * </p>
     *
     * @param id 主键ID
     */
    T getById(Serializable id);

    /**
     * <p>
     * 根据 Wrapper,查询一条记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    T getOne(Wrapper<T> queryWrapper);
```

嗯,差不多了吧,这样需要注意这样一个方法:

```java
    /**
     * <p>
     * 从list中取第一条数据返回对应List中泛型的单个结果
     * </p>
     *
     * @param list
     * @param <E>
     * @return
     */
    public static <E> E getObject(List<E> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            int size = list.size();
            if (size > 1) {
                SqlHelper.logger.warn(
String.format("Warn: execute Method There are  %s results.", size));
            }
            return list.get(0);
        }
        return null;
    }
```

**下面说下分页的问题**

根据官网的说法,需要借助插件,这我们是可以理解。

在Spring Boot启动类里面添加:

```java
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
```

这样就可以使用他提供的分页接口了:

```java
    /**
     * <p>
     * 翻页查询
     * </p>
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
```

我们去看一下:

```java
    @Override
    public IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper) {
        queryWrapper = (Wrapper<T>) SqlHelper.fillWrapper(page, queryWrapper);
        return baseMapper.selectPage(page, queryWrapper);
    }

    /**
     * <p>
     * 填充Wrapper
     * </p>
     *
     * @param page    分页对象
     * @param wrapper SQL包装对象
     */
    @SuppressWarnings("unchecked")
    public static Wrapper<?> fillWrapper(IPage<?> page, Wrapper<?> wrapper) {
        if (null == page) {
            return wrapper;
        }
        if (ArrayUtils.isEmpty(page.ascs())
            && ArrayUtils.isEmpty(page.descs())
            && ObjectUtils.isEmpty(page.condition())) {
            return wrapper;
        }
        QueryWrapper qw;
        if (null == wrapper) {
            qw = new QueryWrapper<>();
        } else {
            qw = (QueryWrapper) wrapper;
        }
        // 排序
        if (ArrayUtils.isNotEmpty(page.ascs())) {
            qw.orderByAsc(page.ascs());
        }
        if (ArrayUtils.isNotEmpty(page.descs())) {
            qw.orderByDesc(page.descs());
        }
        // MAP 参数查询
        if (ObjectUtils.isNotEmpty(page.condition())) {
            qw.allEq(page.condition());
        }
        return qw;
    }

    /**
     * <p>
     * 根据 entity 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
```

分页的代码大抵就是这样,我之前也自己写过,思路还是相当来说比较简单,关键是看你的查询添加如何封装,分页类如何构造。

这里有一点说明:

分页从 **`1`** 开始 !!!

## 枚举类

1、实现 接口

```java
/**
 * <p>
 * 自定义枚举接口
 * </p>
 *
 * @author hubin
 * @since 2017-10-11
 */
public interface IEnum<T extends Serializable> {

    /**
     * 枚举数据库存储值
     */
    T getValue();

}
```

2、实现注意

```
    @Override
    public Integer getValue() {
        return this.value;
    }

    @JsonValue
    public String getDesc() {
        return desc;
    }
```

这是Jackson的写法,我没用FastJson,所以用的伙伴,去官网看一下:[FastJson看官网](http://mp.baomidou.com/#/enum?id=%E4%BA%8C%E3%80%81fastjson)。

3:被忘了在配置文件中添加扫描:

```yaml
mybatis-plus:
  # 扫描枚举类 # 支持统配符 * 或者 ; 分割
  type-enums-package: com.fengwenyi.mp3demo.enums
```

差不多了吧,好像

## 逻辑删除

1、代码生成器中配置:

```java
new StrategyConfig().setLogicDeleteFieldName("is_delete") // 逻辑删除属性名称
```

或者,你可以手写,参考:

```java
    @ApiModelProperty(value = "是否逻辑删除(true:删除;false:正常(默认))")
    @TableLogic
    private Boolean isDelete;
```

2、自定义数据库的值:

```yaml
mybatis-plus:
  global-config:
    db-config:
      #逻辑删除配置
      logic-delete-value: 1
      logic-not-delete-value: 0
```

## 逻辑删除

## 乐观锁

## SQL性能分析

## MyBatis-Plus-Example

MyBatis-Plus的代码都会上传到github上

https://github.com/fengwenyi/MyBatis-Plus-Example

## 参考资料

*  [MyBatis-Plus](http://mp.baomidou.com/#/)

*  [MyBatis-Plus 使用枚举自动关联注入](https://www.imooc.com/article/details/id/29760)

*  [mybatis-plus插件使用的一些问题](https://www.jianshu.com/p/a5c9bab9584a)

*  [设计模式之Builder模式](https://www.jianshu.com/p/e2a2fe3555b9)

*  [修复Long类型太长,而Java序列化JSON丢失精度问题的方法](https://www.jianshu.com/p/fbcdcfc7cd12)

================================================
FILE: doc/01-SpringBoot整合MyBatis-Plus.md
================================================


================================================
FILE: doc/02-mybatis-plus-example.sql
================================================
/*
 Navicat Premium Data Transfer

 Source Server         : localhost.01-192.168.16.128
 Source Server Type    : MySQL
 Source Server Version : 80021
 Source Host           : 192.168.16.128:3306
 Source Schema         : mybatis-plus-example

 Target Server Type    : MySQL
 Target Server Version : 80021
 File Encoding         : 65001

 Date: 07/03/2021 18:15:28
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for shop_category
-- ----------------------------
DROP TABLE IF EXISTS `shop_category`;
CREATE TABLE `shop_category`  (
  `id` bigint(0) NOT NULL COMMENT '主键ID',
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '商品类别名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for shop_goods
-- ----------------------------
DROP TABLE IF EXISTS `shop_goods`;
CREATE TABLE `shop_goods`  (
  `id` bigint(0) NOT NULL COMMENT '主键ID',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '商品名称',
  `category_id` bigint(0) DEFAULT NULL COMMENT '商品类别ID',
  `stock_num` bigint(0) DEFAULT NULL COMMENT '库存数量',
  `price` decimal(9, 4) DEFAULT NULL COMMENT '商品单价',
  `flag` tinyint(1) DEFAULT NULL COMMENT '上下架。0:下架;1:上架。默认0。',
  `delete_status` tinyint(1) DEFAULT NULL COMMENT '逻辑删除状态。0:正常;1:删除。默认0。',
  `create_time` datetime(0) DEFAULT NULL COMMENT '创建时间',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
  `update_time` datetime(0) DEFAULT NULL COMMENT '更新时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '修改人',
  `version` int(0) DEFAULT NULL COMMENT '版本。默认:0。',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;


================================================
FILE: doc/03-MyBatis-Plus代码生成器的使用.md
================================================


================================================
FILE: doc/04-CRUD.md
================================================
# CRUD

- 增加(Create)
- 检索(Retrieve)
- 更新(Update)
- 删除(Delete)

对于MyBatis-Plus而言,增删改查,有三种方式实现。

1、使用MyBatis-Plus提供的服务接口。

2、使用MyBatis的Mapper接口。

3、使用Mybatis-Plus提供的AR特性,Model可进行CRUD操作。

AR即为ActiveRecord,是一种领域模型模式,一个模型类对应一个表。通过实体类对象直接进行表的CRUD操作。

## MyBatis-Plus服务接口

[CategoryRepositoryTests](../src/test/java/com.fengwenyi.mybatisplusexample.CategoryRepositoryTests)

### 数据添加

```
mpXxxService.save(entity);
```

### 数据删除

```
mpXxxService.removeById(entity.getId());
```

### 数据查询

```
mpXxxService.list(queryWrapper);
```

### 数据修改

```
mpXxxService.updateById(entity);
```

## MyBatis数据库操作Mapper接口

[CategoryMapperTests](../src/test/java/com.fengwenyi.mybatisplusexample.CategoryMapperTests)

### 数据添加

```
xxxMapper.insert(entity);
```

### 数据删除

```
xxxMapper.deleteById(entity);
```

### 数据查询

```
xxxMapper.selectList(queryWrapper);
```

### 数据修改

```
xxxMapper.updateById(entity);
```

## Mybatis-Plus提供的AR

[CategoryModelTests](../src/test/java/com.fengwenyi.mybatisplusexample.CategoryModelTests)

### 数据添加

```
xxxModel.insert();
```

### 数据删除

```
xxxModel.deleteById();
```

### 数据修改

```
xxxModel.updateById();
```

================================================
FILE: doc/05-mybatis知识点.md
================================================


================================================
FILE: doc/06-MyBatis-Plus条件查询.md
================================================

# MyBatis-Plus条件查询

## Wrapper

### QueryWrapper

查询条件构造器

### LambdaQueryWrapper

Lambda的使用

### LambdaQueryChainWrapper

链式查询

================================================
FILE: doc/07-MyBatis-Plus分页查询.md
================================================


================================================
FILE: doc/08-MyBatis-Plus数据库枚举实现.md
================================================
# 枚举



================================================
FILE: doc/09-MyBatis-Plus乐观锁.md
================================================
# 乐观锁

添加拦截器

```
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件
```

乐观锁字段注解:

```
@Version
```


================================================
FILE: doc/10-MyBatis-Plus多数据源(动态).md
================================================


================================================
FILE: doc/11-MyBatis-Plus连表查询.md
================================================


================================================
FILE: doc/12-使用p6spy-SQL打印和性能分析.md
================================================


================================================
FILE: doc/13-MyBatis-Plus逻辑删除.md
================================================


================================================
FILE: doc/14-MyBatis-Plus数据安全保护.md
================================================


================================================
FILE: doc/15-MyBatis-Plus字段填充.md
================================================
# 自动填充


@TableField(.. fill = FieldFill.INSERT)

```
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入填充字段
     */
    INSERT,
    /**
     * 更新填充字段
     */
    UPDATE,
    /**
     * 插入和更新填充字段
     */
    INSERT_UPDATE
```

实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler

```
注意事项:

- 填充原理是直接给entity的属性设置值!!!

- 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null

- MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充

- 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段

- 填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入

- 要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法

- 不需要根据任何来区分可以使用父类的fillStrategy方法
```

还需要再研究研究

================================================
FILE: doc/version/3.2.1.md
================================================
# 3.2.1

| 项 | 说明 |
| --- | --- |
| 构建时间 | 2021.02.02 |
| 发布时间 | |
| 版本号 | 3.2.1 |


## 新特性

## 优化

## 删除

## 文档

## 开发者

================================================
FILE: pom.xml
================================================
<?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>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.fengwenyi</groupId>
    <artifactId>MyBatis-Plus-Example</artifactId>
    <version>3.2.1-BUILD</version>
    <packaging>jar</packaging>
    <name>MyBatis-Plus-Example</name>
    <description>Spring Boot 整合 MyBatis Plus 实例</description>

    <properties>
        <java.version>1.8</java.version>
        <swagger2.version>2.9.2</swagger2.version>
        <JavaLib.version>2.1.1</JavaLib.version>
        <mybatis-plus.version>3.4.2</mybatis-plus.version>
        <fastjson.version>1.2.59</fastjson.version>
        <api-result.version>2.3.1</api-result.version>
    </properties>

    <dependencies>
        <!-- Spring Boot : Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Spring Boot : Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <!-- Swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>

        <!-- JavaLib -->
        <dependency>
            <groupId>com.fengwenyi</groupId>
            <artifactId>JavaLib</artifactId>
            <version>${JavaLib.version}</version>
        </dependency>

        <!-- 添加 Api Result 支持 -->
        <dependency>
            <groupId>com.fengwenyi</groupId>
            <artifactId>api-result</artifactId>
            <version>${api-result.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
        <dependency>
            <groupId>p6spy</groupId>
            <artifactId>p6spy</artifactId>
            <version>3.9.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplication.java
================================================
package com.fengwenyi.mybatisplusexample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MybatisPlusExampleApplication {

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

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/config/MyBatisPlusConfiguration.java
================================================
package com.fengwenyi.mybatisplusexample.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
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;

/**
 * @author Erwin Feng
 * @since 2021-03-08
 */
@Configuration
@MapperScan("com.fengwenyi.mybatisplusexample.mapper")
public class MyBatisPlusConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件
        return interceptor;
    }

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/CategoryEntity.java
================================================
package com.fengwenyi.mybatisplusexample.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("shop_category")
public class CategoryEntity extends Model<CategoryEntity> {

    private static final long serialVersionUID = 1L;

    /**
     * 主键ID
     */
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 商品类别名称
     */
    @TableField("name")
    private String name;


    @Override
    protected Serializable pkVal() {
        return this.id;
    }

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/GoodsEntity.java
================================================
package com.fengwenyi.mybatisplusexample.entity;

import java.math.BigDecimal;

import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;

import java.time.LocalDateTime;
import java.io.Serializable;

import com.fengwenyi.mybatisplusexample.entity.enums.GoodsFlagEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("shop_goods")
public class GoodsEntity extends Model<GoodsEntity> {

    private static final long serialVersionUID = 1L;

    /**
     * 主键ID
     */
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 商品名称
     */
    @TableField("name")
    private String name;

    /**
     * 商品类别ID
     */
    @TableField("category_id")
    private Long categoryId;

    /**
     * 库存数量
     */
    @TableField("stock_num")
    private Long stockNum;

    /**
     * 商品单价
     */
    @TableField("price")
    private BigDecimal price;

    /**
     * 上下架。0:下架;1:上架。默认0。
     */
    @TableField("flag")
    private GoodsFlagEnum flag;

    /**
     * 逻辑删除状态。0:正常;1:删除。默认0。
     */
    @TableField("delete_status")
    @TableLogic
    private Boolean deleteStatus;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 创建人
     */
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;

    /**
     * 更新时间
     */
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;

    /**
     * 修改人
     */
    @TableField(value = "update_by", fill = FieldFill.UPDATE)
    private String updateBy;

    /**
     * 版本。默认:0。
     */
    @TableField("version")
    @Version
    private Integer version;


    @Override
    protected Serializable pkVal() {
        return this.id;
    }

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/enums/GoodsFlagEnum.java
================================================
package com.fengwenyi.mybatisplusexample.entity.enums;

import com.baomidou.mybatisplus.annotation.IEnum;
import lombok.Getter;

/**
 * @author Erwin Feng
 * @since 2021-03-08
 */
@Getter
public enum GoodsFlagEnum implements IEnum<Integer> {
    DOWN(0, "下架"),
    UP(1, "上架"),
    ;

    private final Integer value;

    private final String desc;

    GoodsFlagEnum(Integer value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }
}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/handler/MyBatisPlusAutoFillMetaObjectHandler.java
================================================
package com.fengwenyi.mybatisplusexample.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * @author Erwin Feng
 * @since 2021-04-01
 */
@Slf4j
@Component
public class MyBatisPlusAutoFillMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
//        log.info("start insert fill ....");
//        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
        // 或者
//        this.strictUpdateFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
//        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime", LocalDateTime.now());
//        log.info("start update fill ....");
//        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
        // 或者
//        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class); // 起始版本 3.3.3(推荐)
        // 或者
//        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)



    }
}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/mapper/ICategoryMapper.java
================================================
package com.fengwenyi.mybatisplusexample.mapper;

import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
public interface ICategoryMapper extends BaseMapper<CategoryEntity> {

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/mapper/IGoodsMapper.java
================================================
package com.fengwenyi.mybatisplusexample.mapper;

import com.fengwenyi.mybatisplusexample.entity.GoodsEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
public interface IGoodsMapper extends BaseMapper<GoodsEntity> {

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/MPCategoryRepository.java
================================================
package com.fengwenyi.mybatisplusexample.repository;

import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
public interface MPCategoryRepository extends IService<CategoryEntity> {

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/MPGoodsRepository.java
================================================
package com.fengwenyi.mybatisplusexample.repository;

import com.fengwenyi.mybatisplusexample.entity.GoodsEntity;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
public interface MPGoodsRepository extends IService<GoodsEntity> {

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/CategoryRepositoryImpl.java
================================================
package com.fengwenyi.mybatisplusexample.repository.impl;

import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.fengwenyi.mybatisplusexample.mapper.ICategoryMapper;
import com.fengwenyi.mybatisplusexample.repository.MPCategoryRepository;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
@Service
public class CategoryRepositoryImpl extends ServiceImpl<ICategoryMapper, CategoryEntity> implements MPCategoryRepository {

}


================================================
FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/GoodsRepositoryImpl.java
================================================
package com.fengwenyi.mybatisplusexample.repository.impl;

import com.fengwenyi.mybatisplusexample.entity.GoodsEntity;
import com.fengwenyi.mybatisplusexample.mapper.IGoodsMapper;
import com.fengwenyi.mybatisplusexample.repository.MPGoodsRepository;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-07
 */
@Service
public class GoodsRepositoryImpl extends ServiceImpl<IGoodsMapper, GoodsEntity> implements MPGoodsRepository {

}


================================================
FILE: src/main/resources/application-dev.yml
================================================

#spring
spring:
  datasource:
#    driver-class-name: com.mysql.jdbc.Driver
#    url: jdbc:mysql://192.168.16.128:3306/mybatis-plus-example
    username: root
#    password: kU#m5eHY5iTiQj#q
    password: 123456
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://192.168.16.128:3306/mybatis-plus-example
#    url: mpw:pBZqJb+r/StFGyRopKJyhZN8dvstxaXxubewECBMWM3e7XK+719AUXlC1y1Cu14i1MwqEdiJbBa+sEwFzyWEgA==
#    username: mpw:hjR022j+cjKFE+35FLTQgg==
#    password: mpw:kzLGIBmi4hT+dPmqnXLAIw==

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

logback:
  logDir: log/dev

logging:
  level:
    com.fengwenyi.mybatis_plus_example.service.impl: trace
    com.fengwenyi.mybatis_plus_example.controller: trace


================================================
FILE: src/main/resources/application-prod.yml
================================================


================================================
FILE: src/main/resources/application-test.yml
================================================


================================================
FILE: src/main/resources/application.yml
================================================
#app
server:
  port: 8080

spring:
  application:
    name: mybatis-plus-example
  profiles:
    active: dev

#mybatis
mybatis-plus:
  # xml
  mapper-locations: classpath:mapper/*Mapper.xml
  # 实体扫描,多个package用逗号或者分号分隔
  type-aliases-package: com.fengwenyi.mybatisplusexample.entity
  # 扫描枚举类 # 支持统配符 * 或者 ; 分割
  type-enums-package: com.fengwenyi.mybatisplusexample.entity.enums
  global-config:
    db-config:
      #数据库大写下划线转换
      capital-mode: true
      #逻辑删除配置
      # logic-delete-field: delete_status # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑删除
      logic-not-delete-value: 0 # 正常
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler

logback:
  appName: mybatis-plus-example
  fileType: log


================================================
FILE: src/main/resources/logback-spring.xml
================================================
<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<configuration scan="true" scanPeriod="10 seconds">
    <!--继承spring boot提供的logback配置-->
    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->

    <!--设置系统日志目录-->
    <!--<property name="APP_DIR" value="spring-boot-log"/>-->

    <!--application.yml 传递参数,不能使用logback 自带的<property>标签 -->
    <springProperty scope="context" name="logDir" source="logback.logDir"/>
    <springProperty scope="context" name="appName" source="logback.appName"/>
    <springProperty scope="context" name="fileType" source="logback.fileType"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/${appName}-debug.${fileType}</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
                归档的日志文件的路径,例如今天是2017-04-26日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2017-04-26的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引
            -->
            <fileNamePattern>${logDir}/${appName}-debug-%d{yyyy-MM-dd}.%i.${fileType}</fileNamePattern>
            <!--
                除按日志记录之外,还配置了日志文件不能超过500M,若超过500M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2017-04-26.0.log
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/${appName}-info.${fileType}</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
                归档的日志文件的路径,例如今天是2017-04-26日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2017-04-26的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引
            -->
            <fileNamePattern>${logDir}/${appName}-info-%d{yyyy-MM-dd}.%i.${fileType}</fileNamePattern>
            <!--
                除按日志记录之外,还配置了日志文件不能超过500M,若超过500M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2017-04-26.0.log
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/${appName}-warn.${fileType}</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
                归档的日志文件的路径,例如今天是2017-04-26日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2017-04-26的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引
            -->
            <fileNamePattern>${logDir}/${appName}-warn-%d{yyyy-MM-dd}.%i.${fileType}</fileNamePattern>
            <!--
                除按日志记录之外,还配置了日志文件不能超过500M,若超过500M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2017-04-26.0.log
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/${appName}-error.${fileType}</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
                归档的日志文件的路径,例如今天是2017-04-26日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2017-04-26的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引
            -->
            <fileNamePattern>${logDir}/${appName}-error-%d{yyyy-MM-dd}.%i.${fileType}</fileNamePattern>
            <!--
                除按日志记录之外,还配置了日志文件不能超过500M,若超过500M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2017-04-26.0.log
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name="org.springframework.web" level="info"/>
    <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>

    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="DEBUG_FILE"/>
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="WARN_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
    </springProfile>

    <!--测试环境:打印控制台和输出到文件-->
    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="WARN_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
    </springProfile>

    <!--生产环境:输出到文件-->
    <springProfile name="prod">
        <root level="error">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="DEBUG_FILE"/>
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
        </root>
    </springProfile>

</configuration>

================================================
FILE: src/main/resources/mapper/CategoryMapper.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.fengwenyi.mybatisplusexample.mapper.ICategoryMapper">

</mapper>


================================================
FILE: src/main/resources/mapper/GoodsMapper.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.fengwenyi.mybatisplusexample.mapper.IGoodsMapper">

</mapper>


================================================
FILE: src/main/resources/spy.properties
================================================
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryMapperTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.fengwenyi.mybatisplusexample.mapper.ICategoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;

/**
 *
 * MyBatis Mapper CRUD
 *
 * @author Erwin Feng
 * @since 2021-04-01
 */
@Component
@Slf4j
public class CategoryMapperTests extends MybatisPlusExampleApplicationTests {

    private CategoryEntity entity;

    @Resource
    private ICategoryMapper categoryMapper;

    // 创建数据
    private void create() {
        entity = new CategoryEntity().setName("category test data");
        categoryMapper.insert(entity);
    }

    // 清除数据
    private void clear() {
        categoryMapper.deleteById(entity.getId());
    }

    @Test
    public void testAdd() {
        entity = new CategoryEntity().setName("category test data");
        int resultNum = categoryMapper.insert(entity);
        Assert.isTrue(resultNum == 1, "data add test failure");


        clear();
    }

    @Test
    public void testDelete() {
        create();

        int resultNum = categoryMapper.deleteById(entity.getId());
        Assert.isTrue(resultNum == 1, "data delete test failure");
    }

    @Test
    public void testUpdate() {
        create();

        entity.setName("category update");
        int resultNum = categoryMapper.updateById(entity);
        Assert.isTrue(resultNum == 1, "data update test failure");

        clear();
    }

    @Test
    public void testQuery() {
        create();

        List<CategoryEntity> categoryEntityList = categoryMapper.selectList(new QueryWrapper<>());
        for (CategoryEntity entity : categoryEntityList) {
            log.info(entity.toString());
        }

        clear();
    }

}


================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryModelTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import org.junit.jupiter.api.Test;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 *
 * model test
 *
 * <p>
 *     CRUD
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-30
 */
@Component
public class CategoryModelTests extends MybatisPlusExampleApplicationTests {

    private CategoryEntity model;

    // 创建数据
    private void create() {
        model = new CategoryEntity().setName("category test data");
        model.insert();
    }

    // 清除数据
    private void clear() {
        model.deleteById();
    }

    @Test
    public void testAdd() {
        model = new CategoryEntity().setName("category test data");
        boolean testResult = model.insert();
        Assert.isTrue(testResult, "data add test failure");


        clear();
    }

    @Test
    public void testDelete() {
        create();

        boolean testResult = model.deleteById();
        Assert.isTrue(testResult, "data delete test failure");
    }

    @Test
    public void testUpdate() {
        create();

        model.setName("category update");
        boolean testResult = model.updateById();
        Assert.isTrue(testResult, "data update test failure");

        clear();
    }


}


================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryRepositoryTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.fengwenyi.mybatisplusexample.repository.MPCategoryRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.List;

/**
 *
 * MPCategoryRepository test
 *
 * <p>
 *     CRUD
 * </p>
 *
 * @author Erwin Feng
 * @since 2021-03-08
 */
@Component
@Slf4j
public class CategoryRepositoryTests extends MybatisPlusExampleApplicationTests {

    @Autowired
    private MPCategoryRepository mpCategoryRepository;

    private CategoryEntity entity;

    // 创建数据
    private void create() {
        entity = new CategoryEntity().setName("category test data");
        mpCategoryRepository.save(entity);
    }

    // 清除数据
    private void clear() {
        mpCategoryRepository.removeById(entity);
    }

    @Test
    public void testAdd() {
        entity = new CategoryEntity().setName("category test data");
        boolean testResult = mpCategoryRepository.save(entity);
        Assert.isTrue(testResult, "data add test failure");


        clear();
    }

    @Test
    public void testDelete() {
        create();


        boolean testResult = mpCategoryRepository.removeById(entity.getId());
        Assert.isTrue(testResult, "data delete test failure");
    }

    @Test
    public void testDeleteByWrapper() {
        create();


        LambdaQueryWrapper<CategoryEntity> queryWrapper = new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getName, entity.getName())
                ;

        boolean testResult = mpCategoryRepository.remove(queryWrapper);
        Assert.isTrue(testResult, "data delete by wrapper test failure");
    }

    @Test
    public void testUpdate() {
        create();

        entity.setName("category update");
        boolean testResult = mpCategoryRepository.updateById(entity);
        Assert.isTrue(testResult, "data update test failure");

        clear();
    }

    @Test
    public void testQuery() {
        create();

        // 根据主键ID查询
        mpCategoryRepository.getById(entity.getId());


        // 查询所有
        List<CategoryEntity> list = mpCategoryRepository.list();

        // 添加查询
        LambdaQueryWrapper<CategoryEntity> queryWrapper = new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getName, entity.getName())
                ;
        mpCategoryRepository.list(queryWrapper);

        // 分页查询
        int currentPage = 1;
        int pageSize = 10;
        Page<CategoryEntity> categoryPage = mpCategoryRepository.page(new Page<>(currentPage, pageSize), queryWrapper);

        long current = categoryPage.getCurrent();
        long size = categoryPage.getSize();
        long pages = categoryPage.getPages();
        List<CategoryEntity> categoryList = categoryPage.getRecords();
        long total = categoryPage.getTotal();


        clear();
    }

}


================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/GoodsRepositoryTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fengwenyi.mybatisplusexample.entity.CategoryEntity;
import com.fengwenyi.mybatisplusexample.entity.GoodsEntity;
import com.fengwenyi.mybatisplusexample.entity.enums.GoodsFlagEnum;
import com.fengwenyi.mybatisplusexample.repository.MPCategoryRepository;
import com.fengwenyi.mybatisplusexample.repository.MPGoodsRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author Erwin Feng
 * @since 2021-03-08
 */
@Component
@Slf4j
public class GoodsRepositoryTests extends MybatisPlusExampleApplicationTests {

    @Autowired
    private MPCategoryRepository mpCategoryRepository;

    @Autowired
    private MPGoodsRepository mpGoodsRepository;

    @Test
    public void testAdd() {
        LambdaQueryWrapper<CategoryEntity> categoryQueryWrapper = new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getName, "家电")
                ;
        List<CategoryEntity> categoryEntityList = mpCategoryRepository.list(categoryQueryWrapper);
        CategoryEntity categoryEntity = categoryEntityList.get(0);

        GoodsEntity goodsEntity = new GoodsEntity()
                .setName("平板电脑")
                .setPrice(new BigDecimal("4699.00"))
                .setStockNum(10000L)
                .setFlag(GoodsFlagEnum.UP)
                .setCategoryId(categoryEntity.getId())
                .setCreateBy("admin")
                ;
        mpGoodsRepository.save(goodsEntity);
    }

    @Test
    public void testQuery() {
        List<GoodsEntity> goodsEntityList = mpGoodsRepository.list();
        for (GoodsEntity goodsEntity : goodsEntityList) {
            log.info(goodsEntity.toString());
            log.info(goodsEntity.getFlag().getValue() + "");
        }
    }

    @Test
    public void testUpdate() {
        LambdaQueryWrapper<GoodsEntity> goodsQueryWrapper = new LambdaQueryWrapper<GoodsEntity>().eq(GoodsEntity::getName, "平板电脑");
        List<GoodsEntity> goodsEntityList = mpGoodsRepository.list(goodsQueryWrapper);
        GoodsEntity goodsEntity = goodsEntityList.get(0);
        goodsEntity.setPrice(new BigDecimal("6499.00"));
        mpGoodsRepository.updateById(goodsEntity);
    }

    @Test
    void testQueryTime() {
        LambdaQueryWrapper<GoodsEntity> queryWrapper = new LambdaQueryWrapper<GoodsEntity>()
                .lt(GoodsEntity::getCreateTime, LocalDateTime.parse("2021-04-08 10:00:00")) // where create_time < 2021-04-08 10:00:00
                .gt(GoodsEntity::getCreateTime, LocalDateTime.parse("2021-04-09 10:00:00")) // where create_time > 2021-04-09 10:00:00
                ;
        List<GoodsEntity> list = mpGoodsRepository.list(queryWrapper);
    }

}


================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/MPWTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import com.baomidou.mybatisplus.core.toolkit.AES;
import com.fengwenyi.javalib.util.PrintUtils;
import org.junit.jupiter.api.Test;

/**
 * @author Erwin Feng
 * @since 2021-03-31
 */
public class MPWTests {

    @Test
    public void test() {

        // 生成 16 位随机 AES 密钥
        String randomKey = AES.generateRandomKey();
        PrintUtils.info(randomKey);

        String prefix = "mpw:";

        // 随机密钥加密
        String url = "jdbc:p6spy:mysql://192.168.16.128:3306/mybatis-plus-example";
        String result =prefix + AES.encrypt(url, randomKey);
        PrintUtils.info(result);

        String username = "root";
        result =prefix + AES.encrypt(username, randomKey);
        PrintUtils.info(result);

        String password = "123456";
        result =prefix + AES.encrypt(password, randomKey);
        PrintUtils.info(result);

/*
2021-03-31 00:57:49.494 INFO com.fengwenyi.mybatisplusexample.MPWTests#test : ba8a2cea8df4929f
2021-03-31 00:57:49.871 INFO com.fengwenyi.mybatisplusexample.MPWTests#test : mpw:pBZqJb+r/StFGyRopKJyhZN8dvstxaXxubewECBMWM3e7XK+719AUXlC1y1Cu14i1MwqEdiJbBa+sEwFzyWEgA==
2021-03-31 00:57:49.871 INFO com.fengwenyi.mybatisplusexample.MPWTests#test : mpw:hjR022j+cjKFE+35FLTQgg==
2021-03-31 00:57:49.871 INFO com.fengwenyi.mybatisplusexample.MPWTests#test : mpw:kzLGIBmi4hT+dPmqnXLAIw==
 */

    }

}


================================================
FILE: src/test/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplicationTests.java
================================================
package com.fengwenyi.mybatisplusexample;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MybatisPlusExampleApplicationTests {

    @Test
    public void contextLoads() {
    }



}
Download .txt
gitextract_ke3bd0xo/

├── .gitignore
├── README.md
├── doc/
│   ├── 00-mybatis-plus知识点.md
│   ├── 01-SpringBoot整合MyBatis-Plus.md
│   ├── 02-mybatis-plus-example.sql
│   ├── 03-MyBatis-Plus代码生成器的使用.md
│   ├── 04-CRUD.md
│   ├── 05-mybatis知识点.md
│   ├── 06-MyBatis-Plus条件查询.md
│   ├── 07-MyBatis-Plus分页查询.md
│   ├── 08-MyBatis-Plus数据库枚举实现.md
│   ├── 09-MyBatis-Plus乐观锁.md
│   ├── 10-MyBatis-Plus多数据源(动态).md
│   ├── 11-MyBatis-Plus连表查询.md
│   ├── 12-使用p6spy-SQL打印和性能分析.md
│   ├── 13-MyBatis-Plus逻辑删除.md
│   ├── 14-MyBatis-Plus数据安全保护.md
│   ├── 15-MyBatis-Plus字段填充.md
│   └── version/
│       └── 3.2.1.md
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── fengwenyi/
    │   │           └── mybatisplusexample/
    │   │               ├── MybatisPlusExampleApplication.java
    │   │               ├── config/
    │   │               │   └── MyBatisPlusConfiguration.java
    │   │               ├── entity/
    │   │               │   ├── CategoryEntity.java
    │   │               │   ├── GoodsEntity.java
    │   │               │   └── enums/
    │   │               │       └── GoodsFlagEnum.java
    │   │               ├── handler/
    │   │               │   └── MyBatisPlusAutoFillMetaObjectHandler.java
    │   │               ├── mapper/
    │   │               │   ├── ICategoryMapper.java
    │   │               │   └── IGoodsMapper.java
    │   │               └── repository/
    │   │                   ├── MPCategoryRepository.java
    │   │                   ├── MPGoodsRepository.java
    │   │                   └── impl/
    │   │                       ├── CategoryRepositoryImpl.java
    │   │                       └── GoodsRepositoryImpl.java
    │   └── resources/
    │       ├── application-dev.yml
    │       ├── application-prod.yml
    │       ├── application-test.yml
    │       ├── application.yml
    │       ├── logback-spring.xml
    │       ├── mapper/
    │       │   ├── CategoryMapper.xml
    │       │   └── GoodsMapper.xml
    │       └── spy.properties
    └── test/
        └── java/
            └── com/
                └── fengwenyi/
                    └── mybatisplusexample/
                        ├── CategoryMapperTests.java
                        ├── CategoryModelTests.java
                        ├── CategoryRepositoryTests.java
                        ├── GoodsRepositoryTests.java
                        ├── MPWTests.java
                        └── MybatisPlusExampleApplicationTests.java
Download .txt
SYMBOL INDEX (52 symbols across 19 files)

FILE: doc/02-mybatis-plus-example.sql
  type `shop_category` (line 24) | CREATE TABLE `shop_category`  (
  type `shop_goods` (line 34) | CREATE TABLE `shop_goods`  (

FILE: src/main/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplication.java
  class MybatisPlusExampleApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: src/main/java/com/fengwenyi/mybatisplusexample/config/MyBatisPlusConfiguration.java
  class MyBatisPlusConfiguration (line 15) | @Configuration
    method mybatisPlusInterceptor (line 19) | @Bean

FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/CategoryEntity.java
  class CategoryEntity (line 21) | @Data
    method pkVal (line 42) | @Override

FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/GoodsEntity.java
  class GoodsEntity (line 24) | @Data
    method pkVal (line 107) | @Override

FILE: src/main/java/com/fengwenyi/mybatisplusexample/entity/enums/GoodsFlagEnum.java
  type GoodsFlagEnum (line 10) | @Getter
    method GoodsFlagEnum (line 20) | GoodsFlagEnum(Integer value, String desc) {
    method getValue (line 25) | @Override

FILE: src/main/java/com/fengwenyi/mybatisplusexample/handler/MyBatisPlusAutoFillMetaObjectHandler.java
  class MyBatisPlusAutoFillMetaObjectHandler (line 14) | @Slf4j
    method insertFill (line 18) | @Override
    method updateFill (line 29) | @Override

FILE: src/main/java/com/fengwenyi/mybatisplusexample/mapper/ICategoryMapper.java
  type ICategoryMapper (line 14) | public interface ICategoryMapper extends BaseMapper<CategoryEntity> {

FILE: src/main/java/com/fengwenyi/mybatisplusexample/mapper/IGoodsMapper.java
  type IGoodsMapper (line 14) | public interface IGoodsMapper extends BaseMapper<GoodsEntity> {

FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/MPCategoryRepository.java
  type MPCategoryRepository (line 14) | public interface MPCategoryRepository extends IService<CategoryEntity> {

FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/MPGoodsRepository.java
  type MPGoodsRepository (line 14) | public interface MPGoodsRepository extends IService<GoodsEntity> {

FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/CategoryRepositoryImpl.java
  class CategoryRepositoryImpl (line 17) | @Service

FILE: src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/GoodsRepositoryImpl.java
  class GoodsRepositoryImpl (line 17) | @Service

FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryMapperTests.java
  class CategoryMapperTests (line 21) | @Component
    method create (line 31) | private void create() {
    method clear (line 37) | private void clear() {
    method testAdd (line 41) | @Test
    method testDelete (line 51) | @Test
    method testUpdate (line 59) | @Test
    method testQuery (line 70) | @Test

FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryModelTests.java
  class CategoryModelTests (line 19) | @Component
    method create (line 25) | private void create() {
    method clear (line 31) | private void clear() {
    method testAdd (line 35) | @Test
    method testDelete (line 45) | @Test
    method testUpdate (line 53) | @Test

FILE: src/test/java/com/fengwenyi/mybatisplusexample/CategoryRepositoryTests.java
  class CategoryRepositoryTests (line 26) | @Component
    method create (line 36) | private void create() {
    method clear (line 42) | private void clear() {
    method testAdd (line 46) | @Test
    method testDelete (line 56) | @Test
    method testDeleteByWrapper (line 65) | @Test
    method testUpdate (line 78) | @Test
    method testQuery (line 89) | @Test

FILE: src/test/java/com/fengwenyi/mybatisplusexample/GoodsRepositoryTests.java
  class GoodsRepositoryTests (line 23) | @Component
    method testAdd (line 33) | @Test
    method testQuery (line 52) | @Test
    method testUpdate (line 61) | @Test
    method testQueryTime (line 70) | @Test

FILE: src/test/java/com/fengwenyi/mybatisplusexample/MPWTests.java
  class MPWTests (line 11) | public class MPWTests {
    method test (line 13) | @Test

FILE: src/test/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplicationTests.java
  class MybatisPlusExampleApplicationTests (line 6) | @SpringBootTest
    method contextLoads (line 9) | @Test
Condensed preview — 46 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (64K chars).
[
  {
    "path": ".gitignore",
    "chars": 338,
    "preview": "HELP.md\n/target/\n.mvn/\nmvnw\nmvnw.cmd\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans"
  },
  {
    "path": "README.md",
    "chars": 1475,
    "preview": "# MyBatis-Plus-Example\n\nSpring Boot 整合 MyBatis Plus 实例,持续更新!!!\n\n## 代码生成器\n\n[请点击此处的传送门](https://github.com/fengwenyi/mybat"
  },
  {
    "path": "doc/00-mybatis-plus知识点.md",
    "chars": 9111,
    "preview": "# MyBatis-Plus知识点\n\n## Spring Boot整合MyBatis-Plus\n\n第一步:pom.xml引入MyBatis-Plus依赖,注意,不需要再引入MyBatis的包,因为我这里使用Spring Boot搭建的工程,"
  },
  {
    "path": "doc/01-SpringBoot整合MyBatis-Plus.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/02-mybatis-plus-example.sql",
    "chars": 1946,
    "preview": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost.01-192.168.16.128\n Source Server Type    : MySQL\n "
  },
  {
    "path": "doc/03-MyBatis-Plus代码生成器的使用.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/04-CRUD.md",
    "chars": 1129,
    "preview": "# CRUD\n\n- 增加(Create)\n- 检索(Retrieve)\n- 更新(Update)\n- 删除(Delete)\n\n对于MyBatis-Plus而言,增删改查,有三种方式实现。\n\n1、使用MyBatis-Plus提供的服务接口。\n"
  },
  {
    "path": "doc/05-mybatis知识点.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/06-MyBatis-Plus条件查询.md",
    "chars": 128,
    "preview": "\n# MyBatis-Plus条件查询\n\n## Wrapper\n\n### QueryWrapper\n\n查询条件构造器\n\n### LambdaQueryWrapper\n\nLambda的使用\n\n### LambdaQueryChainWrapp"
  },
  {
    "path": "doc/07-MyBatis-Plus分页查询.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/08-MyBatis-Plus数据库枚举实现.md",
    "chars": 6,
    "preview": "# 枚举\n\n"
  },
  {
    "path": "doc/09-MyBatis-Plus乐观锁.md",
    "chars": 132,
    "preview": "# 乐观锁\n\n添加拦截器\n\n```\ninterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件\n```\n\n乐观锁字段注解:\n\n```\n@"
  },
  {
    "path": "doc/10-MyBatis-Plus多数据源(动态).md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/11-MyBatis-Plus连表查询.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/12-使用p6spy-SQL打印和性能分析.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/13-MyBatis-Plus逻辑删除.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/14-MyBatis-Plus数据安全保护.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/15-MyBatis-Plus字段填充.md",
    "chars": 693,
    "preview": "# 自动填充\n\n\n@TableField(.. fill = FieldFill.INSERT)\n\n```\n    /**\n     * 默认不处理\n     */\n    DEFAULT,\n    /**\n     * 插入填充字段\n  "
  },
  {
    "path": "doc/version/3.2.1.md",
    "chars": 120,
    "preview": "# 3.2.1\n\n| 项 | 说明 |\n| --- | --- |\n| 构建时间 | 2021.02.02 |\n| 发布时间 | |\n| 版本号 | 3.2.1 |\n\n\n## 新特性\n\n## 优化\n\n## 删除\n\n## 文档\n\n## 开发者"
  },
  {
    "path": "pom.xml",
    "chars": 3554,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplication.java",
    "chars": 361,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/config/MyBatisPlusConfiguration.java",
    "chars": 1042,
    "preview": "package com.fengwenyi.mybatisplusexample.config;\n\nimport com.baomidou.mybatisplus.annotation.DbType;\nimport com.baomidou"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/entity/CategoryEntity.java",
    "chars": 997,
    "preview": "package com.fengwenyi.mybatisplusexample.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomi"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/entity/GoodsEntity.java",
    "chars": 2042,
    "preview": "package com.fengwenyi.mybatisplusexample.entity;\n\nimport java.math.BigDecimal;\n\nimport com.baomidou.mybatisplus.annotati"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/entity/enums/GoodsFlagEnum.java",
    "chars": 541,
    "preview": "package com.fengwenyi.mybatisplusexample.entity.enums;\n\nimport com.baomidou.mybatisplus.annotation.IEnum;\nimport lombok."
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/handler/MyBatisPlusAutoFillMetaObjectHandler.java",
    "chars": 1541,
    "preview": "package com.fengwenyi.mybatisplusexample.handler;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\nimpo"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/mapper/ICategoryMapper.java",
    "chars": 326,
    "preview": "package com.fengwenyi.mybatisplusexample.mapper;\n\nimport com.fengwenyi.mybatisplusexample.entity.CategoryEntity;\nimport "
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/mapper/IGoodsMapper.java",
    "chars": 317,
    "preview": "package com.fengwenyi.mybatisplusexample.mapper;\n\nimport com.fengwenyi.mybatisplusexample.entity.GoodsEntity;\nimport com"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/repository/MPCategoryRepository.java",
    "chars": 331,
    "preview": "package com.fengwenyi.mybatisplusexample.repository;\n\nimport com.fengwenyi.mybatisplusexample.entity.CategoryEntity;\nimp"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/repository/MPGoodsRepository.java",
    "chars": 322,
    "preview": "package com.fengwenyi.mybatisplusexample.repository;\n\nimport com.fengwenyi.mybatisplusexample.entity.GoodsEntity;\nimport"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/CategoryRepositoryImpl.java",
    "chars": 589,
    "preview": "package com.fengwenyi.mybatisplusexample.repository.impl;\n\nimport com.fengwenyi.mybatisplusexample.entity.CategoryEntity"
  },
  {
    "path": "src/main/java/com/fengwenyi/mybatisplusexample/repository/impl/GoodsRepositoryImpl.java",
    "chars": 568,
    "preview": "package com.fengwenyi.mybatisplusexample.repository.impl;\n\nimport com.fengwenyi.mybatisplusexample.entity.GoodsEntity;\ni"
  },
  {
    "path": "src/main/resources/application-dev.yml",
    "chars": 782,
    "preview": "\n#spring\nspring:\n  datasource:\n#    driver-class-name: com.mysql.jdbc.Driver\n#    url: jdbc:mysql://192.168.16.128:3306/"
  },
  {
    "path": "src/main/resources/application-prod.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/main/resources/application-test.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/main/resources/application.yml",
    "chars": 839,
    "preview": "#app\nserver:\n  port: 8080\n\nspring:\n  application:\n    name: mybatis-plus-example\n  profiles:\n    active: dev\n\n#mybatis\nm"
  },
  {
    "path": "src/main/resources/logback-spring.xml",
    "chars": 9313,
    "preview": "<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->\n<configuration scan=\"true\" scanPeriod=\"10 se"
  },
  {
    "path": "src/main/resources/mapper/CategoryMapper.xml",
    "chars": 235,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/"
  },
  {
    "path": "src/main/resources/mapper/GoodsMapper.xml",
    "chars": 232,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/"
  },
  {
    "path": "src/main/resources/spy.properties",
    "chars": 815,
    "preview": "#3.2.1以上使用\nmodulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFac"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/CategoryMapperTests.java",
    "chars": 1981,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport co"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/CategoryModelTests.java",
    "chars": 1327,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport com.fengwenyi.mybatisplusexample.entity.CategoryEntity;\nimport org.jun"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/CategoryRepositoryTests.java",
    "chars": 3216,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimp"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/GoodsRepositoryTests.java",
    "chars": 3028,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimp"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/MPWTests.java",
    "chars": 1387,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport com.baomidou.mybatisplus.core.toolkit.AES;\nimport com.fengwenyi.javali"
  },
  {
    "path": "src/test/java/com/fengwenyi/mybatisplusexample/MybatisPlusExampleApplicationTests.java",
    "chars": 261,
    "preview": "package com.fengwenyi.mybatisplusexample;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.conte"
  }
]

About this extraction

This page contains the full source code of the fengwenyi/MyBatis-Plus-Example GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 46 files (49.8 KB), approximately 16.4k tokens, and a symbol index with 52 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!