MyBatis-Plus(2.0)

news2025/6/21 14:40:00

ActiveRecord

ActiveRecord(简称AR)一直广受动态语言(PHP、Ruby等)的喜爱,而java作为准静态语言,对于ActiveRecord往往只能感叹器优雅

什么是ActiveRecord?

ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的实现模型的操作,而且简洁易懂

ActiveRecord的主要思想是:

  • 每一个数据库表对应创建一个类,类的每个对象实例对应于数据库表的一行记录;通常表的每个字段在类中都有相应的Field
  • ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CRUD
  • ActiveRecord是一种领域模型(Domain Model),封装了部分业务配置

快速使用

在MP中,开启AR非常简单,只需要将实体对象继承Model即可

注意:先将数据库的tb_user表改为user

将实体对象继承Model

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User extends Model<User> {

    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;

}
根据主键查询
    @Test
    public void testAR() {
        User user = new User();
        user.setId(2L);
        User user1 = user.selectById();
        System.out.println(user1);
    }

效果:

img

新增数据
    @Test
    public void testAR2() {
        User user = new User();
        user.setUserName("liubei");
        user.setAge(30);
        user.setName("刘备");
        user.setPassword("123456");
        user.setEmail("liubei@dc.cn");
        boolean insert = user.insert();
        System.out.println(insert);
    }

效果:

img

更新操作
    @Test
    public void testAR3() {
        User user = new User();
        user.setId(8L);
        user.setAge(35);

        boolean b = user.updateById();
        System.out.println(b);
    }

效果:

img

删除操作
    @Test
    public void testAR4() {
        User user = new User();
        user.setId(7L);
        boolean b = user.deleteById();
        System.out.println(b);
    }

效果:

img

根据条件查询
    @Test
    public void testAR5() {
        User user = new User();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.le("age", 24);

        List<User> users = user.selectList(wrapper);
        for (User user1 : users) {
            System.out.println(user1);
        }
    }

效果:

img

插件

mybatis的插件机制

MyBatis允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括:

  1. Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  2. ParameterHandler(getParameterObject, setParameters)
  3. ResultSetHandler(handlerResultSets, handleOutputParameters)
  4. StatmentHandler(prepare, parameterize, batchm, update, query)

总体概括为:

  1. 拦截执行器的方法
  2. 拦截参数的处理
  3. 拦截结果集的处理
  4. 拦截sql语法构建的处理

拦截器示例:

@Intercepts({
        @Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class}
    )
})
public class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截方法,具体业务逻辑编写的位置
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        // 创建target对象的代理对象,目的是将当前拦截器加入到该对象中
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 属性配置
    }
}

拦截器配置

@Configuration
@MapperScan("com.dc.mapper")
public class MybatisPlusConfig {

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

    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }
}

或者通过xml配置,MyBatis-config.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<plugins>
		<plugin interceptor="cn.itcast.mp.plugins.MyInterceptor"></plugin>
	</plugins>
</configuration>

执行分析插件

在MP中提供了对SQL执行的分页的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境

SpringBoot配置:

@Bean
    public SqlExplainInterceptor sqlExplainInterceptor() {
        SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
        ArrayList<ISqlParser> iSqlParsers = new ArrayList<>();
        iSqlParsers.add(new BlockAttackSqlParser());
        sqlExplainInterceptor.setSqlParserList(iSqlParsers);

        return sqlExplainInterceptor;

    }

结果:

org.apache.ibatis.exceptions.PersistenceException: 
### Error opening session.  Cause: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
### Cause: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)

	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(DefaultSqlSessionFactory.java:100)
	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSession(DefaultSqlSessionFactory.java:57)
	at org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:98)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:428)
	at com.sun.proxy.$Proxy58.update(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:294)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:63)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:62)
	at com.sun.proxy.$Proxy64.update(Unknown Source)
	at com.dc.UserMapperTest.testInterceptor(UserMapperTest.java:296)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
	at org.apache.ibatis.plugin.Plugin.getSignatureMap(Plugin.java:83)
	at org.apache.ibatis.plugin.Plugin.wrap(Plugin.java:44)
	at com.dc.interceptor.MyInterceptor.plugin(MyInterceptor.java:31)
	at org.apache.ibatis.plugin.InterceptorChain.pluginAll(InterceptorChain.java:31)
	at com.baomidou.mybatisplus.core.MybatisConfiguration.newExecutor(MybatisConfiguration.java:168)
	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(DefaultSqlSessionFactory.java:96)
	... 41 more
Caused by: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
	at java.lang.Class.getMethod(Class.java:1786)
	at org.apache.ibatis.plugin.Plugin.getSignatureMap(Plugin.java:80)
	... 46 more

性能分析插件

性能分析拦截器,用于输出每条sql语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。

该插件只用于开发环境,不建议生产环境使用

配置:

    <plugins>
        <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
            <property name="maxTime" value="100"/>
            <property name="format" value="true"/>
        </plugin>
    </plugins>

结果:

img

可以看到执行时间为22ms,如果将maxTime设置为1,该操作会直接报错

乐观锁插件

主要使用场景

意图:

当要更新的时候,希望这条记录没有被别人更新

乐观锁实现方式:

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

插件配置

config.xml:

<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>

SpringBoot:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
	return new OptimisticLockerInterceptor();
}

注解实体字段

需要为实体字段添加@Version注解

第一步,为表添加version字段,并且设置初始值为1

ALTER TABLE 'user'
	ADD COLUMN 'version' int(10) NULL AFTER 'email';
UPDATE 'user' SET 'version' = '1';

第二步,为User实体对象添加version字段,并且添加@Version注解:

@Version
private Integer version;

测试用例:

    @Test
    public void testUpdate() {
        User user = new User();
        user.setAge(30);
        user.setId(2L);
        // 获取到version为1
        user.setVersion(1);

        int i = this.userMapper.updateById(user);
        System.out.println("result = " + i);
    }

执行日志:

img

可以看到,更新的条件中有version条件,并且更新的version为2

如果再次执行,更新则不成功,这样就避免了多人同时更新时导致数据的不一致

特别说明

  • 支持的数据类型只有:int,Integer,long,Date, LocalDateTime
  • 整数类型下newVersion = oldVersion + 1
  • newVersion 会回写到entity中
  • 仅支持updateById(id)与update(entity, wrapper)方法
  • 在update(entity, wrapper)方法下,wrapper不能复用!!!

sql注入器

在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到MyBatis容器,这样这些方法才可以正常执行

那如果需要扩展BaseMapper中的方法,又该如何实现?

编写MyBatisMapper

package cn.itcast.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface MyBaseMapper<T> extends BaseMapper<T> {
	List<T> findAll();
}

其他的Mapper都可以继承该Mapper,这样实现了统一的扩展

package cn.itcast.mp.mapper;
import cn.itcast.mp.pojo.User;
public interface UserMapper extends MyBaseMapper<User> {
	User findById(Long id);
       List<User> findAll();
}

编写MySqlInjector

如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以选择继承DefaultSqlInjector进行扩展

public class MySqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList() {
        List<AbstractMethod> methodList = super.getMethodList();
        methodList.add(new FindAll());
        return methodList;
    }
}

编写FindAll

public class FindAll extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sqlMethod = "findAll";
        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
    }
}

注册到Spring容器中

spring.xml:

<bean class="com.dc.injector.MySqlInjector"/>

SpringBoot:

/**
* 自定义SQL注入器
*/
@Bean
public MySqlInjector mySqlInjector(){
	return new MySqlInjector();
}

测试:

    @Test
    public void testFindAll() {
        List<User> all = userMapper.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }

结果

img

自动填充功能

有些时候可能会有这样的需求,插入或者更新数据的时候,希望有些字段可以自动填充数据,比如密码,version等。在MP中提供了这样的功能,可以实现自动填充

添加@TableField注解

@TableField(fill = FieldFill.INSERT) // 插入数据时进行填充
private String password;

为password添加自动填充功能,在新增数据时有效

FiledFill提供了多种模式选择:

public enum FieldFill {
    /**
    * 默认不处理
    */
    DEFAULT,
    /**
    * 插入时填充字段
    */
    INSERT,
    /**
    * 更新时填充字段
    */
    UPDATE,
    /**
    * 插入和更新时填充字段
    */
    INSERT_UPDATE
}

编写MyMetaObjectHandler

首先,在User实体类中添加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("tb_user")
public class User extends Model<User> {

    private Long id;
    private String userName;
    @TableField(select = false, fill = FieldFill.INSERT)
    private String password;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Integer version;

}

然后编写MyMetaObjectHandler类

public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        Object password = getFieldValByName("password", metaObject);
        if (password == null) {
            // 字段为空,进行填充
            setFieldValByName("password", "88888888", metaObject);
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {

    }
}

spring:最后需要在applicationContext.xml配置文件中配置插件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置所有properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--定义数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="10"/>
        <property name="minIdle" value="5"/>
    </bean>
    <context:component-scan base-package="com.dc.injector"/>
    <!--MP提供的SqlSessionFactory,完成了Spring与MP的整合-->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.dc.domain"/>
        <property name="plugins">
            <array>
                <!--分页插件-->
                <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"/>
                <!--乐观锁插件-->
                <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
            </array>
        </property>
        <!--全局配置-->
        <property name="globalConfig" ref="globalConfig"/>
    </bean>

    <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
        <property name="metaObjectHandler" ref="myMetaObjectHandler"/>
    </bean>

    <bean class="com.dc.injector.MyMetaObjectHandler" id="myMetaObjectHandler"/>

    <bean class="com.dc.injector.MySqlInjector"/>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dc.mapper"/>
    </bean>
    <beans default-autowire="byType"/>

</beans>

SpringBoot:在MyMetaObjectHandler类上添加@Component注解

测试:

@Test
    public void testInsertFill() {
        User user = new User();
        user.setName("关羽");
        user.setUserName("guanyu");
        user.setAge(30);
        user.setEmail("guanyu@dc.cn");
        user.setVersion(1);

        int insert = userMapper.insert(user);
        System.out.println("result = " + insert);
    }

效果:

img

img

逻辑删除

开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。

修改表的结构

为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除

alter table tb_user add COLUMN deleted int(1) null DEFAULT 0 comment '1代表删除,0代表未删除' after version;

同时,也修改User实体,增加deleted属性并且添加@TableLogic注解

@TableLogic
private Integer deleted;

配置

SpringBoot:

# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0

测试

@Test
public void testDeleteById(){
	this.userMapper.deleteById(2L);
}

结果:

img

测试查询:

@Test
public void testSelectById(){
	User user = this.userMapper.selectById(2L);
	System.out.println(user);
}

结果:

img

通用枚举

解决了繁琐的配置,让mybatis优雅的使用枚举属性

修改表结构

ALTER TABLE tb_user
ADD COLUMN sex int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER deleted;

定义枚举

public enum SexEnum implements IEnum<Integer> {

    MAN(1, "男"),
    WOMAN(2, "女");
    private int value;
    private String desc;

    SexEnum(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

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

    @Override
    public String toString() {
        return this.desc;
    }
}

配置:

# 枚举包扫描
mybatis-plus.type-enums-package=cn.itcast.mp.enums

修改实体

private SexEnum sex;

测试:

@Test
public void testInsert1() {
    User user = new User();
    user.setName("貂蝉");
    user.setUserName("diaochan");
    user.setAge(20);
    user.setEmail("diaochan@dc.cn");
    user.setSex(SexEnum.WOMAN);

    int insert = userMapper.insert(user);
    System.out.println(insert);
}

效果:

img

img

查询:

@Test
public void testSelect1() {
    User user = userMapper.selectById(2L);
    System.out.println(user);
}

结果:

img

代码生成器

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

创建工程

pom.xml

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybatis-plus的springboot支持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

代码:

package com.dc;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

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

/**
 * -----在希望中绽放,在苦难中坚持------
 *
 * @author 暮辰
 */
public class MySqlGenerator {

    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }
    /**
     * RUN THIS
     */
    public static void main(String[] args) {
// 代码生成器
        AutoGenerator mpg = new AutoGenerator();
// 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "\\smptest\\src\\main\\java");
        gc.setAuthor("暮辰");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);
// 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        mpg.setDataSource(dsc);
// 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.dc.mp");
        mpg.setPackageInfo(pc);
// 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
// to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("\\templates\\mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
                return projectPath + "/smptest/src/main/resources/mapper/" + pc.getModuleName()
                + "/" + tableInfo.getEntityName() + "Mapper" +
                        StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseE ntity");
        strategy.setEntityLombokModel(true);
       //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.B aseController");
        strategy.setInclude(scanner("表名"));
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

测试:

img

代码生成

img

实体类对象:

@Data
    @EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class TbUser implements Serializable {

    private static final long serialVersionUID = 1L;

            /**
            * 用户名
            */
    private String userName;

            /**
            * 密码
            */
    private String password;

            /**
            * 姓名
            */
    private String name;

            /**
            * 年龄
            */
    private Integer age;

            /**
            * 邮箱
            */
    private String email;

    private Integer version;

            /**
            * 1代表删除,0代表未删除
            */
    private Integer deleted;

            /**
            * 1-男,2-女
            */
    private Integer sex;
}

MyBatisX快速开发插件

MyBatisX是一款基于IDEA的快速开发插件,为效率而生。

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。

功能:

  • Java 与 XML 调回跳转
  • Mapper 方法自动生成 XML

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/631744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频|人人能看懂的苹果visionOS空间设计课程

本周的重磅消息无疑是苹果Vision Pro以及对应的visionOS&#xff0c;考虑到苹果头显硬件上当前以第一方App为主&#xff0c;因此本届WWDC的一个重点就是释放visionOS和相关能力给开发者&#xff0c;让开发者尽快打造出更多、更优质的第三方App阵容。 与此同时&#xff0c;苹果也…

【vue3】10-vue组件化额外知识补充(下)-动态组件-组件缓存-v-model在组件上的应用

组件化-额外知识补充&#xff08;下&#xff09; 动态组件的使用(了解)keep-alive&#xff08;理解&#xff09;认识keep-alivekeep-alive的使用 异步组件的使用webpack分包处理&#xff08;了解&#xff09;Vue中实现异步组件 组件的v-model组件的混入Mixin&#xff08;了解&a…

阿里云弹性公网EIP收费价格表(按量/包年包月/配置费)

阿里云弹性公网EIP怎么收费&#xff1f;EIP地域不同价格不同&#xff0c;EIP计费模式分为包年包月和按量付费&#xff0c;弹性公网IP可以按带宽收费也可以按使用流量收费&#xff0c;阿里云百科分享阿里云弹性公网IP不同地域、不同计费模式、按带宽和按使用流量详细收费价格表&…

基于springboot+vue技术的在线考试系统源码数据库

源码看这里 https://download.csdn.net/download/2301_76965813/87881785 前台 学生登录&#xff1a; 如果没有账号&#xff0c;首先需要以学生的身份进行注册&#xff0c;即输入姓名、性别、密码以及班级&#xff0c;注册成功之后输入账户名和密码进行登录&#xff0c;进入…

conda虚拟环境配置和系统相关配置

一、conda虚拟环境 首先&#xff0c;尽量别在base中直接安装自己的包。原因有以下两个&#xff1a; 1.base环境是conda运行的基础&#xff0c;没法一键清除&#xff0c;如果损坏base环境要么滚回要么卸载重装&#xff0c;比较麻烦 2.base中很多包并不是项目需要的包&#xff0c…

Spring5

Spring5 文章目录 Spring5一.框架概述二.入门案例三.IOC容器1.IOC概念2.IOC底层原理3.IOC接口 四.IOC操做Bean管理1.Bean管理2.基于xml配置文件方式实现(1).创建对象(2).注入属性第一种注入:set方法第二种注入:有参数的构造p名称空间注入(了解)注入空值和特殊符号外部Bean内部B…

itop-3568开发板驱动学习笔记(27)设备树(六)pinctrl

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录 pinctrl 子系统简介pinctrl 设备树语法pinctrl 客户端pinctrl 服务端瑞星微平台全志平台三星平台iMX 平台 pinctrl 子系统简介 Linux pinctrl 子系统用来管理 GPIO 引脚&#xff0c;它主要完成了以下三种功…

MySQL数据库,从入门到精通:第三篇——MySQL 数据库规范和基础查询语句

MySQL数据库&#xff0c;从入门到精通&#xff1a;第三篇——MySQL 数据库规范和基础查询语句 第三篇_MySQL 数据库规范和基础查询语句1. SQL概述1.1 SQL背景知识1.2 SQL语言排行榜1.3 SQL 分类 2. SQL语言的规则与规范2.2 SQL大小写规范 &#xff08;建议遵守&#xff09;2.3 …

设计模式-03.02-创建型-工厂建造者原型

工厂模式【常用】 工厂模式很重要&#xff0c;后面的很多架构设计&#xff0c;都是工厂模式联合着其它设计模式使用。 一般情况下&#xff0c;工厂模式分为三种更加细分的类型&#xff1a;简单工厂、工厂方法和抽象工厂。不过&#xff0c;在 GoF 的《设计模式》一书中&#xff…

docker资源控制cgroup

一、CPU控制 cgroups&#xff0c;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace隔离起来的资源, 还可以为资源设置权重、计算使用量、操控进程启停等等。所以cgroups (Control groups) 实现了对资源的配额和度量。 cgroups有四大功能: 资源限制:可以…

SpringAOP详解

目录 前言&#xff1a; 相关概念 切点表达式规则 代码演示 SpringAOP实现原理 织入&#xff08;代理的生成时机&#xff09; JDK和CGLIB区别 小结&#xff1a; 前言&#xff1a; AOP&#xff08;Aspect Oriented Programming&#xff09;是思想&#xff08;面向切面编程…

文心一言 VS 讯飞星火 VS chatgpt (37)-- 算法导论5.4 1题

一、一个屋子里必须要有多少人&#xff0c;才能让某人和你生日相同的概率至少为1/2? 必须要有多少人&#xff0c;才能让至少两个人生日为 7月 4 日的概率大于 1/2? 文心一言&#xff1a; 一个屋子里必须要有多少人&#xff0c;才能让某人和你生日相同的概率至少为1/2&#…

Linux下ElasticSearch7.9.2安装配置(包含服务器配置、启动停止脚本、开放端口和elasticsearch-head插件的使用)

Linux下ElasticSearch7.9.2安装配置 前言1.下载安装1.1 使用wget的方式下载1.2 官网下载 2.上传到服务器并解压3.修改es配置文件3.1 es目录简介3.2 修改配置文件 4. 创建用户并赋权5. 服务器修改配置5.1 修改文件句柄数和线程数5.2 关闭swapping5.3 修改虚拟内存 6. 启动es6.1 …

“配置DHCP Snooping实验:保护网络中的DHCP服务和防止欺骗攻击“

"配置DHCP Snooping实验&#xff1a;保护网络中的DHCP服务和防止欺骗攻击" 【实验目的】 部署DHCP服务器。熟悉DHCP Snooping的配置方法。验证拓扑。 【实验拓扑】 实验拓扑如图所示。 设备参数如下表所示。 设备 接口 IP地址 子网掩码 默认网关 R1 F0/0 …

腾讯云轻量应用服务器和云服务器区别详细说明

腾讯云轻量应用服务器是什么&#xff1f;腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器费用更低&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程…

基于SPAD / SiPM技术的激光雷达方案

激光雷达(LiDAR)是一种测距技术&#xff0c;近年来越来越多地用于汽车先进驾驶辅助系统(ADAS)、手势识别和3D映射等应用。尤其在汽车领域&#xff0c;随着传感器融合的趋势&#xff0c;LiDAR结合成像、超声波、毫米波雷达&#xff0c;互为补足&#xff0c;为汽车提供全方位感知…

物联网Lora模块从入门到精通(五)光照与温湿度传感器

一、前言 在程序开发中&#xff0c;光照与温湿度的获取是十分常见与重要的&#xff0c;本文我们主要是使用M21温湿度光照三合一传感器&#xff0c;其中温湿度数据通过协议获取&#xff0c;而光照通过ADC获取。 二、代码实现 本文内容较为简单&#xff0c;且后续文章将在本文基…

网络编程Demo:Java的阻塞与非阻塞模式以及Netty

前言 IO既神秘&#xff0c;双简单 IO是什么 从表面理解&#xff0c;IO是输入&#xff08;input&#xff09;、输出(output)的英文首字母的缩写形式&#xff0c;可以简单理解为计算机的输入与输出&#xff0c;描述计算机的数据流动&#xff0c;如使用键盘输入了一个“hello w…

GreenPlum版本升级

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

C语言期末课程设计—【通讯录管理系统】让课程设计不再是痛苦

目录 摘要 第一章 绪论 1.1项目意义 1.2通讯录功能 第二章 详细设计与实现 2.1 Contact程序运行流程图 2.2 AddContact&#xff08;增加&#xff09;函数流程图 2.3 DelContact&#xff08;删除&#xff09;函数流程图 2.4 SearchConact&#xff08;查找&#xff09;…