经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MyBatis » 查看文章
【项目实战】从零到一搭建Spring Boot整合Mybatis-plus
来源:cnblogs  作者:大象只为你  时间:2023/1/20 8:40:19  对本文有异议

前言

2023年想搭建一套属于自己的框架,做一个属于自己想法的项目。这些年工作中一直用公司已有的框架,以前有跟着学习视频搭建过,但自己真正动手搭建时发现问题还是很多,比如没有引入Mybatis-plus包之前,项目api test是成功的,引入Mybatis-plus包后就一直启动不成功,而且异常信息也不抛出,后引入actuator应用健康监测才抛异常信息排查解决。我会下面文中说明为什么引入这个pom作用是什么,pom引入的每个包都有其作用,而不是照搬别人的框架过来,引入不必要的包。

看该文章前需要了解maven pom结构,idea创建一个项目的步骤,spring boot知识,往下阅读默认都具备了。

环境说明:idea2022.3 ,jdk17 ,maven 3.6.3,mysql-8.0.31

一、创建一个maven空项目

项目创建步骤不截图了,默认大家懂了。创建一个空maven项目目的是作为父级引入公用的一些,一般企业级的项目都是这样的结构,当然如果想简单一点,该步骤也是可以省略掉的。

创建出来把一些不要的包,文件都删除掉,目录结构如下图

1、确定spring boot版本号

因为我后面是要实现微服务框架项目,所以在选择Spring Boot版本号是与Spring Cloud是对应的。(最开始我是选择Spring Boot最新版本号3.0.0,但发现在整合Mybatis-Plus 3.5.2出现很多问题,主要是spring boot 3.0自动注入方式改变,原因说明可参考博客:Spring Boot3.0升级,踩坑之旅,附解决方案 :https://www.cnblogs.com/wayn111/p/16950025.html)

访问spring官网https://spring.io,选择projects下 Spring Cloud 右侧Learn ,目前最新版本是2022.0.0GA(上面已有说明不选择最新版),往下找第一个GA版本2021.0.5。


2 、pom整理

关键Spring Boot pom定义如下,完整pom定义详见示例源码。

方便后面Api定义的声明,增加引入Swagger

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.6.13</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <properties>
  8. <!-- Spring Cloud -->
  9. <spring.cloud.version>2021.0.5</spring.cloud.version>
  10. <!-- Spring Boot -->
  11. <spring.boot.version>2.6.13</spring.boot.version>
  12. <!-- Swagger -->
  13. <knife4j.spring.boot.version>2.0.8</knife4j.spring.boot.version>
  14. </properties>
  15. <dependencyManagement>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-dependencies</artifactId>
  20. <version>${spring.boot.version}</version>
  21. <type>pom</type>
  22. <scope>import</scope>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.cloud</groupId>
  26. <artifactId>spring-cloud-dependencies</artifactId>
  27. <version>${spring.cloud.version}</version>
  28. <type>pom</type>
  29. <scope>import</scope>
  30. </dependency>
  31. <!--Swagger-->
  32. <dependency>
  33. <groupId>com.github.xiaoymin</groupId>
  34. <artifactId>knife4j-micro-spring-boot-starter</artifactId>
  35. <version>${knife4j.spring.boot.version}</version>
  36. </dependency>
  37. </dependencies>
  38. </dependencyManagement>

二、添加子模块demo-service

1、Spring Boot Api Test

关键pom引入,就可以进行api test,完整pom定义详见示例源码。

添加spring-boot-starter-web是web应用需要的包,Controller等相关,spring-boot-starter-actuator 是Spring Boot应用健康监测,如果应用有异常可以捕获到,供我们排查。

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <!--actuator-应用健康监测 -->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-actuator</artifactId>
  10. </dependency>
  11. <!--Swagger-->
  12. <dependency>
  13. <groupId>com.github.xiaoymin</groupId>
  14. <artifactId>knife4j-micro-spring-boot-starter</artifactId>
  15. </dependency>
  16. </dependencies>

代码层面自己手动加package: com.elephant.demo , 创建启动类DemoApplication,代码如下:

  1. package com.elephant.demo;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. /**
  6. * @author xiufen.huang
  7. * @description:
  8. * @date 2023-01-08-18:38
  9. */
  10. @Slf4j
  11. @SpringBootApplication
  12. public class DemoApplication {
  13. public static void main(String[] args) {
  14. SpringApplication.run(DemoApplication.class, args);
  15. log.info("========================= elephant-demo-启动成功 ==========================");
  16. }
  17. }

点击试运行,从控制台的日志来看已成功。端口暂时没有设置默认8080。

添加application.yml,设置端口8071

添加测试Controller类:TestController,代码如下:

  1. package com.elephant.demo.controller;
  2. import io.swagger.annotations.Api;
  3. import io.swagger.annotations.ApiOperation;
  4. import lombok.RequiredArgsConstructor;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. /**
  10. * @author xiufen.huang
  11. * @description:
  12. * @date 2023-01-08-18:47
  13. */
  14. @Api(value = "TestController", tags = "测试Controller")
  15. @Slf4j
  16. @RestController
  17. @RequestMapping("/test")
  18. @RequiredArgsConstructor
  19. public class TestController {
  20. @ApiOperation(value = "测试接口")
  21. @GetMapping("/index")
  22. public String test() {
  23. return "ok";
  24. }
  25. }

api test访问 http://127.0.0.1:8071/test/index ,响应成功ok,

2、整合Mybatis-plus

2.1、正常的pom引入说明

数据库采用mysql,mybatis-plus选择版本号3.5.2 ,只需要引入两个包即可。

  1. <properties>
  2. <mybatis.plus.version>3.5.2</mybatis.plus.version>
  3. <mysql.connector.version>8.0.31</mysql.connector.version>
  4. </properties>
  5. <!--Mybatis-plus-start-->
  6. <dependency>
  7. <groupId>com.baomidou</groupId>
  8. <artifactId>mybatis-plus-boot-starter</artifactId>
  9. <version>${mybatis.plus.version}</version>
  10. </dependency>
  11. <!--Mybatis-plus-end-->
  12. <!-- MySql -->
  13. <dependency>
  14. <groupId>mysql</groupId>
  15. <artifactId>mysql-connector-java</artifactId>
  16. <version>${mysql.connector.version}</version>
  17. </dependency>

2.2、正常的yaml配置

mybatis-plus配置,mapper.xml,实体扫描,打印sql

  1. #mybatis-plus配置
  2. mybatis-plus:
  3. mapper-locations: classpath:com/elephant/demo/**/mapper/*Mapper.xml
  4. #实体扫描,多个package用逗号或者分号分隔
  5. type-aliases-package: com.elephant.demo.**.entity
  6. configuration:
  7. # 驼峰转换 从数据库列名到Java属性驼峰命名的类似映射
  8. map-underscore-to-camel-case: true
  9. # 打印sql
  10. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

数据库连接配置

  1. spring:
  2. application:
  3. # 应用名称
  4. name: elephant-demo
  5. datasource:
  6. driver-class-name: com.mysql.cj.jdbc.Driver
  7. # 换成自己的配置
  8. url: jdbc:mysql://127.0.0.1:3306/test
  9. username: root
  10. password: 123456

2.3、测试的建表脚本和数据

我的测试表是订单表,仅针对功能测试使用,不一定按我的,我把建表脚本提供和初始化脚本提供出来。方便如果下载我的demo代码可以初始化后,修改下配置即可运行。在resources/ sql下。

  1. # 创建表语句
  2. CREATE TABLE `ft_order` (
  3. `id` varchar(32) NOT NULL COMMENT '主键',
  4. `create_user` varchar(32) DEFAULT NULL COMMENT '创建人',
  5. `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  6. `update_user` varchar(32) DEFAULT NULL COMMENT '更新人',
  7. `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  8. `status` int DEFAULT NULL COMMENT '业务状态: 0-正常, 1-已删除',
  9. `is_deleted` bit(1) DEFAULT b'0' COMMENT '是否删除',
  10. `order_no` varchar(50) DEFAULT NULL COMMENT '订单编号',
  11. `customer_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
  12. `customer_email` varchar(100) DEFAULT NULL COMMENT '客户邮箱',
  13. `product_status` int DEFAULT NULL COMMENT '货品状态: 1-备车中,2-出口手续办理中,3-转移待出口(手续办理完成),4-报关完成,5-车辆达到指定港口,6-运输中,7-已抵达,8-确认收货',
  14. `remark` varchar(256) DEFAULT NULL COMMENT '备注',
  15. PRIMARY KEY (`id`),
  16. KEY `idx_customer_name` (`customer_name`) USING BTREE,
  17. KEY `idx_order_no_email_name` (`order_no`,`customer_email`,`customer_name`) USING BTREE COMMENT 'PC后台查询组合索引',
  18. KEY `idx_customer_email_name` (`customer_email`,`customer_name`) USING BTREE
  19. )COMMENT='外贸订单信息';

测试初始化数据

  1. INSERT INTO `ft_order`(`id`, `create_user`, `create_time`, `update_user`, `update_time`, `status`, `is_deleted`, `order_no`, `customer_name`, `customer_email`, `product_status`, `remark`) VALUES ('1001', NULL, '2023-01-03 15:18:46', NULL, '2023-01-03 15:18:49', 0, b'0', 'TEST20230103001', 'Jack', 'test1@test.com', NULL, NULL);
  2. INSERT INTO `ft_order`(`id`, `create_user`, `create_time`, `update_user`, `update_time`, `status`, `is_deleted`, `order_no`, `customer_name`, `customer_email`, `product_status`, `remark`) VALUES ('1002', NULL, '2023-01-04 16:18:49', NULL, '2023-01-04 16:18:49', 0, b'0', 'TEST20230104001', 'Jack', 'test1@test.com', NULL, NULL);
  3. INSERT INTO `ft_order`(`id`, `create_user`, `create_time`, `update_user`, `update_time`, `status`, `is_deleted`, `order_no`, `customer_name`, `customer_email`, `product_status`, `remark`) VALUES ('1003', NULL, '2023-01-04 17:18:49', NULL, '2023-01-04 17:18:49', 0, b'0', 'TEST20230104002', 'Jack', 'test1@test.com', NULL, NULL);
  4. INSERT INTO `ft_order`(`id`, `create_user`, `create_time`, `update_user`, `update_time`, `status`, `is_deleted`, `order_no`, `customer_name`, `customer_email`, `product_status`, `remark`) VALUES ('1004', NULL, '2023-01-04 18:18:49', NULL, '2023-01-04 18:18:49', 0, b'0', 'TEST20230104003', 'Jack', 'test1@test.com', NULL, NULL);
  5. INSERT INTO `ft_order`(`id`, `create_user`, `create_time`, `update_user`, `update_time`, `status`, `is_deleted`, `order_no`, `customer_name`, `customer_email`, `product_status`, `remark`) VALUES ('1005', NULL, '2023-01-04 19:18:49', NULL, '2023-01-04 19:18:49', 0, b'0', 'TEST20230104004', 'Jack', 'test1@test.com', NULL, NULL);

2.4、动态数据源的pom引入说明

如果想采用动态数据源,再引入这个pom包

  1. <properties>
  2. <mybatis.plus.dynamic.version>3.5.2</mybatis.plus.dynamic.version>
  3. </properties>
  4. <!-- 动态数据源-start -->
  5. <dependency>
  6. <groupId>com.baomidou</groupId>
  7. <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  8. <version>${mybatis.plus.dynamic.version}</version>
  9. </dependency>
  10. <!-- 动态数据源-end -->

2.5、动态数据源的yaml配置

  1. # 动态数据源
  2. # pom 引入 dynamic-datasource-spring-boot-starter
  3. spring:
  4. application:
  5. # 应用名称
  6. name: elephant-demo
  7. datasource:
  8. dynamic:
  9. primary: master #设置默认的数据源或者数据源组,默认值即为master
  10. strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
  11. datasource:
  12. master:
  13. driver-class-name: com.mysql.cj.jdbc.Driver
  14. url: jdbc:mysql://127.0.0.1:3306/test
  15. username: root
  16. password: 123456
  17. slave:
  18. driver-class-name: com.mysql.cj.jdbc.Driver
  19. url: jdbc:mysql://127.0.0.1:3306/test
  20. username: root
  21. password: 123456

3、示例代码说明

由于代码比较多不一一贴出来,主要代码贴出来做说明。代码结构做一下说明,是采用4层结构,多了一层业务实现层是为了避免后面业务复杂了,出现循环依赖的情况。具体是用3层还是4层可以按需。

本次示例给出3个:根据主键查询,分页列表查询,保存订单数据。

3.1.Dao层代码

接口继承IService ,实现类继承 ServiceImpl<OrderMapper, Order>。IOrderRepository 代码如下:

  1. /**
  2. * @author xiufen.huang
  3. * @description:
  4. * @date 2022-12-21-15:38
  5. */
  6. public interface IOrderRepository extends IService<Order> {
  7. /**
  8. * 获取订单信息
  9. * @param orderId 订单id
  10. * @return com.elephant.demo.model.entity.Order
  11. * @author xiufen.huang
  12. * @date 2023-01-19 11:01
  13. */
  14. Order getById(String orderId);
  15. /**
  16. * 订单分页列表
  17. * @param param 查询参数
  18. * @return com.baomidou.mybatisplus.core.metadata.IPage<com.elephant.demo.model.vo.OrderPageVo>
  19. * @author xiufen.huang
  20. * @date 2023-01-19 11:01
  21. */
  22. IPage<OrderPageVo> getOrderPage(OrderPageParam param);
  23. /**
  24. * 保存订单数据
  25. * @param param
  26. * @return java.lang.Boolean
  27. * @author xiufen.huang
  28. * @date 2022-12-16 15:50
  29. */
  30. Boolean saveOrder(OrderCreateParam param);
  31. }

OrderRepositoryImpl 代码如下:

  1. @Slf4j
  2. @Service
  3. public class OrderRepositoryImpl extends ServiceImpl<OrderMapper, Order> implements IOrderRepository {
  4. // 后面分开讲解
  5. }

3.2.单个查询

比如根据主键查询,可以用Mybatis提供封装好的方法selectById() 。具体代码实现如下

  1. @Override
  2. public Order getById(String orderId) {
  3. Order order = this.baseMapper.selectById(orderId);
  4. return order;
  5. }

Service,Controller的代码只需要调用一下即可,实际业务场景再根据需要做一些处理。

3.3.订单分页列表

实现思路:构造分页参数,具体查询实现在Mapper.xml用原生的sql结合动态参数。比如我的场景:根据关键词(订单号/客户名称/客户邮箱)查询订单数据。

OrderMapper 代码如下

  1. public interface OrderMapper extends BaseMapper<Order> {
  2. IPage<OrderPageVo> getOrderPage(Page page, @Param("param") OrderPageParam param);
  3. }

OrderMapper .xml代码如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.elephant.demo.repository.mapper.OrderMapper">
  4. <select id="getOrderPage" resultType="com.elephant.demo.model.vo.OrderPageVo">
  5. select fto.id,
  6. fto.create_time,
  7. fto.update_time,
  8. fto.`status`,
  9. fto.order_no,
  10. fto.customer_name,
  11. fto.customer_email,
  12. fto.product_status
  13. from ft_order fto
  14. where fto.is_deleted=0
  15. <if test="param.searchWord != null and param.searchWord !=''">
  16. and (
  17. fto.order_no like concat('%',#{param.searchWord},'%')
  18. or fto.customer_email like concat('%',#{param.searchWord},'%')
  19. or fto.customer_name like concat('%',#{param.searchWord},'%')
  20. )
  21. </if>
  22. order by fto.create_time desc
  23. </select>
  24. </mapper>

OrderRepositoryImpl的代码实现就比较简单了,调整下即可,代码如下

  1. @Override
  2. public IPage<OrderPageVo> getOrderPage(OrderPageParam param) {
  3. Page page = new Page(param.getPage().getCurrent(), param.getPage().getSize());
  4. return baseMapper.getOrderPage(page, param);
  5. }

3.4.保存订单数据

实现思路:把提交参数做业务校验后,把对应的字段赋给实体类,然后调用this.save(T entity)方法进行保存,id会自动赋值。OrderRepositoryImpl的代码实现如下:

  1. @Override
  2. public Boolean saveOrder(OrderCreateParam param) {
  3. // 参数赋值
  4. Order order = new Order();
  5. order.setOrderNo(param.getOrderNo());
  6. order.setCustomerName(param.getCustomerName());
  7. order.setCustomerEmail(param.getCustomerEmail());
  8. order.setCreateTime(new Date());
  9. order.setUpdateTime(new Date());
  10. // 订单创建时,默认是0-正常
  11. order.setStatus(0);
  12. // 持久化数据
  13. return this.save(order);
  14. }

4.添加日志打印

实现说明:在src/main/resources下添加日志配置logback-spring.xml,然后application.yml添加配置。

logback-spring.xml各项说明可以阅读博客:https://blog.csdn.net/weixin_43790613/article/details/109428318

4.1.logback-spring.xml配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration scan="true" scanPeriod="60 seconds" debug="true">
  3. <!--
  4. 参考博客:https://blog.csdn.net/weixin_43790613/article/details/109428318
  5. 1. scan:程序运行时配置文件被修改,是否重新加载。true=重新加载;false=不重新加载;默认为true;
  6. 2. scanPeriod:监测配置文件被修改的时间间隔,scan属性必须设置为true才可生效;默认为1分钟,默认单位是毫秒;
  7. 3. debug:是否打印logback程序运行的日志信息。true=打印;false=不打印;默认为false;
  8. -->
  9. <contextName>logback</contextName>
  10. <!-- 路径变量,当前项目所在目录下 -->
  11. <property name="log.path" value="/log/demo/logback.log" />
  12. <!-- 日志格式变量 -->
  13. <property name="logPattern" value="%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} %file:%line - %msg%n" />
  14. <!--
  15. 1. %d{HH:mm:ss.SSS} 显示的时间
  16. 2. [%thread]打印线程号,log4j2使用%t]也可以
  17. 3. %-5level日志级别,并且使用5个字符靠左对齐
  18. 4. %logger{36}——日志输出者的名字,即类的类名
  19. 5. %file 打印类名,也可用%class,打印的全限定类名
  20. 6. %line 打印日志所在代码行数
  21. 7. %msg——日志消息
  22. 8. %n——平台的换行符-->
  23. <!--输出到控制台-->
  24. <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
  25. <!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  26. <level>ERROR</level>
  27. </filter>-->
  28. <encoder>
  29. <pattern>${logPattern}</pattern>
  30. </encoder>
  31. </appender>
  32. <!--输出到文件-->
  33. <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
  34. <file>${log.path}</file>
  35. <!--输出到文件路径一种滚动策略:根据时间制定日志文件的滚动策略,如:按天、按小时、按分钟生成日志文件 -->
  36. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  37. <!-- 文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 -->
  38. <fileNamePattern>${log.path}/%d{yyyy-MM-dd}.log.gz</fileNamePattern>
  39. <!-- 日志在磁盘上保留天数 -->
  40. <maxHistory>30</maxHistory>
  41. </rollingPolicy>
  42. <!-- 另一种滚动策略:表示根据日志文件大小,超过制定大小会触发日志滚动; -->
  43. <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
  44. <maxFileSize>5MB</maxFileSize>
  45. </triggeringPolicy>
  46. <encoder>
  47. <pattern>${logPattern}</pattern>
  48. <!--
  49. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  50. <level>ERROR</level>
  51. </filter>
  52. ThresholdFilter为系统定义的拦截器,例如我们用ThresholdFilter来过滤掉ERROR级别以下的日志不输出到文件中。如果不用记得注释掉,不然你控制台会发现没日志~
  53. -->
  54. <!-- 设置字符集 -->
  55. <charset>UTF-8</charset>
  56. </encoder>
  57. </appender>
  58. <!-- 把日志异步输出到磁盘文件中,避免每次都进行磁盘IO操作 -->
  59. <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
  60. <discardingThreshold>0</discardingThreshold>
  61. <queueSize>10000</queueSize>
  62. <appender-ref ref="file" />
  63. </appender>
  64. <root level="info">
  65. <appender-ref ref="console" />
  66. <appender-ref ref="ASYNC" />
  67. </root>
  68. </configuration>

4.2.application.yml添加配置

  1. # 日志配置
  2. logging:
  3. config: classpath:logback-spring.xml

三、源码地址

上面步骤说明还是不够全面,如果是自己刚开始搭建,可能还是没什么头绪。

因此我把demo分享出来。https://gitee.com/wuqixiufen2/elephant-demo

原文链接:https://www.cnblogs.com/huangxiufen/p/17061756.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号