0%

spring-boot-demo-project

spring boot 集成 mybatisplus,druid,mongodb,redis,kfka

创建 Spring boot 项目

IDE:jetbrain idea

第一步:选择 Spring Initializr 和 jdk,点击 Next

image-20211124201153611

第二步:填写 Group 和 Artifact,Java 版本, 点击 Next

image-20211124201405624

第三步:选择项目依赖和 Spring boot 版本,这里依赖先不选择,Spring boot 版本选择 2.6.0

image-20211124202410096

第四步:选择项目地址,点击完成

image-20211124202508421

创建完成的项目结构如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Demo
│─ pom.xml
└─src
├─main
│ ├─java
│ │ └─com
│ │ └─chenpeng
│ │ └─demo
│ │ DemoApplication.java
│ │
│ └─resources
│ application.properties

└─test
└─java
└─com
└─chenpeng
└─demo
DemoApplicationTests.java

application.properties

集成 MybatisPlus + MySQL

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

framework

图 2.1 框架结构

代码托管:Gitee| Github

文档:MyBatis-Plus

数据库准备

MySQL 版本:8.0.20

创建数据库 demo

1
CREATE DATABASE `demo` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';

创建 user 表

1
2
3
4
5
6
7
8
9
10
DROP TABLE IF EXISTS `info_user`;
CREATE TABLE `info_user` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`age` int UNSIGNED NULL DEFAULT NULL,
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`gmt_create` datetime NULL DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

插入测试数据:

1
2
3
4
5
INSERT INTO `info_user`(id, name,age, email) VALUES (1, 'Jone', 18, 'test1@chenpeng.com');
INSERT INTO `info_user`(id, name,age, email) VALUES (2, 'Jack', 20, 'test2@chenpeng.com');
INSERT INTO `info_user`(id, name,age, email) VALUES (3, 'Tom', 28, 'test3@chenpeng.com');
INSERT INTO `info_user`(id, name,age, email) VALUES (4, 'Sandy', 21, 'test4@chenpeng.com');
INSERT INTO `info_user`(id, name,age, email) VALUES (5, 'Billie', 25, 'test5@chenpeng.com');

添加依赖

引入 Spring Boot Starter 父工程:

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

引入 spring-boot-starterspring-boot-starter-testmybatis-plus-boot-starterMySQLjdbc依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- Mybatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>

配置

application.yml 配置文件中添加 MySQL 数据库的相关配置:

1
2
3
4
5
6
7
8
9
spring:
application:
name: demo

datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: roote
password: chenpeng

创建配置类 MybatisPlusConfig.java,添加 @MapperScan 注解,扫描 Mapper 文件夹:

1
2
3
4
5
6
7
8
9
10
@MapperScan(basePackages = "com.chenpeng.demo.mapper")
@Configuration
public class MybatisPlusConfig {

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource getDataSource() {
return DataSourceBuilder.create().build();
}
}

编码

编写实体类 User.java

1
2
3
4
5
6
7
public class User {
private Long id;
private String name;
private Integer age;
private String email;
// constructor-method, getters and setters, tostring
}

编写Mapper类 UserMapper.java

1
2
public interface UserMapper extends BaseMapper<User> {
}

测试

添加测试类,进行功能测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;

@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(6, userList.size());
userList.forEach(System.out::println);
}
}

UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2021-11-24 21:27:31.275  INFO 26076 --- [           main] com.chenpeng.demo.SampleTest             : Started SampleTest in 2.059 seconds (JVM running for 2.909)

----- selectAll method test ------
2021-11-24 21:27:31.474 INFO 26076 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-11-24 21:27:31.603 INFO 26076 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
User{id=1, name='Jone', age=18, email='test1@chenpeng.com'}
User{id=2, name='Jack', age=20, email='test2@chenpeng.com'}
User{id=3, name='Tom', age=28, email='test3@chenpeng.com'}
User{id=4, name='Sandy', age=21, email='test4@chenpeng.com'}
User{id=5, name='Billie', age=24, email='test5@chenpeng.com'}
User{id=6, name='Neo', age=22, email='tes6@chenpeng.com'}

2021-11-24 21:27:31.680 INFO 26076 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2021-11-24 21:27:31.685 INFO 26076 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

从上面的输出可以看出,jdbc 数据源是 com.zaxxer.hikari.HikariDataSource,这是 Spring boot 2.0 开始使用的默认 DataSource,接下来我们使用 alibaba 的DruidDataSource。

配置 DruidDataSource

[参考](druid/druid-spring-boot-starter at master · alibaba/druid · GitHub)

Druid Spring Boot Starter 用于帮助你在Spring Boot项目中轻松集成Druid数据库连接池和监控。

加入依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>

配置

application.yml 配置文件中添加 Druid 数据库的相关配置:

1
2
3
4
5
6
7
8
9
10
spring:
application:
name: demo

datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: root
password: chenpeng

可以看到,添加了 type 属性,jdbc-url 换成了 url

改写配置类 MybatisPlusConfig.java

1
2
3
4
5
6
7
8
9
10
@MapperScan(basePackages = "com.chenpeng.demo.mapper")
@Configuration
public class MybatisPlusConfig {

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource getDataSource() {
return DruidDataSourceBuilder.create().build();
}
}

编码

其他组件编码不变

测试

使用之前的测试代码进行测试,查看输出

1
2
3
4
5
6
7
8
9
10
11
12
13
----- selectAll method test ------
2021-11-24 21:40:27.651 INFO 25904 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
User{id=1, name='Jone', age=18, email='test1@chenpeng.com'}
User{id=2, name='Jack', age=20, email='test2@chenpeng.com'}
User{id=3, name='Tom', age=28, email='test3@chenpeng.com'}
User{id=4, name='Sandy', age=21, email='test4@chenpeng.com'}
User{id=5, name='Billie', age=24, email='test5@chenpeng.com'}
User{id=6, name='Neo', age=22, email='tes6@chenpeng.com'}

2021-11-24 21:40:27.806 INFO 25904 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
2021-11-24 21:40:27.812 INFO 25904 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed

Process finished with exit code 0

可以看到,数据源已经变为 com.alibaba.druid.pool.DruidDataSource

集成 MongoDB

有一些数据的最佳表现形式是文档(document)。也就是说,不要把这些数据分散到多个表、节点或实体中,将这些信息收集到一个非规范化(也就是文档)的结构中会更有意义。尽管两个或两个以上的文档有可能会彼此产生关联,但是通常来讲,文档是独立的实体。能够按照这种方式优化并处理文档的数据库,我们称之为文档数据库。

例如,假设我们要编写一个应用程序来获取大学生的成绩单,可能需要根据学生的名字来查询其成绩单,或者根据一些通用的属性来查询成绩单。但是,每个学生是相互独立的,任意的两个成绩单之间没有必要相互关联。尽管我们能够使用关系型数据库模式来获取成绩单数据(也许你曾经这样做过),但文档型数据库可能才是更好的方案。

了解文档型数据库能够用于什么场景是很重要的。但是,知道文档型数据库在什么情况下不适用同样也是很重要的。文档数据库不是通用的数据库,它们所擅长解决的是一个很小的问题集。

有些数据具有明显的关联关系,文档型数据库并没有针对存储这样的数据进行优化。例如,社交网络表现了应用中不同的用户之间是如何建立关联的,这种情况就不适合放到文档型数据库中。在文档数据库中存储具有丰富关联关系的数据也并非完全不可能,但这样做的话,你通常会发现遇到的挑战要多于所带来的收益。

MongoDB 是最为流行的开源文档数据库之一。Spring Data MongoDB 提供了三种方式在 Spring 应用中使用 MongoDB:

  • 通过注解实现对象-文档映射;
  • 使用 MongoTemplate 实现基于模板的数据库访问;
  • 自动化的运行时 Repository 生成功能。

在使用这些特性之前,我们首先要配置 Spring Data MongoDB。

配置 MongoDB

第一步:添加依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

第二步:在 application.yml 添加配置

1
2
3
4
5
spring:
# data config
data:
mongodb:
uri: mongodb://chenpeng:chenpeng@localhost:27017/demo

我们不需要配置 MongoClient,因为 Spring boot 的自动配置会为我们生成了客户端,并且生成了一个 MongoTemplate bean,实现基于模板的数据库访问。

编码

编写实体类 Order.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.chenpeng.demo.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

/**
* @Author CHENPENG
* @Date 2021/11/25 15:26
* @Description
*/
@Document(value = "order")
public class Order {
@Id
private String id;

@Field("customer1")
private String customer;

private String type;

public Order() {
}
}

@Document() 标识要持久化到 MongoDB 的域对象。value 属性的值为 MongoDB 中集合名称。如果未配置,默认集合名称将从类型名称派生。

@Id 标识主键。

@Field 注解用于定义文档字段。如果文档字段和类属性名称一致可以省略。

编写 OrderMapper.java,继承自 MongoRespsitory 类,启用 Spring Data MongoDB 的自动化 Repository 生成功能。

1
2
public interface OrderMapper extends MongoRepository<Order, String> {
}

编写 OrderService 接口

1
2
3
4
public interface OrderService {
<T> T save(T objectToSave);
List<Order> findAll();
}

上面我编写了2个方法,第一个方法直接使用 MongoTemplate,第二种方法使用了Spring Data MongoDB 的自动化 Repository 生成功能。具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class OrderServiceImpl implements OrderService {
private final MongoOperations mongo;

private final OrderMapper orderMapper;

public OrderServiceImpl(MongoOperations mongo, OrderMapper orderMapper) {
this.mongo = mongo;
this.orderMapper = orderMapper;
}

@Override
public <T> T save(T objectToSave) {
return mongo.save(objectToSave);
}

@Override
public List<Order> findAll() {
return orderMapper.findAll();
}
}

编写 Controller 方法,来分别测试两种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@RestController
@RequestMapping("/api")
public class OrderController {
private final OrderService orderService;

public OrderController(OrderService orderService) {
this.orderService = orderService;
}

@RequestMapping("/save")
public Order saveOrder() {
Order order = new Order();
String customer = "Joe";
String type = "device";
order.setCustomer(customer);
order.setType(type);
return orderService.save(order);
}

@RequestMapping("/getOrder")
public List<Order> getList() {
return orderService.findAll();
}

}

测试

使用 postman 发送请求,查看结果

1
2
3
4
5
{
"id": "619f692f8c8a1b794a87ea71",
"customer": "Joe",
"type": "device"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[
{
"id": "619f435351088848a3ccb2f9",
"customer": null,
"type": null
},
{
"id": "619f441b6cafda1f68413557",
"customer": "Joe",
"type": "device"
},
{
"id": "619f692f8c8a1b794a87ea71",
"customer": "Joe",
"type": "device"
}
]

测试结果成功