MyBatis-Pluis官网 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:图中blog具体看项目
启动类注解:
@MapperScan("com.example.blog.mapper")配置自动生成时的错误:mybatis-plus自动生成的时候报错 java.lang.NoClassDefFoundError
参考 https://blog.csdn.net/wangjinb/article/details/106488308
MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
添加代码生成器依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.3.2</version> </dependency>添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。
Velocity(***默认就是说该依赖必须添加,否则会报错 ***):
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency>Freemarker:(选择添加)
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency>Beetl:(选择添加)
<dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>3.1.8.RELEASE</version> </dependency>注意!如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。
AutoGenerator generator = new AutoGenerator(); // set freemarker engine generator.setTemplateEngine(new FreemarkerTemplateEngine()); // set beetl engine generator.setTemplateEngine(new BeetlTemplateEngine()); // set custom engine (reference class is your custom engine class) generator.setTemplateEngine(new CustomTemplateEngine()); // other config ...生成文件 CodeCreate.java
package com.example.CodeGenerator; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.mysql.cj.xdevapi.Table; //代码生成器 public class CodeCreate { public static void main(String[] args){ //DataSourceConfig 数据源配置,通过该配置,指定需要生成代码的具体数据库 //StrategyConfig 数据库表配置,通过该配置,可指定需要生成哪些表或者排除哪些表 //PackageConfig 包名配置,通过该配置,指定生成代码的包路径 //TemplateConfig 模板配置,可自定义代码生成的模板,实现个性化操作 //GlobalConfig 全局策略配置,具体请查看 //InjectionConfig 注入配置,通过该配置,可注入自定义参数等操作以实现个性化操作 AutoGenerator mpg = new AutoGenerator();//构建一个代码自动生成器对象 String projectPath = System.getProperty("user.dir"); //1.全局配置 -> GlobalConfig GlobalConfig gc = new GlobalConfig(); gc.setAuthor("lzy"); //开发人员,默认null gc.setActiveRecord(false);//开启 ActiveRecord 模式 gc.setBaseResultMap(false);//开启 BaseResultMap gc.setBaseColumnList(false);//开启 baseColumnList gc.setDateType(DateType.ONLY_DATE); //时间类型对应策略,默认值:TIME_PACK gc.setIdType(IdType.ID_WORKER);//指定生成的主键的ID类型 gc.setEnableCache(false);//是否在xml中添加二级缓存配置 gc.setFileOverride(true);//是否覆盖已有文件,默认false gc.setKotlin(false);//开启 Kotlin 模式 gc.setOpen(false); //是否打开输出目录 gc.setSwagger2(true);//开启 swagger2 模式 gc.setOutputDir(projectPath+"/src/main/java");//生成文件的输出目录 gc.setControllerName("%sController");//controller 命名方式 gc.setEntityName("%sEntity");//实体命名方式 gc.setMapperName("%sMapper");//mapper 命名方式 gc.setServiceName("%sService");//service 命名方式,%s填充实体属性,%s为占位符 gc.setServiceImplName("%sServiceImpl");//service impl 命名方式 gc.setXmlName("%sXml");//Mapper xml 命名方式 mpg.setGlobalConfig(gc); //2.配置数据源 -> dataSourceConfig DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT+8"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); //驱动名称 dsc.setUsername("root"); //数据库连接用户名 dsc.setPassword("123456"); //数据库连接密码 dsc.setDbType(DbType.MYSQL); //数据库类型,该类内置了常用的数据库类型 //dsc.setDbQuery()数据库信息查询类,默认由 dbType 类型决定选择对应数据库内置实现,实现 IDbQuery 接口自定义数据库查询 SQL 语句 定制化返回自己需要的内容 //dsc.setKeyWordsHandler(); //dsc.setSchemaName(); 数据库 schema name //dsc.setTypeConvert();类型转换,默认由 dbType 类型决定选择对应数据库内置实现 mpg.setDataSource(dsc); //4.PackageConfig -> 包的相关配置 PackageConfig pc = new PackageConfig(); pc.setParent("com.example"); //父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名 pc.setModuleName("blog"); //父包模块名 pc.setEntity("entity"); //Entity目录名 pc.setMapper("mapper"); //Mapper目录名 pc.setController("controller"); //Controller目录名 pc.setService("service"); //Service目录名 pc.setServiceImpl("serviceImpl");//Service Impl包名 pc.setXml("xml"); // Mapper XML包名 //pc.setPathInfo() 路径配置信息 mpg.setPackageInfo(pc); //3.数据库表配置 -> StrategyConfig StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("User"); //设置映射表名 strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!"); strategy.setEntityLombokModel(true); //自动lombok strategy.setRestControllerStyle(true);//生成 @RestController 控制器 strategy.setLogicDeleteFieldName("deleted");//逻辑删除名字 //isCapitalMode是否大写命名,skipView是否跳过视图, mpg.setStrategy(strategy); //5.模板配置 -> TemplateConfig // TemplateConfig tc = new TemplateConfig(); // tc.setEntity(); // tc.setEntityKt(); // tc.setService(); // tc.setServiceImpl(); // tc.setMapper(); // tc.setXml(); // tc.setController(); // mpg.setPackageInfo(tc); //6.注入配置 -> injectionConfig mpg.execute(); //执行 } }以数据表one为例运行CodeCreate可以生成如下图的目录结构
简单的CRUD中service、impl、xml并未实际用处可以删除,编写一下controller层即可返回数据。复杂sql语句仍需要在xml中书写。 package com.example.blog.controller; import com.example.blog.entity.UserEntity; import com.example.blog.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * <p> * 前端控制器 * </p> * * @author lzy * @since 2020-07-01 */ @RestController public class UserController { @Autowired UserMapper userMapper; @RequestMapping(value = "/qurry") public UserEntity qurryOne(){ return userMapper.selectById(4L); } @RequestMapping(value = "/list") public List<UserEntity> queryAllUser(){ List<UserEntity> users = userMapper.selectList(null); return users; } @RequestMapping(value = "/insert/{name}/{age}/{email}") public String insertUser(@PathVariable("name")String name,@PathVariable("age")Integer age,@PathVariable("email")String email){ UserEntity user = new UserEntity(); user.setName(name); user.setAge(age); user.setEmail(email); userMapper.insert(user); return "insert is running"; } @RequestMapping(value = "/update/{id}/{name}/{age}/{email}") public String update(@PathVariable("id")Long id,@PathVariable("name")String name,@PathVariable("age")Integer age,@PathVariable("email")String email){ UserEntity user = new UserEntity(); user.setId(id); user.setName(name); user.setAge(age); user.setEmail(email); userMapper.updateById(user); return "update is running"; } @RequestMapping(value = "/delete/{id}") //删除 public String DeleteUserById(@PathVariable("id")Long id){ int r = userMapper.deleteById(id); return "Delete is running"; } }结果截图:如下图是访问/list得到 list里面拿到的json数据。
application.properties文件配置如下:
#配置逻辑删除 mybatis-plus.global-config.db-config.logic-delete-field= flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。 mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0application.yml文件配置如下:
(如果你的默认值和mp默认的一样,该配置可无)
global-config: db-config: logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)在数据库中书写deleted字段,默认为0,逻辑删除后变1。
字段支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
如果使用LocalDateTime,建议逻辑未删除值设置为字符串null
逻辑删除值只支持数据库函数例如now() 效果
使用mp自带方法删除和查找都会附带逻辑删除功能 (自己写的xml不会)
设置逻辑删除,执行删除操作实际是更新操作,更新deleted为1,从而数据库可见,用户不可见
example 删除 update user set deleted=1 where id =1 and deleted=0 查找 select * from user where deleted=0全局逻辑删除: begin 3.3.0
如果公司代码比较规范,比如统一了全局都是flag为逻辑删除字段。
使用此配置则不需要在实体类上添加 @TableLogic。
但如果实体类上有 @TableLogic 则以实体上的为准,忽略全局。
即先查找注解再查找全局,都没有则此表没有逻辑删除。
mybatis-plus: global-config: db-config: logic-delete-field: flag #全局逻辑删除字段值逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。 如果你需要再
查出来就不应使用逻辑删除,而是以一个状态去表示。 如: 员工离职,账号被锁定等都应该是一个
状态字段,此种场景不应使用逻辑删除。
若确需查找删除数据,如老板需要查看历史所有数据的统计汇总信息,请单独手写sql。
test7中有每个选项的简单例子,可以参考
package com.example; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.example.blog.mapper.UserMapper; import com.example.blog.entity.UserEntity; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import java.util.Map; @SpringBootTest public class WrapperTest { @Autowired private UserMapper userMapper; @Test void test1(){ //查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper .isNotNull("name") .isNotNull("email") .ge("age",12); userMapper.selectList(wrapper).forEach(System.out::println); } @Test void test2(){ //查询名字风花雪月 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper.eq("name","风花雪月"); UserEntity user = userMapper.selectOne(wrapper); System.out.println(user); } @Test void test3(){ //查询年龄在18-30 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper.between("age",18,30); Integer count = userMapper.selectCount(wrapper); System.out.println(count); } @Test void test4(){ //查询名字没有e并且右边以t开头 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper .notLike("name","e") .likeRight("email","t"); List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); maps.forEach(System.out::println); } @Test void test5(){ //id在子查询中查询出来 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper.inSql("id","select id from user where id>3"); List<Object> objects = userMapper.selectObjs(wrapper); objects.forEach(System.out::println); } @Test void test6(){ //通过id排序 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); wrapper.orderByAsc("id"); List<UserEntity> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } @Test void test7() { //通过id排序 QueryWrapper<UserEntity> wrapper = new QueryWrapper<>(); //.allEq({id:1,name:"老王",age:null})->id=1 and name = '老王' and age is null wrapper .eq("id",15) //等于 .ne("id",15) //不等于 .gt("id",15)//大于 .ge("id",15)//大于等于 .lt("id",15)//小于 .le("id",15)//小于等于 .between("id",15,20)//介于15和20之间 .notBetween("id",15,20)//不介于15 和 20之间 .like("id","15")//匹配 .notLike("id","15")//不匹配 .likeLeft("","15")//左匹配 .likeRight("","15")//右匹配 .isNull("id")//为空 .isNotNull("id")//不为空 .in("age",1,2,3)//在给定的values之内 .notIn("age",1,2,3)//不在给定的values之内 .inSql("age","select id from table where id < 3")//在写的sql之内 .notInSql("age","select id from table where id < 3")//不在sql之内 .groupBy("id","name")//分组 ID和name .orderByAsc(true,"id","name") //排序 .orderByDesc(true,"name","id")//排序 .orderBy(true,true,"id","name") //排序 .having("sum(age) > 10") // sum(age) > 10 .or() //主动调用or表示紧接着下一个方法不是用and连接! //(不调用or则默认为使用and连接) .and(i -> i.eq("name", "李白").ne("status", "活着")) .nested(i -> i.eq("name", "李白").ne("status", "活着")) .apply("id = 1") //拼接 sql .last("limit 1") //无视优化规则直接拼接到 sql 的最后 .exists("select id from table where age = 1") //拼接EXISTS(sql语句) .notExists("select id from table where age = 1"); //拼接NOT EXISTS (sql语句) List<UserEntity> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } //updateWrapper @Test void test8() { //将没有逻辑删除的设置名字年龄和邮箱全部更新 UpdateWrapper<UserEntity> Uwrapper = new UpdateWrapper<>(); //更新Wrapper Uwrapper.set("name","lzy") .set("age",99).set("email","145236987@qq.com"); //设置年龄为18 UserEntity entity = new UserEntity(); int count = userMapper.update(entity,Uwrapper); //返回更新的目录条数 System.out.println(count);//打印更新的目录条数 } @Test void test9(){ UpdateWrapper<UserEntity> Uwrapper = new UpdateWrapper<>(); Uwrapper.setSql("name = '老李头'"); //设置 SET 部分 SQL,内部写一条sql语句。 UserEntity entity = new UserEntity(); int count = userMapper.update(entity,Uwrapper); //返回更新的目录条数 System.out.println(count);//打印更新的目录条数 } }字段必须声明TableField注解,属性fill选择对应策略,
该声明告知Mybatis-Plus需要预留注入SQL字段,
填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入
要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者trictUpdateFill方法,
不需要根据任何来区分可以使用父类的fillStrategy方法
第一步:在数据库中添加字段version
**第二步:**在实体类中添加字段Integer version 第三步:注册乐观锁插件 输出结果如图