【项目实战】从零到一搭建Spring Boot整合Mybatis()

  本篇文章为你整理了【项目实战】从零到一搭建Spring Boot整合Mybatis()的详细内容,包含有 【项目实战】从零到一搭建Spring Boot整合Mybatis,希望能帮助你了解 【项目实战】从零到一搭建Spring Boot整合Mybatis。

   大象只为你

  
 

   追求梦想有时会遇到不顺,请坚持!我相信下一站会更好,come on , Elephant !

  
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:///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

  

 parent 

 

   groupId org.springframework.boot /groupId

   artifactId spring-boot-starter-parent /artifactId

   version 2.6.13 /version

   relativePath/ !-- lookup parent from repository --

   /parent

   properties

   !-- Spring Cloud --

   spring.cloud.version 2021.0.5 /spring.cloud.version

   !-- Spring Boot --

   spring.boot.version 2.6.13 /spring.boot.version

   !-- Swagger --

   knife4j.spring.boot.version 2.0.8 /knife4j.spring.boot.version

   /properties

   dependencyManagement

   dependencies

   dependency

   groupId org.springframework.boot /groupId

   artifactId spring-boot-dependencies /artifactId

   version ${spring.boot.version} /version

   type pom /type

   scope import /scope

   /dependency

   dependency

   groupId org.springframework.cloud /groupId

   artifactId spring-cloud-dependencies /artifactId

   version ${spring.cloud.version} /version

   type pom /type

   scope import /scope

   /dependency

   !--Swagger--

   dependency

   groupId com.github.xiaoymin /groupId

   artifactId knife4j-micro-spring-boot-starter /artifactId

   version ${knife4j.spring.boot.version} /version

   /dependency

   /dependencies

   /dependencyManagement

  

 

  二、添加子模块demo-service

  1、Spring Boot Api Test

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

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

  

 dependencies 

 

   dependency

   groupId org.springframework.boot /groupId

   artifactId spring-boot-starter-web /artifactId

   /dependency

   !--actuator-应用健康监测 --

   dependency

   groupId org.springframework.boot /groupId

   artifactId spring-boot-starter-actuator /artifactId

   /dependency

   !--Swagger--

   dependency

   groupId com.github.xiaoymin /groupId

   artifactId knife4j-micro-spring-boot-starter /artifactId

   /dependency

   /dependencies

  

 

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

  

package com.elephant.demo;

 

  import lombok.extern.slf4j.Slf4j;

  import org.springframework.boot.SpringApplication;

  import org.springframework.boot.autoconfigure.SpringBootApplication;

   * @author xiufen.huang

   * @description:

   * @date 2023-01-08-18:38

  @Slf4j

  @SpringBootApplication

  public class DemoApplication {

   public static void main(String[] args) {

   SpringApplication.run(DemoApplication.class, args);

   log.info("========================= elephant-demo-启动成功 ==========================");

  

 

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

  添加application.yml,设置端口8071

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

  

package com.elephant.demo.controller;

 

  import io.swagger.annotations.Api;

  import io.swagger.annotations.ApiOperation;

  import lombok.RequiredArgsConstructor;

  import lombok.extern.slf4j.Slf4j;

  import org.springframework.web.bind.annotation.GetMapping;

  import org.springframework.web.bind.annotation.RequestMapping;

  import org.springframework.web.bind.annotation.RestController;

   * @author xiufen.huang

   * @description:

   * @date 2023-01-08-18:47

  @Api(value = "TestController", tags = "测试Controller")

  @Slf4j

  @RestController

  @RequestMapping("/test")

  @RequiredArgsConstructor

  public class TestController {

   @ApiOperation(value = "测试接口")

   @GetMapping("/index")

   public String test() {

   return "ok";

  

 

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

  2、整合Mybatis-plus

  2.1、正常的pom引入说明

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

  

 properties 

 

   mybatis.plus.version 3.5.2 /mybatis.plus.version

   mysql.connector.version 8.0.31 /mysql.connector.version

   /properties

   !--Mybatis-plus-start--

   dependency

   groupId com.baomidou /groupId

   artifactId mybatis-plus-boot-starter /artifactId

   version ${mybatis.plus.version} /version

   /dependency

   !--Mybatis-plus-end--

   !-- MySql --

   dependency

   groupId mysql /groupId

   artifactId mysql-connector-java /artifactId

   version ${mysql.connector.version} /version

   /dependency

  

 

  2.2、正常的yaml配置

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

  

#mybatis-plus配置

 

  mybatis-plus:

   mapper-locations: classpath:com/elephant/demo/**/mapper/*Mapper.xml

   #实体扫描,多个package用逗号或者分号分隔

   type-aliases-package: com.elephant.demo.**.entity

   configuration:

   # 驼峰转换 从数据库列名到Java属性驼峰命名的类似映射

   map-underscore-to-camel-case: true

   # 打印sql

   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  

 

  数据库连接配置

  

spring:

 

   application:

   # 应用名称

   name: elephant-demo

   datasource:

   driver-class-name: com.mysql.cj.jdbc.Driver

   # 换成自己的配置

   url: jdbc:mysql://127.0.0.1:3306/test

   username: root

   password: 123456

  

 

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

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

  

# 创建表语句

 

  CREATE TABLE `ft_order` (

   `id` varchar(32) NOT NULL COMMENT 主键,

   `create_user` varchar(32) DEFAULT NULL COMMENT 创建人,

   `create_time` datetime DEFAULT NULL COMMENT 创建时间,

   `update_user` varchar(32) DEFAULT NULL COMMENT 更新人,

   `update_time` datetime DEFAULT NULL COMMENT 更新时间,

   `status` int DEFAULT NULL COMMENT 业务状态: 0-正常, 1-已删除,

   `is_deleted` bit(1) DEFAULT b0 COMMENT 是否删除,

   `order_no` varchar(50) DEFAULT NULL COMMENT 订单编号,

   `customer_name` varchar(100) DEFAULT NULL COMMENT 客户名称,

   `customer_email` varchar(100) DEFAULT NULL COMMENT 客户邮箱,

   `product_status` int DEFAULT NULL COMMENT 货品状态: 1-备车中,2-出口手续办理中,3-转移待出口(手续办理完成),4-报关完成,5-车辆达到指定港口,6-运输中,7-已抵达,8-确认收货,

   `remark` varchar(256) DEFAULT NULL COMMENT 备注,

   PRIMARY KEY (`id`),

   KEY `idx_customer_name` (`customer_name`) USING BTREE,

   KEY `idx_order_no_email_name` (`order_no`,`customer_email`,`customer_name`) USING BTREE COMMENT PC后台查询组合索引,

   KEY `idx_customer_email_name` (`customer_email`,`customer_name`) USING BTREE

  )COMMENT=外贸订单信息;

  

 

  测试初始化数据

  

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, b0, TEST20230103001, Jack, test1@test.com, NULL, NULL);

 

  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, b0, TEST20230104001, Jack, test1@test.com, NULL, NULL);

  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, b0, TEST20230104002, Jack, test1@test.com, NULL, NULL);

  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, b0, TEST20230104003, Jack, test1@test.com, NULL, NULL);

  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, b0, TEST20230104004, Jack, test1@test.com, NULL, NULL);

  

 

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

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

  

 properties 

 

   mybatis.plus.dynamic.version 3.5.2 /mybatis.plus.dynamic.version

   /properties

   !-- 动态数据源-start --

   dependency

   groupId com.baomidou /groupId

   artifactId dynamic-datasource-spring-boot-starter /artifactId

   version ${mybatis.plus.dynamic.version} /version

   /dependency

   !-- 动态数据源-end --

  

 

  2.5、动态数据源的yaml配置

  

# 动态数据源

 

  # pom 引入 dynamic-datasource-spring-boot-starter

  spring:

   application:

   # 应用名称

   name: elephant-demo

   datasource:

   dynamic:

   primary: master #设置默认的数据源或者数据源组,默认值即为master

   strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源

   datasource:

   master:

   driver-class-name: com.mysql.cj.jdbc.Driver

   url: jdbc:mysql://127.0.0.1:3306/test

   username: root

   password: 123456

   slave:

   driver-class-name: com.mysql.cj.jdbc.Driver

   url: jdbc:mysql://127.0.0.1:3306/test

   username: root

   password: 123456

  

 

  3、示例代码说明

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

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

  3.1.Dao层代码

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

  

/**

 

   * @author xiufen.huang

   * @description:

   * @date 2022-12-21-15:38

  public interface IOrderRepository extends IService Order {

   * 获取订单信息

   * @param orderId 订单id

   * @return com.elephant.demo.model.entity.Order

   * @author xiufen.huang

   * @date 2023-01-19 11:01

   Order getById(String orderId);

   * 订单分页列表

   * @param param 查询参数

   * @return com.baomidou.mybatisplus.core.metadata.IPage com.elephant.demo.model.vo.OrderPageVo

   * @author xiufen.huang

   * @date 2023-01-19 11:01

   IPage OrderPageVo getOrderPage(OrderPageParam param);

   * 保存订单数据

   * @param param

   * @return java.lang.Boolean

   * @author xiufen.huang

   * @date 2022-12-16 15:50

   Boolean saveOrder(OrderCreateParam param);

  

 

  OrderRepositoryImpl 代码如下:

  

@Slf4j

 

  @Service

  public class OrderRepositoryImpl extends ServiceImpl OrderMapper, Order implements IOrderRepository {

   // 后面分开讲解

  

 

  3.2.单个查询

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

  

@Override

 

  public Order getById(String orderId) {

   Order order = this.baseMapper.selectById(orderId);

   return order;

  

 

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

  3.3.订单分页列表

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

  OrderMapper 代码如下

  

public interface OrderMapper extends BaseMapper Order {

 

   IPage OrderPageVo getOrderPage(Page page, @Param("param") OrderPageParam param);

  

 

  OrderMapper .xml代码如下

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   !DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"

   mapper namespace="com.elephant.demo.repository.mapper.OrderMapper"

   select id="getOrderPage" resultType="com.elephant.demo.model.vo.OrderPageVo"

   select fto.id,

   fto.create_time,

   fto.update_time,

   fto.`status`,

   fto.order_no,

   fto.customer_name,

   fto.customer_email,

   fto.product_status

   from ft_order fto

   where fto.is_deleted=0

   if test="param.searchWord != null and param.searchWord !="

   and (

   fto.order_no like concat(%,#{param.searchWord},%)

   or fto.customer_email like concat(%,#{param.searchWord},%)

   or fto.customer_name like concat(%,#{param.searchWord},%)

   /if

   order by fto.create_time desc

   /select

   /mapper

  

 

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

  

@Override

 

  public IPage OrderPageVo getOrderPage(OrderPageParam param) {

   Page page = new Page(param.getPage().getCurrent(), param.getPage().getSize());

   return baseMapper.getOrderPage(page, param);

  

 

  3.4.保存订单数据

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

  

@Override

 

  public Boolean saveOrder(OrderCreateParam param) {

   // 参数赋值

   Order order = new Order();

   order.setOrderNo(param.getOrderNo());

   order.setCustomerName(param.getCustomerName());

   order.setCustomerEmail(param.getCustomerEmail());

   order.setCreateTime(new Date());

   order.setUpdateTime(new Date());

   // 订单创建时,默认是0-正常

   order.setStatus(0);

   // 持久化数据

   return this.save(order);

  

 

  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配置

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   configuration scan="true" scanPeriod="60 seconds" debug="true"

   参考博客:https://blog.csdn.net/weixin_43790613/article/details/109428318

   1. scan:程序运行时配置文件被修改,是否重新加载。true=重新加载;false=不重新加载;默认为true;

   2. scanPeriod:监测配置文件被修改的时间间隔,scan属性必须设置为true才可生效;默认为1分钟,默认单位是毫秒;

   3. debug:是否打印logback程序运行的日志信息。true=打印;false=不打印;默认为false;

   contextName logback /contextName

   !-- 路径变量,当前项目所在目录下 --

   property name="log.path" value="/log/demo/logback.log" /

   !-- 日志格式变量 --

   property name="logPattern" value="%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} %file:%line - %msg%n" /

   1. %d{HH:mm:ss.SSS} 显示的时间

   2. [%thread]打印线程号,log4j2使用%t]也可以

   3. %-5level日志级别,并且使用5个字符靠左对齐

   4. %logger{36}——日志输出者的名字,即类的类名

   5. %file 打印类名,也可用%class,打印的全限定类名

   6. %line 打印日志所在代码行数

   7. %msg——日志消息

   8. %n——平台的换行符--

   !--输出到控制台--

   appender name="console"

   !-- filter

   level ERROR /level

   /filter --

   encoder

   pattern ${logPattern} /pattern

   /encoder

   /appender

   !--输出到文件--

   appender name="file"

   file ${log.path} /file

   !--输出到文件路径一种滚动策略:根据时间制定日志文件的滚动策略,如:按天、按小时、按分钟生成日志文件 --

   rollingPolicy

   !-- 文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 --

   fileNamePattern ${log.path}/%d{yyyy-MM-dd}.log.gz /fileNamePattern

   !-- 日志在磁盘上保留天数 --

   maxHistory 30 /maxHistory

   /rollingPolicy

   !-- 另一种滚动策略:表示根据日志文件大小,超过制定大小会触发日志滚动; --

   triggeringPolicy

   maxFileSize 5MB /maxFileSize

   /triggeringPolicy

   encoder

   pattern ${logPattern} /pattern

   filter

   level ERROR /level

   /filter

   ThresholdFilter为系统定义的拦截器,例如我们用ThresholdFilter来过滤掉ERROR级别以下的日志不输出到文件中。如果不用记得注释掉,不然你控制台会发现没日志~

   !-- 设置字符集 --

   charset UTF-8 /charset

   /encoder

   /appender

   !-- 把日志异步输出到磁盘文件中,避免每次都进行磁盘IO操作 --

   appender name="ASYNC"

   discardingThreshold 0 /discardingThreshold

   queueSize 10000 /queueSize

   appender-ref ref="file" /

   /appender

   root level="info"

   appender-ref ref="console" /

   appender-ref ref="ASYNC" /

   /root

   /configuration

  

 

  4.2.application.yml添加配置

  

# 日志配置

 

  logging:

   config: classpath:logback-spring.xml

  

 

  三、源码地址

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

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

  
感谢您的阅读,如果对您有帮助,请支持我!请点[推荐]

  如果有意见或建议,欢迎留言交流!

  欢迎转载,请保留出处,【大象只为你】感谢您的关注与支持!

  以上就是【项目实战】从零到一搭建Spring Boot整合Mybatis()的详细内容,想要了解更多 【项目实战】从零到一搭建Spring Boot整合Mybatis的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: