前言
使用Mybatis进行开发有以下不足
1.每一张表都需要配置一套基本的增删改查功能,造成代码重复;
3.所有SQL语句全部自己写,表字段名称容易拼写错误;
2.使用xml标签实现动态SQL配置起来比较复杂;
一、MyBatis-Plus介绍
MyBatis-Plus(简称MP)是Mybatis的增强版,MyBatis-Plus在Mybatis的基础上只做增强不做改变,MyBatis-Plus为简化配置、高效率实现持久层而生;
MyBatis-Plus封装好了大量增删改查的方法,程序员只需要继承BaseMapper接口即可以使用这些方法,无需再重复开发;
MyBatis-Plus有以下特性
- 无侵入:只做增强不做改变,不会对现有的工程产生影响;
- 强大的CURD操作:MyBatis-Plus内置了通用Mapper,少量配置即可实现单表的增伤改查
- 支持Lambda表达式:编写查询条件无需担心字段拼写错误
- 支持主键字段自动生成
- 内置分页插件
二、入门案例
在数据库中insert 1条记录;
1.数据库环境准备
在数据库中创建1张user表;
CREATE TABLE user ( id bigint(20) primary key auto_increment, name varchar(32) not null, password varchar(32) not null, age int(3) not null , tel varchar(32) not null ); insert into user values(null,'岳飞','123456',12,'12345678910'); insert into user values(null,'逍遥王','123456',8,'12345667910'); insert into user values(null,'易云','123456',15,'12345678910'); insert into user values(null,'张弢','123456',9,'12345678910'); insert into user values(null,'少林圣僧','123456',28,'12345678910'); insert into user values(null,'张启樵','123456',22,'12345678910'); insert into user values(null,'奔雷','123456',16,'12345018910'); insert into user values(null,'闪电','123456',16,'123908910'); insert into user values(null,'宋远桥','123456',16,'1224350178910');
2.
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.15</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> </dependencies>
3.创建实体类
数据库中有1张表就需要1个实体类与之对应;
@TableName("user"):此注解:用于指定当前实体类关联到数据库中哪1张表, 省略此注解后,为类名首字母小写;
@TableField("id"): 此注解:用于指定当前实体类字段关联到数据库表中哪1个字段,省略此注解后,当前属性名称和数据库表中字段名称一致;
package com.gen.domain; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor //此注解:用于绑定当前实体类关联到MySQL中哪一张表,省略此注解后,为类名首字母小写 @TableName("user") public class User { // 此注解:用于绑定当前实体类字段关联到数据库表中哪个字段,省略此注解后,当前字段和数据库表中字段名称一致 @TableField("id") private Long id; private String name; private String password; private Integer age; private String tel; }
4.创建映射接口
当前接口继承BaseMapper之后拥有BaseMapper接口中基本的CURD方法;
package com.gen.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.springframework.stereotype.Repository; //当前接口继承.BaseMapper之后拥有BaseMapper接口中基本的CURD方法 @Repository public interface UserMapper extends BaseMapper { //如果继承自父接口的方法,无法满足当前业务需求,可以对父接口的方法进行重写 }
spring: datasource: # 数据源 driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.56.18:3306/reggie?useUnicode=true&characterEncoding=utf-8&useSSL=false username: zhanggen password: 123.com type: com.alibaba.druid.pool.DruidDataSource mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志打印
6.创建SpringBoot启动类
package com.gen; import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication //设置扫描的mapper包 @MapperScan("com.gen.mapper") public class MybatisPlusApplication { public static void main(String[] args) { SpringApplication.run(MybatisPlusApplication.class, args); System.out.println("项目启动成功"); } }
7.MybatisPlus主键自动生成
@TableId(type = IdType.INPUT)注解可以帮助我们自动生成1个唯一的主键;
MybatisPlus的主键生成策略有4种:
- AUTO 数据库ID自增
- INPUT 用户输入ID
- ASSIGN_ID 雪花算法生成ID(默认值)
- ASSIGN_UUID UUID算法生成ID
/** * Mybatis支持的主键生成策略 * AUTO 数据库ID自增 * INPUT 用户输入ID * ASSIGN_ID 雪花算法生成ID(默认值) * ASSIGN_UUID UUID算法生成ID */ @TableId(type= IdType.AUTO)
8.测试
package com.gen; import com.gen.domain.User; import com.gen.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @SpringBootTest @RunWith(SpringJUnit4ClassRunner.class) public class UserMapperTest { @Autowired private UserMapper userMapper; //测试保存 @Test public void testInsert() { User user = new User(); //user.setId(10L);//手动设置了id,用设置的 user.setId(null);//不设置id,执行mybatis的主键策略 user.setName("张三丰"); user.setPassword("admin"); user.setAge(20); user.setTel("13700137001"); //保存 userMapper.insert(user); } }
三、基本CURD操作
当maaper接口继承了MybatisPlus提供BaseMapper接口之后,就拥有了单表的增删改查的功能,程序员可以直接使用;
- 插入一条记录:int insert(T entity);
- 主键查询: T selectById(Serializable id);
- 主键批量查询:List<T>selectBatchIds (Collection idList);
- 根据ID更新: int updateById(T entity);
- 根据ID删除: int deleteById(Serializable id);
- 根据ID批量删除:int deleteBatchIds(Collection idList);/
测试代码
package com.gen; import com.gen.domain.User; import com.gen.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.ArrayList; import java.util.List; @SpringBootTest @RunWith(SpringJUnit4ClassRunner.class) public class UserMapperTest { @Autowired private UserMapper userMapper; //测试保存 @Test public void testInsert() { User user = new User(); //user.setId(10L);//手动设置了id,用设置的 user.setId(null);//不设置id,执行mybatis的主键策略 user.setName("张三丰"); user.setPassword("admin"); user.setAge(20); user.setTel("13700137001"); //保存 userMapper.insert(user); } //根据ID查询1条记录 @Test public void testSelectById(){ User user = userMapper.selectById(1); System.out.println(user); } //根据ID批量查询 @Test public void selectBatchIds(){ List<Long> idList=new ArrayList<>(); idList.add(1L); idList.add(2L); idList.add(3L); List<User> userList = userMapper.selectBatchIds(idList); for (User user : userList) { System.out.println(user); } } //根据ID更新1条记录 @Test public void testUpdateById(){ User newUser=new User(); newUser.setId(10L); newUser.setName("鹏举"); newUser.setAge(899); userMapper.updateById(newUser); } //根据id删除 @Test public void testDeleteById(){ userMapper.deleteById(1531090450880974851L); } //根据id批量删除 @Test public void testDeleteBatchIds(){ List<Long> ids = new ArrayList<>(); ids.add(1531089191868391425L); ids.add(1531090450880974849L); ids.add(1531090450880974850L); userMapper.deleteBatchIds(ids); } }
四、复杂操作
当maaper接口继承了MybatisPlus提供BaseMapper接口之后,就拥有了单表的增删改查的功能;
如果简单的查询无法满足当前业务需求;
我们可以通过QueryWrapper和LambdaQueryWrappe条件构造对象,构造各种查询条件,这个2种条件构造器都支持3个参数;
- condition:判断条件
- column:数据库字段
- val:字段的值
然后再把Wrapper对象作为参数传到BaseMapper接口的接口方法中,实现条件、分页、排序、分组、过滤查询等;
BaseMapper接口中定义的接口方法有如下:
- 条件查询,返回值为多条记录:List<T> selectList(Wrapper<T> queryWrapper);
- 条件查询,返回值为1条记录: T selectOne(Wrapper<T> queryWrapper);
- 条件删除:int delete(Wrapper<T> wrapper);
- 条件更新:int update(T entity,Wrapper<T> updateWrapper);
1.QueryWrapper组装查询条件
参数1:判断条件,条件为真后两个参数才生效
参数2:数据库表字段名称的字符串,容易写错(硬编码)
参数3:前端传到后台的参数
//1:QueryWrapper构造查询条件 QueryWrapper<DishFlavor> dishFlavorQueryWrapper = new QueryWrapper<>(); dishFlavorQueryWrapper.eq(dish.getId() != null, "dish_id", dish.getId());
2.LambdaQueryWrapper组装查询条件
参数1:判断条件,条件为真后两个参数才生效
参数2:实体类中的属性名称,支持Lambada拼写,不容易写错(软编码)
参数3:前端传到后台的参数
//2:LambdaQueryWrapper构造查询条件 LambdaQueryWrapper<DishFlavor> dishFlavorQueryWrapper = new LambdaQueryWrapper<>(); dishFlavorQueryWrapper.eq(dish.getId() != null, DishFlavor::getDishId, dish.getId()); dishFlavorMapper.delete(dishFlavorQueryWrapper);
3.联合条件组装
说明 | 例子 | |
---|---|---|
eq、ne、gt、ge、lt、le、isNull、isNotNull | 比较运算 | eq("name", "老王")---> name = '老王' |
like、notLike、likeLeft、likeRight | 模糊查询 | likeRight("name", "王")---> name like '王%' |
in、notIn、between、notBetween | 范围运算 | in("age",{1,2,3})---> age in (1,2,3) |
or、and | 拼接 | eq("id",1).or().eq("name","老王")---> |
1.根据条件判断,生成多查询条件
LambdaQueryWrapper<Cart> cartQueryWrapper = new LambdaQueryWrapper<>(); cartQueryWrapper.eq(cart.getDishId() != null, Cart::getDishId, cart.getDishId()); cartQueryWrapper.eq(cart.getSetmealId() != null, Cart::getSetmealId, cart.getSetmealId()); cartQueryWrapper.eq(Cart::getUserId, UserHolder.get().getId());
2.使用or连接多个查询条件
//组装对个查询条件组装--链式编程 LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>(); userLambdaQueryWrapper.ge(User::getId, iDParam) .or() .between(User::getAge, ageParam, ageParam + 20) .like(User::getName, nameParam) .in(User::getTel, Arrays.asList(telList)); userMapper.selectList(userLambdaQueryWrapper);
//查询投影:SELECT age,id FROM user @Test public void testSelect() { LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>(); userLambdaQueryWrapper.select(User::getAge,User::getId); List<User> userList = userMapper.selectList(userLambdaQueryWrapper); for (User user : userList) { System.out.println(user); } }
4.2.查询排序
//查询排序:正序:orderByAsc 倒序:orderByDes @Test public void testSelect() { LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>(); // 根据年龄排序: userLambdaQueryWrapper.orderByDesc(User::getAge); List<User> userList = userMapper.selectList(userLambdaQueryWrapper); for (User user : userList) { System.out.println(user); } }
4.3.分组和过滤
//查询分组和过滤:select name,count(1) as count from user group by name having count>0; @Test public void testGroupAndHaving() { //分组过滤只能使用QueryWrapper,不能使用LambdaQueryWrapper QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper .select("name", "count(1) as count") .groupBy("name") .having("count>0"); List<Map<String, Object>> list = userMapper.selectMaps(userQueryWrapper); //[ {name=张三, count=1}, {name=李四, count=1} ] System.out.println(list); }
5.单独定义SQL
如果继承自BaseMapper接口的接口方法也无法满足我们的需求,我们也可以在这里mapper接口中单独定义方法;
//当前接口继承.BaseMapper之后拥有BaseMapper接口中基本的CURD方法 @Repository public interface UserMapper extends BaseMapper<User> { //如果继承自父接口的方法,无法满足当前业务需求,可以对父接口的方法进行重写 @Select("select name,count(1) as count from user group by name having count>0") List<Map<String,String>> groupByName(); }
测试
//在映射接口中自定义分组和排序方法 @Test public void testGroupAndHaving1() { List<Map<String, String>> list = userMapper.groupByName(); //[ {name=奔雷, count=1}, {name=宋远桥, count=1} ] System.out.println(list); }
- public class LoginCheckInterceptor implements HandlerInterceptor{} 拦截的是request和response;
package com.gen.config; 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 { @Bean //3.把MybatisPlusInterceptor拦截器对象放入spring的容器中 public MybatisPlusInterceptor mybatisPlusInterceptor() { //1.创建MybatisPlusInterceptor拦截器对象 MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor(); //2.添加分页拦截器对象 MybatisPlusInterceptor拦截器对象中 mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mpInterceptor; } }
或者在启动类入口配置
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(clients = IArticleClient.class) @MapperScan("com.leadnews.wemedia.mapper") @EnableAsync //开启异步注解 public class WemediaApplication { public static void main(String[] args) { SpringApplication.run(WemediaApplication.class,args); } @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor; }
2.代码实现
当使用MyBatis-Plus分页插件之后,mapper层返回的就是1个page对象,我们可以把这个page对象封装到ResultInfo对象中;
代码
//测试分页: @Test public void testPage() { //1.构造page对象: pageNumber、pageSize Page<User> page = new Page<>(2, 3); //2.构造查询条件: LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>(); //3.执行查询 Page<User> userPage = userMapper.selectPage(page, userLambdaQueryWrapper); System.out.println(userPage); //4. 输出结果 System.out.println("总条数:" + page.getTotal()); System.out.println("总页数:" + page.getPages()); System.out.println("当前页数据:" + page.getRecords()); System.out.println("当前页码值:" + page.getCurrent()); System.out.println("每页显示数:" + page.getSize()); }
五、常见注解
-
exist: 当实体类中属性仅在实体类中存在(多表查询),在数据库中不存在时,使用@TableField(exist = false)标识
-
@TableField(select = false)//标识不想将数据表中某个对应字段查询回来 private String password; @TableField(exist = false)//标识当前属性在数据表中没有对应的字段 private String password2;//新增加的属性
@TableLogic(value = "1", delval = "0") private Integer deleted; //表示当前用户是否被删除,正常:1,被删除之后0
3.公共字段自动填充
1.设置公共字段填充时机
使用注解标识公共字段什么时候填充?
//创建时间 @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT) private Date createTime; //更新时间 @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") @TableField(fill = FieldFill.INSERT_UPDATE) //声明当前字段在什么时机进行内容填充 private Date updateTime; //创建人 @TableField(fill = FieldFill.INSERT) private Long createUser; //修改人 @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser;
2.
package com.zhanggen.reggie.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.util.Date; //自定义元数据对象处理器 @Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { //metaObject代表要填充的对象 //插入新增(insert)操作,自动填充 @Override public void insertFill(MetaObject metaObject) { metaObject.setValue("createTime", new Date()); metaObject.setValue("updateTime", new Date()); metaObject.setValue("createUser", 1L); metaObject.setValue("updateUser", 1L); } //更新操作(update),自动填充 @Override public void updateFill(MetaObject metaObject) { metaObject.setValue("updateTime", new Date()); metaObject.setValue("updateUser", 1L); } }
3.Service层调用
修改项目的service层调用MyBatis-Plus的方法
六、使用ThreadLocal存储Session信息
SpringBoot Web层基于SpringMVC,SpringMVC底层基于Servlet;
Servlet的每处理1个来自客户端的Request都使用1个不同的线程,创建1个request对象;
//1、判断登录状态,如果已登录,则直接放行 User user = (User) request.getSession().getAttribute("SESSION_USER");
如果程序员在后台的Web或Service层,开了多个子线程,如何保证这些子线程可以安全访问父线程中的Request对象里面的数据呢?
1.ThreadLocal是什么?
ThreadLocal本质是一块Map结构的内存,和存储Session的内存数据结构一致;
和HttpSession不同的是。这块内存,可以保证多线程模式下,每1个线程之间的set的数据是相互隔离的;
ThreadLocal={
thread_id1: {},
thread_id2: {},
thread_id3: {},
}
2.ThreadLocal特性
不同线程之间数据都是隔离的,当前线程set的值,只有当前线程可以get到;
3.ThreadLocal应用场景
在Flask框架中每个用户的request对象都是由不同的线程创建的,底层就是通过ThreadLocal实现request对象的隔离;
如果每1个用户的Session信息都保存在服务器内存中 ,当用户访问量激增时,用户Session数据失效时间过长,很容易造成服务器端内存跑满;
我们可以搭配SpringMVC的拦截器执行时机+ThreadLocal+JTW,把用户session信息全部保存在ThreadLocal;
- 在用户http请求到达SpringMVC处理器之前, 把当前用户相关信息保存在ThreadLocal中;(set)
- 在用户hhtp请求到达SpringMVC处理器时,使用ThreadLocal中保存的用户信息,去填充数据库表中公共字段数据;(get)
- 在用户hhtp请求离开SpringMVC处理器时,用户信息使用完了,就销毁当前用户保存在ThreadLoca中的值;(remove)
4.ThreadLocal的API
-
-
get():获取当前线程绑定的变量
-
5.代码实现Session信息保存到ThreadLocal
在拦截器中,实现用户Session信息1次性保存到ThreadLocal;
1.EmployeeHolder
在reggie-common下创建com.itheima.reggie.common.EmployeeHolder工具类用于操作ThreadLocal;
package com.itheima.reggie.common; import com.itheima.reggie.domain.Employee; //跟员工相关,操作ThreadLocal的工具类 public class EmployeeHolder { //声明1个ThreadLocal private static ThreadLocal<Employee> threadLocal = new ThreadLocal<Employee>(); //存储 public static void set(Employee employee) { threadLocal.set(employee); } //获取 public static Employee get() { return threadLocal.get(); } //删除 public static void remove() { threadLocal.remove(); } }
2.拦截器
搭配拦截器的执行时机,在用户请求到达拦截器之前设置(set)用户信息,在用户请求离开拦截器之后销毁(remove)用户信息;
package com.itheima.reggie.interceptor; import com.fasterxml.jackson.databind.ObjectMapper; import com.itheima.reggie.common.EmployeeHolder; import com.itheima.reggie.common.ResultInfo; import com.itheima.reggie.domain.Employee; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Component//把拦截器对象放入spring的容器中,以供配置对象注入 public class LoginCheckInterceptor implements HandlerInterceptor { //在请求进入处理器之前进行拦截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //检查用户的session中是否有当前信息信息,以验证当前用户是否登录? HttpSession session = request.getSession(); Employee currentEmployee = (Employee) session.getAttribute("SESSION_EMPLOYEE"); if (currentEmployee == null) { //返回错误信息 ResultInfo resultInfo = ResultInfo.error("NOTLOGIN");//组装对象 //ResultInfo对象转为json String jsonString = new ObjectMapper().writeValueAsString(resultInfo); response.getWriter().write(jsonString); return false; } else { //获取到当前登录用户,保存到ThreadLocal EmployeeHolder.set(currentEmployee); return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } //请求即将离开服务器 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //删除到当前登录用户(线程),存储到ThreadLocal的信息 EmployeeHolder.remove(); } }
3.Mapper层
在项目Mapper层创建com.itheima.reggie.config.MyMetaObjectHandler公共字段填充处理器;
当前用户请求到达SpringMVC的处理器经过Controller---->Service--->Mapper层(MyBatis-Plus);
如果需要调用MyBatis-Plus的insert/updateById()方法,触发公共字段填充处理器执行;
公共字段填充处理器,获取(get)到ThreadLocal中保存的用户信息,自动填充数据库表中公共字段;
package com.itheima.reggie.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.itheima.reggie.common.EmployeeHolder; import com.itheima.reggie.domain.Employee; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; //自定义元数据对象处理器 @Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { //metaObject代表要填充的对象 //插入新增(insert)操作,自动填充 @Override public void insertFill(MetaObject metaObject) { metaObject.setValue("createTime", new Date()); metaObject.setValue("updateTime", new Date()); //从ThreadLocal中获取当前用户的信息 Employee employee = EmployeeHolder.get(); if (employee != null) { metaObject.setValue("createUser", employee.getId()); metaObject.setValue("updateUser", employee.getId()); } } //更新操作(update),自动填充 @Override public void updateFill(MetaObject metaObject) { metaObject.setValue("updateTime", new Date()); Employee employee = EmployeeHolder.get(); if (employee != null) { metaObject.setValue("updateUser", 1L); } } }
七、SpringBoot项目集成MyBatis-Plus
当SpringBoot项目集成MyBatis-Plus之后,之前使用MyBatis的定义的mapper接口功能不受影响(继承BaseMapper接口之后的重写);这就是MyBatis-Plus的无侵入;
1.添加MyBatis-Plus依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency>
2.修改application.yaml,替换MyBatis-Plus的配置
server: port: 8080 spring: application: name: reggie-web-manage # 应用名称 datasource: # 数据源配置 druid: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.56.18:3306/reggie?useUnicode=true&characterEncoding=utf-8&useSSL=false username: zhanggen password: 123.com #mybatis: ## configuration: ## map-underscore-to-camel-case: true # 驼峰命名法映射 address_book ---> AddressBook ## log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志输出 ## mapper-locations: classpath:/mappers/**.xml # 指定xml位置 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:/mappers/**.xml global-config: db-config: id-type: ASSIGN_ID # id生成策略类型
3.修改当前的Mapper接口继承BaseMapper
八、IService
IService是MyBatis-Plus在service层提供的接口
当我们自定义的service层接口继承了IService接口之后;
开发人员自定义的接口就会继承拥有更多Iservice封装的通用逻辑方法;
避免开发人员重复实现大量的业务逻辑,提升开发效率;
1.mapper层
mapper层定义的接口继承MyBatis-Plus提供的BaseMapper接口
@Mapper @Repository public interface TaskinfoLogsMapper extends BaseMapper<TaskinfoLogs> { }
2.service层接口
service层定义的接口,继承IService接口
public interface TaskinfoLogsService extends IService<TaskinfoLogs> { }
3.service层实现类
service层实现类继承MyBatis-Plus提供的ServiceImpl基类,并实现以上在service层中定义的接口;
@Service //Service实现类需要继承MyBatis-Plus通用的基类ServiceImpl //基类ServiceImpl中包含2个泛型:第一个泛型 继承了BaseMapper的Mapper,第二个泛型对应的 Pojo public class TaskinfoLogsServiceImpl extends ServiceImpl<TaskinfoLogsMapper, TaskinfoLogs> implements TaskinfoLogsService { }
4.IService常用API
package com.leadnews.schedule; import com.heima.model.schedule.pojos.TaskinfoLogs; import com.heima.schedule.service.TaskinfoLogsService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class IServiceTest { @Autowired private TaskinfoLogsService taskinfoLogsService; @Test public void test1(){ //根据ID查询1条记录 TaskinfoLogs taskinfoLogs = taskinfoLogsService.getById(1); System.out.println(taskinfoLogs); } }