Jackson 2.x 系列【5】注解大全篇一

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

源码地址:https://gitee.com/pearl-organization/study-jackson-demo

文章目录

    • 1. 前言
    • 2. 注解大全
      • 2.1 @JsonIgnore
      • 2.2 @JsonFormat
      • 2.3 @JsonInclude
      • 2.4 @JsonProperty
      • 2.5 @JsonAlias
      • 2.6 @JsonIgnoreType
      • 2.7 @JsonIgnoreProperties
      • 2.8 @JsonPropertyOrder
      • 2.9 @JsonGetter
      • 2.10 @JsonSetter

1. 前言

在前几篇文档中,我们学习了Jackson中几个非常重要的类,并实现了一些简单的JSON数据转换功能。在实际开发中,可能会遇到的一些个性化要求的场景,而不是简单的一些直接转换,例如,对于null值字段、敏感字段不进行序列化;Long类型的字段需要序列化为String类型(不然返回给前端时会丢失精度)…

Jackson提供了两种方式来满足个性化场景,以定制序列化/反序列化行为:

  • 配置注解Jackson提供了很多注解,用于标识Java Bean类、方法、构造器、属性
  • 配置特性枚举Jackson提供了很多xxxFeature枚举类,在读写对象中进行设置

⛹⛹⛹接下来我们了解下Jackson提供的所有注解,按照它们的使用频率顺序进行讲解。⛹⛹⛹

2. 注解大全

Jackson中的大部分注解都在jackson-annotations模块中,位于com.fasterxml.jackson.annotation包下,在jackson-databind模块中也提供了一些注解。

2.1 @JsonIgnore

@JsonIgnore标识序列化/反序列化时是否忽略该字段。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnore {
	// 是否忽略,默认true
    boolean value() default true;
}

UserInfo类的id属性添加 @JsonIgnore

public class UserInfo{
    @JsonIgnore
    // 用户ID
    private Long id;
    // 省略其他......
}

进行转换:

        ObjectMapper objectMapper = new ObjectMapper();
        // POJO -> JSON
        UserInfo user = new UserInfo();
        user.setId(1767798780627279333L);
        user.setName("老三");
        user.setAge(25);
        String json = objectMapper.writeValueAsString(user);
        System.out.println(json);

        // JSON -> POJO
        String userJson="{\"id\":1767798780627279873,\"name\":\"坤坤\",\"age\":18,\"org\":null,\"roleList\":null}";
        UserInfo readUserByJson = objectMapper.readValue(userJson, UserInfo.class);
        System.out.println(readUserByJson);

可以看到id字段被忽略了:

{"name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=null, name='坤坤', age=18, org=null, roleList=null}

2.2 @JsonFormat

@JsonFormat标识使用格式模板进行序列化/反序列化

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFormat {
    // 默认的 Locale,java.util.Locale#getDefault()
    String DEFAULT_LOCALE = "##default";
    // 默认的 时区,来自于  java.util.TimeZone
    String DEFAULT_TIMEZONE = "##default";
	// 格式模板
    String pattern() default "";
    // 指定序列化后的类型
    Shape shape() default JsonFormat.Shape.ANY;
	// Java Locale 
    String locale() default "##default";
    // 时区
    String timezone() default "##default";
    // 是否启用“宽松”处理
    OptBoolean lenient() default OptBoolean.DEFAULT;
    // 开启某些特性
    Feature[] with() default {};
    // 关闭某些特征
    Feature[] without() default {};
    // 省略其他......
}

UserInfo类的birthdayDate属性添加 @JsonFormat注解:

    @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date birthdayDate;

序列化/反序列化结果:

{"id":1767798780627279333,"birthdayDate":"2024-03-21 09:40:33","birthdayLocalDateTime":null,"name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=1767798780627279333, birthdayDate=Thu Mar 21 09:40:33 CST 2024, birthdayLocalDateTime=null, name='老三', age=25, org=null, roleList=null}

UserInfo类的birthdayLocalDateTime属性添加 @JsonFormat注解:

    @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime birthdayLocalDateTime;

这时会报错InvalidDefinitionException,不支持java.time.LocalDateTime

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.pearl.jacksoncore.demo.databind.anno.UserInfo["birthdayLocalDateTime"])

LocalDateTimeJava 8JSR 310规范下新的日期时间APIJackson核心模块并没有实现支持,需要引入jackson-datatype-jsr310模块:

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.17.0</version>
        </dependency>

并指定序列化/反序列化器:

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime birthdayLocalDateTime;

再次运行,结果如下:

{"id":1767798780627279333,"birthdayDate":"2024-03-21 09:47:59","birthdayLocalDateTime":"2024-03-21 09:47:59","name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=1767798780627279333, birthdayDate=Thu Mar 21 09:47:59 CST 2024, birthdayLocalDateTime=2024-03-21T09:47:59, name='老三', age=25, org=null, roleList=null}

2.3 @JsonInclude

@JsonFormat标识符合指定规格时才进行序列化

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonInclude {
	//   规则:
	//   ALWAYS, 总是序列化
    //   NON_NULL, 不为NULL才序列化
    //   NON_ABSENT, NON_NULL的基础上,支持 Optional
    //   NON_EMPTY,  NON_ABSENT的基础上,支持集合、String
    //   NON_DEFAULT, 不是默认值才序列化
    //   CUSTOM, 自定义
    //   USE_DEFAULTS; 默认
    //  作用于类、属性
    Include value() default JsonInclude.Include.ALWAYS;
	// 作用于 Map、AtomicReference等
    Include content() default JsonInclude.Include.ALWAYS;
    // 自定义规则需要实现的过滤器
    Class<?> valueFilter() default Void.class;
	// 自定义规则需要实现的过滤器
    Class<?> contentFilter() default Void.class;

UserInfo类的birthdayDate属性添加 @JsonFormat注解,配置规则为NON_NULL时才进行序列化:

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String name;

运行结果如下:

        user.setName(null);
        String JsonIncludeJson = objectMapper.writeValueAsString(user);
        System.out.println(JsonIncludeJson);
        // {"birthdayDate":"2024-03-21 11:00:23","birthdayLocalDateTime":"2024-03-21 11:00:23","age":25,"org":null,"roleList":null}

2.4 @JsonProperty

@JsonProperty用于在序列化/反序列化时进行重命名。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty {
    String USE_DEFAULT_NAME = "";
    int INDEX_UNKNOWN = -1;
	// 重命名后的属性名称
    String value() default "";
    String namespace() default "";
    boolean required() default false;
	// 索引位置
    int index() default -1;
    String defaultValue() default "";
	// 可见性配置 可以控制只在序列化或者只反序列化时生效
    Access access() default JsonProperty.Access.AUTO;

    public static enum Access {
    	// 自动确定对此属性的读/或访问权限
        AUTO,
        // 只读
        READ_ONLY,
        // 只写
        WRITE_ONLY,
        // 可读写
        READ_WRITE;
    }
}

UserInfo类的age属性添加 @JsonProperty注解:

    @JsonProperty(value = "userAge")
    private Integer age;

序列化后结果:

{"userAge":25,"birthdayDate":"2024-03-21 11:43:25","birthdayLocalDateTime":"2024-03-21 11:43:25","org":null,"roleList":null}

2.5 @JsonAlias

@JsonAlias用于在反序列化时进行重命名。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAlias {
    String[] value() default {};
}

例如JSON中属性名称为usernameUserInfo类中的属性名称为name,则可以使用@JsonAlias指定反序列化时的别名:

    @JsonAlias("username")
    private String name;

示例如下:

        String userAliasJson="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":null,\"roleList\":null}";
        UserInfo readUserByAliasJson = objectMapper.readValue(userAliasJson, UserInfo.class);
        System.out.println(readUserByAliasJson);
        // UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=null, roleList=null}

2.6 @JsonIgnoreType

@JsonIgnoreType作用于类,当该类作为对象属性在序列化/反序列化时会被忽略。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreType {
	// 是否忽略,默认 ture
    boolean value() default true;
}

例如我们在Org类中添加该注解:

@JsonIgnoreType
public class Org {
	// 省略.....
 }

执行反序列化:

        // 6. @JsonIgnoreType
        String userJsonIgnoreTypeStr="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
        UserInfo readUserByJsonIgnoreType = objectMapper.readValue(userJsonIgnoreTypeStr, UserInfo.class);
        System.out.println(readUserByJsonIgnoreType);

虽然JSON内容包含了Org对象,但是被忽略掉了:

UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=null, roleList=null}

2.7 @JsonIgnoreProperties

@JsonIgnoreProperties用于在序列化/反序列化时忽略某个字段属性,比@JsonIgnore功能更强,可以作用于类,配置多个忽略属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreProperties {
	// 忽略的多个属性名称
    String[] value() default {};
	// 是否忽略不能识别的属性
    boolean ignoreUnknown() default false;
	// 是否允许访问属性的Getter方法,即支持Getter进行序列化
    boolean allowGetters() default false;
	// 是否允许访问属性的Setters方法,即支持Setters进行反序列化
    boolean allowSetters() default false;
}

Org类上标识忽略idorgName属性:

@JsonIgnoreProperties({"orgName","id"})
public class Org {
	// 省略.....
 }

案例演示,当前JSON包含了idorgName属性:

        String userIgnorePropertiesStr="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
        UserInfo readUserByIgnoreProperties = objectMapper.readValue(userIgnorePropertiesStr, UserInfo.class);
        System.out.println(readUserByIgnoreProperties);

反序列化时idorgName属性被忽略:

UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=Org{id=null, orgName='null', address='浙江杭州'}, roleList=null}

之外还支持allowGetters 配置可以进行序列化,但反序列化时被忽略(allowSetters同理):

@JsonIgnoreProperties( value = "password",allowGetters = true)

2.8 @JsonPropertyOrder

@JsonPropertyOrder用于在序列化时进行排序。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyOrder {
	// 指定顺序
    String[] value() default {};
	// 是否按照字母表排序
    boolean alphabetic() default false;
}

示例代码:

@JsonPropertyOrder({"org","roleList","birthdayDate","id"})

输出结果:

{"org":null,"roleList":null,"birthdayDate":"2024-03-21 14:44:49","birthdayLocalDateTime":"2024-03-21 14:44:49","password":null,"userAge":25}

2.9 @JsonGetter

@JsonGetter@JsonProperty功能类似用于重命名,官方提示使用其替代方案@JsonProperty

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonGetter {
    String value() default "";
}

示例代码:

    @JsonGetter("userSex")
    public String getSex() {
        return sex;
    }

可以看到在序列化/反序列化时都会生效,一般使用@JsonProperty即可:

        user.setSex("男");
        String jsonGettersStr = objectMapper.writeValueAsString(user);
        System.out.println(jsonGettersStr);

        String jsonGetterStr="{\"userSex\":\"男\",\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
        UserInfo readUserByJsonGetter = objectMapper.readValue(jsonGetterStr, UserInfo.class);
        System.out.println(readUserByJsonGetter);

2.10 @JsonSetter

@JsonSetter@JsonProperty功能类似用于重命名,官方提示使用其替代方案@JsonProperty

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSetter {
    String value() default "";

    Nulls nulls() default Nulls.DEFAULT;

    Nulls contentNulls() default Nulls.DEFAULT;

示例代码:

    @JsonSetter("mobilePhone")
    public void setPhone(String phone) {
        this.phone = phone;
    }

可以看到在序列化/反序列化时都会生效:

        user.setPhone("13899996666");
        String jsonSettersStr = objectMapper.writeValueAsString(user);
        System.out.println(jsonSettersStr);

        String jsonSetterStr="{\"mobilePhone\":\"13899996666\",\"userSex\":\"男\",\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
        UserInfo readUserByJsoSetter = objectMapper.readValue(jsonSetterStr, UserInfo.class);
        System.out.println(readUserByJsoSetter);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自动化测试 —— Pytest fixture及conftest详解

前言 fixture是在测试函数运行前后&#xff0c;由pytest执行的外壳函数。fixture中的代码可以定制&#xff0c;满足多变的测试需求&#xff0c;包括定义传入测试中的数据集、配置测试前系统的初始状态、为批量测试提供数据源等等。fixture是pytest的精髓所在&#xff0c;类似u…

Linux系统使用Docker部署MinIO结合内网穿透实现公网访问本地存储服务

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

pulsar: kafka on pulsar之把pulsar当kafka用

一、下载协议包&#xff08;要和pulsar版本比较一致&#xff09; https://github.com/streamnative/kop/releases?q2.8.0&expandedtrue二、在pulsar的根目录创建一个protocols目录&#xff0c;将上述包放到这个目录里 三、编辑broker.conf(如果是集群)或者standalone.con…

学点儿数据库_Day12_数据库SQL练习题

0 版本与工具 mysql-8.0.31 Navicat Premium 16 每做一题&#xff0c;选中相应代码运行即可&#xff0c;很方便 1 建表 create table goods (goods_id mediumint(8) unsigned primary key auto_increment,goods_name varchar(120) not null default ,cat_id smallint(5) un…

cesium vue 绘制标记实体(撒点),监听鼠标左击事件

添加实体 const viewer new Cesium.Viewer(cesiumContainer, {})viewer.entities.add()查看实体 const viewer new Cesium.Viewer(cesiumContainer, {}) const billboard viewer.entities.add({...})viewer.zoomTo(billboard)删除实体 根据实体删除 if (billboard.value…

C#手术麻醉信息系统全套商业源码,自主版权,支持二次开发 医院手麻系统源码

手术麻醉信息系统是HIS产品的中的一个组成部分&#xff0c;主要应用于医院的麻醉科&#xff0c;属于电子病历类产品。医院麻醉监护的功能覆盖整个手术与麻醉的全过程&#xff0c;包括手术申请与排班、审批、安排、术前、术中和术后的信息管理提供支持。 手术麻醉信息系统可与EM…

《QT实用小工具·一》电池电量组件

1、概述 项目源码放在文章末尾 本项目实现了一个电池电量控件&#xff0c;包含如下功能&#xff1a; 可设置电池电量&#xff0c;动态切换电池电量变化。可设置电池电量警戒值。可设置电池电量正常颜色和报警颜色。可设置边框渐变颜色。可设置电量变化时每次移动的步长。可设置…

重学SpringBoot3-SpringBoot可执行JAR的原因

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-SpringBoot可执行JAR的原因 Spring Boot可执行JAR的结构打包运行JAR 包内部结构 工作原理优点总结 Spring Boot 的一个核心特性是它的可执行 JAR&#x…

stm32之GPIO寄存器

文章目录 1 背景2 GPIO寄存器的类型2.1 端口配置寄存器2.2 设置/清除寄存器和位清除寄存器 3 总结 1 背景 C51单片机在进行数据的输入输出时&#xff0c;是直接操作与外部引脚关联的内部寄存器&#xff0c;例如&#xff0c;当设置P2_1为0时&#xff0c;就是将外部引脚的P21引脚…

Composer常见错误解决指南 ️

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

基于java疫情防控系统

疫情防控系统 伴随着新年的喜悦&#xff0c;2020年春节之际一场新冠疫情席卷了全球&#xff0c;但是在中国领导人的英明领导之下我国的疫情很快得到了控制&#xff0c;但是因为欧美等国家对疫情的不够重视&#xff0c;仍然有很多的境外疫情携带者会出入我国&#xff0c;为了能…

语句数据库查询有数据,放在帆软预览没数据

问题描述&#xff1a; 要展示的数据&#xff0c;写的sql放在帆软里面预览没数据&#xff0c;然后将语句预览丢在数据库里执行有数据。 问题解决: 1. 首先你要确保两个用的是一个数据库&#xff0c;如果在生产环境中&#xff0c;一般是会有多个数据库&#xff0c;所以你要确保你…

Spring boot 发送文本邮件 和 html模板邮件

Spring boot 发送文本邮件 和 html模板邮件 提示&#xff1a;这里使用 spring-boot-starter-mail 发送文本邮件 和 html模板邮件 文章目录 Spring boot 发送文本邮件 和 html模板邮件一、开启QQ邮箱里的POP3/SMTP服务①&#xff1a;开启步骤 二、简单配置①&#xff1a;引入依赖…

「JavaSE」Lambda表达式

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;快来卷Java啦 &#x1f387;欢迎点赞收藏加关注哦&#xff01; Lambda表达式 &#x1f349;简介&#x1f349;函数式接口&#x1f34c;注解 &#x1f349;语法&#x1f349;Lambda表达式的基本…

如何使用Java语言发票查验接口实现发票真伪查验、票据ocr

随着时代潮流的发展&#xff0c;企业也在寻找更加便捷、高效的办公模式&#xff0c;尤其是针对财务工作人员而言&#xff0c;繁琐的发票录入、查验工作占据了财务人员的大部分时间。对此&#xff0c;翔云提供了发票识别接口、发票查验接口&#xff0c;那么企业应当如何将这些接…

第二证券|沪指震荡涨0.49%,石油、有色等板块拉升

29日早盘&#xff0c;沪指盘中强势上扬&#xff0c;深成指、创业板指小幅走低&#xff0c;科创50指数跌超1%。 到午间收盘&#xff0c;沪指涨0.49%报3025.56点&#xff0c;深成指跌0.22%&#xff0c;创业板指微跌0.07%&#xff0c;科创50指数跌1.34%&#xff1b;两市算计成交5…

SAMRTFORMS 转换PDF 发送邮件

最终成果&#xff1a; *&---------------------------------------------------------------------**& Report ZLC_FIND_EXIT*&---------------------------------------------------------------------**&根据T-CODE / 程序名查询出口、BADI增强*&-------…

【LeetCode】LeetCode 547. 省份数量(Java版 什么是并查集)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 一、题目描述 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间接相连。 省份 是一组直…

位操作符

简介&#xff1a; &&#xff0c;|,^,~都是常见的位操作符&#xff0c;操作对象是二进制数&#xff0c;运算时须将原码转换成补码&#xff08;符号位为0&#xff0c;即正数时&#xff0c;补码与原码一致&#xff0c;不需要再转换&#xff09;&#xff0c;位数不一致时&#…

ros2相关代码记录

1.ros2概述 ROS2&#xff08;Robot Operating System 2&#xff09;是一个用于机器人应用程序的开源软件框架。它是ROS&#xff08;Robot Operating System&#xff09;的下一代版本&#xff0c;旨在改进和扩展原始ROS的特性&#xff0c;以适应更广泛的机器人应用场景和需求。…
最新文章