SSM整合快速入门案例(二)

news2024/12/29 8:38:48

文章目录

  • 前言
  • 一、表现层与前端数据传输协议定义
  • 二、表现层与前端数据传输协议实现
  • 三、异常处理器
  • 四、项目异常处理
  • 五、前后台协议联调实现CRUD
    • - - 查询
    • - - 添加
    • - - 修改
    • - - 删除
  • 总结


前言

为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

1. 本文建立在SSM整合快速入门案例(一)的基础上进行编写,该博客可以在我的ssm专栏里找到

一、表现层与前端数据传输协议定义

1. 情景引入

后端返回的数据格式不统一,不利于前端访问数据,需要统一格式

在这里插入图片描述

2. 解决方案

前端接收数据格式-创建结果模型类,封装数据到data属性中

在这里插入图片描述

3. 不足与改进1.0

  1. 在ssm快速入门的基础案例中我们发现增删改查返回到前端页面的结果都是true,不利于区分
  2. 因此我们在结果模型类data中添加一个code属性,代表具体的查询结果(示例中用200X代表操作种类,用0和1代表操作是否成功)

在这里插入图片描述

4. 不足与改进2.0

  1. 当查询空时数据data返回null,页面渲染空数据,此时展示什么给用户看呢?
  2. 因此我们在结果模型类中添加一个message属性用于解决该类问题

在这里插入图片描述

5. 表现层数据封装

  1. 设置统一数据返回结果类
  2. Result类中的字段并不是固定的,可以根据需要自行增减,提供若干个构造方法,方便操作

在这里插入图片描述

二、表现层与前端数据传输协议实现

结果模型类属于表现层,故将其定义在controller包下

1. 在controller包中创建编辑结果模型类Result,并定义几个构造方法模拟需求

public class Result {
    //此处省略gerter、setter方法
    //描述统一格式中的数据
    private Object data;
    //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
    private Integer code;
    //描述统一格式中的消息,可选属性
    private String msg;

    public Result() {
    }

    public Result(Integer code, Object data) {
        this.data = data;
        this.code = code;
    }

    public Result(Integer code, Object data, String msg) {
        this.data = data;
        this.code = code;
        this.msg = msg;
    }

2. 在controller包中创建定义状态码类Code

Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET OK,GET ALL OK,GET PAGE OK

//状态码
public class Code {
    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 20021;
    public static final Integer UPDATE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 20020;
    public static final Integer UPDATE_ERR = 20030;
    public static final Integer GET_ERR = 20040;
}

3. 修改优化BookController

  1. 所有方法都返回Result类型
  2. return语句中进行操作成功与否判断并返回状态码和数据(增删改查返回数据的结构有所差别,对应了结果模型类中不同的构造方法)
//统一每一个控制器方法返回值

("/books")
public class BookController {

    
    private BookService bookService;

    
    public Result save( Book book) {
        boolean flag = bookService.save(book);
        return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
    }

    
    public Result update( Book book) {
        boolean flag = bookService.update(book);
        return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
    }

    ("/{id}")
    public Result delete( Integer id) {
        boolean flag = bookService.delete(id);
        return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
    }

    ("/{id}")
    public Result getById( Integer id) {
        Book book = bookService.getById(id);
        Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
        String msg = book != null ? "" : "数据查询失败,请重试!";
        return new Result(code,book,msg);
    }

    
    public Result getAll() {
        List<Book> bookList = bookService.getAll();
        Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = bookList != null ? "" : "数据查询失败,请重试!";
        return new Result(code,bookList,msg);
    }
}

4. 测试示例

在这里插入图片描述

三、异常处理器

1. 情景导入

程序在开发中不可避免的会遇到异常现象,无法正常返回数到表现层,影响了业务的正常运行和用户体验,因此我们需要对其进行处理

在这里插入图片描述

2. 异常的分类

  1. 框架内部抛出的异常: 因使用不合规导致(比如mybatis配置中写错相关信息)
  2. 数据层抛出的异常: 因外部服务器故障导致 (例如: 服务器访问超时、sql语句书写错误)
  3. 业务层抛出的异常:因业务逻辑书写错误导致(例如: 遍历业务书写操作,导致索引异常等
  4. 表现层抛出的异常:因数据收集、校验等规则导致 (例如: 不匹配的数据类型间导致异常)
  5. 工具类抛出的异常: 因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

3. 异常处理器

  • 各个层级均出现异常,异常处理代码书写在哪一层

所有的异常全部抛到表现层进行分类处理

  • 表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决

采用AOP思想,当程序出异常时都到AOP思想定义的方法中去处理

  • 是否自己单独写AOP

其实spring提供了基于AOP思想的异常处理器来集中统一解决异常,一般格式如下:

  1. 名称: @RestControllerAdvice
    类型:类注解
    位置: Rest风格开发的控制器增强类定义上方
    作用:用于标识当前类为REST风格对应的异常处理器,为Rest风格开发的控制器类做增强,
    说明:此注解自带@ResponseBody注解与@Component注解,具备对应的功能
  2. 名称: @ExceptionHandler
    类型:方法注解
    位置:专用于异常处理的控制器方法上方
    作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
    说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常
  3. 示例:

在这里插入图片描述

四、项目异常处理

1. 项目异常分类

  1. 业务异常 (BusinessException)
    规范的用户行为产生的异常和不规范的用户行为操作产生的异常
  2. 系统异常 (SystemException)
    项目运行过程中可预计且无法避免的异常其他异常
  3. 其他异常 (Exception)
    编程人员未预期到的异常

2. 项目异常处理方案

  1. 业务异常 (BusinessException
    发送对应消息传递给用户,提醒规范操作.
  2. 系统异常 (SystemException)
    发送固定消息传递给用户,安抚用户;
    发送特定消息给运维人员,提醒维护;
    记录日志.
  3. 其他异常 (Exception)
    发送固定消息传递给用户,安抚用户;
    发送特定消息给编程人员,提醒维护 (纳入预期范围内);
    记录日志.

3. 定义异常类

  • 创建exception包,创建定义系统异常类SystemException
//自定义异常处理器,用于封装异常信息,对异常进行分类
public class SystemException extends RuntimeException{
    //异常状态码
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

  • 创建定义异常类SystemException
//自定义异常处理器,用于封装异常信息,对异常进行分类
public class BusinessException extends RuntimeException{
    //异常状态码
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

4. 在Code类中添加对应的异常状态码

    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
    public static final Integer SYSTEM_UNKNOW_ERR = 59999;
    public static final Integer BUSINESS_ERR = 60002;

5. 在业务层实现类BookServiceImpl中模拟异常

public Book getById(Integer id) {
        //模拟业务异常,包装成自定义异常
        if(id == 1){
            throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
        }
        //模拟系统异常,将可能出现的异常进行包装,转换成自定义异常
        try{
            int i = 1/0;
        }catch (Exception e){
            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);
        }
        return bookDao.getById(id);
    }

6. 在Controller包中创建编写项目异常处理类ProjectExceptionAdvice

//1.@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器

public class ProjectExceptionAdvice {
    //2.@ExceptionHandler用于设置当前处理器类对应的异常类型
    (SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    (BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
    (Exception.class)
    public Result doOtherException(Exception ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
    }
}

7. 模拟异常访问与文件结构示例

在这里插入图片描述

8. 小结:项目异常案例处步骤

  1. 自定义项目系统级异常
  2. 自定义项目业务级异常
  3. 自定义异常编码
  4. 触发自定义异常
  5. 拦截并处理异常
  6. 异常处理器效果对比

五、前后台协议联调实现CRUD

1. 导入前端页面

具体代码可以在我主页上传的的资源里找到

在这里插入图片描述

2. 在config包下编辑创建springmvc路径支持类SpringMvcSupport


public class SpringMvcSupport extends WebMvcConfigurationSupport {
    
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}

3. 加载springmvc支持类(在springmvc配置中扫描config包)


({"org.example.controller","org.example.config"})

public class SpringMvcConfig {

}

4. 运行tomcat,访问页面

在这里插入图片描述

- - 查询

5. 查询获取数据(渲染数据是前端双向绑定做的)

  • 注释及相关的查询js代码
  1. 发送ajax请求
  2. 请求类型是get
  3. 请求路径是rest风格“/books”
  4. 请求结果模型dataList
    在这里插入图片描述
  5. 从res.data中取数据
  6. 进一步从自定义的data字段中取数据
 getAll() {         
     axios.get("/books").then((res)=>{
          this.dataList = res.data.data;
     });
}
  • 重启tomcat再次访问books.html

在这里插入图片描述

- - 添加

6. 添加功能

  • 为了实现判断是否添加失败的功能,BookDao中的方法的返回值由void改为int,代表行计数(即该操作改变了多少行)
public interface BookDao {

//    @Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
    ("insert into tbl_book (type,name,description) values(#{type},#{name},#{description})")
    public int save(Book book);

    ("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
    public int update(Book book);

    ("delete from tbl_book where id = #{id}")
    public int delete(Integer id);

    ("select * from tbl_book where id = #{id}")
    public Book getById(Integer id);

    ("select * from tbl_book")
    public List<Book> getAll();
}
  • 修改业务层实现类,当操作成功则返回值大于1,为true;反之,为false

public class BookServiceImpl implements BookService {
    
    private BookDao bookDao;

    public boolean save(Book book) {
        return bookDao.save(book) > 0;
    }

    public boolean update(Book book) {
        return bookDao.update(book) > 0;
    }

    public boolean delete(Integer id) {
        return bookDao.delete(id) > 0;
    }

    public Book getById(Integer id) {
        if(id == 1){
            throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
        }
//        //将可能出现的异常进行包装,转换成自定义异常
//        try{
//            int i = 1/0;
//        }catch (Exception e){
//            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);
//        }
        return bookDao.getById(id);
    }

    public List<Book> getAll() {
        return bookDao.getAll();
    }
}

  • 注释及相关的添加操作js代码
  1. 发送ajax请求
  2. 添加的请求类型是post
  3. 请求的rest风格路径是“/books”
  4. 提交的内容是表单数据,经查询,本案例中添加表单自定义标识符叫formData
  5. $message.error() 在该前端框架中代表切换失败的样式
  6. 获得的数据res.data,自定义状态码code,获取的数据中的状态码res.data.code
  7. 添加操作完后重新获取所有数据this.getAll()
handleAdd () {
    axios.post("/books",this.formData).then((res)=>{
        console.log(res.data);
        //如果操作成功,关闭弹层,显示数据
        if(res.data.code == 20011){
            this.dialogFormVisible = false;
            this.$message.success("添加成功");
        }else if(res.data.code == 20010){
            this.$message.error("添加失败");
        }else{
            this.$message.error(res.data.msg);
        }
     }).finally(()=>{
        this.getAll();
    });
},


  • 运行结果示例

添加成功示例
在这里插入图片描述

添加失败示例

在这里插入图片描述

- - 修改

7. 修改功能

  • 注释及相关的查询js代码
  1. 修改分两步,弹出编辑窗口根据id查询数据 + 编辑后保存加载数据
  2. 根据上文的设计可知从row获取行数据
    在这里插入图片描述
  3. 根据上文的设计可知弹窗的标签名为dialogFormVisible4Edit,值为true代表展示弹层
    在这里插入图片描述
 //弹出编辑窗口
handleUpdate(row) {
    // console.log(row);   //row.id 查询条件
    //查询数据,根据id查询
    axios.get("/books/"+row.id).then((res)=>{
        // console.log(res.data.data);
        if(res.data.code == 20041){
            //展示弹层,加载数据
            this.formData = res.data.data;
            this.dialogFormVisible4Edit = true;
        }else{
            this.$message.error(res.data.msg);
        }
    });
},

//编辑
handleEdit() {
    //发送ajax请求
    axios.put("/books",this.formData).then((res)=>{
    //如果操作成功,关闭弹层,显示数据
    if(res.data.code == 20031){
            this.dialogFormVisible4Edit = false;
            this.$message.success("修改成功");
        }else if(res.data.code == 20030){
            this.$message.error("修改失败");
        }else{
            this.$message.error(res.data.msg);
        }
    }).finally(()=>{
       this.getAll();
    });
},
  • 运行示例

在这里插入图片描述

在这里插入图片描述

- - 删除

8. 删除功能

  1. 删除应该出现一个提示框,提示用户是否删除
  2. 删除的提交类型为delete
  • 相关注释及js代码
handleDelete(row) {
    //1.弹出提示框
    this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
        type:'info'
    }).then(()=>{
        //2.做删除业务
        axios.delete("/books/"+row.id).then((res)=>{
            if(res.data.code == 20021){
                this.$message.success("删除成功");
            }else{
                this.$message.error("删除失败");
            }
        }).finally(()=>{
            this.getAll();
        });
    }).catch(()=>{
        //3.取消删除
        this.$message.info("取消删除操作");
    });
}
  • 运行示例

在这里插入图片描述

在这里插入图片描述

`博客内容借鉴了bilibili黑马程序员SSM课程资料,如有侵权,请联系作者删除`

总结

欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

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

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

相关文章

Netty核心源码剖析(五)

1.Netty核心组件EventLoop源码剖析 1>.NioEventLoop继承图 说明: ①.ScheduledExecutorService接口表示是一个定时任务接口,EventLoop可以接受定时任务; ②.EventLoop接口:Netty 接口文档说明该接口作用:一旦Channel注册了,就处理该Channel对应的所有I/O操作; ③.Single…

学成在线----day7

1、 视频处理-技术方案 1. 作业分片方案 掌握了xxl-job的分片广播调度方式&#xff0c;下边思考如何分布式去执行学成在线平台中的视频处理任务。 任务添加成功后&#xff0c;对于要处理的任务会添加到待处理任务表中&#xff0c;现在启动多个执行器实例去查询这些待处理任务…

FPGA基础知识-层次建模的概念

学习目标&#xff1a; 提示&#xff1a;这里可以添加学习目标 理解数字电路设计中自底向上和自顶向下的设计方法&#xff1b; 解释verilog中模块和模块实例之间的区别&#xff1b; 学习从4中不同的抽象角度来描述同一个模块&#xff1b; 解释仿真中的各个组成部分&#xf…

动态NAT过载配置与验证实验

动态NAT过载配置与验证实验 【实验目的】 部署端口地址转换。熟悉端口地址转换的应用方法。验证配置。 【实验拓扑】 实验拓扑如图所示。 实验拓扑 设备参数如表所示。 设备参数表 设备 接口 IP地址 子网掩码 默认网关 R1 f0/0 192.168.10.1 255.255.255.0 N/A …

《低代码指南》低代码开发平台Noodl即将开源

Noodl 是一个低代码开发平台,让设计师、开发者能够用低代码的可视化编程方法构建强大的 Web 应用。目前 Noodl 已被亚马逊、三星、沃尔玛等财富 500 强企业应用于原型设计到生产环境中。 日前,Noodl 官方发出公告表示,将从现有的付费订阅模式向开源模式过渡。 Noodl 目前的…

FineReport 连接mysql报错 当前驱动加载路径...

报错内容&#xff1a; 原因为帆软自带的jar包与当前使用的mysql&#xff08;8.0&#xff09;版本不一致&#xff0c;需要去官网下载对应连接的jar包 官网下载地址… 下载后在帆软对应路径替换掉jar包即可 FineReport_11.0\webapps\webroot\WEB-INF\lib

海格里斯HEGERLS四向穿梭车系统比件箱自动化解决方案有哪些突出优势?

随着仓储物流、电商行业的快速发展&#xff0c;自动化立体库的型式和技术日益完善&#xff0c;除了典型的单深度单货位立体库外&#xff0c;也逐渐发展了双深度和多货位的立体仓库。在自动化存储设备方面&#xff0c;除堆垛机外&#xff0c;利用四向穿梭车、子母车等技术构成的…

软件自动化测试基本流程(附流程图)

“自动化测试与软件开发过程从本质上来讲是一样的,无非是利用自动化测试工具(相当于软件开发工具),经过对测试需求的分析(软件过程中的需求分析),设计出自动化测试用例(软件过程中的需求规格),从而搭建自动化测试的框架(软件过程中的概要设计),设计与编写自动化脚本(详细设计与…

网络安全合规-网络安全架构

一、安全框架及模型定义 信息安全模型是用于精确和形式的描述信息系统的安全特征,以及用于解释系统安全相关行为的理由。 安全模型的作用&#xff1a; 准确地描述安全的重要方面与系统行为的关系。 提高对成功实现关键安全需求的理解层次。 从中开发出一套安全性评估准则&…

【来不及刷题之】37、排序链表(链表归并排序)

使用直接插入排序时间复杂度太多无法通过&#xff0c;使用归并排序&#xff0c;主要有三个步骤&#xff1a; 寻找链表的中间结点&#xff0c;断开成两个等长的链表 对这两个链表分别排序 &#xff08;递归&#xff09; 合并两个排序链表 思路比较简单&#xff0c;但是这里寻…

全解析!汽车APP面临的18种攻击风险

目录 车企App普遍面临的攻击风险 技术风险 合规风险 《白皮书》提供两大安全解决方案 App加固 App隐私合规检测 近日&#xff0c;顶象发布《车企App安全研究白皮书》。该白皮书总结了目前汽车公司App所面临的主要技术威胁和合规风险&#xff0c;详细分析了这些风险产生的…

<Android开发> 集成so库

&#xff1c;Android开发&#xff1e; 集成so库 &#xff1c;Android开发&#xff1e; HAL层集成第三方so库 一 前言 在笔者的另一个文章&#xff1c;Android开发&#xff1e; HAL层集成第三方so库 分析了如何在hal层将第三方的so库文件集成到系统中&#xff1b;本文其实与其…

用组件注解符精简Spring配置文件

一、利用组件注解符精简Spring配置文件 &#xff08;一&#xff09;创建新包 创建net.huawei.spring.day02包 &#xff08;二&#xff09;复制四个类 &#xff08;三&#xff09;修改杀龙任务类 package net.huawei.spring.day02;import org.springframework.stereotype.C…

索引的最左匹配原则全面分析

简介 组合索引中的最左优先&#xff0c;以组合索引中最左边的列为起点任何连续的索引都能匹配上。如果遇到范围查询(>、<、between、like)就会停止匹配。 准备 表 CREATE TABLE test (id bigint(11) NOT NULL,column1 int DEFAULT NULL,column2 int DEFAULT NULL,col…

振弦采集仪在岩土工程安全监测使用的解决方案

振弦采集仪是一种岩土工程安全监测仪器&#xff0c;主要用于监测建筑物、桥梁、隧道、地铁等工程结构的动态响应&#xff0c;以及岩土体的振动情况。其工作原理是通过振弦传感器采集结构或岩土体的振动信号&#xff0c;再通过数据采集系统进行处理和分析&#xff0c;得出结构或…

一文让你快速写出高效的软件测试用例

前言 编写测试用例的目的就是确保测试过程全面高效、有据可查。但要编写出高效的测试用例&#xff0c;需要搞清楚什么是测试用例&#xff0c;以及如何编写出高效的测试用例&#xff1f;接下来将从以下几个部分来进行展开 1、什么是测试用例 2、如何编写测试用例 3、软件测试学…

element-plus的el-select实现触底加载更多(新版本报错踩坑)

前言 element-plus新版增加了一个属性&#xff0c;且默认为true&#xff0c;使得下拉菜单被插入到了body元素下。即.el-select下默认不包含.el-select-dropdown了。 现象 当依旧按照之前的方式&#xff0c;封装自定义指令&#xff0c;实现滚动到el-select下拉菜单的底部&…

Redis从入门到精通之底层数据结构快表QuickList详解

文章目录 0.前言1. 快表的结构2. Redis 6.0 快表quicklist 基本结构2.1 成员变量2.1 主要操作2.1 推导结果 3. 快表的操作 3. 快表的优缺点3.1 优点&#xff1a;3.2 缺点&#xff1a; 5. Redis从入门到精通系列文章 0.前言 上个篇章回顾&#xff0c;我们上个章节&#xff0c;讲…

计算机中丢失msvcp140.dll的解决方案-由于找不到msvcp140.dll的解决方法

本教程操作系统&#xff1a;电脑 Windows系统、 msvcp140.dll是电脑文件中的dll文件&#xff08;动态链接库文件&#xff09;。如果计算机中丢失了某个dll文件&#xff0c;可能会导致某些软件和游戏等程序无法正常启动运行&#xff0c;并且导致电脑系统弹窗报错。 在我们打开…

STM32串口DMA双缓冲,数据接收与发送,HAL库实现

STM32串口DMA双缓冲 1.简介 STM32F429系列DMA支持双缓冲模式进行数据传输&#xff0c;相当于数字电路设计领域的乒乓操作&#xff0c;但是HAL库并没有实现像单缓冲区一样可以简单使用的函数&#xff0c;有的方法是使用单缓冲的方式&#xff0c;但是通过接收半满的中断控制CPU…