当前位置: 首页 > news >正文

ruoyi+Hadoop+hbase实现大数据存储查询

前言

有个现实的需求,数据量可能在100亿条左右。现有的数据库是SQL Server,随着采集的数据不断的填充,查询的效率越来越慢(现有的SQL Server查询已经需要数十秒钟的时间),看看有没有优化的方案。

考虑过SQL Server加索引、分区表、分库分表等方案,但数据量增长太快,还是很快就会遇到瓶颈,因此需要更优化的技术。在众多的NOSQL和大数据技术之下,针对此场景,主要考虑了两种方案:

  1. MongoDB:json文档型数据库,可以通过集群拓展。但更适合列比较复杂的场景快速查询。

  2. Hadoop:大数据领域的瑞士军刀,周边有很多相配套的工具可以使用,后期拓展性较强。

因为此需求只是简单的根据编码找到对应的卷号,因此最终选择Hadoop实现。

部署Hadoop

直接去官方下载,https://hadoop.apache.org/。

要注意版本的问题,版本不匹配会带来很多麻烦。我这里选择的是hadoop 3.3.4的版本。

步骤:

  1. 找到hadoop对应版本的winutils.exe、hadoop.dll文件

复制hadoop 3.3.4版本对应的winutils.exe和hadoop.dll文件到hadoop的bin文件夹下面。同步复制这两个文件,到C:\Windows\System32下面。

这两个文件可以去github上面搜索,一定要注意跟你的hadoop版本一致,否则不通过。

  1. 文件配置(下面的配置文件都在 hadoop 3.3.4/etc/hadoop 文件夹内)

a). hadoop-env.cmd文件配置

set JAVA_HOME=C:\Users\Administrator\.jdks\corretto-11.0.21

注意:这里的JAVA_HOME是指向的openjdk(开源)的版本,oracle的jdk用不起来。必须要安装openjdk。
b). core-site.xml

<configuration><property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property>
</configuration>

c). hdfs-site.xml

<configuration><property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/hadoop-3.3.4/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/hadoop-3.3.4/data/datanode</value> </property> 
</configuration>

d). yarn-site.xml

<configuration><property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.auservices.mapreduce.shuffle.class</name> <value>org.apache.hadoop.mapred.ShuffleHandler</value> </property> 
</configuration>
  1. 配置环境变量
    在这里插入图片描述
    再添加到Path,%HADOOP_HOME%\bin
    可以在控制台输入:hadoop version,验证是否安装配置正确
    在这里插入图片描述
    最后在控制台输入:start-all.cmd ,启动Hadoop。没有错误信息,表示Hadoop启动成功。
    在这里插入图片描述

部署Hbase

安装Hbase可以到官网下载:https://hbase.apache.org/。

同样要非常关注版本的问题,因为我上面选择的Hadoop是3.3.4,与之配套的Hbase的版本是2.5.5。

步骤:

  1. 将之前下载的winutils.exe和hadoop.dll文件拷贝到 hbase的bin目录下,比如我的:E:\hbase-2.5.5\bin。

  2. 文件配置

在hbase的conf目录下,打开hbase-site.xml文件,添加如下内容:

<configuration><property><name>hbase.rootdir</name><value>file:///E:/hbase-2.5.5/root</value></property><property><name>hbase.cluster.distributed</name><value>false</value></property><property><name>hbase.zookeeper.quorum</name><value>127.0.0.1</value></property><property><name>hbase.tmp.dir</name><value>./tmp</value></property><property><name>hbase.unsafe.stream.capability.enforce</name><value>false</value></property>
</configuration>

按照上述的配置说明,在hbase目录下,添加root和tmp文件夹。

3.配置环境变量(此处省略,参考上面的hadoop的截图)

找到hbase的bin目录下的start-hbase.cmd文件,双击启动。

hbase启动完成后的界面:
在这里插入图片描述

基于若依进行二次开发

直接引用ruoyi的项目,在里面添加功能,当然首先需要导入相应的jar包(这些jar包在hadoop和hbase里面都有,直接引用即可)。
在这里插入图片描述
当然下面还有引用的jar包,这里就不截图了,供参考。
在这里插入图片描述
该项目基于SpringBoot框架,实现了基于HDFS、hbase的基础功能。

控制器代码如下:

package com.ruoyi.web.controller.roll;import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.roll.RollEntity;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.client.coprocessor.AggregationClient;
import org.apache.hadoop.hbase.client.coprocessor.LongColumnInterpreter;
import org.apache.hadoop.hbase.filter.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.mapreduce.Job;@Controller
@RequestMapping("/roll")
public class RollController extends BaseController {private String prefix = "/roll";/*** 新增角色*/@GetMapping("/add")public String add() {
//        long count = rowCountByCoprocessor("mytb");
//        System.out.println("总记录数->>>"+count + "");return prefix + "/add";}@PostMapping("/list")@ResponseBodypublic TableDataInfo list(String inputEPC) {
//        startPage();
//        List<SysRole> list = roleService.selectRoleList(role);//String epc = "E280117020000333BF040B34";//String epc = "E280119120006618A51D032D"; //查询的EPCString epc = inputEPC;String tableName = "mytb";String columnFamily = "mycf";//        create(tableName, columnFamily);
//        insert(tableName,columnFamily);long startTime = System.currentTimeMillis();//E280119120006BEEA4E5032String reVal = query(tableName, columnFamily, epc);long endTime = System.currentTimeMillis();System.out.println("卷号查询时间为:" + (endTime - startTime) + "ms");RollEntity model = new RollEntity();model.epc = epc;model.rollName = reVal;model.searchTime = (endTime - startTime) + "ms";List<RollEntity> list = new ArrayList<>();list.add(model);return getDataTable(list);}// 创建表public static void create(String tableName, String columnFamily) {Configuration conf = HBaseConfiguration.create();conf.set("hbase.rootdir", "hdfs://localhost:9000/hbase");conf.set("hbase.zookeeper.quorum", "localhost");try {Connection conn = ConnectionFactory.createConnection(conf);if (conn.getAdmin().tableExists(TableName.valueOf(tableName))) {System.err.println("Table exists!");} else {HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf(tableName));try {tableDesc.addFamily(new HColumnDescriptor(columnFamily));conn.getAdmin().createTable(tableDesc);System.err.println("Create Table SUCCESS!");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 插入数据public static void insert(String tableName, String columnFamily) {Configuration conf = HBaseConfiguration.create();conf.set("hbase.rootdir", "hdfs://localhost:9000/hbase");conf.set("hbase.zookeeper.quorum", "localhost");try {Connection conn = ConnectionFactory.createConnection(conf);TableName tn = TableName.valueOf(tableName);Table table = conn.getTable(tn);try {//                for (int i = 17742000; i <= 100000000; i++) {
//                    Put put = new Put(Bytes.toBytes("row" + i));
//                    put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes("code"),
//                            Bytes.toBytes("E280119120006BEEA4E5032" + i));
//                    table.put(put);
//                }//                Put put = new Put(Bytes.toBytes("E280119120006618A51D032D"));
//                put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes("code"),
//                            Bytes.toBytes("CQ-230308009"));
//                table.put(put);Put put = new Put(Bytes.toBytes("E280117020000333BF040B34"));put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes("code"),Bytes.toBytes("CQ-230309002"));table.put(put);table.close();// 释放资源System.err.println("record insert SUCCESS!");} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 查询public static String query(String tableName, String columnFamily, String rowName) {String reVal = "";Configuration conf = HBaseConfiguration.create();conf.set("hbase.rootdir", "hdfs://localhost:9000/hbase");conf.set("hbase.zookeeper.quorum", "localhost");try {Connection conn = ConnectionFactory.createConnection(conf);TableName tn = TableName.valueOf(tableName);Table table = conn.getTable(tn);try {Get get = new Get(rowName.getBytes());Result r = table.get(get);for (Cell cell : r.rawCells()) {String family = new String(CellUtil.cloneFamily(cell));String qualifier = new String(CellUtil.cloneQualifier(cell));String value = new String(CellUtil.cloneValue(cell));System.out.println("列:" + family + ":" + qualifier + " 值:" + value);reVal = value;break;}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {conn.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return reVal;}//过滤查询public static void queryFilter(String tableName, String columnFamily, String rowName, String value) {Configuration conf = HBaseConfiguration.create();conf.set("hbase.rootdir", "hdfs://localhost:9000/hbase");conf.set("hbase.zookeeper.quorum", "localhost");try {Connection conn = ConnectionFactory.createConnection(conf);TableName tn = TableName.valueOf(tableName);Table table = conn.getTable(tn);try {Scan scan = new Scan();Filter filter = new ValueFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes(value)));scan.setFilter(filter);ResultScanner rs = table.getScanner(scan);for (Result res : rs) {System.out.println(res);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//读取HDFS文件private static void readHDFSFileContents() {InputStream is = null;OutputStream os = null;BufferedInputStream bufferInput = null;BufferedOutputStream bufferOutput = null;try {is = new URL("hdfs://127.0.0.1:9000/myHadoop/1.txt").openStream();bufferInput = new BufferedInputStream(is);// IOUtils.copyBytes(is, os, 4096,false);byte[] contents = new byte[1024];int bytesRead = 0;String strFileContents = "";while ((bytesRead = is.read(contents)) != -1) {strFileContents += new String(contents, 0, bytesRead);}System.out.println(strFileContents);} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {// IOUtils.closeStream(is);}}//创建HDFS目录private static void createHDFSDirectory() {// TODO Auto-generated method stubtry {Configuration conf = new Configuration();conf.set("fs.defaultFS", "hdfs://127.0.0.1:9000");FileSystem fs = FileSystem.get(conf);boolean result = fs.mkdirs(new Path("/myHadoop"));System.out.println(result);} catch (Exception e) {e.printStackTrace();}}//查询Hbase有多少条记录public long rowCountByCoprocessor(String tablename){long count = 0;try {Configuration conf = HBaseConfiguration.create();conf.set("hbase.rootdir", "hdfs://localhost:9000/hbase");conf.set("hbase.zookeeper.quorum", "localhost");Connection connection = ConnectionFactory.createConnection(conf);//提前创建connection和confAdmin admin = connection.getAdmin();//admin.enableTable(TableName.valueOf("mytb"));TableName name=TableName.valueOf(tablename);//先disable表,添加协处理器后再enable表//admin.disableTable(name);HTableDescriptor descriptor = new HTableDescriptor(name); //admin.getTableDescriptor(name);//descriptor.setReadOnly(false);String coprocessorClass = "org.apache.hadoop.hbase.coprocessor.AggregateImplementation";if (! descriptor.hasCoprocessor(coprocessorClass)) {descriptor.addCoprocessor(coprocessorClass);}//admin.modifyTable(name, descriptor);//admin.enableTable(name);//计时StopWatch stopWatch = new StopWatch();stopWatch.start();Scan scan = new Scan();AggregationClient aggregationClient = new AggregationClient(conf);//System.out.println("RowCount: " + aggregationClient.rowCount(name, new LongColumnInterpreter(), scan));count = aggregationClient.rowCount(name, new LongColumnInterpreter(), scan);stopWatch.stop();System.out.println("统计耗时:" +stopWatch.getTotalTimeMillis());connection.close();} catch (Throwable e) {e.printStackTrace();}return count;}
}

最终效果

在这里插入图片描述

相关文章:

ruoyi+Hadoop+hbase实现大数据存储查询

前言 有个现实的需求&#xff0c;数据量可能在100亿条左右。现有的数据库是SQL Server&#xff0c;随着采集的数据不断的填充&#xff0c;查询的效率越来越慢&#xff08;现有的SQL Server查询已经需要数十秒钟的时间&#xff09;&#xff0c;看看有没有优化的方案。 考虑过S…...

Word 在页眉或页脚中设置背景颜色

目录预览 一、问题描述二、解决方案三、参考链接 一、问题描述 如何在word的页眉页脚中设置背景色&#xff1f; 二、解决方案 打开 Word 文档并进入页眉或页脚视图。在 Word 2016 及更高版本中&#xff0c;你可以通过在“插入”选项卡中单击“页眉”或“页脚”按钮来进入或者…...

python获取js data.now同款时间戳

import requestsimport time from datetime import datetimecu_t datetime.now() se cu_t.timestamp()*1000 se int(se) print(se)#cur_time time.time()*1000 #seconds int(cur_time) #print(seconds)...

线上超市小程序可以做什么活动_提升用户参与度与购物体验

标题&#xff1a;线上超市小程序&#xff1a;精心策划活动&#xff0c;提升用户参与度与购物体验 一、引言 随着移动互联网的普及&#xff0c;线上购物已经成为人们日常生活的一部分。线上超市作为线上购物的重要组成部分&#xff0c;以其便捷、快速、丰富的商品种类和个性化…...

旺店通:API无代码开发的集成解决方案,连接电商平台、CRM和客服系统

集成电商生态&#xff1a;旺店通的核心优势 在数字化转型的浪潮中&#xff0c;旺店通旗舰版奇门以其无代码开发的集成解决方案&#xff0c;正成为电商领域的关键变革者。商家们通过旺店通可以轻松实现与电商平台、CRM系统和客服系统的连接&#xff0c;无需深入了解复杂的API开…...

命令查询pg 数据库版本,并且分析结果行各代表什么意思

目录 1 问题2 实现 1 问题 命令查询pg 数据库版本&#xff0c;并且分析结果行各代表什么意思 2 实现 SELECT version(); PostgreSQL 11.7 (Debian 11.7-2.pgdg1001) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit这是一条关于 PostgreSQL 数据库…...

Elaticsearch 学习笔记

文章目录 Elaticsearch 学习笔记一、什么是 Elaticsearch &#xff1f;二、Elaticsearch 安装1 es 安装2 问题解决3 数据格式 三、索引操作1 PUT 请求&#xff1a;在postman中&#xff0c;向 ES 服务器发 PUT 请求&#xff08;PUT请求相当于创建的意思&#xff09;2 GET 请求&a…...

计算机网络体系的形成

目录 1、开放系统互连参考模型OSI/RM 2、两种国际标准 3、协议与划分层次 4、网络协议的三要素 5、划分层次 &#xff08;1&#xff09;文件发送模块使两个主机交换文件 &#xff08;2&#xff09;通信服务模块 &#xff08;3&#xff09;接入网络模块 6、分层带来的好…...

PyTorch 基础篇(1):Pytorch 基础

Pytorch 学习开始 入门的材料来自两个地方&#xff1a; 第一个是官网教程&#xff1a;WELCOME TO PYTORCH TUTORIALS&#xff0c;特别是官网的六十分钟入门教程 DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ。 第二个是韩国大神 Yunjey Choi 的 Repo&#xff1a;pytorch-t…...

掌握Selenium4:详解各种定位方式

Selenium4中有多种元素定位方式&#xff0c;主要包括以下几种&#xff1a; 通过ID属性定位&#xff1a;根据元素的id属性进行定位。通过name属性定位&#xff1a;当元素没有id属性而有name属性时&#xff0c;可以使用name属性进行元素定位。通过class name定位&#xff1a;可以…...

go-fastfds部署心得

我是windows系统安装 Docker Desktop部署 docker run --name go-fastdfs&#xff08;任意的一个名称&#xff09; --privilegedtrue -t -p 3666:8080 -v /data/fasttdfs_data:/data -e GO_FASTDFS_DIR/data sjqzhang/go-fastdfs:lastest docker run&#xff1a;该命令用于运…...

Python第三次练习

Python 一、如何判断一个字符串是否是另一个字符串的子串二、如何验证一个字符串中的每一个字符均在另一个字符串中出现三、如何判定一个字符串中既有数字又有字母四、做一个注册登录系统 一、如何判断一个字符串是否是另一个字符串的子串 实现代码&#xff1a; string1 inp…...

从Java8升级到Java17,特色优化点

从Java8升级到Java17&#xff0c;特色优化点 一、局部变量类型推断二、switch表达式三、文本块四、Records五、模式匹配instanceof六、密封类七、NullPointerException 从Java 8 到 Java 20&#xff0c;Java 已经走过了漫长的道路&#xff0c;自 Java 8 以来&#xff0c;Java 生…...

js实现富文本

当涉及到使用 JavaScript 实现富文本时&#xff0c;一种常见的方法是使用一些现成的富文本编辑器库&#xff0c;比如&#xff1a; Quill&#xff1a;一个功能强大、易于集成的富文本编辑器&#xff0c;支持自定义样式和格式&#xff0c;提供丰富的插件和API。 TinyMCE&#xf…...

每日OJ题_算法_双指针②_力扣1089. 复写零

目录 力扣1089. 复写零 解析代码 力扣1089. 复写零 1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 难度 简单 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在…...

C++——红黑树

作者&#xff1a;几冬雪来 时间&#xff1a;2023年12月7日 内容&#xff1a;C——红黑树讲解 目录 前言&#xff1a; 红黑树的概念&#xff1a; 红黑树的性质&#xff1a; 红黑树的路径计算&#xff1a; 最长路径和最短路径&#xff1a; AVL树与红黑树的区别&#xff…...

【神化世界】asp网页500内部服务器错误的解决方法

问题解决方案记录 一、问题 在asp网页调试的时候&#xff0c;不小心改错了&#xff0c;好好的页面突然出现如下错误信息了&#xff1a; 二、解决方法 终于找到了问题所在&#xff0c;是sql语句出错造成的&#xff0c;特别记录一下。 正确的写法 sql"select * from mem…...

java面试题6

1.什么是Java中的泛型&#xff08;Generic&#xff09;&#xff1f; 答案&#xff1a;泛型是一种参数化类型的机制&#xff0c;在编译时提供类型安全性检查和重用代码的能力。使用泛型可以在编译时检测类型错误&#xff0c;并减少类型转换的需要。 2.Java中的反射&#xff08;…...

(03)vite 处理 css

文章目录 系列全集vite 处理css流程vite如何解决协同开发&#xff0c;样式重复覆盖的问题&#xff1f;使用less通过配置&#xff0c;更改vite的css默认行为vite 利用postcss样式兼容低版本浏览器 系列全集 &#xff08;01&#xff09;vite 从启动服务器开始 &#xff08;02&am…...

阿里云上传文件出现的问题解决(跨域设置)

跨域设置引起的问题 起因&#xff1a;开通对象存储服务后&#xff0c;上传文件限制在5M 大小&#xff0c;无法上传大文件。 1.查看报错信息 2.分析阿里云服务端响应内容 <?xml version"1.0" encoding"UTF-8"?> <Error><Code>Invali…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...