Springboot项目整合RabbitMQ+Redis实现可靠的阿里云短信异步收发功能(手把手实操详细教程)

news2024/10/5 17:11:15

文章目录

    • 1、项目介绍
      • 1.1、项目描述
      • 1.2、项目结构
    • 2、创建项目(idea)
      • 2.1、依赖引入
      • 2.2、 配置文件
      • 2.3、 数据库表
      • 2.4、 实体类
      • 2.5、 配置类
      • 2.6、 验证码服务类
      • 2.7、 短信发送服务类
      • 2.8、 消费者类
      • 2.9、发送服务类
      • 2.10、定时任务类
      • 2.11、启动类
      • 2.12、测试控制器
    • 3、效果测试
    • 4、总结
    • 5、附件-整个源码仓库

1、项目介绍

1.1、项目描述

以下是一个完整的 Spring Boot 项目案例,整合 RabbitMQ 实现阿里云短信异步收发,并将发送情况存入数据库,同时使用 Redis 缓存验证码;

这个项目旨在实现一个可靠的短信发送系统,结合了多种技术来确保短信的高效发送和管理。以下是对各个部分的详细描述:

1.2、项目结构

项目结构如下:

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── tigerhhzz
│   │   │           ├── SpringbootMqAliyunAmsApplication.java
│   │   │           ├── config
│   │   │           │   └── RabbitMQConfig.java
│   │   │           ├── model
│   │   │           │   └── SmsLog.java
│   │   │           ├── service
│   │   │           │   ├── SmsConsumer.java
│   │   │           │   ├── SmsSenderService.java
│   │   │           │   ├── SmsService.java
│   │   │           │   └── VerificationCodeService.java
│   │   │           └── task
│   │   │               └── SmsResendTask.java
│   │   ├── resources
│   │   │   ├── application.yml
│   │   │   └── schema.sql
│   └── test
│       └── java
└── pom.xml

2、创建项目(idea)

2.1、依赖引入

  • 通过pom.xml文件引入了必要的依赖,包括 Spring Boot 的 AMQP 模块用于与 RabbitMQ 集成、JDBC 模块用于数据库操作、MySQL 数据库驱动、阿里云短信服务 SDK 和 Redis 模块用于缓存验证码。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tigerhhzz</groupId>
    <artifactId>springboot-rabbitmq-aliyun-sms-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.0.6</version> <!-- 注:如提示报错,先升级基础包版,无法解决可联系技术支持 -->
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>tea-openapi</artifactId>
            <version>0.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>tea-util</artifactId>
            <version>0.2.20</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2、 配置文件

  • application.yml文件中配置了 RabbitMQ、阿里云短信服务、数据库和 Redis 的连接信息。这些配置使得项目能够连接到相应的服务和资源。
server:
  port: 8080
spring:
  application:
    name: springboot-rabbitmq-demo
    # 添加数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/springbootrabbitmq_db_msg?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  #rabbitmq
  rabbitmq:
    host: xxxxxxxxxxx
    port: 5672
    virtual-host: /
    username: guest
    password: guest
    # 开启confirms回调 P -> Exchange
    publisher-confirms: true
    # 开启returnedMessage回调 Exchange -> Queue
    publisher-confrms-type: correlation
    publisher-returns: true
    # 设置手动确认(ack) Queue -> C
    listener:
      simple:
        acknowledge-mode: manual
      prefetch: 100
  #redis
  redis:
    host: 8.217.205.108
    port: 6379
    password: xxxxxxxx
    timeout: 50000
#阿里短信配置
aliyun:
  sms:
    accessKey: xxxxxxxx
    accessKeySecret: xxxxxxxxx
    signName: 珑湾崖头
    templateCode: SMS_474285221
    domain: dysmsapi.aliyuncs.com
    regionId: cn-beijing

# 配置mybatis的xml配置文件扫描目录
mybatis:
  mapper-locations:
    - classpath:mapper/*.xml
  configuration:
    # 打印SQL语句,需要注射掉这个mybatis属性配置,否则启动报错
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.3、 数据库表

  • schema.sql文件中创建了sms_log表,用于记录短信的发送状态和时间。这个表有助于跟踪短信的发送历史,并可以用于后续的分析和故障排除。
CREATE TABLE sms_log (
    id INT AUTO_INCREMENT PRIMARY KEY,
    unique_id VARCHAR(36), -- 存储 UUID
    phone_number VARCHAR(20),
    message_content VARCHAR(255),
    send_status TINYINT, -- 0 表示未发送成功,1 表示发送成功
    send_time TIMESTAMP
);

2.4、 实体类

  • SmsLog类是一个简单的 Java 对象,用于表示数据库中的短信记录。它包含了短信的相关信息,如手机号码、发送状态和发送时间。
package com.tigerhhzz.model;

import lombok.Data;

import java.util.Date;

/**
 * @Author tigerhhzz
 * @Date 2024 10 05 11 37
 **/
@Data
public class SmsLog {
    private int id;
    private String uniqueId;
    private String phoneNumber;
    private String messageContent;
    private int sendStatus;
    private Date sendTime;
}

2.5、 配置类

  • RabbitMQConfig类配置了 RabbitMQ 的队列、交换器和绑定关系。通过定义这些元素,项目可以使用 RabbitMQ 进行异步消息传递。
package com.tigerhhzz.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author tigerhhzz
 * @Date 2024 10 05 11 38
 **/
@Configuration
public class RabbitMQConfig {

    public static final String SMS_QUEUE = "smsQueue";
    public static final String SMS_EXCHANGE = "smsExchange";
    public static final String SMS_ROUTING_KEY = "smsRoutingKey";

    @Bean
    public Queue smsQueue() {
        return new Queue(SMS_QUEUE);
    }

    @Bean
    public TopicExchange smsExchange() {
        return new TopicExchange(SMS_EXCHANGE);
    }

    @Bean
    public Binding binding(Queue smsQueue, TopicExchange smsExchange) {
        return BindingBuilder.bind(smsQueue).to(smsExchange).with(SMS_ROUTING_KEY);
    }
}

2.6、 验证码服务类

  • VerificationCodeService类负责生成和验证验证码。它使用 Redis 来缓存生成的验证码,并设置了过期时间。生成验证码时,它会生成一个随机的 6 位数字验证码,并将其存储在 Redis 中,同时返回给调用者。验证验证码时,它会从 Redis 中获取存储的验证码,并与用户输入的验证码进行比较。
package com.tigerhhzz.service;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class VerificationCodeService {

    private final RedisTemplate<String, String> redisTemplate;

    public VerificationCodeService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public String generateVerificationCode(String key) {
        // 生成随机验证码
        String verificationCode = generateRandomCode();
        // 将验证码存入 Redis,并设置过期时间,比如 5 分钟
        redisTemplate.opsForValue().set(key, verificationCode, 5, TimeUnit.MINUTES);
        return verificationCode;
    }

    public boolean verifyVerificationCode(String key, String code) {
        String storedCode = redisTemplate.opsForValue().get(key);
        return storedCode!= null && storedCode.equals(code);
    }

    private String generateRandomCode() {
        // 生成 6 位随机数字验证码
        Random random = new Random();
        int code = random.nextInt(900000) + 100000;
        return String.valueOf(code);
    }
}

2.7、 短信发送服务类

  • SmsService类负责实际的短信发送操作。它使用阿里云短信服务的 SDK 来发送短信,并在发送成功或失败时更新数据库中的发送状态。此外,它还与验证码服务类交互,生成并包含验证码在短信内容中。
package com.tigerhhzz.service;

import com.aliyun.teaopenapi.Client;
import com.aliyun.teaopenapi.models.Config;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import com.aliyuncs.profile.DefaultProfile;

/**
 * @Author tigerhhzz
 * @Date 2024 10 05 11 40
 **/
@Service
public class SmsService {

    @Value("${aliyun.sms.accessKey}")
    private String accessKeyId;

    @Value("${aliyun.sms.regionId}")
    private String regionId;

    @Value("${aliyun.sms.domain}")
    private String domain;

    @Value("${aliyun.sms.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.sms.signName}")
    private String signName;

    @Value("${aliyun.sms.templateCode}")
    private String templateCode;

    private final JdbcTemplate jdbcTemplate;
    private final VerificationCodeService verificationCodeService;

    public SmsService(JdbcTemplate jdbcTemplate, VerificationCodeService verificationCodeService) {
        this.jdbcTemplate = jdbcTemplate;
        this.verificationCodeService = verificationCodeService;
    }

    public String sendSms(String phoneNumber, String uniqueId) {
        try {
            // 生成验证码
            String verificationCode = verificationCodeService.generateVerificationCode(phoneNumber);


            DefaultProfile profile = DefaultProfile.getProfile(regionId,accessKeyId, accessKeySecret);
            IAcsClient client = new DefaultAcsClient(profile);

            CommonRequest request = new CommonRequest();
            request.setMethod(MethodType.POST);
            request.setDomain(domain);
            request.setVersion("2017-05-25");
            request.setAction("SendSms");
            request.putQueryParameter("RegionId", regionId);
            request.putQueryParameter("PhoneNumbers", phoneNumber); //目标手机号
            request.putQueryParameter("SignName", signName); //签名名称
            request.putQueryParameter("TemplateCode", templateCode); //短信模板code
            request.putQueryParameter("TemplateParam", "{\"code\":\"" + verificationCode + "\"}");//模板中变量替换

            CommonResponse response = client.getCommonResponse(request);
            String data = response.getData();
            System.out.println("发送短信后的响应结果:"+data);
            if (StringUtils.contains(data, "\"Message\":\"OK\"")) {
                // 发送成功,更新数据库状态
                jdbcTemplate.update("UPDATE sms_log SET send_status = 1, send_time = NOW() WHERE unique_id =?", uniqueId);
                return "发送成功,验证码:"+verificationCode;
            } else {
                // 发送失败,也可以记录失败原因等
                jdbcTemplate.update("UPDATE sms_log SET send_status = 0 WHERE unique_id =?", uniqueId);
                return "发送失败,验证码:"+verificationCode;
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 发送异常,更新数据库状态为失败
            jdbcTemplate.update("UPDATE sms_log SET send_status = 0 WHERE unique_id =?", uniqueId);
            System.out.println("发送短信验证码失败~ phoneNumber = " + phoneNumber + e);
        }
        return null;
    }
}


2.8、 消费者类

  • SmsConsumer类是 RabbitMQ 的消费者,它监听特定的队列,并在接收到消息时调用短信发送服务类的方法来发送短信。
package com.tigerhhzz.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class SmsConsumer {

    private static final Logger LOGGER = LoggerFactory.getLogger(SmsConsumer.class);
    @Autowired
    private SmsService smsService;

//    @RabbitListener(queues = "smsQueue")
    @RabbitListener(queues = {"smsQueue"})
    public void receiveSmsTask( Map<String,String> map) {
        String phoneNumber = map.get("phoneNumber");
        String uniqueId = map.get("uniqueId");
        // 解析消息,获取手机号码和 UUID
        smsService.sendSms(phoneNumber, uniqueId);
    }
}

2.9、发送服务类

  • SmsSenderService类提供了一个方法,用于将短信发送任务异步发送到 RabbitMQ。在发送任务之前,它会将任务记录到数据库中,初始状态为未发送。
package com.tigerhhzz.service;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class SmsSenderService {

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void sendSmsAsync(String phoneNumber) {
        // 生成 UUID 作为唯一 ID
        String uniqueId = UUID.randomUUID().toString();
        // 先记录发送任务到数据库,初始状态为未发送
        jdbcTemplate.update("INSERT INTO sms_log (phone_number, message_content, send_status, unique_id) VALUES (?,?, 0,?)", phoneNumber, null, uniqueId);
        String message = phoneNumber + "," + uniqueId;
        amqpTemplate.convertAndSend("smsExchange", "smsRoutingKey", message);
    }
}

2.10、定时任务类

  • SmsResendTask类定义了一个定时任务,用于检查数据库中未发送成功的短信,并重新发送它们。这个定时任务每分钟执行一次,确保未发送成功的短信能够尽快得到重新发送。
package com.tigerhhzz.task;

import com.tigerhhzz.service.SmsSenderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.stereotype.Component;

/**
 * 定时任务
 * @Author tigerhhzz
 * @Date 2024 10 05 13 15
 **/
@Component
public class SmsResendTask {

    private static final Logger LOGGER = LoggerFactory.getLogger(SmsResendTask.class);

    private final SmsSenderService smsSenderService;
    private final JdbcTemplate jdbcTemplate;

    public SmsResendTask(SmsSenderService smsSenderService, JdbcTemplate jdbcTemplate) {
        this.smsSenderService = smsSenderService;
        this.jdbcTemplate = jdbcTemplate;
    }

    //@Scheduled(fixedRate = 60000) // 每分钟检查一次
    @Scheduled(cron = "0/30 * * * * ?")
    public void checkAndResendSms() {
        LOGGER.info("开始执行重新发送失败的消息!");
        jdbcTemplate.query("SELECT phone_number, unique_id FROM sms_log WHERE send_status = 0", (rs, rowNum) -> {
            String phoneNumber = rs.getString("phone_number");
            String uniqueId = rs.getString("unique_id");
            smsSenderService.sendSmsAsync(phoneNumber);
            return null;
        });
    }
}


2.11、启动类

  • Application类是项目的启动类,它使用 Spring Boot 的自动配置功能来启动应用程序。通过@SpringBootApplication注解和@ComponentScan注解,确保项目中的所有组件都能够被正确扫描和加载。
package com.tigerhhzz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * @Author tigerhhzz
 * @Date 2024 10 05 10 10
 **/
@SpringBootApplication
@ComponentScan(basePackages = "com.tigerhhzz")
public class SpringbootMqAliyunAmsApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMqAliyunAmsApplication.class, args);
        System.out.println("SpringbootMqAliyunAmsApplication启动成功!!!");
    }
}

2.12、测试控制器

package com.tigerhhzz.controller;

import com.tigerhhzz.service.SmsSenderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Author tigerhhzz
 * @Date 2024 10 05 13 35
 **/
@RestController
@RequestMapping("/sms")
public class SmsController {

    @Autowired
    private SmsSenderService smsSenderService;

    /**
     * 通过mq发送短信验证码
     * @param phoneNumber
     */
    @RequestMapping(value="/sendsmsbymq/{phoneNumber}",method= RequestMethod.POST)
    public String sendCode(@PathVariable String phoneNumber ){
        smsSenderService.sendSmsAsync(phoneNumber);
        System.out.println("手机号:" +phoneNumber+";发送短信验证码成功");
        return "短信发送任务已提交,将异步发送。";
    }
}

3、效果测试

启动主启动类:

post请求:http://localhost:8080/sms/sendsmsbymq/150xxxx0598

使用postman进行测试:在这里插入图片描述

idea后台打印结果:
在这里插入图片描述
rabbitmq监控消息:
在这里插入图片描述
查看数据库:
在这里插入图片描述
结果:消息成功发送!!!

4、总结

通过以上的设计和实现,这个项目可以实现可靠的短信发送功能,并使用 Redis 缓存验证码来提高系统的安全性和用户体验。同时,通过异步发送和定时任务重发机制,可以确保短信的高可用性和可靠性。在实际应用中,可以根据具体需求进一步扩展和优化这个项目。

5、附件-整个源码仓库

https://gitee.com/spring2020/springboot-mq-aliyun-ams-application
感谢关注点赞!!!

在这里插入图片描述


人生从来没有真正的绝境。只要一个人的心中还怀着一粒信念的种子,那么总有一天,他就能走出困境,让生命重新开花结果。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190220.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机科学英语词汇汇总(上)(Computer Science English Complete Vocabulary)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

对不经常变动的数据集合添加Redis缓存

目录 前言 什么是缓存 如何使用缓存 添加商户缓存 缓存模型和思路 实现代码 问题分析 解决方案 实现商铺和缓存与数据库双写一致 实现代码 前言 什么是缓存 缓存(Cache),就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码 缓存…

【框架篇】过滤器和拦截器的区别以及使用场景

在项目开发中&#xff0c;常常会同时配置拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;&#xff0c;以下就是它们两个主要的区别&#xff1a; 过滤器&#xff08;Filter&#xff09; 配置和实现 Filter的实现还是很简单的&#xff0c;可…

提升快递管理效率的必备技能:教你批量查询与导出物流信息

在当今快节奏的商业环境中&#xff0c;快递与物流行业的效率直接关系到企业的运营成本和客户满意度。随着订单量的不断增加&#xff0c;如何高效地管理和追踪大量的物流信息成为了企业面临的一大挑战。批量查询与导出物流信息作为一种高效的数据处理手段&#xff0c;正逐渐成为…

微信小程序-npm支持-如何使用npm包

文章目录 1、在内建终端中打开2、npm init -y3、Vant Weapp4、通过 npm 安装5、构建 npm 1、在内建终端中打开 Windows PowerShell 版权所有 (C) Microsoft Corporation。保留所有权利。尝试新的跨平台 PowerShell https://aka.ms/pscore6PS C:\Users\dgq\WeChatProjects\minip…

重学SpringBoot3-集成Redis(三)

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;三&#xff09; 1. 引入 Redis 依赖2. 配置 RedisCacheManager 及自定义过期策略2.1 示例代码&#xff1a;自定义过期策略 3. 配置…

大学生就业招聘系统:Spring Boot技术解析

3系统分析 3.1可行性分析 通过对本大学生就业招聘系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本大学生就业招聘系统采用JAVA作为开发语言&#xff0c;S…

【现代控制理论】第2-5章课后题刷题笔记

文章目录 第二章&#xff1a;线性控制系统的状态空间描述第三章&#xff1a;控制系统状态空间描述的特性3.1 计算状态转移矩阵&#xff08;矩阵指数函数&#xff09;3.2 计算系统的时间响应&#xff08;状态方程的解&#xff09;3.3 判断系统的能控性和能观性&#xff0c;以及能…

【笔记】I/O总结王道强化视频笔记

文章目录 从中断控制器的角度来理解整个中断处理的过程复习 处理器的中断处理机制**中断驱动I/O方式** printf——从系统调用到I/O控制方式的具体实现1轮询方式下输出一个字符串(程序查询)中断驱动方式下输出一个字符串中断服务程序中断服务程序与设备驱动程序之间的关系 DMA方…

【测试】接口测试与接口自动化

壹、接口测试基础 一、接口测试概念 I、基础概念 是测试系统组件间接口的一种测试。 主要用于检测外部系统与系统间、内部子系统间的交互点&#xff1b;测试重点检查数据的交换、传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系。 内部接口调用相当于函数调用&am…

C语言基础(9)之指针(1)

目录 1. 指针的概念 1.1 内存 1.2 指针是什么 1.3 指针变量的大小 2. 指针类型 2.1 指针类型的意义 2.2 指针类型意义的疑问 3. 野指针 3.1 野指针的概念 3.2 野指针的成因 3.3 如何规避野指针 4. 指针运算 4.1 指针 或 - 整数 4.2 指针 - 指针 4.3 指…

国庆普及模拟赛-5

题目链接&#xff1a; file:///C:/Users/Administrator/Desktop/%E4%B8%8B%E5%8F%91%E6%96%87%E4%BB%B61005/20241005.pdf T1&#xff1a; 题目分析&#xff1a;不需要进行模拟&#xff0c;想要获得分数最大化&#xff0c;只需要将大的数据相加&#xff0c;再减去小的数据。 …

AD7606 ADC的SPI驱动——FPGA学习笔记17

素材来源 米联客 一、AD7606简介 功能框图&#xff1a; 转换控制时序&#xff1a; AD7606 支持 2 种时序转换&#xff0c; 由于我们采用的时串行 SPI 模式&#xff0c; 本身 SPI 读取数据就会耽误很多时间&#xff0c; 所以必须采用第二种工作时序&#xff0c; 才…

呆仔君最新可用版本及作废版本说明截止日期10.5

呆仔君最新可用版本及作废版本说明 当前最新可用版本为 5.0 及以上版本。 截至今天&#xff0c;最新版本为 5.3。本次 5.3 版本的更新功能如下&#xff1a; 新增清悦阁&#xff08;用于搜歌&#xff09;新增手绘功能新增语音合成&#xff08;包括卢本伟、刘华强、特朗普等人物…

[大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠

[大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠 目录 文章目录 [大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠目录0. 摘要1. 核心内容3. 创新点4. 算法模型5. 实验效果6. 重要数据与实验结论7. 推荐阅读指数&#xff1a;8. 推荐理由 后记 论文…

【Java】—— 集合框架:Collections工具类的使用

目录 7. Collections工具类 7.1 常用方法 7.2 举例 7.3 练习 7. Collections工具类 参考操作数组的工具类&#xff1a;Arrays&#xff0c;Collections 是一个操作 Set、List 和 Map 等集合的工具类。 7.1 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序…

超声波清洗机什么牌子值得入手?推荐四款入手不亏的眼镜清洗机

在当今这个注重细节完美的时代&#xff0c;超声波清洗机凭借其卓越的清洁效率、深层渗透力及细腻的清洗效果&#xff0c;迅速赢得了家庭与专业场景的青睐。无论是精细的珠宝、眼镜框&#xff0c;还是金属装饰品、电子设备乃至医疗器具&#xff0c;超声波技术都能精准祛除隐秘处…

汇编语言笔记2

7.MASM,NASM,ATT,ARM的介绍 MASM:Windows下编译汇编指令的软件,可以在DOSBox下运行 NASM:优化版的MASM,主要用于Linux操作系统 ATT:Linux默认的汇编风格(但不友好) ARM:非PC(IOT设备)的汇编,比如写51单片机打开keil4的界面可以看到ARM 8.汇编 C语言 C 之间的关系 发展历程…

45集 ESP32 ADC按键程序编写

45集 ESP32 ADC按键程序编写 参考例程是 D:\Espressif\esp-adf\examples\checks\check_board_buttons 1、config 这个向下兼容的要加上&#xff0c;如果不加会有错误。 CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITYy 2、程序里面引入如下头文件 #include “periph_adc_but…

Python+Matplotlib可视化y = e^(1/x)函数

可视化y e^(1/x)函数&#xff1a; import numpy as np import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] Falsefig, ax plt.subplots(figsize(12, 8))def e_to_1_over_x(x):return np.where(x ! 0, np.exp(1/x), …