4. SSM 整合

news2024/11/25 20:15:30

文章目录

  • 1. 引言
  • 2. 创建工程
  • 3. SSM 整合
  • 2. 统一结果封装
  • 3. 统一异常处理
    • 3.1 异常处理器
    • 3.2 项目异常处理方案
      • 3.2.1 异常分类
      • 3.2.2 异常解决方案
      • 3.2.3 异常解决方案的具体实现
  • 4. 前后台协议联调
    • 4.1 列表功能
    • 4.2 添加功能
    • 4.3 修改功能
    • 4.4 删除功能
  • 5. 拦截器
    • 5.1 拦截器概念

1. 引言

前面已经学习了 Mybatis、Spring 和 SpringMVC 三个框架,现在要把这三个框架整合在一起,完成业务功能开发,整合流程如下:

在这里插入图片描述

2. 创建工程

(1) 新建 module

在这里插入图片描述

(2) 选择模板

在这里插入图片描述

(3) module 名称和路径

在这里插入图片描述

(4) 补充项目结构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(5) 新建必要的包

在这里插入图片描述

3. SSM 整合

Spring 配置类

@Configuration
@ComponentScan("com.itheima.service")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}

不检查 bean 自动装配的语法:

在这里插入图片描述

在这里插入图片描述

2. 统一结果封装

如果后端返回的数据类型很杂乱,前端解析数据会很麻烦。所以后端要能够返回统一的数据类型。

所以就想能不能将返回结果的数据进行统一,思路为:
创建结果模型类,将返回的结果数据封装到 data 属性中;
返回的数据是何种操作及是否操作成功封装到 code 属性中;
操作失败后返回的错误信息封装到 msg 属性中

具体步骤如下:

(1) 设置统一数据返回结果类

public class Result {
    //返回的数据是何种操作及是否操作成功
    private Integer code;
    //返回的结果数据
    private Object data;
    //操作失败后返回的错误信息,可选属性
    private String msg;

    //添加构造方法,方便设置属性,set太麻烦
    public Result() {
    }

    //不带消息的构造方法
    public Result(Integer code, Object data) {
        this.code = code;
        this.data = data;
    }
    //带消息的构造方法
    public Result(Integer code, Object data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }
	//setter...getter...省略
}

注意:Result 类名及类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。

(2) 定义返回码 Code 类

public class Code {
	//增删改查分别为2001、2002、2003、2004
	//成功为1,失败为2
	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;
}

code 类中的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为 GET_OK,GET_ALL_OK,GET_PAGE_OK 等。

(3) 修改 Controller 类的返回值

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;
    @PostMapping
    public Result save(@RequestBody Book book) {
        boolean flag = bookService.save(book);
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }
    @PutMapping
    public Result update(@RequestBody Book book) {
        boolean flag = bookService.update(book);
        return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR, flag);
    }
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        boolean flag = bookService.delete(id);
        return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);
    }
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        Book book = bookService.getById(id);
        int code = (book!=null) ? Code.GET_OK : Code.GET_ERR;
        String msc = (book!=null) ? "" : "查询失败,请重试";
        return new Result(code,book,msc);
    }
    @GetMapping
    public Result getAll() {
        List<Book> bookList = bookService.getAll();
        // bookList里面没有东西不是查询失败,是真的没有
        // bookList为空才是查询失败
        int code = (bookList!=null) ? Code.GET_OK : Code.GET_ERR;
        String msc = (bookList!=null) ? "" : "查询失败,请重试";
        return new Result(code,bookList,msc);
    }
}

3. 统一异常处理

3.1 异常处理器

异常的种类及出现异常的原因:

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

看完上面这些出现异常的位置,会发现,在任何一个位置都有可能出现异常,而且这些异常是不能避免的。所以就得处理异常。

思考:

  • 各个层级均可能出现异常,异常处理代码书写在哪一层?
    所有的异常均抛出到表现层进行处理(数据层抛到业务层,业务层抛到表现层)
  • 异常的种类很多,表现层如何将所有的异常都处理到呢?
    异常分类
  • 表现层处理异常,如果用 try-catch 写,代码量巨大且意义不强,如何解决?
    AOP

对于上面这些问题及解决方案,SpringMVC 提供了一套解决方案:
异常处理器:集中统一地处理项目中出现的异常。

(1) 创建异常处理器类

//当前类为REST风格对应的异常处理器
//被SpringMvcConfig中的@ComponentScan("com.itheima.controller")扫描到
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //拦截所有类型的异常
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        return new Result(666, null);
    }
}

一定要确保 SpringMvcConfig 能够扫描到异常处理器类。

(2) 让程序抛出异常

修改 BookController 的 getById 方法,添加 int i = 1/0。

@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
    int i = 1/0;
    Book book = bookService.getById(id);
    int code = (book!=null) ? Code.GET_OK : Code.GET_ERR;
    String msc = (book!=null) ? "" : "查询失败,请重试";
    return new Result(code,book,msc);
}

启动运行程序,测试:

在这里插入图片描述

3.2 项目异常处理方案

3.2.1 异常分类

异常处理器已经能够使用了,那么在项目中该如何来处理异常呢?

因为异常的种类有很多,如果每个异常都对应一个@ExceptionHandler,那就要写很多个方法来处理各自的异常,所以在处理异常之前,需要对异常进行一个分类:

(1) 业务异常(BusinessException)

  • 规范的用户行为产生的异常:用户在页面输入内容的时候未按照指定格式进行数据填写,如在年龄框输入的是字符串。
    在这里插入图片描述
  • 不规范的用户行为操作产生的异常:如用户故意传递错误数据
    在这里插入图片描述

(2) 系统异常(SystemException)

  • 项目运行过程中可预计但无法避免的异常:如数据库或服务器宕机

(3) 其他异常(Exception)

  • 编程人员未预期到的异常,如:用到的文件不存在

将异常分类以后,针对不同类型的异常,要提供具体的解决方案。

3.2.2 异常解决方案

(1) 业务异常(BusinessException)

  • 发送对应消息传递给用户,提醒规范操作
    常见的就是提示用户名已存在、密码格式不正确等

(2) 系统异常(SystemException)

  • 发送固定消息传递给用户,安抚用户
    • 系统繁忙,请稍后再试
    • 系统正在维护升级,请稍后再试
    • 系统出问题,请联系系统管理员等
  • 发送特定消息给运维人员,提醒维护
    • 可以发送短信、邮箱或者是公司内部通信软件
  • 记录日志

发消息和记录日志对用户来说是不可见的,属于后台程序。

(3) 其他异常(Exception)

  • 发送固定消息传递给用户,安抚用户
  • 发送特定消息给编程人员,提醒维护(纳入预期范围内)
    • 一般是程序没有考虑全,比如未做非空校验等
  • 记录日志

3.2.3 异常解决方案的具体实现

  • 先通过自定义异常,完成 BusinessException 和SystemException 的定义
  • 将其他异常包装成自定义异常类型
  • 在异常处理器类中对不同的异常进行处理

在这里插入图片描述

(1) 自定义异常类

//运行时异常可以不处理,自动向上抛。
//如果该类不继承RuntimeException,该类下的每个方法都要throws SystemException
public class SystemException extends RuntimeException{
    //出异常之后,加个编号,来帮助识别是哪一种异常
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
    //加上需要的构造方法
    //alt+insert会出来很多构造方法,选择需要的即可,也可以都加
    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;
    }
}

BusinessException.java 由 SystemException.java 复制粘贴就行,会自动更改构造方法名。

//运行时异常可以不处理,自动向上抛。
//如果该类不继承RuntimeException,该类下的每个方法都要throws SystemException
public class BusinessException extends RuntimeException{
    //出异常之后,加个编号,来帮助识别是哪一种异常
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
    //加上需要的构造方法
    //alt+insert会出来很多构造方法,选择需要的即可,也可以都加
    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;
    }
}

(2) 将其他异常包成自定义异常

具体的包装方式有:

  • 方式 1:直接 throw 自定义异常。
  • 方式 2:try-catch,在 catch 中重新 throw 自定义的异常。
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
    //模拟业务异常,使用方式 1
    if (id == 1){
        throw new BusinessException(Code.BUSINESS_ERR, "请不要使用你的技术挑战我的耐心!");
    }
    //模拟系统异常,使用方式 2
    try {
        int i = 1/0;
    }catch (Exception e){
        throw new SystemException(Code.SYSTEM_TIMEOUT_ERR, "服务器访问超时,请重试!", e);
    }

    Book book = bookService.getById(id);
    int code = (book!=null) ? Code.GET_OK : Code.GET_ERR;
    String msc = (book!=null) ? "" : "查询失败,请重试";
    return new Result(code,book,msc);
}

上面为了使 code 看着更专业些,在 Code 类中再新增需要的属性:

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;
    //新增属性
    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;
}

(3) 拦截并处理自定义异常

//当前类为REST风格对应的异常处理器
//被SpringMvcConfig中的@ComponentScan("com.itheima.controller")扫描到
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //拦截系统异常
    @ExceptionHandler(SystemException.class)
    public Result doException(SystemException ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(ex.getCode(), null, ex.getMessage());
        //getMessage是继承得来的
    }
    //拦截业务异常
    @ExceptionHandler(BusinessException.class)
    public Result doException(BusinessException ex){
        return new Result(ex.getCode(), null, ex.getMessage());
        //getMessage是继承得来的
    }
    //拦截其他未知的异常
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统繁忙,请稍后再试");
    }
}

运行测试:

(1) 测试业务异常

在这里插入图片描述

(2) 测试系统异常

在这里插入图片描述

4. 前后台协议联调

4.1 列表功能

在这里插入图片描述

4.2 添加功能

新增时首先显示窗口,清理表单数据,然后添加表单中填写的数据。

在这里插入图片描述

//弹出添加窗口
handleCreate() {
    this.dialogFormVisible = true;
    this.resetForm();
},

//重置表单
resetForm() {
    this.formData = {};
},

//添加
handleAdd () {
    //发送ajax请求
    axios.post("/books",this.formData).then((res)=>{
        //如果操作成功,关闭弹层,显示数据
        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();
    });
},

4.3 修改功能

在这里插入图片描述

//弹出编辑窗口
handleUpdate(row) {
    //查询数据,根据id查询
    axios.get("/books/"+row.id).then((res)=>{
        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)=>{
        console.log(res.data);
        //如果操作成功,关闭弹层,显示数据
        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();
    });
},

4.4 删除功能

在这里插入图片描述

// 删除
handleDelete(row) {
    //弹出提示框
    this.$confirm("此操作永久删除当前数据,是否继续?", "提示", {
        type: 'info'
    }).then(()=>{//确定时
        //做删除业务
        axios.delete("/books/"+row.id).then((res)=>{
            if(res.data.code == 20021){
                this.getAll();
                this.$message.success("删除成功");
            }else{
                this.$message.error("删除失败");
            }
        });
    }).catch(()=>{//取消时
        //取消删除
        this.$message.info("取消删除操作");
    });
}

5. 拦截器

5.1 拦截器概念

讲解拦截器的概念之前,先看一张图:

在这里插入图片描述
(1) 浏览器发送一个请求会先到 Tomcat 的 web 服务器
(2) Tomcat 服务器接收到请求以后,会去判断请求的是静态资源还是动态资源
(3) 如果是静态资源,会直接到 Tomcat 的项目部署目录下去直接访问
(4) 如果是动态资源,就需要交给项目的后台代码进行处理
(5) 在找到具体的方法之前,可以去配置过滤器(可以配置多个),按照顺序进行执行
(6) 然后进入到到中央处理器(SpringMVC 中的内容),SpringMVC 会根据配置的规则进行拦截
(7) 如果满足规则,则进行处理,找到其对应的 controller 类中的方法进行执行,完成后返回结果
(8) 如果不满足规则,则不进行处理
(9) 这个时候,如果需要在每个 Controller 方法执行的前后添加业务,具体该如何来实现?这个就是拦截器要做的事

拦截器(Interceptor)是一种动态拦截方法调用的机制,在 SpringMVC 中动态拦截控制器方法的执行作用:在指定的方法调用前后执行预先设定的代码阻止原始方法的执行总结:拦截器就是用来做增强看完以后,大家会发现

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

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

相关文章

mysql数据库之innodb存储引擎架构之内存架构

一、逻辑存储结构 mysql5.5版本开始&#xff0c;默认使用innodb存储引擎&#xff0c;它擅长事务处理&#xff0c;具有崩溃恢复特性&#xff0c;在日常开发中使用非常广泛。 架构图&#xff08;左侧为内存架构&#xff0c;右侧为磁盘架构&#xff09; 二、 内存架构。 1、缓冲…

SpringBoot使用Redis实现缓存

目录 实现步骤 1. 在 pom.xml 配置文件中添加如下依赖 2. 在 application.properties 中添加如下配置 3. 新建 RedisConfig.class&#xff0c;继承 CachingConfigurerSupport&#xff0c;添加如下方法 4. 新建 RedisService.class 添加如下方法 注意&#xff1a;cacheKey…

看完书上的栈不过瘾,为什么不动手试试呢?

一.栈的基本概念1.栈的定义栈&#xff08;Stack&#xff09;&#xff1a;是只允许在一端进行插入或删除的线性表。首先栈是一种线性表&#xff0c;但限定这种线性表只能在某一端进行插入和删除操作。其中注意几点&#xff1a;栈顶&#xff08;Top&#xff09;&#xff1a;线性表…

2023年新三板产品及服务研究报告

第一章 概述 全国中小企业股份转让系统&#xff08;英语&#xff1a;National Equities Exchange and Quotations&#xff0c;缩写NEEQ&#xff09;&#xff0c;简称股转系统&#xff0c;是第三家全国性证券交易场所&#xff0c;因挂牌企业均为高科技企业而不同于原转让系统内…

软件测试12

一 Linux命令的共通知识点 1.通配符的使用 通配符&#xff1a;又叫文件名替换符号&#xff0c;符号具备特殊含义&#xff0c;例如&#xff1a;文件名&#xff1a;test&#xff0c;通配符可以写成???或者* *&#xff1a;代表可以匹配任意长度的文件名&#xff08;all所有&am…

xxl-job registry fail

解决方法&#xff1a; 1、检查nacos是否正确&#xff0c;一定要注意格式&#xff0c;一般都是addersses的地址问题&#xff0c;一定的要加/不然找不到&#xff0c;本机就不要使用ip了&#xff0c;用localhost。 xxl: job: admin: addresses: http://localhost:8080/xxl-job-ad…

【java】 java开发中 常遇到的各种难点 思路方案

文章目录逻辑删除如何建立唯一索引唯一索引失效问题加密字段模糊查询问题maven依赖冲突问题&#xff08;jar包版本冲突问题&#xff09;sql in条件查询时 将结果按照传入顺序排序作为一个开发人员 总会遇到各种难题 本文列举博主 遇见/想到 的例子 &#xff0c;也希望同学们可以…

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S跑LVGL图形demo

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S屏幕跑LVGL图形demo&#x1f3ac;运行LVGL 按键组件demo ✨基于STM32CubeMX配置工程是因为方便移植&#xff0c;只要是STM32芯片&#xff0c;拿到我的这个工程源码就可以根据自己的stm32芯片&#xff0c;自…

操作系统复试

2017软学 给出操作系统的定义&#xff0c;分别从资源管理&#xff0c;任务调度&#xff0c;用户接口等三个方面论述操作系统的职能 操作系统是位于硬件层之上、所有其他系统软件层之下的一个系统软件&#xff0c;使得管理系统中的各种软件和硬件资源得以充分利用&#xff0c;方…

MATLAB——求连续系统的响应

题目&#xff1a; 已知RC一阶高通电路图的系统函数H(s)为 H(s)UR(S)U(S)RRR1SCsRCsRC1H(s)\frac {UR(S)}{U(S)}R\frac {R}{R\frac {1}{SC}}\frac {sRC}{sRC1}H(s)U(S)UR(S)​RRSC1​R​sRC1sRC​ 其中&#xff1a;R200Ω &#xff0c;C0.47μF 。求其幅度频率响应与相位频率响应…

公网NAT网关与VPC NAT网关介绍与实践

NAT网关介绍 NAT网关是一种网络地址转换服务&#xff0c;提供NAT代理&#xff08;SNAT和DNAT&#xff09;能力。 公有云NAT分为公网NAT网关和VPC NAT网关。 1&#xff09;公网NAT网关&#xff1a;提供公网地址转换服务。 2&#xff09;VPC NAT网关&#xff1a;提供私网地址转换…

商品获价API调用说明:获取商品历史价格信息 代码分享

接口名称&#xff1a;item_history_price公共参数名称类型必须描述keyString是调用key&#xff08;获取测试key&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString…

Linux磁盘空间占满了

Linux服务器没有安装很多东西&#xff0c;但是硬盘空间爆满了。。。 df -h 查看硬盘空间&#xff0c;发现使用了99%。 刚开始以为是日志文件的占用的&#xff0c;删除了linux日志文件&#xff0c;发现作用不大&#xff0c;只多了几G。 不妨试试下面的命令 lsof L1 发现了有个…

SQL技能 - 窗口函数

SQL技能 - 窗口函数1. 排序函数1.1. 不分组排序1.2. 分组排序2. 聚合函数实现滑动窗口计算2.1. 常用聚合函数2.2. 滑动行范围的常用表达2.3. 示例3. lag、lead函数求增长率&#xff08;同比、环比&#xff09;窗口函数表达式&#xff1a; function(arg) OVER ([PARTITION BY ex…

K8s kubectl 高效使用技巧,搞定批处理!

1.kubectl用法详解 1. kubectl语法 kubectl [command] [Type] [NAME] [flags] command: 子命令&#xff0c;用于操作kubernetes集群资源对象的命令&#xff0c;例如&#xff1a;create, delete, describe, get, apply等等 TYPE: 资源对象的类型&#xff0c;区分大小写&#…

可视化组件届的仙女‖蝴蝶结图、玫瑰环图、小提琴图

在上一篇内容中为大家介绍了几个堪称可视化组件届吴彦祖的高级可视化图表。既然帅哥有了&#xff0c;怎么能少得了美女呢&#xff1f;今天就为大家介绍几个可视化组件届的“美女姐姐”&#xff0c;说一句是组件届的刘亦菲不为过。蝴蝶结图蝴蝶结图因其形似蝴蝶结而得名&#xf…

SDL—安全培训

0x00 前言 软件开发团队的所有成员都必须接受适当的培训&#xff0c;了解安全基础知识以及安全和隐私方面的最新趋势。直接参与软件程序开发的技术角色人员&#xff08;开发人员、测试人员和程序经理&#xff09;每年必须参加至少一门特有的安全培训课程。 这个是微软针对安全培…

蓝牙耳机哪个戴的最舒服?久戴不累的蓝牙耳机推荐

在喧嚣的时代中&#xff0c;快节奏和疲惫充斥着我们的生活&#xff0c;于是耳机成为了人们必不可少的东西&#xff0c;无论是闲暇时亦或是正处在工作时&#xff0c;都会将它戴上&#xff0c;出门在外戴耳机变成了常态&#xff0c;所以小编就整理了一期久戴不累的蓝牙耳机。 No…

【专项】112. 路径总和

112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 …

深度学习部署笔记(八): CUDA RunTime API-2.1Hello CUDA

1. CUDA Driver API和CUDA Runtime API CUDA Driver API和CUDA Runtime API都是用于访问GPU的API。它们之间的区别在于它们的功能和使用方法不同。 CUDA Driver API是一个底层的API&#xff0c;它提供了对GPU硬件的底层访问&#xff0c;以及GPU硬件的直接控制。使用Driver AP…