Springboot 整合 mybatisplus

springboot整合mybatisplus

application.yml

这里以TDengine时序数据库为例

spring:
  datasource:
    driver-class-name: com.taosdata.jdbc.TSDBDriver
#    driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
#    url: jdbc:TAOS-RS://um.tdengine.com:6041/test?timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
    url: jdbc:TAOS://um.tdengine.com:6030/test?timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
    username: root
    password: taosdata

    hikari:
      pool-name: HikariPool
      # 最小空闲链接数
      minimum-idle: 32
      # 空闲连接存活最大时间 默认 600000(10分钟)
      idle-timeout: 0
      # 连接池最大连接数,默认 10
      maximum-pool-size: 128
      # 如果池无法成功初始化连接,则此属性控制池是否将fail fast
      initialization-fail-timeout: -1
      # 数据库连接超时时间,默认30s
      connection-timeout: 60000
      # 此属性控制池中连接的最大生命周期,值0表示无限生命周期,默认1800000即30分钟
      max-lifetime: 0
      # 连接检查 。 mysql 使用的 为 select 1  tdengine 特有语句 select server_status()
      connection-test-query: select server_status()

mybatis-plus:
  configuration:
    # 控制台打印sql
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 数据库下划线字段 与 实体中的驼峰属性映射(false,手动设置映射,推荐用 resultMap)
    # mybatis的驼峰法映射并不是严格限制的驼峰法语法,具体来说,对应“aa_bb”字段,其既可以匹配上“aaBb”属性,也可以匹配上“Aabb”属性。这一点在日常写代码时需要注意下。
    map-underscore-to-camel-case: false
  # mapper.xml所在目录
  mapper-locations: classpath:/mapper/**/*.xml

logging:
  level:
    com.taosdata.example.mybatisplusdemo.mapper: debug

maven依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <!--3.1.2 -->
    <version>3.5.1</version>
</dependency>

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

配置分页插件

MybatisPlusInterceptor

package com.yomahub.liteflow.example.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加自动分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        // 自定义配置
        return configuration -> {

        };
    }
}

配置字段自动填充

针对 createTime、updateTime、createBy、updateBy

这里指定时间为 13位时间戳 Long类型, 时区 +8

package com.yomahub.liteflow.example.config;

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;
import java.time.ZoneOffset;

/**
 * @description 配置 字段自动填充,针对 createTime、updateTime
 * @author peizhao.ma
 * @date 2022-07-13
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), Long.class); // 起始版本 3.3.3(推荐)
//        // 或者
//        this.strictInsertFill(metaObject, "createTime", Long.class, LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()); // 起始版本 3.3.0(推荐使用)

//        // 或者
//        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(), Long.class); // 起始版本 3.3.3(推荐)

        // 或者
//        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)

        // 或者
//        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }
}

自动填充注解

标注什么时候自动填充。 如 INSERT 、 UPDATE 时填充对应字段

package com.yomahub.liteflow.example.pojo.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;

public class BaseEntity {

    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;

    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Long createTime;

    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private Long updateTime;

}

配置实体

标注表对应的实体

复合组件无法使用@TableId标注。 主键id默认使用雪花id

package com.yomahub.liteflow.example.pojo.entity;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;

@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("rule_node")
public class RuleNode extends BaseEntity{

    @TableId
    private Long id;

    @TableField("node_uid")
    private String nodeUid;

    @TableField("node_name")
    private String nodeName;

    @TableField("node_type")
    private Byte nodeType;

    @TableField("script")
    private String script;

    @TableField("script_type")
    private Byte scriptType;

    @TableField("clazz")
    private String clazz;

    @TableField("script_file_address")
    private String scriptFileAddress;

    @TableField("service_uid")
    private String serviceUid;
}

配置mapper

继承BaseMapper

package com.yomahub.liteflow.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yomahub.liteflow.example.pojo.entity.RuleNode;

public interface RuleNodeMapper extends BaseMapper<RuleNode> {
}

配置service

继承IService接口

package com.yomahub.liteflow.example.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yomahub.liteflow.example.pojo.dto.NodeAddDTO;
import com.yomahub.liteflow.example.pojo.dto.NodeQueryDTO;
import com.yomahub.liteflow.example.pojo.dto.NodeUpdateDTO;
import com.yomahub.liteflow.example.pojo.entity.RuleNode;
import com.yomahub.liteflow.example.pojo.vo.PageVO;

import java.util.List;

public interface RuleNodeService extends IService<RuleNode>{


    boolean save(NodeAddDTO dto);

    PageVO<RuleNode> pageNode(NodeQueryDTO dto);

    boolean update(NodeUpdateDTO dto);

    boolean deleteById(Long nodeId);

    boolean deleteBatchByIds(List<Long> ids);
}

继承IService实现类 ServiceImpl<RuleNodeMapper, RuleNode>

package com.yomahub.liteflow.example.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yomahub.liteflow.example.config.LiteServiceConfig;
import com.yomahub.liteflow.example.exception.ServiceException;
import com.yomahub.liteflow.example.mapper.RuleNodeChainMapper;
import com.yomahub.liteflow.example.pojo.dto.NodeAddDTO;
import com.yomahub.liteflow.example.pojo.dto.NodeQueryDTO;
import com.yomahub.liteflow.example.pojo.dto.NodeUpdateDTO;
import com.yomahub.liteflow.example.pojo.entity.RuleNode;
import com.yomahub.liteflow.example.mapper.RuleNodeMapper;
import com.yomahub.liteflow.example.pojo.entity.RuleNodeChain;
import com.yomahub.liteflow.example.pojo.vo.PageVO;
import com.yomahub.liteflow.example.service.RuleNodeService;
import com.yomahub.liteflow.example.service.ScriptService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class RuleNodeServiceImpl extends ServiceImpl<RuleNodeMapper, RuleNode> implements RuleNodeService {

    @Resource
    private LiteServiceConfig LiteServiceConfig;

    @Resource
    private RuleNodeChainMapper ruleNodeChainMapper;

    @Resource
    private ScriptService scriptService;

    @Transactional
    @Override
    public boolean save(NodeAddDTO dto) {
        RuleNodeMapper ruleNodeMapper = this.getBaseMapper();

        // 检查是否存在该规则节点名称
        String nodeName = dto.getNodeName();
        LambdaQueryWrapper<RuleNode> wrapper = new QueryWrapper<RuleNode>().lambda()
                .eq(!ObjectUtils.isEmpty(dto.getNodeUid()), RuleNode::getNodeUid, dto.getNodeUid())
                .or()
                .eq(RuleNode::getNodeName, nodeName);
        RuleNode node = ruleNodeMapper.selectOne(wrapper);

        if(!ObjectUtils.isEmpty(node)){
            throw new ServiceException("node name 已经存在");
        }

        RuleNode saveNode = BeanUtil.copyProperties(dto, RuleNode.class);
        // node节点需要以字母开头,且名字中不能包含中划线-,因为-是EL中的减号,才能通过脚本编译,如 node13078cabb0ed4ff89729aeb12492fcf1
        saveNode.setNodeUid("node" + UUID.randomUUID().toString().replace("-", ""));
        saveNode.setServiceUid(LiteServiceConfig.getServiceUid());
        int rows = ruleNodeMapper.insert(saveNode);
        if(rows > 0){
            scriptService.loadNodesAndChains();
        }
        return rows > 0;
    }

    @Override
    public PageVO<RuleNode> pageNode(NodeQueryDTO dto) {

        RuleNodeMapper ruleNodeMapper = this.getBaseMapper();
        IPage<RuleNode> page = new PageDTO<>(dto.getPageNum(), dto.getPageSize());

        LambdaQueryWrapper<RuleNode> wrapper = new QueryWrapper<RuleNode>().lambda()
                .eq(!ObjectUtils.isEmpty(dto.getNodeName()), RuleNode::getNodeName, dto.getNodeName())
                .eq(!ObjectUtils.isEmpty(dto.getNodeType()), RuleNode::getNodeType, dto.getNodeType())
                .eq(!ObjectUtils.isEmpty(dto.getNodeUid()), RuleNode::getNodeUid, dto.getNodeUid());

        IPage<RuleNode> pageResult = ruleNodeMapper.selectPage(page, wrapper);

        return new PageVO<>(pageResult.getTotal(), pageResult.getRecords());
    }

    @Transactional
    @Override
    public boolean update(NodeUpdateDTO dto) {

        RuleNodeMapper ruleNodeMapper = this.getBaseMapper();

        // 更新前,先检查是否存在该node
        LambdaQueryWrapper<RuleNode> wrapper = new QueryWrapper<RuleNode>().lambda()
                        .eq(RuleNode::getId, dto.getId());
        RuleNode node = ruleNodeMapper.selectOne(wrapper);

        if(ObjectUtils.isEmpty(node)){
            throw new ServiceException("当前要修改的节点:<" + dto.getNodeName() + "> 不存在");
        }

        // 存在则进行修改
        RuleNode updateNode = BeanUtil.copyProperties(dto, RuleNode.class);
        int rows = ruleNodeMapper.updateById(updateNode);
        if(rows > 0){
            scriptService.loadNodesAndChains();
        }
        return rows > 0;
    }

    @Override
    public boolean deleteById(Long nodeId) {

        // 检查节点是否被关联
        LambdaQueryWrapper<RuleNodeChain> wrapper = new QueryWrapper<RuleNodeChain>().lambda()
                .eq(RuleNodeChain::getNodeId, nodeId);
        Long relatedRows = ruleNodeChainMapper.selectCount(wrapper);
        if(relatedRows > 0){
            throw new ServiceException("节点" + nodeId + "已关联规则链,无法删除");
        }

        // 没被关联,则直接删除
        RuleNodeMapper ruleNodeMapper = this.getBaseMapper();
        int rows = ruleNodeMapper.deleteById(nodeId);
        if(rows > 0){
            scriptService.loadNodesAndChains();
        }
        return rows > 0;
    }

    @Override
    public boolean deleteBatchByIds(List<Long> ids) {

        // 检查节点是否被关联
        LambdaQueryWrapper<RuleNodeChain> wrapper = new QueryWrapper<RuleNodeChain>().lambda()
                .in(RuleNodeChain::getNodeId, ids);
        List<RuleNodeChain> list = ruleNodeChainMapper.selectList(wrapper);
        if(!ObjectUtils.isEmpty(list)){
            List<Long> relatedNode = list.stream().map(RuleNodeChain::getNodeId).distinct().collect(Collectors.toList());
            throw new ServiceException("节点" + relatedNode.toString() + "已关联规则链,无法删除");
        }

        // 没被关联,则直接删除
        RuleNodeMapper ruleNodeMapper = this.getBaseMapper();
        int rows = ruleNodeMapper.deleteBatchIds(ids);
        if(rows > 0){
            scriptService.loadNodesAndChains();
        }
        return rows > 0;
    }
}

mapper接口扫描/注入

在 启动类 上加@MapperScan注解进行mapper接口扫描

在 mapper接口 上加 @Mapper注解

@SpringBootApplication
@MapperScan("com.yomahub.liteflow.example.mapper")
public class LiteflowExampleApplication {

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

}

参考资料:

[1] 官网 https://baomidou.com/

[2] 尚硅谷2022 mybatisplus

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容