下面采用的是 SpringBoot 框架:
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
在 application.yml 配置文件中添加 MySQL 数据库的相关配置:
spring:
datasource:
username: root
password: 123456?
url: jdbc:mysql://mybatis_plus?userUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
在 spring boot 启动类中添加 @MapperScan 注解,扫描Mapper文件夹:
@SpringBootApplication
@MapperScan("com.wen.mybatis_plus.mapper") //扫描mapper
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
在对应的 mapper 上面添加 @Mapper 注解,并继承 BaseMapper<> 类:
@Mapper
public interface UserMapper extends BaseMapper<User> {
//所有的CRUD都已经完成
//不需要像以前一样配置一大堆文件:pojo-dao(连接mybatis,配置mapper.xml文件)==>service-controller
}
所有的SQL都是不可见的,所以在后台是希望看到SQL是怎么执行的,就必须要配置日志。
在.yml配置文件中配置日志:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
编写测试类:
@SpringBootTest
class MybatisPlusApplicationTests {
//继承了BaseMapper所有的方法,可以编写自己的扩展方法
@Autowired
private UserMapper userMapper;
@Test
public void testSelect(){
//查询全部用户,参数是一个Wrapper,条件构造器,先不使用为null
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
在常用业务中有些属性需要配置一些默认值,MyBatis-Plus 提供了实现此功能的插件,也就是自动填充功能。
比如创建时间、修改时间这些操作一般都是自动化完成的,是不用去手动更新的。
@TableField(fill = FieldFill.INSERT)
private Data createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Data updateTime;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start intsert fill ....");
//strictInsertFill(MetaObject metaObject, String fieldName, Class fieldType, E fieldVal)
this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());// 起始版本 3.3.0(推荐使用)
}
//更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
}
}
1.全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
1.趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
1.单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。
1.信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,甚至可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。
上述 1 2 3 对应三类不同的场景,3和4需求还是互斥的,无法使用同一个方案满足。
@Data
public class User {
//对应数据库中的主键(UUID、自增id、雪花算法、redis、zookeeper)
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
}
selectById()
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
selectBatchIds 方法,方法内放入的是集合,可以通过源码看
public void selectBatchIds(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
public void selectByMap(){
HashMap<String,Object> map = new HashMap<>();
//自定义查询
map.put("name","小文");
map.put("age",20);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
overflow | boolean | false | 溢出总页数后是否进行处理(默认不处理) |
maxLimit | Long | 单页分页条数限制(默认无限制) | |
dbType | DbType | 数据库类型(根据类型获取应使用的分页方言) | |
dialect | IDialect | 方言实现类 |
建议单一数据库类型的均设置 dbType
配置拦截器组件:
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
// 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认false
pageInterceptor.setOverflow(false);
// 单页分页条数限制,默认无限制
pageInterceptor.setMaxLimit(500L);
// 设置数据库类型
pageInterceptor.setDbType(DbType.MYSQL);
interceptor.addInnerInterceptor(pageInterceptor);
return interceptor;
}
分页组件测试:
public void testMybatisPlus_Page(){
// 两个参数:current的值默认是1,从1开始,不是0。size是每一页的条数。
Page<User> page = new Page<>(1, 4);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
public void testUpdate(){
User user = new User();
//可以通过条件自动拼接动态SQL
user.setId(5L);
user.setName("id:5,修改过后");
//updateById 参数是一个对象!
int i = userMapper.updateById(user);
System.out.println(i);
}
public void testDeleteById(){
userMapper.deleteById(4L);
}
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(1L,2L));
}
public void testdeleteByMap(){
Map<String, Object> map = new HashMap<>();
map.put("name","xiaotian");
userMapper.deleteByMap(map);
}
@TableLogic //逻辑删除
private Integer deleted;
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
public void testDeleteById(){
userMapper.deleteById(4L);
}
public void testSelectById(){
User user = userMapper.selectById(4L);
System.out.println(user);
}
查看日志输出可以看到,seletc的语句以经发生了更改
增加了deleted的判断语句,判断deleted是否为1,为1则能搜索,0则不能
Wrapper,可以通过其构造复杂的SQL
void WrapperTest(){
//查询name、邮箱不为空且年龄大于等于20的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}
void WrapperTest2(){
//查询姓名为小文的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","小文"); //equals
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
void WrapperTest3(){
//查询年龄在19-23之间的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 19, 23);
Long count = userMapper.selectCount(wrapper);//查询结果数
System.out.println(count);
}
void WrapperTest6(){
//通过ID进行排序
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("id"); //通过id升序
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
void WrapperTest4(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notLike("name","a") //查询姓名中不包含a的用户
.likeRight("email","t"); //左和右是代表%的位置 两边都要匹配则为%e%,这里是email以t开头的 t%
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
void WrapperTest5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from user where id < 4");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
可输出 SQL 语句以及其执行时间,建议开发测试时启⽤该功能,能快速揪出 慢查询。
注意:PerformanceInterceptor在3.2.0被移除了,如果想进⾏性能分析,⽤第三⽅的,官⽅这样写的“该插件 3.2.0 以上版本移除 推荐使⽤第三⽅扩展 执⾏SQL分析打印 功能”。也就是 p6spy。
<dependency>
<groupId>p6spygroupId>
<artifactId>p6spyartifactId>
<version>最新版本version>
dependency>
spring:
datasource:
username: root
password: 123456
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://mybatis_plus
# 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
public void testMybatisPlus_Page(){
// 两个参数:current的值默认是1,从1开始,不是0。size是每一页的条数。
Page<User> page = new Page<>(2, 4);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
@Version //乐观锁version注解
private Integer version;
<bean class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor" id="optimisticLockerInnerInterceptor"/>
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
<property name="interceptors">
<list>
<ref bean="optimisticLockerInnerInterceptor"/>
list>
property>
bean>
@Configuration //配置类
@MapperScan("com.wen.mybatis_plus.mapper") //扫描mapper
@EnableTransactionManagement
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
测试更新失败的情况:
void testOptimisticLocker_failure() {
//模拟多线程实现插队效果
//线程1
User user = userMapper.selectById(1l);
user.setName("tian");
user.setAge(21);
//线程2
User user2 = userMapper.selectById(1l);
user2.setName("xiaotian");
user2.setAge(19);
userMapper.updateById(user2); //在这里插队
// 乐观锁时,更新会失败
userMapper.updateById(user); //如果没有乐观锁就会覆盖插队线程的值
}
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.27version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatisplus-spring-boot-starterartifactId>
<version>1.0.5version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plusartifactId>
<version>3.4.3.4version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>2.3version>
dependency>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
password: 123456
username: root
url: jdbc:mysql://localhost:3306?test_user&useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
server:
port: 8086
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.Collections;
public class CodeGeneration {
public static void main(String[] args) {
MySqlQuery mySqlQuery = new MySqlQuery() {
@Override
public String[] fieldCustom() {
return new String[]{"Default"};
}
};
DataSourceConfig dsc = new DataSourceConfig.Builder("jdbc:mysql://localhost:3306/flowerpotnet?&useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai","root","123456")
.dbQuery(mySqlQuery).build();
//通过datasourceConfig创建AutoGenerator
AutoGenerator generator = new AutoGenerator(dsc);
/**
* 全局配置
*/
String projectPath = System.getProperty("user.dir"); //获取项目路径
String filePath = projectPath + "/src/main/java"; //java下的文件路径
GlobalConfig global = new GlobalConfig.Builder()
.outputDir(filePath)//生成的输出路径
.author("young")//生成的作者名字
//.enableSwagger()开启swagger,需要添加swagger依赖并配置
.dateType(DateType.TIME_PACK)//时间策略
.commentDate("yyyy-MM-dd")//格式化时间格式
.disableOpenDir()//禁止打开输出目录,默认false
.fileOverride()//覆盖生成文件
.build();
/**
* 包配置
*/
PackageConfig packages = new PackageConfig.Builder()
.entity("entity")//实体类包名
.parent("com.yy")//父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名
.controller("controller")//控制层包名
.mapper("dao")//mapper层包名
.xml("mapper.xml")//数据访问层xml包名
.service("service")//service层包名
.serviceImpl("service.impl")//service实现类包名
.other("output")//输出自定义文件时的包名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper")) //路径配置信息,就是配置各个文件模板的路径信息,这里以mapper.xml为例
.build();
/**
* 模板配置
*/
// 如果模板引擎是 freemarker
// String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
TemplateConfig template = new TemplateConfig.Builder()
// .disable()//禁用所有模板
//.disable(TemplateType.ENTITY)禁用指定模板
// .service(filePath + "/service.java")//service模板路径
// .serviceImpl(filePath + "/service/impl/serviceImpl.java")//实现类模板路径
// .mapper(filePath + "/mapper.java")//mapper模板路径
// .mapperXml("/templates/mapper.xml")//xml文件模板路路径
// .controller(filePath + "/controller")//controller层模板路径
.build();
/**
* 注入配置,自定义配置一个Map对象
*/
// Map map = new HashMap<>();
// map.put("name","young");
// map.put("age","22");
// map.put("sex","男");
// map.put("description","深情不及黎治跃");
//
// InjectionConfig injectionConfig = new InjectionConfig.Builder()
// .customMap(map)
// .build();
/**
* 策略配置开始
*/
StrategyConfig strategyConfig = new StrategyConfig.Builder()
.enableCapitalMode()//开启全局大写命名
//.likeTable()模糊表匹配
.addInclude()//添加表匹配,指定要生成的数据表名,不写默认选定数据库所有表
//.disableSqlFilter()禁用sql过滤:默认(不使用该方法)true
//.enableSchema()启用schema:默认false
.entityBuilder() //实体策略配置
//.disableSerialVersionUID()禁用生成SerialVersionUID:默认true
.enableChainModel()//开启链式模型
.enableLombok()//开启lombok
.enableRemoveIsPrefix()//开启 Boolean 类型字段移除 is 前缀
.enableTableFieldAnnotation()//开启生成实体时生成字段注解
//.addTableFills()添加表字段填充
.naming(NamingStrategy.underline_to_camel)//数据表映射实体命名策略:默认下划线转驼峰underline_to_camel
.columnNaming(NamingStrategy.underline_to_camel)//表字段映射实体属性命名规则:默认null,不指定按照naming执行
.idType(IdType.AUTO)//添加全局主键类型
.formatFileName("%s")//格式化实体名称,%s取消首字母I
.build()
.mapperBuilder()//mapper文件策略
.enableMapperAnnotation()//开启mapper注解
.enableBaseResultMap()//启用xml文件中的BaseResultMap 生成
.enableBaseColumnList()//启用xml文件中的BaseColumnList
//.cache(缓存类.class)设置缓存实现类
.formatMapperFileName("%sMapper")//格式化Dao类名称
.formatXmlFileName("%sMapper")//格式化xml文件名称
.build()
.serviceBuilder()//service文件策略
.formatServiceFileName("%sService")//格式化 service 接口文件名称
.formatServiceImplFileName("%sServiceImpl")//格式化 service 接口文件名称
.build()
.controllerBuilder()//控制层策略
//.enableHyphenStyle()开启驼峰转连字符,默认:false
.enableRestStyle()//开启生成@RestController
.formatFileName("%sController")//格式化文件名称
.build();
/*至此,策略配置才算基本完成!*/
/**
* 将所有配置项整合到AutoGenerator中进行执行
*/
generator.global(global)
.template(template)
// .injection(injectionConfig)
.packageInfo(packages)
.strategy(strategyConfig)
.execute();
}
}
执行完成后即可看到我们相关的文件已经全部生成,并且注解,介绍已经基本到位。这样就能为我们的开发节省很多时间。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'deptServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zgnj.mapper.DeptMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:660) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.7.jar:5.3.7]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.7.jar:5.3.7]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771) [spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763) [spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) [spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) [spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) [spring-boot-2.4.6.jar:2.4.6]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1318) [spring-boot-2.4.6.jar:2.4.6]
at com.zgnj.PersonnelManagementApplication.main(PersonnelManagementApplication.java:10) [classes/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zgnj.mapper.DeptMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.7.jar:5.3.7]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) ~[spring-beans-5.3.7.jar:5.3.7]
... 21 common frames omitted
Process finished with exit code 1
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.liuyang.mapper.EmployeeMapper' available: expected at least 1 bean which qualifies as autowire candidate. Depend
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
建立数据库
在IDEA配置连接数据库
使用 EasyCode