hbase 工具类
hbase 工具类
pom.xml
<dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.5.10-hadoop3</version>
</dependency>
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>33.2.1-jre</version>
</dependency>
RowKey注解
package cn.lhz.util.annotation;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;/*** @author 李昊哲* @version 1.0.0*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RowKeyAnnotation {
}
hbase 自定义 过滤器
package cn.lhz.util.hbase;import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hadoop.hbase.Cell;/*** hbase 自定义 过滤器** @author 李昊哲* @version 1.0.0*/
public class CustomFilter extends FilterBase {private final String targetValue;public CustomFilter(String targetValue) {this.targetValue = targetValue;}@Overridepublic ReturnCode filterCell(Cell cell) {// 在这里实现过滤逻辑// 比如,如果单元格的值等于 targetValue,则允许它通过byte[] value = cell.getValueArray();String cellValue = new String(value, cell.getValueOffset(), cell.getValueLength());if (cellValue.equals(targetValue)) {// 允许通过return ReturnCode.INCLUDE;} else {// 跳过此单元格return ReturnCode.SKIP;}}
}
hbase 工具类
package cn.lhz.util.hbase;import cn.lhz.util.annotation.RowKeyAnnotation;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.util.Bytes;import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;/*** @author 李昊哲* @version 1.0.0*/
public class HbaseUtil {// 创建 hbase 配置 对象private final static Configuration conf = HBaseConfiguration.create();/*** 获取 Hbase 连接** @return Hbase 连接* @throws IOException IOException*/public static Connection getConnection() throws IOException {return ConnectionFactory.createConnection(conf);}/*** 获取 org.apache.hadoop.hbase.client.Admin 对象** @return org.apache.hadoop.hbase.client.Admin 对象* @throws IOException IOException*/public static Admin getAdmin() throws IOException {return getConnection().getAdmin();}/*** 获取 org.apache.hadoop.hbase.client.Admin 对象** @param connection Connection* @return org.apache.hadoop.hbase.client.Admin 对象* @throws IOException IOException*/public static Admin getAdmin(Connection connection) throws IOException {return connection.getAdmin();}/*** 断开 hbase 连接** @param connection Connection* @throws IOException IOException*/public static void closeConnection(Connection connection) throws IOException {if (connection != null) {connection.close();}}/*** 释放 org.apache.hadoop.hbase.client.Admin 对象** @param admin org.apache.hadoop.hbase.client.Admin 对象* @throws IOException IOException*/public static void closeAdmin(Admin admin) throws IOException {if (admin != null) {admin.close();}}/*** 释放集群管理对象和连接** @param admin 集群管理对象* @param connection 客户端与集群建立的连接* @throws IOException IOException*/public static void closeAdminAndConnection(Admin admin, Connection connection) throws IOException {closeAdmin(admin);closeConnection(connection);}/*** 获取 数据表** @param tableName 数据表名称* @return 数据表* @throws IOException IOException*/public static Table getTable(String tableName) throws IOException {return getConnection().getTable(TableName.valueOf(tableName));}/*** 获取 数据表** @param connection 客户端与集群建立的连接* @param tableName 数据表名称* @return 数据表* @throws IOException IOException*/public static Table getTable(Connection connection, String tableName) throws IOException {return connection.getTable(TableName.valueOf(tableName));}/*** 创建数据表** @param admin 集群管理对象* @param name 数据表名称* @param columnFamilyNames 一个或多个ColumnFamilyName* @throws IOException IOException*/public static void createTable(Admin admin, String name, String... columnFamilyNames) throws IOException {// 4.1、定义表名称TableName tableName = TableName.valueOf(name);// 4.2、构建表描述构造器TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName);// 4.3、构建列簇描述构造器Collection<ColumnFamilyDescriptor> collection = new ArrayList<>();if (columnFamilyNames != null) {for (String columnFamilyName : columnFamilyNames) {// 4.4、构建列簇描述collection.add(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamilyName)).build());}}// 4.5、表结构构造器与列簇构造器建立关联tableDescriptorBuilder.setColumnFamilies(collection);// 4.6、定义描述对象TableDescriptor tableDescriptor = tableDescriptorBuilder.build();// 4.7、创建表admin.createTable(tableDescriptor);}/*** 删除数据表** @param admin 数据库管理对象* @param name 数据表名称* @return 是否删除* @throws IOException IOException*/public static boolean deleteTable(Admin admin, String name) throws IOException {// 定义表名称TableName tableName = TableName.valueOf(name);// 删除表 分两步 先禁用再删除if (admin.tableExists(tableName)) {// 禁用表admin.disableTable(tableName);// 删除表admin.deleteTable(tableName);}return true;}/*** 新增或更新数据** @param columnFamilyName columnFamilyName* @param e 数据表对应 javabean 对象* @param <E> 数据表对应 javabean 数据类型* @throws IOException IOException* @throws IllegalAccessException IllegalAccessException*/public static <E> void upsert(Table table, String columnFamilyName, E e) throws IOException, IllegalAccessException {// 获取对象的 Class 对象Class<?> aClass = e.getClass();Put put = null;for (Field field : aClass.getDeclaredFields()) {// 设置允许访问私有属性field.setAccessible(true);// 获取属性 RowKeyAnnotation 注解RowKeyAnnotation annotation = field.getAnnotation(RowKeyAnnotation.class);if (annotation != null) {// 根据 RowKey 构建 Put 对象put = new Put(Bytes.toBytes(String.valueOf(field.get(e))));} else {if (put == null) {return;}// 添加 字段 与 字段对应的值put.addColumn(Bytes.toBytes(columnFamilyName), Bytes.toBytes(field.getName()), Bytes.toBytes(String.valueOf(field.get(e))));}}if (put != null) {// 插入数据table.put(put);}}/*** 新增或更新数据** @param connection 客户端与集群建立的连接* @param name 数据表名称* @param columnFamilyName columnFamilyName* @param e 数据表对应 javabean 对象* @param <E> 数据表对应 javabean 数据类型* @return upsert 是否成功* @throws IOException IOException* @throws IllegalAccessException IllegalAccessException*/public static <E> boolean upsert(Connection connection, String name, String columnFamilyName, E e) throws IOException, IllegalAccessException {// 定义表名称TableName tableName = TableName.valueOf(name);// 连接 person 表Table table = connection.getTable(tableName);// 获取对象的 Class 对象Class<?> aClass = e.getClass();Put put = null;for (Field field : aClass.getDeclaredFields()) {// 设置允许访问私有属性field.setAccessible(true);// 获取属性 RowKeyAnnotation 注解RowKeyAnnotation annotation = field.getAnnotation(RowKeyAnnotation.class);if (annotation != null) {// 根据 RowKey 构建 Put 对象put = new Put(Bytes.toBytes(String.valueOf(field.get(e))));} else {if (put == null) {return false;}// 添加 字段 与 字段对应的值put.addColumn(Bytes.toBytes(columnFamilyName), Bytes.toBytes(field.getName()), Bytes.toBytes(String.valueOf(field.get(e))));}}if (put != null) {// 插入数据table.put(put);return true;}return false;}/*** 根据 RowKey 删除数据** @param connection 客户端与集群建立的连接* @param name 数据表名称* @param rowKey 数据表对应 RowKey* @return upsert 是否成功* @throws IOException IOException*/public static boolean delete(Connection connection, String name, String rowKey) throws IOException {// 定义表名称TableName tableName = TableName.valueOf(name);// 连接 数据表 表Table table = connection.getTable(tableName);// 根据 RowKey 构建 Delete 对象Delete delete = new Delete(Bytes.toBytes(rowKey));// 执行请求table.delete(delete);return true;}/*** 获取数据表中 ColumnFamily** @param admin 数据库管理对象* @param name 数据表名称* @return ColumnFamily 名称集合* @throws IOException IOException*/public static Set<String> columnFamilyNames(Admin admin, String name) throws IOException {// 指定表名TableName tableName = TableName.valueOf(name);// 获取表的描述对象TableDescriptor tableDescriptor = admin.getDescriptor(tableName);Set<String> columnFamilyNames = new HashSet<>();for (byte[] columnFamilyName : tableDescriptor.getColumnFamilyNames()) {columnFamilyNames.add(Bytes.toString(columnFamilyName));}return columnFamilyNames;}/*** 获取数据表中 column** @param connection 客户端与集群建立的连接* @param name 数据表名称* @return 字段名名称集合* @throws IOException IOException*/public static List<String> columnNames(Connection connection, String name) throws IOException {List<String> columnNames = new ArrayList<>();// 指定表名TableName tableName = TableName.valueOf(name);// 连接 数据表 表Table table = connection.getTable(tableName);// 获取表的描述对象Admin admin = connection.getAdmin();TableDescriptor tableDescriptor = admin.getDescriptor(tableName);// 获取列簇ColumnFamilyDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();for (ColumnFamilyDescriptor columnFamilyDescriptor : columnFamilies) {Result result = table.getScanner(columnFamilyDescriptor.getName()).next();for (Cell cell : result.rawCells()) {byte[] column = CellUtil.cloneQualifier(cell);columnNames.add(Bytes.toString(column));// String columnName = Bytes.toString(column);// String columnValue = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());}}return columnNames;}/*** 使用RowKey获取查询数据表中RowKey对应的记录** @param connection 客户端与集群建立的连接* @param name 数据表名称* @param rowKey 数据表RowKey* @param clazz 返回对象数据类型* @return 数据表模型类对象* @throws IOException IOException*/public static <T> Class<T> selectByRowKey(Connection connection, String name, String rowKey, Class<T> clazz) throws IOException, NoSuchFieldException, IllegalAccessException {Admin admin = connection.getAdmin();// 定义表名称TableName tableName = TableName.valueOf(name);// 连接 person 表Table table = connection.getTable(tableName);// 根据 RowKey 构建 Get 对象Get get = new Get(Bytes.toBytes(rowKey));// 执行请求 获取结果Result result = table.get(get);// 获取表的描述对象TableDescriptor tableDescriptor = admin.getDescriptor(tableName);// 获取列簇ColumnFamilyDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();for (ColumnFamilyDescriptor columnFamilyDescriptor : columnFamilies) {List<String> columnNames = new ArrayList<>();byte[] columnFamilyByteName = columnFamilyDescriptor.getName();Result rs = table.getScanner(columnFamilyDescriptor.getName()).next();for (Cell cell : rs.rawCells()) {byte[] column = CellUtil.cloneQualifier(cell);columnNames.add(Bytes.toString(column));}for (String columnName : columnNames) {// 解析结果String value = Bytes.toString(result.getValue(columnFamilyByteName, Bytes.toBytes(columnName)));Field field = clazz.getDeclaredField(nameInDb2nameInJava(columnName));field.setAccessible(true);field.set(clazz, value);}}return clazz;}/*** @param connection 客户端与集群建立的连接* @param name 数据表名称* @param columnFamilyName ColumnFamily 名称* @param columnName 字段名称* @param columnValue 字段匹配的值* @param clazz 数据表对应的模型类* @param cacheCount 缓存数量* @param <T> 返回值泛型* @return 查询结果* @throws IOException IOException* @throws NoSuchFieldException NoSuchFieldException* @throws IllegalAccessException IllegalAccessException*/public static <T> List<Class<T>> filter(Connection connection, String name, String columnFamilyName, String columnName, String columnValue, Class<T> clazz, int cacheCount) throws IOException, NoSuchFieldException, IllegalAccessException {List<Class<T>> list = new ArrayList<>();Table table = connection.getTable(TableName.valueOf(name));// 创建扫描对象Scan scan = new Scan();// 设置缓存scan.setCaching(cacheCount);// 创建自定义过滤器Filter customFilter = new CustomFilter(columnValue);scan.setFilter(customFilter);// 进行扫描try (ResultScanner scanner = table.getScanner(scan)) {for (Result result : scanner) {for (Field field : clazz.getDeclaredFields()) {field.setAccessible(true);field.set(clazz, null);}List<String> columnNames = new ArrayList<>();Result rs = table.getScanner(Bytes.toBytes(columnFamilyName)).next();for (Cell cell : rs.rawCells()) {byte[] column = CellUtil.cloneQualifier(cell);columnNames.add(Bytes.toString(column));}for (String columnTempName : columnNames) {// 解析结果String value = Bytes.toString(result.getValue(Bytes.toBytes(columnTempName), Bytes.toBytes(columnName)));Field field = clazz.getDeclaredField(nameInDb2nameInJava(columnName));field.setAccessible(true);field.set(clazz, value);}list.add(clazz);}}return list;}/*** 数据库里下划线命名规则转化为java里面驼峰式命名** @param filedName 字段名称* @return javabean属性名称*/public static String nameInDb2nameInJava(String filedName) {String coluname = filedName.toLowerCase();//正则if (Pattern.compile("^\\S+_+\\S+$").matcher(coluname).find()) {char[] ca = coluname.toCharArray();for (int j = 1; j < ca.length - 1; j++) {if (ca[j] == '_') {ca[j] = '\0';ca[j + 1] = Character.toUpperCase(ca[j + 1]);}}coluname = new String(ca);}return coluname.replaceAll("\0", "");}public static void main(String[] args) throws IOException {Admin admin = getAdmin();ServerName master = admin.getMaster();System.out.println(master.getHostname() + ":" + master.getPort());Collection<ServerName> regionServers = admin.getRegionServers();for (ServerName serverName : regionServers) {System.out.println(serverName.getHostname() + ":" + serverName.getPort());}}
}相关文章:
hbase 工具类
hbase 工具类 pom.xml <dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.5.10-hadoop3</version> </dependency> <dependency><groupId>com.google.guava<…...
会议直击|美格智能受邀出席第三届无锡智能网联汽车生态大会,共筑汽车产业新质生产力
11月10日,2024世界物联网博览会分论坛——第三届无锡智能网联汽车生态大会在无锡举行,美格智能CEO杜国彬受邀出席,并参与“中央域控:重塑汽车智能架构的未来”主题圆桌论坛讨论,与行业伙伴共同探讨智能网联汽车产业领域…...
在 Jupyter Notebook 中使用 Matplotlib 进行交互式可视化的教程
在 Jupyter Notebook 中使用 Matplotlib 进行交互式可视化的教程 引言 数据可视化是数据分析的重要组成部分,能够帮助我们更直观地理解数据。Matplotlib 是 Python 中最流行的绘图库之一,而 Jupyter Notebook 则是进行数据分析和可视化的理想环境。本文…...
Android13 系统/用户证书安装相关分析总结(三) 增加安装系统证书的接口遇到的问题和坑
一、前言 接上回说到,修改了程序,增加了接口,却不知道有没有什么问题,于是心怀忐忑等了几天。果然过了几天,应用那边的小伙伴报过来了问题。用户证书安装没有问题,系统证书(新增的接口)还是出现了问题。调…...
【C++ 算法进阶】算法提升十三
目录标题 抽牌概率问题 (动态规划)动态规划题目分析代码 洗衣机问题 (贪心)题目题目分析 抽牌概率问题 (动态规划) 动态规划 假设现在有1~N N张牌 每张牌的序号就代表着他的大小 (1 2 … N&am…...
【计网不挂科】计算机网络期末考试(综合)——【选择题&填空题&判断题&简述题】完整试卷
前言 大家好吖,欢迎来到 YY 滴计算机网络 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的计算机网络题目,供yy应对期中考试复习。大家可以参考 本章是去答案版本。带答案的版本在下…...
2024年11月中旬记录
11.11 pigz的使用 压缩文件夹命令: tar -cvf - dir_name | pigz > xxx.tar.gz 解压分两步,pigz解压和tar解压: pigz -d xxx.tar.gz tar -xf xxx.tar...
单体架构 IM 系统之长轮询方案设计
在上一篇技术短文(单体架构 IM 系统之核心业务功能实现)中,我们讨论了 “信箱模型” 在单体架构 IM 系统中的应用,“信箱模型” 见下图。 客户端 A 将 “信件” 投入到客户端 B 的 “信箱” 中,然后客户端 B 去自己的 …...
Android Studio加载旧的安卓工程项目报错处理
文章目录 Invalid Gradle JDK configuration foundNDK not configuredCMake 3.10.2 was not found安装cmake适配cmake版本号 com.intellij.openapi.externalSystem.model.ExternalSystemExceptiongradle版本过低或下载不了下载gradle与依赖库超时替换gradle国内源替换Maven 仓库…...
阿里公告:停止 EasyExcel 更新与维护
最近,阿里发布公告通知,将停止对知名 Java Excel 工具库 EasyExcel 的更新和维护。EasyExcel 由阿里巴巴开源,作者是玉箫,在 GitHub 上拥有 30k stars、7.5k forks 的高人气。 据悉,EasyExcel 作者玉箫去年已从阿里离…...
Spring 中的 BeanWrapper
BeanWrapper 是 Spring 框架中的一个接口,它提供了一种方式来设置和获取 JavaBean 的属性。JavaBean 是一种特殊的 Java 类,遵循特定的编码约定(例如,私有属性和公共的 getter/setter 方法),通常用于封装数…...
2024鹏城杯msic部分WP
MISC 网安第一课 查找字符key,发现key1,但是没看到key2 后缀改为zip,打开以后发现不一样的地方,三张图片和一个misc文件夹 图片放到010看一眼 编号为1的图片在文件尾发现key2 misc文件夹中是一个out.pcb,放到010发现…...
DAY23|回溯算法Part02|LeetCode: 39. 组合总和 、40.组合总和II 、131.分割回文串
目录 LeetCode: 39. 组合总和 基本思路 C代码 LeetCode: 40.组合总和II 基本思路 C代码 LeetCode: 131.分割回文串 基本思路 C代码 LeetCode: 39. 组合总和 力扣代码链接 文字讲解:LeetCode: 39. 组合总和 视频讲解:带你学透回溯算法-组合总和…...
go map
1、数据结构 // A header for a Go map. type hmap struct {// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.// Make sure this stays in sync with the compilers definition.count int // # live cells size of map.…...
三十七、Python基础语法(异常)
在 Python 中,异常是在程序执行过程中发生的错误情况。当出现异常时,程序的正常执行流程会被中断,并尝试寻找相应的异常处理机制来处理这个错误。 一、异常的类型 Python 中有很多内置的异常类型,例如: ZeroDivision…...
ThreadLocal的熟悉与使用
目录 1.ThreadLocal介绍2.ThreadLocal源码解析2.1 常用方法2.2 结构设计2.3 类图2.4 源码分析2.4.1 set方法分析2.4.2 get方法分析2.4.3 remove方法分析 3.ThreadLocal内存泄漏分析3.1 相关概念3.1.1 内存溢出3.1.2 内存泄漏3.1.3 强引用3.1.4 弱引用 3.2 内存泄漏是否和key使用…...
如何使用 Puppeteer 和 Browserless 抓取亚马逊产品数据?
您可以在亚马逊上找到所有有关产品、卖家、评论、评分、特价、新闻等的相关且有价值的信息。无论是卖家进行市场调研还是个人收集数据,使用高质量、便捷且快速的工具将极大地帮助您准确地抓取亚马逊上的各种信息。 为什么抓取亚马逊产品数据很重要? 亚…...
使用Python求解经典“三门问题”,揭示概率的奇妙之处
三门问题(Monty Hall Problem)是经典的概率问题,描述了一位游戏选手在三个门中选择一扇门,其中一扇门后有奖品,其余两扇门后是空的。选手做出选择后,主持人会打开另一扇空门,然后给选手一次更改…...
数据库基础(6) . DDL
3.2.DDL 数据定义语言 DDL : Data Definition Language 用于创建新的数据库、模式(schema)、表(tables)、视图(views)以及索引(indexes)等。 常见的DDL语句包括SHOW、CREATE、DRO…...
2024 年度分布式电力推进(DEP)系统发展探究
分布式电力推进 (DEP) 的发明是为了尝试和改进现代飞机:我们如何提高飞机的效率?提高它的机动性?缩短它的起飞和着陆距离? DEP 概念有望在提高性能的同时减少燃料消耗,在我们孜孜不倦地努力使航…...
PHP 数组 vs SPL 数据结构:队列与栈场景下的性能对决
PHP 数组 vs SPL 数据结构:队列与栈场景下的性能对决在 PHP 开发中,我们常常面临一个经典的选择:是使用灵活的原生数组(Array)模拟队列/栈,还是使用标准库(SPL)提供的 SplQueue 和 S…...
硬件加速对比:Qwen3-32B镜像在RTX4090D与A100上的OpenClaw表现
硬件加速对比:Qwen3-32B镜像在RTX4090D与A100上的OpenClaw表现 1. 测试背景与实验设计 最近在部署OpenClaw自动化工作流时,遇到了一个实际需求:如何为本地AI智能体选择最具性价比的GPU硬件?我的工作流主要依赖Qwen3-32B模型进行…...
Kimi-VL-A3B-Thinking Chainlit定制化开发:添加历史记录/多用户会话/图片标注功能
Kimi-VL-A3B-Thinking Chainlit定制化开发:添加历史记录/多用户会话/图片标注功能 1. 项目背景与模型介绍 Kimi-VL-A3B-Thinking是一款基于混合专家架构(MoE)的开源视觉语言模型(VLM),在多模态推理和长上下文理解方面表现出色。该模型仅激活2.8B参数就…...
Linux服务器运维:5个最容易被忽略的故障排查技巧(附实战命令)
Linux服务器运维:5个最容易被忽略的故障排查技巧(附实战命令) 在Linux服务器运维的日常工作中,有些故障排查点往往被工程师们忽视,直到问题爆发才追悔莫及。本文将揭示五个最容易被忽略但至关重要的排查技巧ÿ…...
程序员转行学习 AI 大模型: 提示词工程 | 附精选学习资料
本文是程序员转行学习AI大模型的第12个核心知识点笔记,笔记后附精选的提示词工程学习资料。 当前阶段:还在学习知识点,由点及面,从 0 到 1 搭建 AI 大模型知识体系中。 系列更新,关注我,后续会持续记录分享…...
Day25(高阶篇):RAG检索与重排序算法精研|从原理到参数调优,彻底攻克检索瓶颈
Day25(高阶篇):RAG检索与重排序算法精研|从原理到参数调优,彻底攻克检索瓶颈 引言: 进阶篇我们搞定了RAG系统的生产级落地,能满足常规项目的精准问答需求,但如果想让系统达到极致准确…...
OpenClaw多模型管理:Qwen3.5-4B-Claude与其他模型的协作方案
OpenClaw多模型管理:Qwen3.5-4B-Claude与其他模型的协作方案 1. 为什么需要多模型协作 去年冬天,当我第一次尝试用OpenClaw自动化处理技术文档时,发现单一模型很难兼顾所有任务场景。有些模型擅长代码生成但逻辑推理薄弱,有些长…...
全基因组序列比对工具mVISTA的保姆级使用指南:从文件准备到结果解读
全基因组序列比对工具mVISTA的保姆级使用指南:从文件准备到结果解读 在基因组学研究领域,序列比对是揭示物种间进化关系、识别保守区域和功能元件的基础操作。mVISTA作为一款专门用于全基因组序列比对的在线工具,凭借其直观的可视化界面和强…...
某民办高校关键人才梯队建设项目成功案例纪实
——破解“断层”隐忧,构建人才梯队蓄水池【客户行业】学校、民办学校、民办高等教育【问题类型】人才梯队建设;人才培养体系;激励体系;核心人才保留【客户背景】长三角地区一所知名的民办应用型本科院校,建校25年&…...
Mac开发者必备:OpenClaw调试QwQ-32B代码补全全流程
Mac开发者必备:OpenClaw调试QwQ-32B代码补全全流程 1. 为什么选择OpenClaw作为代码助手 作为一名长期在Mac上开发的全栈工程师,我一直在寻找能够真正融入工作流的智能编码工具。直到遇到OpenClaw,才发现这个开源的本地化AI智能体框架完美契…...
