HBase API

我們之后的實際開發中不可能在服務器那邊直接使用shell命令一直敲的,一般都是通過API進行操作的。

環境準備

新建Maven項目,導入Maven依賴

<dependencies><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.4.17</version></dependency></dependencies>

1、創建連接

? ? ? ? HBase 的客戶端連接由 ConnectionFactory 類來創建(工廠模式直接創建),我們使用完之后需要手動關閉連接。同時連接 是一個重量級的,推薦一個進程使用一個連接,對 HBase 的命令通過連接中的兩個屬性 Admin 和 Table 來實現。其中 Admin 主要是針對元數據-表格的創建修改進行操作, Table 則是針對表格中數據的增加修改進行操作。

1.1、單線程創建連接

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;import java.io.IOException;
import java.util.concurrent.CompletableFuture;public class HBaseConnection {public static void main(String[] args) throws IOException {// 1. 創建連接配置參數Configuration conf = new Configuration();//對應我們 hbase-site.xml 中的配置信息的<name>和<value>的值conf.set("hbase.zookeeper.quorum","hadoop102,hadoop103,hadoop104");// 2. 創建連接// 默認使用同步連接Connection connection = ConnectionFactory.createConnection(conf);// 3. 使用連接System.out.println(connection);// 4. 關閉連接connection.close();}
}

1.2、多線程創建連接

我們真正開發中首先不會把配置參數寫到代碼中的,我們是通過Maven項目下的resources目錄來讀取配置文件來設置配置參數的,我們可以看源碼:

Connection connection = ConnectionFactory.createConnection();

我們調用了工廠模式的 ConnectionFactory 的 createConnection 方法來創建連接,這里我們。

沒有配置參數,因為HBase默認其實會自動幫我們添加配置參數:

我們可以看到當調用ConnectionFactory 的 createConnection 方法的時候,其實又調用了HBaseConfiguration 的 create 方法,

?

?該方法內部幫我們添加了配置參數:

可以看到,它其實是去讀取我們Maven項目下的resources目錄下的文件,所以我們需要將我們的配置參數寫到resources目錄下,最好使用 "hbase-ste.xml" 來命名,至于這個文件,我們直接復制我們hbase集群中conf目錄下的hbase-site.xml 。?

其中,我們只需要留下關于我們zookeeper服務器連接地址的配置信息即可,別的全部刪除,因為我們是客戶端,我們不能設置服務端的配置,那些即使寫了也不會生效。

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property><name>hbase.zookeeper.quorum</name><value>hadoop102,hadoop103,hadoop104</value><description>The directory shared by RegionServers.</description></property>
</configuration>

?使用類單例模式確保只使用一個連接,可以同時用于多個線程。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;import java.io.IOException;
import java.util.concurrent.CompletableFuture;public class HBaseConnection {// 聲明一個靜態屬性public static Connection connection = null;static {// 1. 創建連接// 默認使用同步連接try {//使用讀取本地配置文件的方式來添加參數connection = ConnectionFactory.createConnection();} catch (IOException e) {e.printStackTrace();}}public static void closeConnection() throws IOException {// 判斷連接是否為 nullif (connection != null){connection.close();}}public static void main(String[] args) throws IOException {//使用多線程連接 直接使用創建好的連接 不再main線程單獨創建System.out.println(HBaseConnection.connection);//在main線程的最后記得關閉連接HBaseConnection.closeConnection();}}

2、DDL

創建 HBaseDDL類,添加HBaseConnection的靜態屬性作為我們的連接對象,確保單例模式。

2.1、創建命名空間

我們上面說了,HBase中的 DDL 語句被封裝到了 Admin中,所以我們需要先獲取 Admin。

Admin admin = connection.getAdmin();

注意:在coding的過程中遇到異常不要老想著直接在方法名之后直接 throws ,這樣雖然是簡潔了一些,但是如果第一行拋出了一個IOException,之后幾行再出現異常我們就察覺不到了,所以盡量在我們核心代碼處try-catch,方便了解異常信息。

然后我們直接通過方法來創建 namespace ,這里的namespace是一個對象,這樣做的原因是因為我們 HBase 的shell命令中創建namespace的時候就是不止一種方法,所以這里單純字符串來創建namespace肯定不行,對象具有更完整屬性。

第二種創建命名空間的方式中,我們可以看到有一個 鍵值對參數,這就需要設置我們對象的屬性了。?

import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;import java.io.IOException;public class HBaseDDL {public static Connection connection = HBaseConnection.connection;/*** 創建命名空間* @param namespace 命名空間的名稱*/public static void createNamespace(String namespace) throws IOException {// 1. 獲取admin//admin是輕量級的 并且不是線程安全的 不推薦池化或者緩存這個連接//也就是說 用的時候再去獲取 不用就把它關閉掉Admin admin = connection.getAdmin();// 2. 調用方法創建 namespace// 代碼比shell更加底層 所以shell能實現的功能代碼 一定也可以// 所以代碼實現時 需要更完整的命名空間描述// 2.1 獲取一個命名空間的建造者 => 設計師NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);// 2.2 給命名空間添加屬性// 給namespace添加鍵值對屬性其實并沒有什么意義 只是給人注釋一樣builder.addConfiguration("user","lyh");// 2.3 使用builder構造出namespace對象// 創建命名空間造成的問題 屬于方法本身的問題 不應該拋出try {admin.createNamespace(builder.build());} catch (IOException e) {System.out.println("該命名空間已經存在!");e.printStackTrace();}// 3. 關閉資源admin.close();}public static void main(String[] args) throws IOException {//測試創建馬命名空間createNamespace("lyh");//記得關閉HBase連接HBaseConnection.closeConnection();}
}

運行結果?

?

2.2、判斷表格是否存在

    /*** 判斷表格是否存在* @param namespace 命名空間* @param tableName 表名* @return true-存在 false-不存在*/public static boolean isTableExists(String namespace,String tableName) throws IOException {// 1. 獲取adminAdmin admin = connection.getAdmin();// 2. 使用方法判斷表格是否存在boolean b = false;try {b = admin.tableExists(TableName.valueOf(namespace, tableName));} catch (IOException e) {e.printStackTrace();}// 3. 關閉adminadmin.close();// 4.返回結果return b;}

2.3、創建表

    /*** 創建表格* @param namespace 命名空間* @param tableName 表格名稱* @param columnFamilies 列族名稱 可以有多個*/public static void createTable(String namespace,String tableName,String... columnFamilies) throws IOException {// 判斷是否有至少一個列族if (columnFamilies.length == 0){System.out.println("創建表格至少應該有一個列族");return;}// 判斷表格是否已經存在if (isTableExists(namespace,tableName)){System.out.println("表格已經存在");return;}// 1. 獲取adminAdmin admin = connection.getAdmin();// 2. 調用方法創建表格// 2.1 獲取表格的建造者TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(namespace,tableName));// 2.2 添加參數for (String columnFamily : columnFamilies) {// 2.3 獲取列族建造者ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));// 2.4 通過建造者創建對應列族描述// 添加版本參數-維護的版本數columnFamilyDescriptorBuilder.setMaxVersions(5);// 2.5 創建添加完參數的列族描述builder.setColumnFamily(columnFamilyDescriptorBuilder.build());}// 2.3 創建表格描述try {admin.createTable(builder.build());} catch (IOException e) {//System.out.println("表格已經存在");e.printStackTrace();}// 2.4 關閉adminadmin.close();}

2.4、修改表

這里需要注意的比較多:

我們這里修改表格的列族版本,首先就需要獲取表格描述和列族描述,但是我們不能重新通過newBuilder創建這兩種描述,而是應該使用舊的描述。

對于舊的表格描述來說,我們可以通過admin的getDescriptor()來獲取舊的描述。

對于舊的列族描述來說,我們可以通過表格描述對象的getColumnFamily()方法來獲取。

    /*** 修改表格中一個列族的版本* @param namespace 命名空間* @param tableName 表名* @param columnFamily 列族* @param version 維護的版本*/public static void modifyTable(String namespace,String tableName,String columnFamily,int version) throws IOException {// 判斷表格是否存在if (!isTableExists(namespace,tableName)){System.out.println("表格不存在");return;}// 1. 獲取adminAdmin admin = connection.getAdmin();// 2. 調用方法修改表格// 2.0 獲取之前的表格描述TableDescriptor tableDescriptor = null;try {tableDescriptor = admin.getDescriptor(TableName.valueOf(namespace, tableName));} catch (IOException e) {System.out.println("表格不存在");e.printStackTrace();}// 2.1 創建一個表格描述建造者// 如果使用填寫 tableName 的方法 相當于創建了一個新的表格描述 沒有之前的信息// 如果想要修改表格的信息 必須調用方法填寫一個舊的表格描述TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);// 2.2 對應建造者進行表格數據的修改// 獲取舊的列族描述ColumnFamilyDescriptor columnFamily1 = tableDescriptor.getColumnFamily(Bytes.toBytes(columnFamily));// 創建列族描述建造者ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(columnFamily1);// 修改對應的版本columnFamilyDescriptorBuilder.setMaxVersions(version);// 在這里修改的時候 如果填寫的是新創建的列族描述 那么我們表格之前的其它屬性會被初始化 所以要使用舊的列族描述builder.modifyColumnFamily(columnFamilyDescriptorBuilder.build());try {admin.modifyTable(builder.build());} catch (IOException e) {e.printStackTrace();}// 3. 關閉adminadmin.close();}

2.5、刪除表

需要注意HBase中刪除表前必須標記表為不可用!

/*** 刪除表格* @param namespace 命名空間* @param tableName 表名* @return true-刪除成功*/public static boolean deleteTable(String namespace,String tableName) throws IOException {// 1. 判斷表格是否存在if (!isTableExists(namespace,tableName)){System.out.println("表格不存在 無法刪除");return false;}// 2. 獲取adminAdmin admin = connection.getAdmin();// 3. 調用相關的方法刪除表格try {// hbase 刪除表格前必須標記標記表格為不可用才能刪除admin.disableTable(TableName.valueOf(namespace,tableName));admin.deleteTable(TableName.valueOf(namespace,tableName));} catch (IOException e) {e.printStackTrace();}// 4. 關閉adminadmin.close();return true;}

3、DML

3.1、插入數據

我們可以看到,插入數據的put方法中要求參數必須為Byte類型,這也應證了我們之前第一篇博客說的-HBase的Cell的數據都是以Byte字節類型存儲的。

public class HBaseDML {//靜態屬性public static Connection connection = HBaseConnection.connection;/*** 插入數據* @param namespace 命名空間* @param tableName 表名* @param rowKey 行鍵* @param columnFamily 列族* @param columnName 列名* @param value 值*/public static void putCell(String namespace,String tableName,String rowKey,String columnFamily,String columnName,String value) throws IOException {// 1. 獲取 TableTable table = connection.getTable(TableName.valueOf(namespace,tableName));// 2. 調用相關方法實現數據插入// 2.1 創建 put 對象Put put = new Put(Bytes.toBytes(rowKey));// 2.2 給 put 對象添加屬性put.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),Bytes.toBytes(value));// 2.3 將對象寫入對應的方法try {table.put(put);} catch (IOException e) {e.printStackTrace();}// 3. 關閉tabletable.close();}public static void main(String[] args) throws IOException {// 測試插入數據putCell("bigdata","student","1005","info","name","hbase");System.out.println("其他代碼");// 關閉連接HBaseConnection.closeConnection();}
}

3.2、查詢數據

    /**讀取數據 讀取對應的一行中的某一列* @param namespace 命名空間* @param tableName 表名* @param rowKey 行鍵* @param columnFamily 列族* @param columnName 列名* @return 返回最小單位集合 Cells*/public static Cell[] getCells(String namespace,String tableName,String rowKey,String columnFamily,String columnName) throws IOException {// 1. 獲取TableTable table = connection.getTable(TableName.valueOf(namespace,tableName));// 2. 創建get對象Get get = new Get(Bytes.toBytes(rowKey));// 3. 讀取數據// 如果直接調用get方法讀取數據 讀到的是一整行數據// 如果想讀取某一列的數據 需要添加對應的參數get.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName));// 設置讀取數據的版本所有版本get.readAllVersions();// 讀取數據 得到result對象Result result = null;try {result = table.get(get);} catch (IOException e) {e.printStackTrace();}finally {table.close();}//返回結果if (result!=null)return result.rawCells();elsereturn null;}/*** 打印Cell的值* @param cells Cell數組*/public static void printCells(Cell[] cells){for (Cell cell : cells) {// cell 存儲數據比較底層String rowKey = new String((CellUtil.cloneRow(cell)));String columnFamily = new String(CellUtil.cloneFamily(cell));String columnName = new String(CellUtil.cloneQualifier(cell));String value = new String(CellUtil.cloneValue(cell));System.out.print(rowKey + "-" + columnFamily + "-" + columnName + "-" + value + "\t");}}

3.3、掃描數據

我們打印的范圍是 [startRow,stopRow) 的,是不包含 stopRow 的,如果我們要打印出最后一位的話,stopRow+1 越界也是沒有問題的,比如下面我們一共有5行數據,我們設置終止行鍵為 6 就是沒問題的不會報錯。?

/*** 打印Cell的值* @param cells Cell數組*/public static void printCells(Cell[] cells){for (Cell cell : cells) {// cell 存儲數據比較底層String rowKey = new String((CellUtil.cloneRow(cell)));String columnFamily = new String(CellUtil.cloneFamily(cell));String columnName = new String(CellUtil.cloneQualifier(cell));String value = new String(CellUtil.cloneValue(cell));System.out.print(rowKey + "-" + columnFamily + "-" + columnName + "-" + value + "\t");}}/*** 掃描數據 [起始行健,終止行鍵)* @param namespace 命名空間* @param tableName 表名* @param startRow 起始行健* @param stopRow 終止行鍵*/public static void scan(String namespace,String tableName,String startRow,String stopRow) throws IOException {// 1. 獲取tableTable table = connection.getTable(TableName.valueOf(namespace, tableName));// 2. 創建Scan對象Scan scan = new Scan();// 添加參數 來限制掃描的范圍 否則掃描整張表scan.withStartRow(Bytes.toBytes(startRow));scan.withStopRow(Bytes.toBytes(stopRow));try {// 讀取多行數據 獲得scannerResultScanner scanner = table.getScanner(scan);// result 來記錄一行數據 本質是一個 Cell 數組// resultScanner 來記錄多行數據 本質是一個 result 數組for (Result result : scanner) {printCells(result.rawCells());System.out.println();   //打印完一個行鍵對應的行后換行}} catch (IOException e) {e.printStackTrace();}// 3. 關閉tabletable.close();}

3.4、帶過率掃描

帶過濾掃描不僅可以掃描最新的數據,還可以掃描到該列族維護的最大版本范圍內的歷史數據。

    /*** 單列帶過濾掃描數據 [起始行健,終止行鍵)* @param namespace 命名空間* @param tableName 表名* @param startRow 起始行鍵* @param stopRow 終止行鍵* @param columnFamily 列族* @param columnName 列名* @param value value值* @throws IOException IO異常*/public static void filterScan(String namespace,String tableName,String startRow,String stopRow,String columnFamily,String columnName,String value) throws IOException {// 1. 獲取tableTable table = connection.getTable(TableName.valueOf(namespace, tableName));// 2. 創建Scan對象Scan scan = new Scan();// 添加參數 來限制掃描的范圍 否則掃描整張表scan.withStartRow(Bytes.toBytes(startRow));scan.withStopRow(Bytes.toBytes(stopRow));// 可以添加多個過濾FilterList filterList = new FilterList();// 創建過濾器// (1) 結果只保留當前列的數據ColumnValueFilter columnValueFilter = new ColumnValueFilter(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),// 比較關系CompareOperator.EQUAL,Bytes.toBytes(value));filterList.addFilter(columnValueFilter);// 添加過濾scan.setFilter(filterList);try {// 讀取多行數據 獲得scannerResultScanner scanner = table.getScanner(scan);// result 來記錄一行數據 本質是一個 Cell 數組// resultScanner 來記錄多行數據 本質是一個 result 數組for (Result result : scanner) {printCells(result.rawCells());System.out.println();   //打印完一個行鍵對應的行后換行}} catch (IOException e) {e.printStackTrace();}// 3. 關閉tabletable.close();}

整行過濾就是結果集不只是單單我們搜索的那一列數據而是整行數據(是整行數據,包括所有列族所有列,而不是一個Cell),需要使用 SingleColumnVlaueFilter 就好,需要注意的是,如果一行數據的某一列為空,而那一列的值恰好是我們過濾的關鍵字,那么這一行數據也會被添加到結果集。

// (2) 結果保留整行數據 包含其他列// 結果會保留沒有當前列的數據 比如我們要info:name=張三的整行數據 但是有這么一行數據的info列族下name是空的 這種數據也會被獲取到結果集中去SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),CompareOperator.EQUAL,Bytes.toBytes(value));filterList.addFilter(singleColumnValueFilter);

3.5、刪除數據

????????HBase使用版本控制來管理數據的多個版本,當最新版本的數據被刪除后,HBase會使用次新版本的數據填充原來的位置。所以如果一個Cell的某一列有多個版本,當我們僅僅刪除最新版之后,會有舊版本來填充被刪除的位置。

/*** 刪除一行中的一列數據* @param namespace 命名空間* @param tableName 表格名稱* @param rowKey 行鍵* @param columnFamily 列族* @param columnName 列名*/public static void deleteColumn(String namespace,String tableName,String rowKey,String columnFamily,String columnName) throws IOException {// 1. 獲取tableTable table = connection.getTable(TableName.valueOf(namespace,tableName));// 2. 創建delete對象Delete delete = new Delete(Bytes.toBytes(rowKey));// 添加列信息// addColumn 刪除最新版本// addColumns 刪除所有版本delete.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName));//        delete.addColumns(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName));// 刪除數據try {table.delete(delete);} catch (IOException e) {e.printStackTrace();}// 關閉tabletable.close();}

刪除前,我們的歷史版本有3個,最新的是 ls

刪除后,name變為了 zs

?


至此,HBase的基本使用已經完畢,還是比較簡單的,解下來就是深入了解一下HBase的底層,畢竟沒有學習難度的能力就沒有競爭力!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/37326.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/37326.shtml
英文地址,請注明出處:http://en.pswp.cn/news/37326.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

命令執行漏洞

1、命令執行漏洞 1.1、簡介 Django是用Python開發的一個免費開源的Web結構&#xff0c;幾乎包括了Web使用方方面面&#xff0c;能夠用于快速建立高性能、文雅的網站&#xff0c;Diango提供了許多網站后臺開發常常用到的模塊&#xff0c;使開發者可以專注于業務部分。 1.2、漏…

【Terraform學習】管理顯式依賴關系-depends_on(Terraform配置語言學習)

背景&#xff1a; 關于如何在機器上拉terraform代碼&#xff0c;初始化就不重復了&#xff0c;需要的可以查看前面的文章&#xff1a; 【Terraform學習】Terraform-AWS部署快速入門&#xff08;快速入門&#xff09;_向往風的男子的博客-CSDN博客 管理顯式依賴關系 隱式依賴…

【刪除vlan的方法】

提示錯誤 [SW1]undo vlan 10 Error: The VLAN has a L3 interface. Please delete it first. 解決辦法 undo interface Vlanif10 #刪除vlan 10下的接口 [SW1-GigabitEthernet0/0/1]dis this #刪除下列的IP

接口自動化必備技能——jmeter提取token方式以及設置成全局變量(跨線程組傳token值)方式

前言 今天Darren洋教大家如何使用jmeter中的插件來進行token值的提取與調用&#xff0c;今天Darren洋介紹兩種jmeter提取token值的方式&#xff0c;一種是在當前線程組中直接提取token值&#xff0c;一種是跨線程組的方式進行token值的提取并調用給不同線程組里的HTTP接口使用。…

如何讀取文件夾內的諸多文件,并選擇性的保留部分文件

目錄 問題描述: 問題解決: 問題描述: 當前有一個二級文件夾,第一層是文件夾名稱是“Papers(LNAI14302-14304)",第二級文件夾目錄名稱如下圖藍色部分所示。第三層為存放的文件,如下下圖所示,每一個文件中,均存放三個文件,分別為copyright.pdf, submission.pdf, s…

【PYTHON】WebSocket服務端與客戶端通信實現

目錄 1 簡介 2 WebSocket優點 3 前后端交互的方式 4 心跳機制和重連機制 5 后端代碼 6 測試

重磅發布!曙光存儲“3+N”,綠色存力新選擇

8月9-10日&#xff0c;2023年數據中心市場年會在京舉辦。會上&#xff0c;中科曙光存儲產品事業部總監石靜發表《綠色存力 打通綠色數據中心最后一站》主題演講。“在今天&#xff0c;數據中心正在成為‘高能耗’產業&#xff0c;綠色節能從可選項走向必選項。曙光存儲跨越綠色…

管理 IBM Spectrum LSF

管理 IBM Spectrum LSF 了解如何管理 IBM Spectrum LSF 集群&#xff0c;控制守護程序&#xff0c;更改集群配置以及使用主機和隊列。 管理 LSF 作業和作業調度策略。 查看作業信息和控制作業。 了解如何配置資源并將其分配給 LSF 作業。 了解如何在 LSF 集群中提交&#xff0…

開發測試框架一 - 創建springboot工程及基礎操作

一、創建及運行方式 1. 從官網導入&#xff1a; 注意&#xff1a;由于我的java版本是1.8&#xff1b;所以選中了spring2.7.14&#xff1b;如果你的java版本是9及以上&#xff0c;選中spring3相關的同時Java 版本也要對應起來 2. 創建第一個get請求 創建Controller package及…

mysql滑動窗口案例

獲取學科最高分 SELECT DISTINCT name,subject,MAX(score) OVER (PARTITION by subject) as 此學科最高分數 from scores;獲取學科的報名人數 select DISTINCT subject,count(name) over (partition by subject) as 報名此學科的人數 from scores; 求學科總分 SELECT DISTI…

JavaScript高級:常見設計模式

設計模式是在軟件開發中重復出現的問題的解決方案&#xff0c;它們是經過驗證的、被廣泛接受的最佳實踐。設計模式可以讓我們避免重復造輪子&#xff0c;提高代碼質量和可維護性。在本文中&#xff0c;我們將介紹幾種常見的設計模式&#xff0c;以及它們的實現和應用。 1. 單例…

Conda(Python管理工具)

1.簡介 Conda是一個開源的包管理器和環境管理器&#xff0c;主要用于管理Python&#xff0c;但也可以用于其他語言。它主要用于安裝、管理和更新軟件包及其依賴項&#xff0c;以及創建、保存、加載和切換不同的開發環境。Conda可以在Windows、MacOS和Linux系統上使用&#xff…

Spring Boot + Vue3前后端分離實戰wiki知識庫系統十二--用戶管理單點登錄開發一...

目標&#xff1a; 在上一次https://www.cnblogs.com/webor2006/p/17533745.html我們已經完成了文檔管理的功能模塊開發&#xff0c;接下來則開啟新模塊的學習---用戶登錄&#xff0c;這塊還是有不少知識點值得學習的&#xff0c;先來看一下整體的效果&#xff0c;關于效果官網有…

2023全國大學生數學建模競賽C提思路模型代碼

目錄 1.C題思路模型&#xff1a;比賽開始后&#xff0c;第一時間更新&#xff0c;獲取見文末名片 2.比賽時間&#xff1a;2023年9月7日18點到2023年9月10日20點 3 全國大學生數學建模競賽常見數模問題 3.1 分類問題 3.2 優化問題 詳細思路見此名片&#xff0c;開賽第一時間…

YOLOv8目標檢測算法

YOLOv8目標檢測算法相較于前幾代YOLO系列算法具有如下的幾點優勢&#xff1a; 更友好的安裝/運行方式速度更快、準確率更高新的backbone&#xff0c;將YOLOv5中的C3更換為C2FYOLO系列第一次嘗試使用anchor-free新的損失函數 YOLOv8簡介 YOLOv8 是 Ultralytics 公司繼 YOLOv5…

FiboSearch Pro – Ajax Search for WooCommerce 商城AJAX實時搜索插件

FiboSearch Pro是最受歡迎的WooCommerce 產品搜索插件。它為您的用戶提供精心設計的高級 AJAX 搜索欄&#xff0c;并提供實時搜索建議。默認情況下&#xff0c;WooCommerce 提供非常簡單的搜索解決方案&#xff0c;沒有實時產品搜索&#xff0c;甚至沒有 SKU 搜索。FiboSearch&…

網絡基礎(一)橋接網絡

網絡基礎知識 橋接網絡 橋接網絡是一種網絡設計技術&#xff0c;其目的是將兩個或多個網絡段連接在一起&#xff0c;使它們在邏輯上表現為單個網絡。這通過使用網絡橋來實現&#xff0c;網絡橋工作在數據鏈路層&#xff08;第2層&#xff09;&#xff0c;只關心MAC地址&#…

uniapp開發微信小程序底部地區選擇彈框

個人項目地址&#xff1a; SubTopH前端開發個人站 &#xff08;自己開發的前端功能和UI組件&#xff0c;一些有趣的小功能&#xff0c;感興趣的伙伴可以訪問&#xff0c;歡迎提出更好的想法&#xff0c;私信溝通&#xff0c;網站屬于靜態頁面&#xff09; SubTopH前端開發個人站…

React Native 圖片組件基礎知識

在 React Native 中使用圖片其實跟 HTML 中使用圖片一樣簡單&#xff0c;在 React Native 中我們使用Image組件來呈現圖片的內容&#xff0c;其中主要的屬性有&#xff1a;source。這個屬性主要是設置圖片的內容&#xff0c;它可以是網絡圖像地址、靜態資源、臨時本地圖像以及本…

Android側滑欄(一)可縮放可一起移動的側滑欄

在實際的各類App開發中&#xff0c;經常會需要做一個左側的側滑欄&#xff0c;類似于QQ這種。 今天這篇文章總結下自己在開發中遇到的這類可以跟隨移動且可以縮放的側滑欄。 一、實現原理 使用 HorizontalScrollView 實現一個水平方向的可滑動的View&#xff0c;左布局為側滑…