SpringBoot-整合篇


整合篇包含SpringBoot对各种第三方技术的整合。例如SQL、NoSQL、缓存、消息队列、定时任务、文档操作、认证授权、消息通知等等

小简从 0 开始学 Java 知识之 Java-学习路线 中的《SpringBoot-整合篇》,不定期更新所学笔记,期待一年后的蜕变吧!<有同样想法的小伙伴,可以联系我一起交流学习哦!>

  • 🚩时间安排:本篇长期更新
  • 🎯开始时间:09-15
  • 🎉结束时间:∞

1.整合SQL

①MyBatis

步骤①:导入 MyBatis 的 starter 和对应数据库的坐标,或者创建项目时勾选要使用的技术

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

步骤②:配置数据源相关信息,没有这个信息你连接哪个数据库都不知道

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=Asia/Shanghai
    username: root
    password: root

测试

  • 测试表
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tbl_book
-- ----------------------------
DROP TABLE IF EXISTS `tbl_book`;
CREATE TABLE `tbl_book`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of tbl_book
-- ----------------------------
INSERT INTO `tbl_book` VALUES (1, '三体', '科幻', '大刘的巅峰之作,将中国科幻推向世界舞台。总共分为三部曲:《地球往事》、《黑暗森林》、《死神永生》。');
INSERT INTO `tbl_book` VALUES (2, '格林童话', '童话', '睡前故事。');
INSERT INTO `tbl_book` VALUES (3, 'Spring 5设计模式', '计算机理论', '深入Spring源码剖析Spring源码中蕴含的10大设计模式');

SET FOREIGN_KEY_CHECKS = 1;
  • 实体类
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
  • 映射接口(Dao)
@Mapper
public interface BookDao {
    @Select("select * from tbl_book where id = #{id}")
    public Book getById(Integer id);
}
  • 测试类
@SpringBootTest
class Springboot05MybatisApplicationTests {
    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
        System.out.println(bookDao.getById(1));
    }
}

总结

  1. 整合操作需要勾选MyBatis技术,也就是导入MyBatis对应的starter

  2. 数据库连接相关信息转换成配置

  3. 数据库SQL映射需要添加@Mapper被容器识别到

  4. MySQL 8.X驱动强制要求设置时区

    • 修改url,添加serverTimezone设定
    • 修改MySQL数据库配置:修改mysql中的配置文件mysql.ini,在mysqld项中添加default-time-zone=+8:00
  5. 驱动类过时,提醒更换为com.mysql.cj.jdbc.Driver

②MyBatis-Plus

步骤①:导入对应的 starter 和数据库驱动

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

步骤②:配置数据源相关信息

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/ssm_db
    username: root
    password: root

步骤③:配置表名的通用前缀名

数据库的表名定义规则是tbl_模块名称,为了能和实体类相对应,需要设置所有表名的通用前缀名

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_		#设置所有表的通用前缀名称为tbl_

步骤④:配置运行日志

通过配置运行日志就可以查阅执行时的SQL语句

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置日志

测试

  • 实体类
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
  • 映射接口(Dao)
@Mapper
public interface BookDao extends BaseMapper<Book> {
}

核心在于Dao接口继承了一个BaseMapper的接口,这个接口中帮助开发者预定了若干个常用的API接口,简化了通用API接口的开发工作。

  • 测试类
@SpringBootTest
class SpringbootApplicationTests {
    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
        System.out.println(bookDao.selectById(2));
        System.out.println(bookDao.selectList(null));
    }
}

总结

  1. 手工添加MyBatis-Plus对应的starter
  2. 数据层接口使用BaseMapper简化开发
  3. 借助MyBatis-Plus日志可以查阅执行SQL语句
  4. 需要使用的第三方技术无法通过勾选确定时,需要手工添加坐标

③Durid

前面整合 MyBatis 和 MyBatis-Plus 的时候,使用的数据源对象都是SpringBoot默认的数据源对象 HiKari,下面我们手工控制一下,自己指定了一个数据源对象 Druid。

步骤①:导入对应的starter

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.6</version>
    </dependency>
</dependencies>

步骤②:修改配置

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
      username: root
      password: root
      
#除了这4个常规配置外,还有druid专用的其他配置。通过提示功能可以打开druid相关的配置查阅

总结

  1. 整合Druid需要导入Druid对应的starter
  2. 根据Druid提供的配置方式进行配置

2.整合NoSQL

①Redis

步骤①:导入对应的 starter 和依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

步骤②:修改配置

spring:
  redis:
    host: 127.0.0.1 #指定redis所在的host
    port: 6379  #指定redis的端口
    password: 123456  #设置redis密码
    lettuce:
      pool:
        max-active: 8 #最大连接数
        max-idle: 8 #最大空闲数
        min-idle: 0 #最小空闲数
        max-wait: 100ms #连接等待时间

步骤③:使用springboot整合redis的专用客户端接口操作

  • RedisTemplate
@SpringBootTest
class SpringRedisApplicationTests {
    @Resource
    private RedisTemplate redisTemplate;
    @Test
    void testString() {
        // 1.通过RedisTemplate获取操作String类型的ValueOperations对象
        ValueOperations ops = redisTemplate.opsForValue();
        // 2.插入一条数据
        ops.set("name","jianjian");
        // 3.获取数据,需要进行类型转换
        String name = (String) ops.get("name");
        System.out.println("name = " + name);
    }
}
  • StringRedisTemplate

由于redis内部不提供java对象的存储格式,因此当操作的数据以对象的形式存在时,会进行转码,转换成字符串格式后进行操作。为了方便开发者使用基于字符串为数据的操作,springboot整合redis时提供了专用的API接口StringRedisTemplate,可以理解为这是RedisTemplate的一种指定数据泛型的操作API。

@SpringBootTest
public class StringRedisTemplateTest {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    void get(){
        ValueOperations ops = stringRedisTemplate.opsForValue();
        String name = ops.get("name");
        System.out.println(name);
    }
}

redis客户端选择

springboot整合redis技术提供了多种客户端兼容模式,默认提供的是lettuce客户端技术,也可以根据需要切换成指定客户端技术,例如jedis客户端技术,切换成jedis客户端技术操作步骤如下:

步骤①:导入jedis坐标

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

步骤②:配置客户端技术类型,设置为jedis

spring:
  redis:
    host: localhost
    port: 6379
    client-type: jedis

步骤③:根据需要设置对应的配置

spring:
  redis:
    host: localhost
    port: 6379
    client-type: jedis
    lettuce:
      pool:
        max-active: 16
    jedis:
      pool:
        max-active: 16

lettcus与jedis区别

  • jedis连接Redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响
  • lettcus基于Netty框架进行与Redis服务器连接,底层设计中采用StatefulRedisConnection。 StatefulRedisConnection自身是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用。当然lettcus也支持多连接实例一起工作

②ElasticSearch

步骤①:导入对应的依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
</dependencies>

步骤②:修改配置

elasticsearch:
    cluster-name: my-application
    cluster-nodes: 127.0.0.1:9200 

③MongoDB

3.整合消息队列

①kafka

概念 解释
Broker 节点,一个Broker代表是一个Kafka实例节点,多个Broker可以组成Kafka集群
Topic 主题,等同于消息系统中的队列(queue),一个Topic中存在多个Partition
Partition 分区,构成Kafka存储结构的最小单位
offset offset为消息偏移量,以Partition为单位,即使在同一个Topic中,不同Partition的offset也是重新开始计算(也就是会重复)
Group 消费者组,一个Group里面包含多个消费者
Message 消息,是队列中消息的承载体,也就是通信的基本单位,Producer可以向Topic中发送Message

❶下载并启动

  • 下载 kafka

下载地址:https://kafka.apache.org/downloads

  • 启动 Kafka 环境

运行以下命令以正确的顺序启动所有服务:

# Start the ZooKeeper service
$ bin/zookeeper-server-start.sh config/zookeeper.properties

打开另一个终端会话并运行:

# Start the Kafka broker service
$ bin/kafka-server-start.sh config/server.properties

成功启动所有服务后,您将拥有一个基本的 Kafka 环境运行并可供使用。

❷引入依赖并配置

  • 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
    <version>3.0.6</version>
</dependency>
  • 配置
sping:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: my-group # 默认的消费组ID
      auto-offset-reset: earliest
    producer:
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      key-serializer: org.apache.kafka.common.serialization.StringSerializer

❸生产者发送消息

@Component
class KafkaProducer {

    @Autowired
    private KafkaTemplate kafkaTemplate;
  
    public void sendMessage(String topic, String content) {
        kafkaTemplate.send(topic, content);
    }
}

❹消费者接收消息

@Component
class KafkaConsumer {
    @KafkaListener(topics = {"test"})
    public void handleMessage(ConsumerRecord record) {
        System.out.println(record.value());
    }
}

❺测试

@SpringBootTest
public class KafkaTests {

    @Autowired
    private KafkaProducer kafkaProducer;

    @Test
    public void testKafka() {
        kafkaProducer.sendMessage("test", "你好");
        kafkaProducer.sendMessage("test", "在吗");

        try {
            Thread.sleep(1000 * 10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

②RabbitMQ

❶安装RabbitMQ

  • 拉取镜像
docker pull rabbitmq:3-management
  • 运行镜像
docker run \
 -e RABBITMQ_DEFAULT_USER=jianjian \
 -e RABBITMQ_DEFAULT_PASS=123321 \
 --name mq \
 --hostname mq1 \
 -p 15672:15672 \
 -p 5672:5672 \
 -d rabbitmq:3-management

访问 http://127.0.0.1:15672 即可

❷引入依赖并配置

导入springboot整合amqp的starter,amqp协议默认实现为rabbitmq方案

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

配置RabbitMQ的服务器地址

spring:
  rabbitmq:
    host: 127.0.0.1 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: jianjian # 用户名
    password: 123321 # 密码    

案例

  1. 利用@RabbitListener声明Exchange、Queue、RoutingKey
  2. 在consumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
  3. 在publisher中编写测试方法,向jianjian. direct发送消息

❸消息接收(direct)

在consumer的SpringRabbitListener中添加两个消费者,同时基于注解来声明队列和交换机:

@Component
public class SpringRabbitListener {
  
    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "direct.queue1"),
        exchange = @Exchange(name = "jianjian.direct", type = ExchangeTypes.DIRECT),
        key = {"red", "blue"}
    ))
    public void listenDirectQueue1(String msg){
        System.out.println("消费者接收到direct.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(bindings = @QueueBinding(
        value = @Queue(name = "direct.queue2"),
        exchange = @Exchange(name = "jianjian.direct", type = ExchangeTypes.DIRECT),
        key = {"red", "yellow"}
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("消费者接收到direct.queue2的消息:【" + msg + "】");
    }
}

❹消息发送(direct)

在publisher服务中添加测试方法:

@SpringBootTest
public class SpringAmqpTest {
    @Test
    public void testSendDirectExchange() {
        // 交换机名称
        String exchangeName = "jianjian.direct";
        // 消息
        String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";
        // 发送消息
        rabbitTemplate.convertAndSend(exchangeName, "red", message);
    }
}

③RocketMQ

4.整合定时任务

①Quartz

Quartz技术是一个比较成熟的定时任务框架。springboot对其进行整合后,简化了一系列的配置,将很多配置采用默认设置,这样开发阶段就简化了很多。

Quartz相关概念

  • 工作(Job):用于定义具体执行的工作
  • 工作明细(JobDetail):用于描述定时工作相关的信息
  • 触发器(Trigger):用于描述触发工作的执行规则,通常使用cron表达式定义规则
  • 调度器(Scheduler):描述了工作明细与触发器的对应关系

简单说就是你定时干什么事情,这就是工作;工作不可能就是一个简单的方法,还要设置一些明细信息;工作啥时候执行,设置一个触发器;工作和触发器都是独立定义的,它们两个怎么配合到一起呢?用调度器。

步骤①:导入springboot整合Quartz的starter

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

步骤②:定义任务Bean,按照Quartz的开发规范制作,继承QuartzJobBean

public class MyQuartz extends QuartzJobBean { //工作
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("quartz task run...");
    }
}

步骤③:创建Quartz配置类,定义工作明细(JobDetail)与触发器的(Trigger)bean

@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail printJobDetail(){ //工作明细
        //绑定具体的工作
        return JobBuilder.newJob(MyQuartz.class).storeDurably().build();
    }
    @Bean
    public Trigger printJobTrigger(){ //触发器
        //调度器定义触发工作的执行规则 从0s开始每隔5s运行一次
        ScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
        //绑定对应的工作明细
        return TriggerBuilder.newTrigger().forJob(printJobDetail()).withSchedule(schedBuilder).build();
    }
}

工作明细中要设置对应的具体工作,使用newJob()操作传入对应的工作任务类型即可。

触发器需要绑定任务,使用forJob()操作传入绑定的工作明细对象。此处可以为工作明细设置名称然后使用名称绑定,也可以直接调用对应方法绑定。

触发器中最核心的规则是执行时间,此处使用调度器定义执行时间,执行时间描述方式使用的是cron表达式

cron表达式详解

在spring 4.x中已经不支持7个参数的cron表达式了,要求必须是6个参数。cron表达式格式如下:

{} {} {} {日期(具体哪天)} {} {星期}
  • 秒:必填项,允许的值范围是0-59,支持的特殊符号包括, - * /
    • ,表示特定的某一秒才会触发任务
    • -表示一段时间内会触发任务
    • *表示每一秒都会触发
    • /表示从哪一个时刻开始,每隔多长时间触发一次任务。
  • 分:必填项,允许的值范围是0-59,支持的特殊符号和秒一样,含义类推
  • 时:必填项,允许的值范围是0-23,支持的特殊符号和秒一样,含义类推
  • 日期:必填项,允许的值范围是1-31,支持的特殊符号相比秒多了?,表示与{星期}互斥,即意味着若明确指定{星期}触发,则表示{日期}无意义,以免引起冲突和混乱。
  • 月:必填项,允许的值范围是1-12 (JAN-DEC),支持的特殊符号与秒一样,含义类推
  • 星期:必填项,允许值范围是1~7 (SUN-SAT),1代表星期天(一星期的第一天),以此类推,7代表星期六,支持的符号相比秒多了?,表达的含义是与{日期}互斥,即意味着若明确指定{日期}触发,则表示{星期}无意义。

总结

  1. springboot整合Quartz就是将Quartz对应的核心对象交给spring容器管理,包含两个对象,JobDetail和Trigger对象
  2. JobDetail对象描述的是工作的执行信息,需要绑定一个QuartzJobBean类型的对象
  3. Trigger对象定义了一个触发器,需要为其指定绑定的JobDetail是哪个,同时要设置执行周期调度器

②Task

Spring Task是Spring 3.0自带的定时任务,可以将它看作成一个轻量级的Quartz,功能虽然没有Quartz那样强大,但是使用起来非常简单,无需增加额外的依赖,可直接上手使用。

步骤①:开启定时任务功能,在引导类上开启定时任务功能的开关,使用注解@EnableScheduling

@SpringBootApplication
@EnableScheduling //开启定时任务功能
public class SpringbootTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot22TaskApplication.class, args);
    }
}

步骤②:定义Bean,在对应要定时执行的操作上方,使用注解@Scheduled定义执行的时间,执行时间的描述方式还是cron表达式

@Component
public class MyBean {
    @Scheduled(cron = "0/1 * * * * ?")
    public void print(){
        System.out.println("spring task run...");
        System.out.println(Thread.currentThread().getName()); //调度线程名 ssm_1
    }
}

步骤③:如何想对定时任务进行相关配置,可以通过配置文件进行

spring:
  task:
       scheduling:
      pool:
           size: 1							# 任务调度线程池大小 默认 1
      thread-name-prefix: ssm_      	# 调度线程名称前缀 默认 scheduling-      
        shutdown:
          await-termination: false		# 线程池关闭时等待所有任务完成
          await-termination-period: 10s	# 调度线程关闭前最大等待时间,确保最后一定关闭

总结

  1. spring task需要使用注解@EnableScheduling开启定时任务功能

  2. 注解@Scheduled为定时执行的的任务设置执行周期,描述方式cron表达式

5.整合认证授权

①Spring Security

②Shiro

③Oauth2

6.整合文档操作

①PDF

②Word

③Excel

④上传下载

7.整合通知

①邮件

②钉钉

③微信

④短信

Sponsor❤️

您的支持是我不断前进的动力,如果您感觉本文对您有所帮助的话,可以考虑打赏一下本文,用以维持本博客的运营费用,拒绝白嫖,从你我做起!🥰🥰🥰

支付宝 微信

文章作者: 简简
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 简简 !
评论
填上邮箱会收到评论回复提醒哦!!!
 上一篇
SpringCloud-实用篇 SpringCloud-实用篇
实用篇包含微服务治理(注册发现,远程调用,配置管理,网关路由)、Docker技术、异步通信、分布式缓存、分布式搜索 小简从 0 开始学 Java 知识之 Java-学习路线 中的《SpringCloud-实用篇》,不定期更新所学笔记,期
2022-09-20
下一篇 
SpringBoot-原理篇 SpringBoot-原理篇
原理篇包含自动配置工作流程、自定义starter开发、springboot程序启动流程、掌握SpringBoot内部工作流程、理解SpringBoot整合第三方技术的原理 小简从 0 开始学 Java 知识之 Java-学习路线 中的《
2022-09-15
  目录