MyBatis-Plus入门,看这一篇就足够了

文章设计源代码和笔记:gitee

一、Mybatis-Plus

简介

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

支持数据库

  • mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver 、 presto
  • 达梦数据库 、 虚谷数据库 、 人大金仓数据库

框架结构

代码托管

Gitee | Github

二、快速入门

地址:https://mp.baomidou.com/guide/quick-start.html#初始化工程

使用第三方组件

  1. 导入对应依赖
  2. 研究依赖配置
  3. 代码如何编写
  4. 提高扩展技术能力!

步骤

  1. 创建数据库mybatis_plus
  2. 创建user表,插入数据
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
  1. 编写项目,初始化项目! 使用SpringBoot初始化!
  2. 导入依赖
<dependency>
    <groupId>org.springframework.boot</groupI
    <artifactId>spring-boot-starter-web</arti
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupI
    <artifactId>spring-boot-starter-test</art
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</group
            <artifactId>junit-vintage-engine<
        </exclusion>
    </exclusions>
</dependency>
<!--数据库驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifac
    <version>8.0.20</version>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>
<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</ar
    <version>3.3.1</version>
</dependency>

说明:我们使用mybatis-plus可以节省大量代码,尽量不要同时导入mybatis和mybatis-plus!版本差异!

  1. 配置数据库,和mybatis一样
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username=mybatis_plus
spring.datasource.password=mybatis_plus123
  1. 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
@MapperScan("com.godfrey.mapper")
@SpringBootApplication
public class MybatisPlusApplication {

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

}
  1. 编码

编写实体类 User.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

编写Mapper类 UserMapper.java

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

8.使用

添加测试类,进行功能测试:

@SpringBootTest
class MybatisPlusApplicationTests {

    @Resource
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        //查询全部用户
        //参数是一个Wrapper,条件构造器
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

控制台输出:

User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

小结

通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。

三、配置日志

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

四、CRUD扩展

插入操作

//测试插入
@Test
public void testInsert(){
    User user = new User();
    user.setName("淮城一只猫");
    user.setAge(5);
    user.setEmail("2424496907@qq.com");
    int result = userMapper.insert(user); //自动生成id
    System.out.println(result); //受影响的行数
    System.out.println(user); //发现id自动回填
}

数据库插入的id默认是全局唯一id

主键生成策略

默认ID_WORKER,全局唯一id

分布式系统唯一id生成方案汇总

雪花算法:

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

主键自增

我们需要配置注解自增:

  1. 实体类字段上:@TableId(type = IdType.AUTUO)
  2. 数据库字段一定要自增

3.再次测试插入即可!

其余的策略解释

public enum IdType {
    AUTO(0), //id自增
    NONE(1), //未设置主键
    INPUT(2), //手动输入
    ID_WORKER(3), //默认值,全局唯一id
    UUID(4), //全局唯一id,uuid
    ID_WORKER_STR(5); //ID_WORKER的字符串表示法
}

更新操作

//测试更新
@Test
public void testUpdate(){
    User user = new User();
    user.setId(6L);
    user.setName("我的博客叫:淮城一只猫");
    user.setAge(6);
    user.setEmail("2424496907@qq.com");
    //注意:updateById参数是一个对象
    int result = userMapper.updateById(user); //自动生成id
    System.out.println(result); //受影响的行数
}

自动填充

创建时间、修改时间!这些操作一般自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有表都要配置上!而且需要自动化!

方式一:数据库级别(工作中不建议这么做)

  1. 在表中新增字段create_time、update_time

  1. 再次测试插入方法,需要先把实体类同步!
private Date creteTime;
private Date updateTime;

方式二:代码级别

  1. 输出数据库中的默认值、更新操作

  1. 在实体类字段属性上需要注释
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date creteTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
  1. 编写处理器处理注解!
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler{
    //插入时填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //更新时填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}
  1. 测试插入
  2. 测试更新、观察时间即可!

乐观锁

乐观锁:顾名思义乐观,它总是认为不会出现问题,无论干什么都不去上锁!如果出现问题,再次更新值测试

悲观锁:顾名思义悲观,它总是认为会出现问题,无论干什么都会加上锁!再去操作

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

测试MP乐观锁插件

  1. 数据库中添加version字段!

  1. 实体类添加对应字段
@Version  //乐观锁注解
private Integer version;
  1. 注册组件
@MapperScan("com.godfrey.mapper")
@EnableTransactionManagement  //自动管理事务(默认也是开启的)
@Configuration  //配置类
public class MybaitsPlusConfig {

    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}
  1. 测试一下
//测试乐观锁成功!
@Test
public void testOptimisticLocker1() {
    //1.查询用户信息
    User user = userMapper.selectById(1L);
    //2.修改用户信息
    user.setName("godfrey");
    user.setEmail("13610506606@163.com");
    //3.执行更新操作
    userMapper.updateById(user);
}


//测试乐观锁失败!多线程下
@Test
public void testOptimisticLocker2() {
    //线程1
    User user1 = userMapper.selectById(1L);
    user1.setName("godfrey111");
    user1.setEmail("13610506606@163.com");

    //模拟另外一个线程执行插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("godfrey222");
    user2.setEmail("13610506606@163.com");
    userMapper.updateById(user2);

    //自旋锁多次操作尝试提交
    userMapper.updateById(user1);
}

查询操作

//测试查询
@Test
public void testSelectById() {
    User user = userMapper.selectById(1L);
    System.out.println(user);
}

//测试批量查询
@Test
public void testSelectByBatchId() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
    users.forEach(System.out::println);
}

//条件查询之一 使用map操作
@Test
public void testSelectBatchIds() {
    HashMap<String, Object> map = new HashMap<>();
    //自定义查询
    map.put("name","Tom");
    map.put("age",28);

    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

分页查询

分页在网站中使用非常多!

  1. 原始limit进行分页
  2. pageHelper第三方插件
  3. MP其实也内置了分页插件

如何使用?

  1. 配置分页插件
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}
  1. 直接使用Page对象即可!
//测试分页查询
@Test
public void testPage() {
    //参数一:当前页
    //参数二:页面大小
    //使用了分页插件之后,所有的分页操作页变得简单了
    Page<User> page = new Page<>(1,5);
    userMapper.selectPage(page,null);

    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

删除操作

基本的删除操作

//通过id删除
@Test
public void testDeleteById() {
    userMapper.deleteById(8L);
}

//通过id批量删除
@Test
public void testDeleteBatchId() {
    userMapper.deleteBatchIds(Arrays.asList(6L, 7L));
}

//通过map删除
@Test
public void testDeleteMap() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "godfrey");
    userMapper.deleteByMap(map);
}

我们在工作中会遇到一些问题:逻辑删除!

逻辑删除

物理删除:从数据库中直接移除

逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效!delete=0 => delete=1

管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!

测试一下:

  1. 在数据表中增加deleted字段

  1. 实体类中同步属性
//逻辑删除字段
private Integer deleted;
  1. 配置
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-field=deleted # 全局逻辑删除的实体字段名
mybatis-plus.global-config.db-config.logic-delete-value=1 # 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-not-delete-value=0 # 逻辑未删除值(默认为 0)
  1. 测试一下删除

以上的所有CRUD操作及其扩展操作,我们都必须精通掌握!会大大提高工作和写项目效率

性能分析插件

我们在开发中,会遇到一些慢sql,我们有必要把它揪出来 。测试!druid...

MP也提供性能分析插件,如果超过这个时间就停止运行!官方3.1.0以上版本推荐使用p6spy!

  1. 导入依赖
<!--p6spy性能分析插件-->
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.0</version>
</dependency>
  1. 修改数据库连接配置
# 数据库连接配置
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
  1. 新建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
# 日期格式gui
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
  1. 测试使用!(只要超过了规定时间就会抛出异常)

注意,插件会影响性能,建议开发和测试环境下使用

条件构造器

  1. 测试一
@Test
void test1() {
    //查询name不为空的用户,并且邮箱不为空的,年龄大于等于12
    QueryWrapper<User> wapper = new QueryWrapper<>();
    wapper.isNotNull("name")
            .isNotNull("email")
            .ge("age", 12);
    userMapper.selectList(wapper).forEach(System.out::println);
}
  1. 测试二
@Test
void test2() {
    //查询名字为Tom
    QueryWrapper<User> wapper = new QueryWrapper<>();
    wapper.eq("name","Tom");
    User user = userMapper.selectOne(wapper);
    System.out.println(user);
}
  1. 测试三
//范围查询
@Test
void test3() {
    //查询年龄在20~30岁之间的用户
    QueryWrapper<User> wapper = new QueryWrapper<>();
    wapper.between("age", 20, 30);//区间
    System.out.println(userMapper.selectCount(wapper));//查询结果数
}
  1. 测试四
//模糊查询
@Test
void test4() {
    //查询名字有
    QueryWrapper<User> wapper = new QueryWrapper<>();
    wapper.notLike("name","e")//%e%
            .likeRight("email","t");//t%
    List<Map<String, Object>> maps = userMapper.selectMaps(wapper);
    maps.forEach(System.out::println);
}
  1. 测试五
//子查询
@Test
void test5() {
    QueryWrapper<User> wapper = new QueryWrapper<>();
    //id在子查询中查出来
    wapper.inSql("id","select id from user where id<3");
    List<Object> objects = userMapper.selectObjs(wapper);
    objects.forEach(System.out::println);
}
  1. 测试六
//排序
@Test
void test6() {
    QueryWrapper<User> wapper = new QueryWrapper<>();
    //通过id进行排序
    wapper.orderByDesc("id");
    userMapper.selectList(wapper).forEach(System.out::println);
}

代码生成器

mapper、pojo、service、controller都给我自己去编写完成!

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

1.EasyCode介绍


1.1 EasyCode是一个什么东西?


EasyCode是基于IntelliJ IDEA Ultimate版开发的一个代码生成插件,主要通过自定义模板(基于velocity)来生成各种你想要的代码。通常用于生成Entity、Dao、Service、Controller。如果你动手能力强还可以用于生成HTML、JS、PHP等代码。理论上来说只要是与数据有关的代码都是可以生成的。


1.2 原理

基于Mybatis底层强大的逆向工程能力和良好的项目架构


1.3 使用环境

IntelliJ IDEA Ultimate版


1.4 支持的数据库类型

因为是基于Database Tool开发,所有Database Tool支持的数据库都是支持的。

包括如下数据库:

  1. MySQL
  2. SQL Server
  3. Oracle
  4. PostgreSQL
  5. Sqlite
  6. Sybase
  7. Derby
  8. DB2
  9. HSQLDB
  10. H2

当然支持的数据库类型也会随着Database Tool插件的更新同步更新。


1.5 功能说明:

  • 支持多表同时操作
  • 支持同时生成多个模板
  • 支持自定义模板
  • 支持自定义类型映射(支持正则)
  • 支持自定义附加列
  • 支持列附加属性
  • 所有配置项目支持分组模式,在不同项目(或选择不同数据库时),只需要切换对应的分组,所有配置统一变化

1.6 功能对比:

功能 Easy Code 其他工具
自定义模板 支持 支持
多表生成 支持 支持
生成方式 无缝集成在项目中 部分工具需要复制粘贴
附加列 支持 不支持
附加列属性 支持 不支持
动态调试模板 支持 不支持
图形化界面 支持 部分支持
使用环境 仅限IDEA 支持各种形式
在线支持 后期扩展 不支持
自定义类型映射 支持 部分支持
全局变量 支持 不支持

2.EasyCode使用


2.1 下载Easy Code插件


2.2 创建一个SpringBoot项目

2.3 配置数据源

使用Easy Code一定要使用IDEA自带的数据库工具来配置数据源

.


打开侧边的Database,查看效果

,


提前准备的数据表

,


2.4 自定义生成模板


第一次安装EasyCode的时候默认的模板(服务于MyBatis)可以生成下面类型的代码

  1. entity.java
  2. dao.java
  3. service.java
  4. serviceImpl.java
  5. controller.java
  6. mapper.xml
  7. debug.json

2.5 以user表为例,根据你定义的模板生成代码,文章的最后贴出我使用的自定义的模板

,


选择模板

,


点击OK之后,就可以看到生成了这些代码

,


2.6 代码展示

实体类层:User.java
package com.godfrey.easycode.entity;

import java.io.Serializable;

/**
 * (User)实体类
 *
 * @author godfrey
 * @since 2020-04-20 19:21:17
 */
public class User implements Serializable {
    private static final long serialVersionUID = 502672392114472688L;
    /**
     * 主键ID
     */
    private Integer id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 邮箱
     */
    private String email;

        
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
        
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
        
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
        
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                "name=" + name +
                "age=" + age +
                "email=" + email +
                '}';
    }
}

Dao数据库访问层:UserDao.java
package com.godfrey.easycode.dao;

import com.godfrey.easycode.entity.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * description : (User)表数据库访问层
 *
 * @author godfrey
 * @since  2020-04-20 19:21:17
 */
@Mapper
public interface UserDao {

    /**
     * description : 添加User
     *
     * @param user 实例对象
     * @return 影响行数
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    int insert(User user);

    /**
     * description : 删除User
     *
     * @param  id 主键
     * @return 影响行数
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    int deleteById(Integer id);

    /**
     * description : 通过ID查询单条数据
     *
     * @param  id 主键
     * @return 实例对象
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    User queryById(Integer id);

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    List<User> queryAll();

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param  user 实例对象
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    List<User> queryAll(User user);

    /**
     * description : 修改User
     *
     * @param  user 根据user的主键修改数据
     * @return 影响行数
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    int update(User user);
}

Service服务接口层:UserService.java
package com.godfrey.easycode.service;

import com.godfrey.easycode.entity.User;
import java.util.List;

/**
 * description : (User)表服务接口
 *
 * @author godfrey
 * @since  2020-04-20 19:21:17
 */
public interface UserService {

    /**
     * description : 添加User
     *
     * @param  user 实例对象
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    boolean insert(User user);

    /**
     * description : 删除User
     *
     * @param  id 主键
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    boolean deleteById(Integer id);

    /**
     * description : 查询单条数据
     * @param  id 主键
     * @return 实例对象
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    User queryById(Integer id);

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    List<User> queryAll();

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param  user 实例对象
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    List<User> queryAll(User user);

    /**
     * description : 修改数据,哪个属性不为空就修改哪个属性
     *
     * @param  user 实例对象
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    boolean update(User user);
}

ServiceImpl服务接口实现层:UserServiceImpl.java
package com.godfrey.easycode.service.impl;

import com.godfrey.easycode.entity.User;
import com.godfrey.easycode.dao.UserDao;
import com.godfrey.easycode.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

 /**
  * description : (User)表服务实现类
  *
  * @author godfrey
  * @since  2020-04-20 19:21:17
  **/
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    protected UserDao userDao;

    /**
     * description : 添加User
     *
     * @param  user 实例对象
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public boolean insert(User user) {
        return userDao.insert(user) == 1;
    }

    /**
     * description : 删除User
     *
     * @param  id 主键
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public boolean deleteById(Integer id) {
        return userDao.deleteById(id) == 1;
    }

    /**
     * description : 查询单条数据
     *
     * @param  id 主键
     * @return 实例对象
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public User queryById(Integer id) {
        return userDao.queryById(id);
    }

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public List<User> queryAll() {
        return userDao.queryAll();
    }

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param user 实例对象
     * @return 对象列表
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public List<User> queryAll(User user) {
        return userDao.queryAll(user);
    }

    /**
     * description : 修改数据,哪个属性不为空就修改哪个属性
     *
     * @param user 实例对象
     * @return 是否成功
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @Override
    public boolean update(User user) {
        return userDao.update(user) == 1;
    }
}

前端控制器:UserController.java
package com.godfrey.easycode.controller;

import com.godfrey.easycode.entity.User;
import com.godfrey.easycode.service.UserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * description : (User)表控制层
 *
 * @author godfrey
 * @since  2020-04-20 19:21:17
 */
@RestController
@RequestMapping("user")
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    /**
     * description : 通过主键查询单条数据
     *
     * @param  id 主键
     * @return 单条数据
     * @author godfrey
     * @since  2020-04-20 19:21:17
     */
    @GetMapping("selectOne")
    public User selectOne(Integer id) {
        return this.userService.queryById(id);
    }
}

Mapper映射文件:UserMapper.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.godfrey.easycode.dao.UserDao">

    <!--user的映射结果集-->
    <resultMap type="com.godfrey.easycode.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="email" column="email" jdbcType="VARCHAR"/>
    </resultMap>

    <!--全部字段-->
    <sql id="allColumn"> id, name, age, email </sql>

    <!--添加语句的字段列表-->
    <sql id="insertColumn">
        <if test="name != null and name != ''">
            name,
        </if>
        <if test="age != null">
            age,
        </if>
        <if test="email != null and email != ''">
            email,
        </if>
    </sql>

    <!--添加语句的值列表-->
    <sql id="insertValue">
        <if test="name != null and name != ''">
            #{name},
        </if>
        <if test="age != null">
            #{age},
        </if>
        <if test="email != null and email != ''">
            #{email},
        </if>
    </sql>

    <!--通用对User各个属性的值的非空判断-->
    <sql id="commonsValue">
        <if test="name != null and name != ''">
            name = #{name},
        </if>
        <if test="age != null">
            age = #{age},
        </if>
        <if test="email != null and email != ''">
            email = #{email},
        </if>
    </sql>

    <!--新增user:哪个字段不为空就添加哪列数据,返回自增主键-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into user
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <include refid="insertColumn"/>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <include refid="insertValue"/>
        </trim>
    </insert>

    <!--删除user:通过主键-->
    <delete id="deleteById">
        delete from user
        <where>
            id = #{id}
        </where>
    </delete>

    <!--查询单个user-->
    <select id="queryById" resultMap="UserMap">
        select
        <include refid="allColumn"></include>
        from user
        <where>
            id = #{id}
        </where>
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="UserMap">
        select
        <include refid="allColumn"></include>
        from user
        <trim prefix="where" prefixOverrides="and" suffixOverrides=",">
            <include refid="commonsValue"></include>
        </trim>
    </select>

    <!--通过主键修改数据-->
    <update id="update">
        update user
        <set>
            <include refid="commonsValue"></include>
        </set>
        <where>
            id = #{id}
        </where>
    </update>
</mapper>

以上代码完全是生成出来了,从头到尾只需要点几下鼠标,是不是很神奇!


3.我的默认定制模板


entity.java

##引入宏定义
$!define

##使用宏定义设置回调(保存位置与文件后缀)
#save("/entity", ".java")

##使用宏定义设置包后缀
#setPackageSuffix("entity")

##使用全局变量实现默认包导入
$!autoImport
import java.io.Serializable;

##使用宏定义实现类注释信息
#tableComment("实体类")
public class $!{tableInfo.name} implements Serializable {
    private static final long serialVersionUID = $!tool.serial();
#foreach($column in $tableInfo.fullColumn)
    #if(${column.comment})/**
     * ${column.comment}
     */#end

    private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end

#foreach($column in $tableInfo.fullColumn)
    ##使用宏定义实现get,set方法
    #getSetMethod($column)
#end

    @Override
    public String toString() {
        return "$!{tableInfo.name}{" +
    #foreach($column in $tableInfo.fullColumn)
            "$!{column.name}=" + $!{column.name} +
    #end
            '}';
    }
}

dao.java

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Dao"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/dao"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao;

import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * description : $!{tableInfo.comment}($!{tableInfo.name})表数据库访问层
 *
 * @author $!author
 * @since  $!time.currTime()
 */
@Mapper
public interface $!{tableName} {

    /**
     * description : 添加$!{tableInfo.name}
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 影响行数
     * @author $!author
     * @since  $!time.currTime()
     */
    int insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * description : 删除$!{tableInfo.name}
     *
     * @param  $!pk.name 主键
     * @return 影响行数
     * @author $!author
     * @since  $!time.currTime()
     */
    int deleteById($!pk.shortType $!pk.name);

    /**
     * description : 通过ID查询单条数据
     *
     * @param  $!pk.name 主键
     * @return 实例对象
     * @author $!author
     * @since  $!time.currTime()
     */
    $!{tableInfo.name} queryById($!pk.shortType $!pk.name);

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    List<$!{tableInfo.name}> queryAll();

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param  $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    List<$!{tableInfo.name}> queryAll($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * description : 修改$!{tableInfo.name}
     *
     * @param  user 根据$!tool.firstLowerCase($!{tableInfo.name})的主键修改数据
     * @return 影响行数
     * @author $!author
     * @since  $!time.currTime()
     */
    int update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
}

service.java

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Service"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;

import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import java.util.List;

/**
 * description : $!{tableInfo.comment}($!{tableInfo.name})表服务接口
 *
 * @author $!author
 * @since  $!time.currTime()
 */
public interface $!{tableName} {

    /**
     * description : 添加$!{tableInfo.name}
     *
     * @param  $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    boolean insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * description : 删除$!{tableInfo.name}
     *
     * @param  $!pk.name 主键
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    boolean deleteById($!pk.shortType $!pk.name);

    /**
     * description : 查询单条数据
     * @param  $!pk.name 主键
     * @return 实例对象
     * @author $!author
     * @since  $!time.currTime()
     */
    $!{tableInfo.name} queryById($!pk.shortType $!pk.name);

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    List<$!{tableInfo.name}> queryAll();

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param  $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    List<$!{tableInfo.name}> queryAll($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));

    /**
     * description : 修改数据,哪个属性不为空就修改哪个属性
     *
     * @param  $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    boolean update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}));
}

serviceImpl.java

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "ServiceImpl"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/service/impl"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;

import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao;
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

 /**
  * description : $!{tableInfo.comment}($!{tableInfo.name})表服务实现类
  *
  * @author $!author
  * @since  $!time.currTime()
  **/
@Service("$!tool.firstLowerCase($!{tableInfo.name})Service")
public class $!{tableName} implements $!{tableInfo.name}Service {

    @Autowired
    protected $!{tableInfo.name}Dao $!tool.firstLowerCase($!{tableInfo.name})Dao;

    /**
     * description : 添加$!{tableInfo.name}
     *
     * @param  $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public boolean insert($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.insert($!tool.firstLowerCase($!{tableInfo.name})) == 1;
    }

    /**
     * description : 删除$!{tableInfo.name}
     *
     * @param  $!pk.name 主键
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public boolean deleteById($!pk.shortType $!pk.name) {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.deleteById($!pk.name) == 1;
    }

    /**
     * description : 查询单条数据
     *
     * @param  $!pk.name 主键
     * @return 实例对象
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public $!{tableInfo.name} queryById($!pk.shortType $!pk.name) {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryById($!pk.name);
    }

    /**
     * description : 查询全部数据(分页使用MyBatis的插件实现)
     *
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public List<$!{tableInfo.name}> queryAll() {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryAll();
    }

    /**
     * description : 实体作为筛选条件查询数据
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 对象列表
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public List<$!{tableInfo.name}> queryAll($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.queryAll($!tool.firstLowerCase($!{tableInfo.name}));
    }

    /**
     * description : 修改数据,哪个属性不为空就修改哪个属性
     *
     * @param $!tool.firstLowerCase($!{tableInfo.name}) 实例对象
     * @return 是否成功
     * @author $!author
     * @since  $!time.currTime()
     */
    @Override
    public boolean update($!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name})) {
        return $!{tool.firstLowerCase($!{tableInfo.name})}Dao.update($!tool.firstLowerCase($!{tableInfo.name})) == 1;
    }
}

controller.java

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Controller"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))
##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;

import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name};
import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * description : $!{tableInfo.comment}($!{tableInfo.name})表控制层
 *
 * @author $!author
 * @since  $!time.currTime()
 */
@RestController
@RequestMapping("$!tool.firstLowerCase($tableInfo.name)")
public class $!{tableName} {
    /**
     * 服务对象
     */
    @Resource
    private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;

    /**
     * description : 通过主键查询单条数据
     *
     * @param  id 主键
     * @return 单条数据
     * @author $!author
     * @since  $!time.currTime()
     */
    @GetMapping("selectOne")
    public $!{tableInfo.name} selectOne($!pk.shortType id) {
        return this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id);
    }
}

mapper.xml

##引入mybatis支持
$!mybatisSupport

##设置保存名称与保存位置
$!callback.setFileName($tool.append($!{tableInfo.name}, "Dao.xml"))
$!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mybatis/mapper"))

##拿到主键
#if(!$tableInfo.pkColumn.isEmpty())
    #set($pk = $tableInfo.pkColumn.get(0))
#end

<?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="$!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao">

    <!--$!{tableInfo.obj.name}的映射结果集-->
    <resultMap type="$!{tableInfo.savePackageName}.entity.$!{tableInfo.name}" id="$!{tableInfo.name}Map">
#foreach($column in $tableInfo.fullColumn)
        <result property="$!column.name" column="$!column.obj.name" jdbcType="$!column.ext.jdbcType"/>
#end
    </resultMap>

    <!--全部字段-->
    <sql id="allColumn"> #allSqlColumn() </sql>

    <!--添加语句的字段列表-->
    <sql id="insertColumn">
#foreach($column in $tableInfo.otherColumn)
        <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
            $!column.obj.name,
        </if>
#end
    </sql>

    <!--添加语句的值列表-->
    <sql id="insertValue">
#foreach($column in $tableInfo.otherColumn)
        <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
            #{$!column.name},
        </if>
#end
    </sql>

    <!--通用对$!{tableInfo.name}各个属性的值的非空判断-->
    <sql id="commonsValue">
#foreach($column in $tableInfo.otherColumn)
        <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end">
            $!column.obj.name = #{$!column.name},
        </if>
#end
    </sql>

    <!--新增$!{tableInfo.obj.name}:哪个字段不为空就添加哪列数据,返回自增主键-->
    <insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true">
        insert into $!{tableInfo.obj.name}
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <include refid="insertColumn"/>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <include refid="insertValue"/>
        </trim>
    </insert>

    <!--删除$!{tableInfo.obj.name}:通过主键-->
    <delete id="deleteById">
        delete from $!{tableInfo.obj.name}
        <where>
            $!pk.obj.name = #{$!pk.name}
        </where>
    </delete>

    <!--查询单个$!{tableInfo.obj.name}-->
    <select id="queryById" resultMap="$!{tableInfo.name}Map">
        select
        <include refid="allColumn"></include>
        from $!tableInfo.obj.name
        <where>
            $!pk.obj.name = #{$!pk.name}
        </where>
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="$!{tableInfo.name}Map">
        select
        <include refid="allColumn"></include>
        from $!tableInfo.obj.name
        <trim prefix="where" prefixOverrides="and" suffixOverrides=",">
            <include refid="commonsValue"></include>
        </trim>
    </select>

    <!--通过主键修改数据-->
    <update id="update">
        update $!{tableInfo.obj.name}
        <set>
            <include refid="commonsValue"></include>
        </set>
        <where>
            $!pk.obj.name = #{$!pk.name}
        </where>
    </update>
</mapper>

新创建一个分组Lombok,可以在生成实体类的时候使用Lombok注解

,

实体类层:entity.java

##引入宏定义
$!define

##使用宏定义设置回调(保存位置与文件后缀)
#save("/entity", ".java")

##使用宏定义设置包后缀
#setPackageSuffix("entity")

##使用全局变量实现默认包导入
$!autoImport
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

##使用宏定义实现类注释信息
#tableComment("实体类")
@AllArgsConstructor
@Data
@Builder
public class $!{tableInfo.name} implements Serializable {
    private static final long serialVersionUID = $!tool.serial();
#foreach($column in $tableInfo.fullColumn)
    #if(${column.comment})/**
    * ${column.comment}
    */#end

    private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end
}

多个分组的切换

选择好分组后,点击OK,之后在Datebase视图的数据表右键选择EasyCode生成的时候会让你选择当前分组的模板

,

,

,

.

posted @ 2020-07-04 23:42  对弈  阅读(4204)  评论(2编辑  收藏  举报