数据脱敏方案
数据脱敏方案
什么是数据脱敏
数据脱敏的定义
数据脱敏百度百科中是这样定义的:
数据脱敏,指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。这样就可以在开发、测试和其它非生产环境以及外包环境中安全地使用脱敏后的真实数据集。在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供测试使用,如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。是数据库安全技术之一。
总的来说,数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。
在数据脱敏过程中,通常会采用不同的算法和技术,以根据不同的需求和场景对数据进行处理。例如,对于身份证号码,可以使用掩码算法(masking)将前几位数字保留,其他位用 “X” 或 “*” 代替;对于姓名,可以使用伪造(pseudonymization)算法,将真实姓名替换成随机生成的假名。
常用脱敏规则
常用脱敏规则是为了保护敏感数据的安全性,在处理和存储敏感数据时对其进行变换或修改。
下面是几种常见的脱敏规则:
- 替换(常用):将敏感数据中的特定字符或字符序列替换为其他字符。例如,将信用卡号中的中间几位数字替换为星号(*)或其他字符。
- 删除:将敏感数据中的部分内容随机删除。比如,将电话号码的随机 3 位数字进行删除。
- 重排:将原始数据中的某些字符或字段的顺序打乱。例如,将身份证号码的随机位交错互换。
- 加噪:在数据中注入一些误差或者噪音,达到对数据脱敏的效果。例如,在敏感数据中添加一些随机生成的字符。
- 加密(常用):使用加密算法将敏感数据转换为密文。例如,将银行卡号用 MD5 或 SHA-256 等哈希函数进行散列。
常用脱敏工具
Hutool
Hutool 一个 Java 基础工具类,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法进行封装,组成各种 Util 工具类,同时提供以下组件:
模块 | 介绍 |
---|---|
hutool-aop | JDK 动态代理封装,提供非 IOC 下的切面支持 |
hutool-bloomFilter | 布隆过滤,提供一些 Hash 算法的布隆过滤 |
hutool-cache | 简单缓存实现 |
hutool-core | 核心,包括 Bean 操作、日期、各种 Util 等 |
hutool-cron | 定时任务模块,提供类 Crontab 表达式的定时任务 |
hutool-crypto | 加密解密模块,提供对称、非对称和摘要算法封装 |
hutool-db | JDBC 封装后的数据操作,基于 ActiveRecord 思想 |
hutool-dfa | 基于 DFA 模型的多关键字查找 |
hutool-extra | 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等) |
hutool-http | 基于 HttpUrlConnection 的 Http 客户端封装 |
hutool-log | 自动识别日志实现的日志门面 |
hutool-script | 脚本执行封装,例如 Javascript |
hutool-setting | 功能更强大的 Setting 配置文件和 Properties 封装 |
hutool-system | 系统参数调用封装(JVM 信息等) |
hutool-json | JSON 实现 |
hutool-captcha | 图片验证码实现 |
hutool-poi | 针对 POI 中 Excel 和 Word 的封装 |
hutool-socket | 基于 Java 的 NIO 和 AIO 的 Socket 封装 |
hutool-jwt | JSON Web Token (JWT) 封装实现 |
可以根据需求对每个模块单独引入,也可以通过引入hutool-all
方式引入所有模块,本文所使用的数据脱敏工具就是在 hutool.core
模块。
现阶段最新版本的 Hutool 支持的脱敏数据类型如下,基本覆盖了常见的敏感信息。
- 用户 id
- 中文姓名
- 身份证号
- 座机号
- 手机号
- 地址
- 电子邮件
- 密码
- 中国大陆车牌,包含普通车辆、新能源车辆
- 银行卡
一行代码实现脱敏
Hutool 提供的脱敏方法如下图所示:
注意:Hutool 脱敏是通过 * 来代替敏感信息的,具体实现是在 StrUtil.hide 方法中,如果我们想要自定义隐藏符号,则可以把 Hutool 的源码拷出来,重新实现即可。
这里以手机号、银行卡号、身份证号、密码信息的脱敏为例,下面是对应的测试代码。
import cn.hutool.core.util.DesensitizedUtil;
import org.junit.Test;
import org.springframework.boot.test.context.Spring BootTest;/**** @description: Hutool实现数据脱敏*/
@Spring BootTest
public class HuToolDesensitizationTest {@Testpublic void testPhoneDesensitization(){String phone="13723231234";System.out.println(DesensitizedUtil.mobilePhone(phone)); //输出:137****1234}@Testpublic void testBankCardDesensitization(){String bankCard="6217000130008255666";System.out.println(DesensitizedUtil.bankCard(bankCard)); //输出:6217 **** **** *** 5666}@Testpublic void testIdCardNumDesensitization(){String idCardNum="411021199901102321";//只显示前4位和后2位System.out.println(DesensitizedUtil.idCardNum(idCardNum,4,2)); //输出:4110************21}@Testpublic void testPasswordDesensitization(){String password="www.jd.com_35711";System.out.println(DesensitizedUtil.password(password)); //输出:****************}
}
以上就是使用 Hutool 封装好的工具类实现数据脱敏。
配合 JackSon 通过注解方式实现脱敏
现在有了数据脱敏工具类,如果前端需要显示数据数据的地方比较多,我们不可能在每个地方都调用一个工具类,这样就显得代码太冗余了,那我们如何通过注解的方式优雅的完成数据脱敏呢?
如果项目是基于 Spring Boot 的 web 项目,则可以利用 Spring Boot 自带的 jackson 自定义序列化实现。它的实现原来其实就是在 json 进行序列化渲染给前端时,进行脱敏。
第一步:脱敏策略的枚举。
/*** @author* @description:脱敏策略枚举*/
public enum DesensitizationTypeEnum {//自定义MY_RULE,//用户idUSER_ID,//中文名CHINESE_NAME,//身份证号ID_CARD,//座机号FIXED_PHONE,//手机号MOBILE_PHONE,//地址ADDRESS,//电子邮件EMAIL,//密码PASSWORD,//中国大陆车牌,包含普通车辆、新能源车辆CAR_LICENSE,//银行卡BANK_CARD
}
上面表示支持的脱敏类型。
第二步:定义一个用于脱敏的 Desensitization 注解。
@Retention (RetentionPolicy.RUNTIME)
:运行时生效。@Target (ElementType.FIELD)
:可用在字段上。@JacksonAnnotationsInside
:此注解可以点进去看一下是一个元注解,主要是用户打包其他注解一起使用。@JsonSerialize
:上面说到过,该注解的作用就是可自定义序列化,可以用在注解上,方法上,字段上,类上,运行时生效等等,根据提供的序列化类里面的重写方法实现自定义序列化。
/*** @author*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {/*** 脱敏数据类型,在MY_RULE的时候,startInclude和endExclude生效*/DesensitizationTypeEnum type() default DesensitizationTypeEnum.MY_RULE;/*** 脱敏开始位置(包含)*/int startInclude() default 0;/*** 脱敏结束位置(不包含)*/int endExclude() default 0;
}
注:只有使用了自定义的脱敏枚举 MY_RULE
的时候,开始位置和结束位置才生效。
第三步:创建自定的序列化类
这一步是我们实现数据脱敏的关键。自定义序列化类继承 JsonSerializer
,实现 ContextualSerializer
接口,并重写两个方法。
/*** @author* @description: 自定义序列化类*/
@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {private DesensitizationTypeEnum type;private Integer startInclude;private Integer endExclude;@Overridepublic void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {switch (type) {// 自定义类型脱敏case MY_RULE:jsonGenerator.writeString(CharSequenceUtil.hide(str, startInclude, endExclude));break;// userId脱敏case USER_ID:jsonGenerator.writeString(String.valueOf(DesensitizedUtil.userId()));break;// 中文姓名脱敏case CHINESE_NAME:jsonGenerator.writeString(DesensitizedUtil.chineseName(String.valueOf(str)));break;// 身份证脱敏case ID_CARD:jsonGenerator.writeString(DesensitizedUtil.idCardNum(String.valueOf(str), 1, 2));break;// 固定电话脱敏case FIXED_PHONE:jsonGenerator.writeString(DesensitizedUtil.fixedPhone(String.valueOf(str)));break;// 手机号脱敏case MOBILE_PHONE:jsonGenerator.writeString(DesensitizedUtil.mobilePhone(String.valueOf(str)));break;// 地址脱敏case ADDRESS:jsonGenerator.writeString(DesensitizedUtil.address(String.valueOf(str), 8));break;// 邮箱脱敏case EMAIL:jsonGenerator.writeString(DesensitizedUtil.email(String.valueOf(str)));break;// 密码脱敏case PASSWORD:jsonGenerator.writeString(DesensitizedUtil.password(String.valueOf(str)));break;// 中国车牌脱敏case CAR_LICENSE:jsonGenerator.writeString(DesensitizedUtil.carLicense(String.valueOf(str)));break;// 银行卡脱敏case BANK_CARD:jsonGenerator.writeString(DesensitizedUtil.bankCard(String.valueOf(str)));break;default:}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {if (beanProperty != null) {// 判断数据类型是否为String类型if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {// 获取定义的注解Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);// 为nullif (desensitization == null) {desensitization = beanProperty.getContextAnnotation(Desensitization.class);}// 不为nullif (desensitization != null) {// 创建定义的序列化类的实例并且返回,入参为注解定义的type,开始位置,结束位置。return new DesensitizationSerialize(desensitization.type(), desensitization.startInclude(),desensitization.endExclude());}}return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}return serializerProvider.findNullValueSerializer(null);}
}
经过上述三步,已经完成了通过注解实现数据脱敏了,下面我们来测试一下。
首先定义一个要测试的 pojo,对应的字段加入要脱敏的策略。
/**** @description:*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestPojo {private String userName;@Desensitization(type = DesensitizationTypeEnum.MOBILE_PHONE)private String phone;@Desensitization(type = DesensitizationTypeEnum.PASSWORD)private String password;@Desensitization(type = DesensitizationTypeEnum.MY_RULE, startInclude = 0, endExclude = 2)private String address;
}
接下来写一个测试的 controller
@RestController
public class TestController {@RequestMapping("/test")public TestPojo testDesensitization(){TestPojo testPojo = new TestPojo();testPojo.setUserName("我是用户名");testPojo.setAddress("地球中国-北京市通州区京东总部2号楼");testPojo.setPhone("13782946666");testPojo.setPassword("sunyangwei123123123.");System.out.println(testPojo);return testPojo;}}
可以看到我们成功实现了数据脱敏。
Apache ShardingSphere
ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar(计划中)这 3 款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能 。
Apache ShardingSphere 下面存在一个数据脱敏模块,此模块集成的常用的数据脱敏的功能。其基本原理是对用户输入的 SQL 进行解析拦截,并依靠用户的脱敏配置进行 SQL 的改写,从而实现对原文字段的加密及加密字段的解密。最终实现对用户无感的加解密存储、查询。
通过 Apache ShardingSphere 可以自动化&透明化数据脱敏过程,用户无需关注脱敏中间实现细节。并且,提供了多种内置、第三方(AKS)的脱敏策略,用户仅需简单配置即可使用。
FastJSON
平时开发 Web 项目的时候,除了默认的 Spring 自带的序列化工具,FastJson 也是一个很常用的 Spring Web Restful 接口序列化的工具。
FastJSON 实现数据脱敏的方式主要有两种:
- 基于注解
@JSONField
实现:需要自定义一个用于脱敏的序列化的类,然后在需要脱敏的字段上通过@JSONField
中的serializeUsing
指定为我们自定义的序列化类型即可。 - 基于序列化过滤器:需要实现
ValueFilter
接口,重写process
方法完成自定义脱敏,然后在 JSON 转换时使用自定义的转换策略。
Mybatis-mate
MybatisPlus 也提供了数据脱敏模块 mybatis-mate。mybatis-mate 为 MybatisPlus 企业级模块,使用之前需要配置授权码(付费),旨在更敏捷优雅处理数据。
配置内容如下所示:
# Mybatis Mate 配置
mybatis-mate:cert:grant: jxftsdfggggxlicense: GKXP9r4MCJhGID/DTGigcBcLmZjb1YZGjE4GXaAoxbtGsPC20sxpEtiUr2F7Nb1ANTUekvF6Syo6DzraA4M4oac
MyBatis-Flex
类似于 MybatisPlus,MyBatis-Flex 也是一个 MyBatis 增强框架。MyBatis-Flex 同样提供了数据脱敏功能,并且是可以免费使用的。
MyBatis-Flex 提供了 @ColumnMask()
注解,以及内置的 9 种脱敏规则,开箱即用:
- 用户名脱敏
- 手机号脱敏
- 固定电话脱敏
- 身份证号脱敏
- 车牌号脱敏
- 地址脱敏
- 邮件脱敏
- 密码脱敏
- 银行卡号脱敏
/*** 内置的数据脱敏方式*/
public class Masks {/*** 手机号脱敏*/public static final String MOBILE = "mobile";/*** 固定电话脱敏*/public static final String FIXED_PHONE = "fixed_phone";/*** 身份证号脱敏*/public static final String ID_CARD_NUMBER = "id_card_number";/*** 中文名脱敏*/public static final String CHINESE_NAME = "chinese_name";/*** 地址脱敏*/public static final String ADDRESS = "address";/*** 邮件脱敏*/public static final String EMAIL = "email";/*** 密码脱敏*/public static final String PASSWORD = "password";/*** 车牌号脱敏*/public static final String CAR_LICENSE = "car_license";/*** 银行卡号脱敏*/public static final String BANK_CARD_NUMBER = "bank_card_number";//...
}
使用示例:
@Table("tb_account")
public class Account {@Id(keyType = KeyType.Auto)private Long id;@ColumnMask(Masks.CHINESE_NAME)private String userName;@ColumnMask(Masks.EMAIL)private String email;}
如果这些内置的脱敏规则不满足你的要求的话,你还可以自定义脱敏规则。
作者声明
如有问题,欢迎指正!
相关文章:

数据脱敏方案
数据脱敏方案 什么是数据脱敏 数据脱敏的定义 数据脱敏百度百科中是这样定义的: 数据脱敏,指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。这样就可以在开发、测试和其它非生产环境以及外包环境中安全地使用脱敏…...

蓝桥杯每日一题2023.11.28
题目描述 三羊献瑞 - 蓝桥云课 (lanqiao.cn) 题目分析 本题首先进行观察可以确定 1.“三”为 1 (十进制数字要进位进一位) 2.“祥”一定不为 0 (有前导0就不能算为 4 位数) 使用搜索时将其特判 #include<bits/stdc.h> …...
【数据库连接池】01:连接池初始化
连接池初始化 OVERVIEW 连接池初始化1.Connection类Connection.hConnection.cpp 2.CommonConnectionPool类CommonConnectionPool.hCommonConnectionPool.cpp 1.Connection类 封装Connection类,在该类内调用mysql提供的接口实现对数据库的增删改查, Con…...

Java基于springboot开发的土特产网站商城多商家源码
主要功能:用户可以浏览特产,按分类和产地搜索,按分类查询特产,搜索店铺,查看评价,加入购物车,下单,查看店铺主页信息特产等店铺内搜索等;用户可申请开通店铺,…...

Linux CentOS7 LVM
LVM(Logical Volume Manger)逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分区管理的灵活性。物理设备,是用于保留逻辑卷中所存储数据的存储设备。它们是块设备,可以是…...
ArkTS开发webview,html页面中的input和按钮等操作均无响应 【Bug已解决-鸿蒙开发】
文章目录 项目场景:问题描述原因分析:解决方案(根据此方法即可解决此Bug):本文相关知识本Bug常规排除步骤ArkTS项目场景: 在鸿蒙开发过程遇到的问题: 问题 ArkTS API9 使用webview加载的html,页面中的按钮和input等操作均无响应 是有相关API设置webview是否可以touch或…...

滴滴、阿里云、语雀相继宕机,损失巨大,软件的高可用失效了么?
在北京寒冬的夜里,小程加班完成了当天最后一个任务,他拖着疲惫的身体离开了位于西二旗的工位,走到办公楼下,下意识地拿出手机打开滴滴,准备打车回家,但是他却发现滴滴的打车页面显示网络异常。起初小程以为…...
基于binlog实现一些业务(Binlog4j)
前言 今天要跟大家分享的是监控数据变化,实现自己的业务的另一个思路,基于数据库的binglog。我这里是用的Binlog4j实现,希望看总结的,直接看最后。 一、Binlog4j是什么? Binlog4j是轻量级 Mysql Binlog 客户端, 提供宕…...

python实现rpc的几种方式(SimpleXMLRPCServer 自带的、第三方ZeroRPC)、连接linux远程开发分布式锁、分布式id
1 python实现rpc的几种方式 1.1 SimpleXMLRPCServer 自带的 1.2 第三方ZeroRPC 2 连接linux远程开发 3 分布式锁 4 分布式id 1 python实现rpc的几种方式 # 远程过程调用-1 借助于rabbitmq,可以跨语言-2 SimpleXMLRPCServer 自带的-3 ZeroRPC-4 GRPC:跨语言的 htt…...

ARM麒麟V10 auditctl启动失败处理
问题: 业务服务器需要启用审计服务,但是启动审计服务失败,查看状态提示audit0。 修改配置文件/boot/efi/EFI/kylin/grub.cfg 删除audit0,或者设置audit1。 重启服务器后验证状态。 auditctl -D echo "-w /data -p rwxa"…...
day67
今日回内容 视图层 响应对象 cbv和fbv 上传文件 模板层 视图层 一、响应对象 响应对象的本质都是 HttpResponse HttpResponse:字符串 render: 将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。 redirect:重定向 …...

04:2440---内存控制器
目录 一:介绍 1:引入 2:概念 3:通信 A:片选信号 B:片选信号的地址空间范围 4:地址线 A:不同位数的接法 B:访问原理 C:访问地址 5:时序 1:NOR FLASH A:2440NOR FLASH时序 B:原理/时序图 C:寄存器 6:SDARM A:访问方式 B:原理图 C:BWSCON D:BANKCON…...

【深度学习】CNN中pooling层的作用
1、pooling是在卷积网络(CNN)中一般在卷积层(conv)之后使用的特征提取层,使用pooling技术将卷积层后得到的小邻域内的特征点整合得到新的特征。一方面防止无用参数增加时间复杂度,一方面增加了特征的整合度…...

基于H1ve一分钟搭好CTF靶场
写在前面 ◉ ‿ ◉ 上一篇文章给大家详细介绍了基于H1ve搭建CTF靶场,以及过程中可能遇到的报错及解决方法,那么这篇文章,我总结了一下,将不会遇到报错的方法给到大家,但是前提是你的服务器最好是一个全新的哦~~~ 我…...

网络篇---第五篇
系列文章目录 文章目录 系列文章目录前言一、如何实现跨域?二、TCP 为什么要三次握手,两次不行吗?为什么?三、说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…...

Git——Git应用入门
将会介绍以下知识: 搭建Git环境和创建Git版本库(init、clone)。文件添加、状态检查、创建注释和查看历史记录。与其他Git版本库交互(pull、push)。解决合并冲突。创建分支列表、列表切换和合并。创建标签。 1、版本控…...
【SpringBoot】Redisson 分布式锁注解和 @Transactional 注解一起使用问题
一、前言 平时使用切面去加分布式锁,是先开启事务还是先尝试获得锁?这两者有啥区别? 业务中怎么控制切面的顺序?切面的顺序对事务的影响怎么避免? 下面程序分析: OverrideTransactionalpublic ReceiveH5…...
Druid数据库连接池框架
1.Druid概述 Druid 是一个开源的数据库连接池框架,用于管理和优化数据库连接的使用。它提供了高效的、可扩展的连接池管理,可以用于 Java 应用程序连接到关系型数据库。 之前有了解过 C3P0 数据库连接池,所谓数据库连接池就是重复利用连接数据…...
Python项目打包
Python项目如何打包? 本指南总结了Python项目打包的最佳实践,主要涉及代码的打包和分发,以及环境和依赖的管理。 0. 一般项目清单 源代码(可使用git托管)数据包(可使用DVC托管)Docker环境镜像…...

ASUS(华硕) B760M-AYW WIFI D4_解决wifi不能使用
1、最近新购买了一套 diy电脑主机,选用的是 ASUS B760M-AYW WIFI D4电脑主板 win10 系统,到货后 发现右下角电脑图标处及网络适配器中 没有wifi选项 首先 在官网和旗舰店客服处,确认了 该主板 有集成wifi模块,鲨鱼鳍天线未安装…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...