# MyBatis-Plus ## 一、介绍 [MyBatis-Plus](https://github.com/baomidou/mybatis-plus) 是一个 [MyBatis](https://www.mybatis.org/mybatis-3/) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 其愿景是成为 MyBatis 最好的搭档,就像 **魂斗罗** 中的 1P、2P,基友搭配,效率翻倍。 #### 特性 - **无侵入**:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 - **损耗小**:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 - **强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 - **支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 - **支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 - **支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作 - **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere ) - **内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用 - **内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 - **分页插件支持多种数据库**:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库 - **内置性能分析插件**:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询 - **内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作 ## 二、依赖安装 #### 1、创建SpringBoot项目 起步依赖只选择`MySQL Driver`即可,`Spring Web`是额外的。 #### 2、添加依赖 因为其内置的`mybatis-spring`依赖易与其他依赖起冲突,所以排除在外另加版本。 ```xml com.baomidou mybatis-plus-boot-starter 3.5.14 org.mybatis mybatis-spring org.mybatis mybatis-spring 3.0.5 ``` #### 3、配置Spring配置 修改`application.properties` ```properties spring.application.name=mybatisplus spring.main.banner-mode=off logging.level.cn.doooog.mybatisplus=debug # DBConfig spring.datasource.url=jdbc:mysql://localhost/database?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 spring.datasource.username=username spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Mybatis-Plus # 关闭大写转换小写加下划线 mybatis-plus.configuration.map-underscore-to-camel-case=false # 关闭调试信息的banner mybatis-plus.global-config.banner=false # 使用Mapper.xml映射sql # mybatis-plus.mapper-locations=classpath*:mapper/*.xml # po类取别名 # mybatis-plus.type-aliases-package=cn.doooog.mybatisplus.po ``` 修改`Application.java` ```java package cn.doooog.mybatisplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("cn.doooog.mybatisplus.mapper") public class MybatisplusApplication { public static void main(String[] args) { SpringApplication.run(MybatisplusApplication.class, args); } } ``` ## 三、软件层创建 #### 1、`po` 创建`po/Emp.java` ##### 手动创建 ```java package cn.doooog.mybatisplus.po; import java.util.Objects; public class Emp { private Integer empno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; private Integer deptno; public Emp() { } public Emp(Integer empno) { this.empno = empno; } public Emp(Integer empno, String ename, String job, Integer mgr, String hiredate, Double sal, Double comm, Integer deptno) { this.empno = empno; this.ename = ename; this.job = job; this.mgr = mgr; this.hiredate = hiredate; this.sal = sal; this.comm = comm; this.deptno = deptno; } public Integer getDeptno() { return deptno; } public void setDeptno(Integer deptno) { this.deptno = deptno; } public Double getComm() { return comm; } public void setComm(Double comm) { this.comm = comm; } public Double getSal() { return sal; } public void setSal(Double sal) { this.sal = sal; } public String getHiredate() { return hiredate; } public void setHiredate(String hiredate) { this.hiredate = hiredate; } public Integer getMgr() { return mgr; } public void setMgr(Integer mgr) { this.mgr = mgr; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Integer getEmpno() { return empno; } public void setEmpno(Integer empno) { this.empno = empno; } @Override public String toString() { return "Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Emp emp)) return false; return Objects.equals(getEmpno(), emp.getEmpno()) && Objects.equals(getEname(), emp.getEname()) && Objects.equals(getJob(), emp.getJob()) && Objects.equals(getMgr(), emp.getMgr()) && Objects.equals(getHiredate(), emp.getHiredate()) && Objects.equals(getSal(), emp.getSal()) && Objects.equals(getComm(), emp.getComm()) && Objects.equals(getDeptno(), emp.getDeptno()); } @Override public int hashCode() { return Objects.hash(getEmpno(), getEname(), getJob(), getMgr(), getHiredate(), getSal(), getComm(), getDeptno()); } } ``` **注意**:所有的字段对应属性名必须为小写,否则大写会替换为小写加下划线,可以使用下面注解解决该问题或在配置文件中取消大小写转换 ##### Lombok自动创建 **导入依赖** ```xml org.projectlombok lombok provided ``` ```java package cn.doooog.mybatisplus.po; 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.Data; import java.util.Objects; /** * Lombok * 作用 检查po类代码 * 通过注解省略Getter与Setter * @Setter * @Getter * @ToString * @EqualsAndHashCode * @NoArgsConstructor 无参构造方法 * @AllArgsConstructor 全参构造方法 * @Data 相当于上面的总和 */ @Data @TableName("EMP") public class Emp { /** * @TableName:表名注解 * @TableField:普通字段 * @TableId:主键字段 */ @TableId(value = "EMPno",type = IdType.AUTO) private Integer EMPno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; @TableField("DEPTno") private Integer DEPTno; } ``` **注意**:字段对应属性名若有大写字母,需要在上面用`@TableField`取别名或在配置文件中添加配置;主键对应的属性需要使用`@TableId`进行标记。 #### 2、`mapper` 创建`mapper/EmpMapper.java` ```java package cn.doooog.mybatisplus.mapper; import cn.doooog.mybatisplus.po.Emp; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * 使用MP,核心接口BaseMapper * 所有Mapper都需要集成BaseMapper * 单表所有操作:增删改查 */ @Mapper public interface EmpMapper extends BaseMapper { } ``` #### 3、`service` 创建`service/Emp.java` ```java package cn.doooog.mybatisplus.service; import cn.doooog.mybatisplus.mapper.EmpMapper; import cn.doooog.mybatisplus.po.Emp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class EmpService { @Autowired private EmpMapper empMapper; public List listEmpAll(){ return empMapper.selectList(null); } } ``` #### 4、`controller` 创建`controller/EmpController.java` ```java package cn.doooog.mybatisplus.controller; import cn.doooog.mybatisplus.po.Emp; import cn.doooog.mybatisplus.service.EmpService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/api/emp") public class EmpController { @Autowired private EmpService empService; @GetMapping("/all") public List listEmpAll() { return empService.listEmpAll(); } } ``` ## 四、使用Mybatis-Plus #### 1、查询 ##### 查询多个 ```java public List listEmpAll() { return empMapper.selectList(null); } ``` ##### 查询单个 ```java public Emp getEmpById(Integer id) { return empMapper.selectById(id); } ``` #### 2、新增 ```java public int addEmp(Emp emp) { return empMapper.insert(emp); } ``` #### 3、修改 ```java public int updateEmpById(Emp emp) { return empMapper.updateById(emp); } ``` #### 4、删除 ```java public int deleteEmpById(Emp emp){ return empMapper.deleteById(emp); } ``` #### 5、查询条件构造器 * `like`: like %data% * `eq`: = * `gt`: > * `lt`: < * `ne`: <> * `ge`: >= * `le`: <= * `between`: between low and high * `notLike`: not like %data% * `likeLeft`: like '%data' * `likeRight`: like 'data%' * `isNull`: isNull * `in`: in (array) * `orderBy`: order by field ```java // select * from EMP where ename like '%ename%'; public List listEmpByName(String ename) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.like("ename", ename); return empMapper.selectList(wrapper); } ``` #### 6、更新条件构造器 * `like`: like %data% * `eq`: = * `gt`: > * `lt`: < * `ne`: <> * `ge`: >= * `le`: <= * `between`: between low and high * `notLike`: not like %data% * `likeLeft`: like '%data' * `likeRight`: like 'data%' * `isNull`: isNull * `in`: in (array) * `orderBy`: order by field ```java // update emp set ename = 'name' where EMPno=7935; public int updateEmpNameById(String name, int EMPno) { UpdateWrapper wrapper = new UpdateWrapper<>(); wrapper.set("ename", name); wrapper.eq("EMPno", EMPno); return empMapper.update(wrapper); } ``` #### 7、分页查询 ##### 导入依赖`mybatis-plus-jsqlparser` 在`3.5.9`版本后分页插件被分离出来 ```xml com.baomidou mybatis-plus-jsqlparser 3.5.14 ``` ##### 导入分页插件 创建`util/MybatisPlusConfig.java` ```java package cn.doooog.mybatisplus.util; import com.baomidou.mybatisplus.annotation.DbType; 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 public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` ##### 使用`IPage` ```java public List listEmpWithPage(int page, int size) { IPage pg = new Page<>(page, size); IPage empIPage = empMapper.selectPage(pg, null); // 获取业务数据 List empList = empIPage.getRecords(); // 获取总页数 long totalPage = empIPage.getPages(); // 获取总记录数 long totalNum = empIPage.getTotal(); // 获取当前页 long currentPage = empIPage.getCurrent(); // 获取每页最大条数 long maxSize = empIPage.getSize(); System.out.println(totalPage + " | " + totalNum + " | " + currentPage + " | " + maxSize); return empList; } ``` # SpringBoot ## 一、AOP输出日志 #### 1、配置日志级别 ```properties #项目级别日志 logging.level.cn.doooog.[project]=debug #spring框架级别日志 logging.level.org.springframework=info #把日志写到特定文件中 logging.file.name=D://mylog/bootm.txt ``` #### 2、创建切面类 创建`aop/Log.java` ```java package cn.doooog.mybatisplus.aop; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @Component @Aspect @EnableAspectJAutoProxy public class Log { private static final Logger log = LoggerFactory.getLogger(Log.class); @Pointcut("execution(* cn.doooog.mybatisplus.controller.*.*(..))") private void cut() { } @Before("cut()") public void before(JoinPoint point) { //获得方法签名 Signature signature = point.getSignature(); //获得业务方法名 String name = signature.getName(); //获得业务方法所在控制器类的信息 String className = signature.getDeclaringTypeName(); //把上述信息写入日志文件中 log.info("业务方法前执行:"); log.info("业务方法:{}", className + "." + name); log.info("业务方法参数:{}", point.getArgs()); //以下可以用来记录获取访问本服务端应用的客户端信息 ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { //获得请求对象 HttpServletRequest request = requestAttributes.getRequest(); //获得请求地址 String url = request.getRequestURL().toString(); //获得客户端IP地址 String ip = request.getRemoteAddr(); log.info("客户端IP地址:{}", url); log.info("请求地址:{}", ip); } } } ``` ## 二、AOP应用全局异常处理器 #### 1、思路 * 定义全局异常处理器GlobalExceptionDeal * 类前使用注解@ControllerAdvice(该注解Wie组合注解,等价于@ControllerAdvice和@ResponseBody) * 类中方法前需要加两个主机诶 * 第一:@ExceptionHandler, 参数为异常类型字节码 * 第二:@ResponseStatus, 参数为Http状态码 ```txt 例如:HttpStatus.Internal_Server_Error = 500 HttpStatus.Bad_Request = 400 ``` #### 2、创建GlobalExceptionDeal类 ```java package cn.doooog.function02; import cn.doooog.po.ResponseResult; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionDeal { // 空指针异常 @ExceptionHandler(NullPointerException.class) @ResponseStatus(value= HttpStatus.INTERNAL_SERVER_ERROR) public ResponseResult dealNullException(){ ResponseResult rb=new ResponseResult(500,"空指针异常"); return rb; } } ``` #### 3、创建ResponseResult类 ```java package cn.doooog.po; //全局响应数据结构,作用和Map类似,用于封装数据状态 public class ResponseResult { // T是泛型,代表任意数据类型 private T data; // 数据状态码 private Integer status; // 数据状态信息 private String msg; // 操作成功,能取到业务数据 public ResponseResult(T data) { super(); this.data = data; this.status=200; this.msg="success"; } // 操作失败 public ResponseResult(Integer status, String msg) { super(); this.status = status; this.msg = msg; } // 属性设置器 public T getData() { return data; } public void setData(T data) { this.data = data; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } ``` #### 4、发生异常后写入LogAOP日志文件,在AOP中加入异常通知 ```java package cn.doooog.function01; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Component: 将该类标记为Spring的组件,使其能够被Spring容器扫描并管理。 * @Aspect: 标识该类为一个切面类,用于定义切点和通知方法。 * @EnableAspectJAutoProxy: 启用AspectJ自动代理功能,使切面能够正常工作。 */ @Component @Aspect @EnableAspectJAutoProxy public class LogAOP { private static final Logger log=LoggerFactory.getLogger(LogAOP.class); /** * 作用: 定义切点 * 格式: execution(访问修饰符 返回值类型 包名.类名.方法名(参数列表)) */ @Pointcut("execution(* cn.doooog.controller.*.*(..))") public void cut(){ } // 异常抛出通知方法 @AfterThrowing(value="cut()",throwing="ex") public void dealException(JoinPoint jp,Exception ex){ log.debug("异常信息:",ex); } } ``` # Redis #### 一、启动Redis服务 ``` redis-server redis.windows.conf ``` #### 二、导入Redis依赖 ```xml org.springframework.boot spring-boot-starter-data-redis ``` #### 三、配置Redis连接 #### 1、添加信息 修改`application.properties` ```properties spring.data.redis.host=localhost spring.data.redis.port=6379 # 1~16 spring.data.redis.database=0 ``` #### 2、创建配置类 ```java package cn.doooog.mybatisplus.util; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisTemplateConfig { /** * redisTemplate 不可更改名称 */ @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisFactory){ RedisTemplate redis = new RedisTemplate<>(); redis.setConnectionFactory(redisFactory); /*配置键序列化*/ StringRedisSerializer keySerializer = new StringRedisSerializer(); /*配置值序列化*/ Jackson2JsonRedisSerializer valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class); redis.setKeySerializer(keySerializer); redis.setValueSerializer(valueSerializer); return redis; } } ``` #### 四、创建DAO层 新建`dao`、`dao.impl`包 #### 1、创建`Redis.java`接口 ```java package cn.doooog.mybatisplus.dao; public interface Redis { // 存数据 void save(String key,Object value); // 存数据并设置过期时间 // TimeUnit.SECONDS等 void save(String key, Object value, long time, TimeUnit timeUnit); // 取数据 Object get(String key); // 删除数据并返回删除的数据 Object delete(String key); } ``` #### 2、创建`RedisImpl.java`类 ```java package cn.doooog.mybatisplus.dao.impl; import cn.doooog.mybatisplus.dao.Redis; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository public class RedisImpl implements Redis { @Autowired private RedisTemplate redisTemplate; @Override public void save(String key, Object value) { redisTemplate.opsForValue().set(key,value); } @Override public void save(String key, Object value, long time, TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, time, timeUnit); } @Override public Object get(String key) { return redisTemplate.opsForValue().get(key); } @Override public Object delete(String key) { return redisTemplate.opsForValue().getAndDelete(key); } } ``` Loading... # MyBatis-Plus ## 一、介绍 [MyBatis-Plus](https://github.com/baomidou/mybatis-plus) 是一个 [MyBatis](https://www.mybatis.org/mybatis-3/) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 其愿景是成为 MyBatis 最好的搭档,就像 **魂斗罗** 中的 1P、2P,基友搭配,效率翻倍。 #### 特性 - **无侵入**:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 - **损耗小**:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 - **强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 - **支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 - **支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 - **支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作 - **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere ) - **内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用 - **内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 - **分页插件支持多种数据库**:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库 - **内置性能分析插件**:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询 - **内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作 ## 二、依赖安装 #### 1、创建SpringBoot项目 起步依赖只选择`MySQL Driver`即可,`Spring Web`是额外的。 <img src="https://pic.soki.me/file/piclist/image-20251104090918186.png" alt="image-20251104090918186" style="zoom:50%;" style=""> #### 2、添加依赖 因为其内置的`mybatis-spring`依赖易与其他依赖起冲突,所以排除在外另加版本。 ```xml <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.14</version> <exclusions> <exclusion> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.5</version> </dependency> ``` #### 3、配置Spring配置 修改`application.properties` ```properties spring.application.name=mybatisplus spring.main.banner-mode=off logging.level.cn.doooog.mybatisplus=debug # DBConfig spring.datasource.url=jdbc:mysql://localhost/database?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 spring.datasource.username=username spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Mybatis-Plus # 关闭大写转换小写加下划线 mybatis-plus.configuration.map-underscore-to-camel-case=false # 关闭调试信息的banner mybatis-plus.global-config.banner=false # 使用Mapper.xml映射sql # mybatis-plus.mapper-locations=classpath*:mapper/*.xml # po类取别名 # mybatis-plus.type-aliases-package=cn.doooog.mybatisplus.po ``` 修改`Application.java` ```java package cn.doooog.mybatisplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("cn.doooog.mybatisplus.mapper") public class MybatisplusApplication { public static void main(String[] args) { SpringApplication.run(MybatisplusApplication.class, args); } } ``` ## 三、软件层创建 #### 1、`po` 创建`po/Emp.java` ##### 手动创建 ```java package cn.doooog.mybatisplus.po; import java.util.Objects; public class Emp { private Integer empno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; private Integer deptno; public Emp() { } public Emp(Integer empno) { this.empno = empno; } public Emp(Integer empno, String ename, String job, Integer mgr, String hiredate, Double sal, Double comm, Integer deptno) { this.empno = empno; this.ename = ename; this.job = job; this.mgr = mgr; this.hiredate = hiredate; this.sal = sal; this.comm = comm; this.deptno = deptno; } public Integer getDeptno() { return deptno; } public void setDeptno(Integer deptno) { this.deptno = deptno; } public Double getComm() { return comm; } public void setComm(Double comm) { this.comm = comm; } public Double getSal() { return sal; } public void setSal(Double sal) { this.sal = sal; } public String getHiredate() { return hiredate; } public void setHiredate(String hiredate) { this.hiredate = hiredate; } public Integer getMgr() { return mgr; } public void setMgr(Integer mgr) { this.mgr = mgr; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Integer getEmpno() { return empno; } public void setEmpno(Integer empno) { this.empno = empno; } @Override public String toString() { return "Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Emp emp)) return false; return Objects.equals(getEmpno(), emp.getEmpno()) && Objects.equals(getEname(), emp.getEname()) && Objects.equals(getJob(), emp.getJob()) && Objects.equals(getMgr(), emp.getMgr()) && Objects.equals(getHiredate(), emp.getHiredate()) && Objects.equals(getSal(), emp.getSal()) && Objects.equals(getComm(), emp.getComm()) && Objects.equals(getDeptno(), emp.getDeptno()); } @Override public int hashCode() { return Objects.hash(getEmpno(), getEname(), getJob(), getMgr(), getHiredate(), getSal(), getComm(), getDeptno()); } } ``` **注意**:所有的字段对应属性名必须为小写,否则大写会替换为小写加下划线,可以使用下面注解解决该问题或在配置文件中取消大小写转换 ##### Lombok自动创建 **导入依赖** ```xml <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> ``` ```java package cn.doooog.mybatisplus.po; 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.Data; import java.util.Objects; /** * Lombok * 作用 检查po类代码 * 通过注解省略Getter与Setter * @Setter * @Getter * @ToString * @EqualsAndHashCode * @NoArgsConstructor 无参构造方法 * @AllArgsConstructor 全参构造方法 * @Data 相当于上面的总和 */ @Data @TableName("EMP") public class Emp { /** * @TableName:表名注解 * @TableField:普通字段 * @TableId:主键字段 */ @TableId(value = "EMPno",type = IdType.AUTO) private Integer EMPno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; @TableField("DEPTno") private Integer DEPTno; } ``` **注意**:字段对应属性名若有大写字母,需要在上面用`@TableField`取别名或在配置文件中添加配置;主键对应的属性需要使用`@TableId`进行标记。 #### 2、`mapper` 创建`mapper/EmpMapper.java` ```java package cn.doooog.mybatisplus.mapper; import cn.doooog.mybatisplus.po.Emp; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * 使用MP,核心接口BaseMapper * 所有Mapper都需要集成BaseMapper * 单表所有操作:增删改查 */ @Mapper public interface EmpMapper extends BaseMapper<Emp> { } ``` #### 3、`service` 创建`service/Emp.java` ```java package cn.doooog.mybatisplus.service; import cn.doooog.mybatisplus.mapper.EmpMapper; import cn.doooog.mybatisplus.po.Emp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class EmpService { @Autowired private EmpMapper empMapper; public List<Emp> listEmpAll(){ return empMapper.selectList(null); } } ``` #### 4、`controller` 创建`controller/EmpController.java` ```java package cn.doooog.mybatisplus.controller; import cn.doooog.mybatisplus.po.Emp; import cn.doooog.mybatisplus.service.EmpService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/api/emp") public class EmpController { @Autowired private EmpService empService; @GetMapping("/all") public List<Emp> listEmpAll() { return empService.listEmpAll(); } } ``` ## 四、使用Mybatis-Plus #### 1、查询 ##### 查询多个 ```java public List<Emp> listEmpAll() { return empMapper.selectList(null); } ``` ##### 查询单个 ```java public Emp getEmpById(Integer id) { return empMapper.selectById(id); } ``` #### 2、新增 ```java public int addEmp(Emp emp) { return empMapper.insert(emp); } ``` #### 3、修改 ```java public int updateEmpById(Emp emp) { return empMapper.updateById(emp); } ``` #### 4、删除 ```java public int deleteEmpById(Emp emp){ return empMapper.deleteById(emp); } ``` #### 5、查询条件构造器 * `like`: like %data% * `eq`: = * `gt`: > * `lt`: < * `ne`: <> * `ge`: >= * `le`: <= * `between`: between low and high * `notLike`: not like %data% * `likeLeft`: like '%data' * `likeRight`: like 'data%' * `isNull`: isNull * `in`: in (array) * `orderBy`: order by field ```java // select * from EMP where ename like '%ename%'; public List<Emp> listEmpByName(String ename) { QueryWrapper<Emp> wrapper = new QueryWrapper<>(); wrapper.like("ename", ename); return empMapper.selectList(wrapper); } ``` #### 6、更新条件构造器 * `like`: like %data% * `eq`: = * `gt`: > * `lt`: < * `ne`: <> * `ge`: >= * `le`: <= * `between`: between low and high * `notLike`: not like %data% * `likeLeft`: like '%data' * `likeRight`: like 'data%' * `isNull`: isNull * `in`: in (array) * `orderBy`: order by field ```java // update emp set ename = 'name' where EMPno=7935; public int updateEmpNameById(String name, int EMPno) { UpdateWrapper<Emp> wrapper = new UpdateWrapper<>(); wrapper.set("ename", name); wrapper.eq("EMPno", EMPno); return empMapper.update(wrapper); } ``` #### 7、分页查询 ##### 导入依赖`mybatis-plus-jsqlparser` 在`3.5.9`版本后分页插件被分离出来 ```xml <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-jsqlparser --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-jsqlparser</artifactId> <version>3.5.14</version> </dependency> ``` ##### 导入分页插件 创建`util/MybatisPlusConfig.java` ```java package cn.doooog.mybatisplus.util; import com.baomidou.mybatisplus.annotation.DbType; 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 public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` ##### 使用`IPage` ```java public List<Emp> listEmpWithPage(int page, int size) { IPage<Emp> pg = new Page<>(page, size); IPage<Emp> empIPage = empMapper.selectPage(pg, null); // 获取业务数据 List<Emp> empList = empIPage.getRecords(); // 获取总页数 long totalPage = empIPage.getPages(); // 获取总记录数 long totalNum = empIPage.getTotal(); // 获取当前页 long currentPage = empIPage.getCurrent(); // 获取每页最大条数 long maxSize = empIPage.getSize(); System.out.println(totalPage + " | " + totalNum + " | " + currentPage + " | " + maxSize); return empList; } ``` # SpringBoot ## 一、AOP输出日志 #### 1、配置日志级别 ```properties #项目级别日志 logging.level.cn.doooog.[project]=debug #spring框架级别日志 logging.level.org.springframework=info #把日志写到特定文件中 logging.file.name=D://mylog/bootm.txt ``` #### 2、创建切面类 创建`aop/Log.java` ```java package cn.doooog.mybatisplus.aop; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @Component @Aspect @EnableAspectJAutoProxy public class Log { private static final Logger log = LoggerFactory.getLogger(Log.class); @Pointcut("execution(* cn.doooog.mybatisplus.controller.*.*(..))") private void cut() { } @Before("cut()") public void before(JoinPoint point) { //获得方法签名 Signature signature = point.getSignature(); //获得业务方法名 String name = signature.getName(); //获得业务方法所在控制器类的信息 String className = signature.getDeclaringTypeName(); //把上述信息写入日志文件中 log.info("业务方法前执行:"); log.info("业务方法:{}", className + "." + name); log.info("业务方法参数:{}", point.getArgs()); //以下可以用来记录获取访问本服务端应用的客户端信息 ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { //获得请求对象 HttpServletRequest request = requestAttributes.getRequest(); //获得请求地址 String url = request.getRequestURL().toString(); //获得客户端IP地址 String ip = request.getRemoteAddr(); log.info("客户端IP地址:{}", url); log.info("请求地址:{}", ip); } } } ``` ## 二、AOP应用全局异常处理器 #### 1、思路 * 定义全局异常处理器GlobalExceptionDeal * 类前使用注解@ControllerAdvice(该注解Wie组合注解,等价于@ControllerAdvice和@ResponseBody) * 类中方法前需要加两个主机诶 * 第一:@ExceptionHandler, 参数为异常类型字节码 * 第二:@ResponseStatus, 参数为Http状态码 ```txt 例如:HttpStatus.Internal_Server_Error = 500 HttpStatus.Bad_Request = 400 ``` #### 2、创建GlobalExceptionDeal类 ```java package cn.doooog.function02; import cn.doooog.po.ResponseResult; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionDeal { // 空指针异常 @ExceptionHandler(NullPointerException.class) @ResponseStatus(value= HttpStatus.INTERNAL_SERVER_ERROR) public ResponseResult dealNullException(){ ResponseResult rb=new ResponseResult(500,"空指针异常"); return rb; } } ``` #### 3、创建ResponseResult类 ```java package cn.doooog.po; //全局响应数据结构,作用和Map类似,用于封装数据状态 public class ResponseResult<T> { // T是泛型,代表任意数据类型 private T data; // 数据状态码 private Integer status; // 数据状态信息 private String msg; // 操作成功,能取到业务数据 public ResponseResult(T data) { super(); this.data = data; this.status=200; this.msg="success"; } // 操作失败 public ResponseResult(Integer status, String msg) { super(); this.status = status; this.msg = msg; } // 属性设置器 public T getData() { return data; } public void setData(T data) { this.data = data; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } ``` #### 4、发生异常后写入LogAOP日志文件,在AOP中加入异常通知 ```java package cn.doooog.function01; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Component: 将该类标记为Spring的组件,使其能够被Spring容器扫描并管理。 * @Aspect: 标识该类为一个切面类,用于定义切点和通知方法。 * @EnableAspectJAutoProxy: 启用AspectJ自动代理功能,使切面能够正常工作。 */ @Component @Aspect @EnableAspectJAutoProxy public class LogAOP { private static final Logger log=LoggerFactory.getLogger(LogAOP.class); /** * 作用: 定义切点 * 格式: execution(访问修饰符 返回值类型 包名.类名.方法名(参数列表)) */ @Pointcut("execution(* cn.doooog.controller.*.*(..))") public void cut(){ } // 异常抛出通知方法 @AfterThrowing(value="cut()",throwing="ex") public void dealException(JoinPoint jp,Exception ex){ log.debug("异常信息:",ex); } } ``` # Redis #### 一、启动Redis服务 ``` redis-server redis.windows.conf ``` #### 二、导入Redis依赖 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` #### 三、配置Redis连接 #### 1、添加信息 修改`application.properties` ```properties spring.data.redis.host=localhost spring.data.redis.port=6379 # 1~16 spring.data.redis.database=0 ``` #### 2、创建配置类 ```java package cn.doooog.mybatisplus.util; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisTemplateConfig { /** * redisTemplate 不可更改名称 */ @Bean public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisFactory){ RedisTemplate<String,Object> redis = new RedisTemplate<>(); redis.setConnectionFactory(redisFactory); /*配置键序列化*/ StringRedisSerializer keySerializer = new StringRedisSerializer(); /*配置值序列化*/ Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class); redis.setKeySerializer(keySerializer); redis.setValueSerializer(valueSerializer); return redis; } } ``` #### 四、创建DAO层 新建`dao`、`dao.impl`包 #### 1、创建`Redis.java`接口 ```java package cn.doooog.mybatisplus.dao; public interface Redis { // 存数据 void save(String key,Object value); // 存数据并设置过期时间 // TimeUnit.SECONDS等 void save(String key, Object value, long time, TimeUnit timeUnit); // 取数据 Object get(String key); // 删除数据并返回删除的数据 Object delete(String key); } ``` #### 2、创建`RedisImpl.java`类 ```java package cn.doooog.mybatisplus.dao.impl; import cn.doooog.mybatisplus.dao.Redis; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository public class RedisImpl implements Redis { @Autowired private RedisTemplate<String,Object> redisTemplate; @Override public void save(String key, Object value) { redisTemplate.opsForValue().set(key,value); } @Override public void save(String key, Object value, long time, TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, time, timeUnit); } @Override public Object get(String key) { return redisTemplate.opsForValue().get(key); } @Override public Object delete(String key) { return redisTemplate.opsForValue().getAndDelete(key); } } ``` 最后修改:2025 年 11 月 04 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 👆请简单粗暴地爱我。