前言
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
org.springframework.boot spring-boot-starter-parent 2.6.13 2021.0.5 2.6.13 2.0.8 org.springframework.boot spring-boot-dependencies ${spring.boot.version} pom import org.springframework.cloud spring-cloud-dependencies ${spring.cloud.version} pom import com.github.xiaoymin knife4j-micro-spring-boot-starter ${knife4j.spring.boot.version}
二、添加子模块demo-service
1、Spring Boot Api Test
关键pom引入,就可以进行api test,完整pom定义详见示例源码。
添加spring-boot-starter-web是web应用需要的包,Controller等相关,spring-boot-starter-actuator 是Spring Boot应用健康监测,如果应用有异常可以捕获到,供我们排查。
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator com.github.xiaoymin knife4j-micro-spring-boot-starter
代码层面自己手动加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@SpringBootApplicationpublic 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")@RequiredArgsConstructorpublic class TestController { @ApiOperation(value = "测试接口") @GetMapping("/index") public String test() { return "ok"; }}
api test访问 http://127.0.0.1:8071/test/index ,响应成功ok,
2、整合Mybatis-plus2.1、正常的pom引入说明
数据库采用mysql,mybatis-plus选择版本号3.5.2 ,只需要引入两个包即可。
3.5.2 8.0.31 com.baomidou mybatis-plus-boot-starter ${mybatis.plus.version} mysql mysql-connector-java ${mysql.connector.version}
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 b'0' 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, b'0', '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, b'0', '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, b'0', '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, b'0', '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, b'0', 'TEST20230104004', 'Jack', 'test1@test.com', NULL, NULL);
2.4、动态数据源的pom引入说明
如果想采用动态数据源,再引入这个pom包
3.5.2 com.baomidou dynamic-datasource-spring-boot-starter ${mybatis.plus.dynamic.version}
2.5、动态数据源的yaml配置
# 动态数据源# pom 引入 dynamic-datasource-spring-boot-starterspring: 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。IOrderRepository 代码如下:
/** * @author xiufen.huang * @description: * @date 2022-12-21-15:38 */public interface IOrderRepository extends IService { /** * 获取订单信息 * @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 * @author xiufen.huang * @date 2023-01-19 11:01 */ IPage getOrderPage(OrderPageParam param); /** * 保存订单数据 * @param param * @return java.lang.Boolean * @author xiufen.huang * @date 2022-12-16 15:50 */ Boolean saveOrder(OrderCreateParam param);}
OrderRepositoryImpl 代码如下:
@Slf4j@Servicepublic class OrderRepositoryImpl extends ServiceImpl implements IOrderRepository { // 后面分开讲解}
3.2.单个查询
比如根据主键查询,可以用Mybatis提供封装好的方法selectById() 。具体代码实现如下
@Overridepublic 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 { IPage getOrderPage(Page page, @Param("param") OrderPageParam param);}
OrderMapper .xml代码如下
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 and ( fto.order_no like concat('%',#{param.searchWord},'%') or fto.customer_email like concat('%',#{param.searchWord},'%') or fto.customer_name like concat('%',#{param.searchWord},'%') ) order by fto.create_time desc
OrderRepositoryImpl的代码实现就比较简单了,调整下即可,代码如下
@Overridepublic IPage 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的代码实现如下:
@Overridepublic 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配置
logback <!-- ERROR --> ${logPattern} ${log.path} ${log.path}/%d{yyyy-MM-dd}.log.gz 30 5MB ${logPattern} <!-- ERROR ThresholdFilter为系统定义的拦截器,例如我们用ThresholdFilter来过滤掉ERROR级别以下的日志不输出到文件中。如果不用记得注释掉,不然你控制台会发现没日志~ --> UTF-8 0 10000
4.2.application.yml添加配置
# 日志配置logging: config: classpath:logback-spring.xml
三、源码地址
上面步骤说明还是不够全面,如果是自己刚开始搭建,可能还是没什么头绪。
因此我把demo分享出来。https://gitee.com/wuqixiufen2/elephant-demo
感谢您的阅读,如果对您有帮助,请支持我!请点[推荐]如果有意见或建议,欢迎留言交流!欢迎转载,请保留出处,【大象只为你】感谢您的关注与支持!