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

Hyperledger Fabric区块链离线部署

前言: 在最近的业务上确实需要用到这个区块链进行数据上链及存证溯源,我也花了一些时间在研究在麒麟v10服务器去部署这个fabric(超级账本)区块链

也确实在部署的过程中遇到了很多的一些问题,花费很多时间在排查这些问题上, 也是想通过这篇博客来为后来者及自己在以后部署fabric区块链时能少走点弯路

部署准备工作

1.部署dokcer

这个可以参考我之前的一篇文章: https://www.cnblogs.com/magepi/p/19637502

2.配置docker下载镜像源

先创建docker目录
mkdir -p /etc/docker在编辑daemon.json配置文件
vim /etc/docker/daemon.json

daemon.json(第一个是我自己配置的阿里云镜像源加速地址,可根据需要配置自己的)

{ "registry-mirrors" : [ "https://test.mirror.aliyuncs.com","https://docker.m.daocloud.io","https://docker.xuanyuan.me", "https://docker.1ms.run","https://dockerproxy.com","https://docker.mirrors.ustc.edu.cn","https://docker.nju.edu.cn","https://mirror.baidubce.com"] 
}

配置完后记得重启下docker  systemctl restart docker

3.下载离线所需镜像包

当然离线部署一般是找一台有网络的服务器先下载好再传到离线服务器并导入镜像,有时候网络比较慢,下载这些镜像还是比较耗时的

docker pull hyperledger/fabric-tools:2.4.9
docker pull hyperledger/fabric-peer:2.4.9
docker pull hyperledger/fabric-orderer:2.4.9
docker pull hyperledger/fabric-ca:1.5.7
docker pull hyperledger/fabric-nodeenv:2.4
docker pull hyperledger/fabric-ccenv:2.4

我这边因为之前下过,直接导入镜像即可

查看镜像命令

4.下载fabric官方示例包

 需要下载fabric-samples-2.4.9.tar,这是fabric区块链的官方示例包, 在部署时需要用到

 

fabric区块链开始部署

1.配置文件夹及文件

vdc是我挂载的磁盘目录,可以根据自己服务器情况选择放到那个目录下

# 创建核心目录+子目录(证书/区块/配置全放这里)
mkdir -p /vdc/docker/fabric-offline/config/{crypto-config,channel-artifacts}
# 进入核心目录(后续操作默认在此目录,避免路径混乱)
cd /vdc/docker/fabric-offline/config

这一步go或node.js都可以先把对应目录拷过来起
这一步可以先做(创建链码时需要用到的node.js源码(fabric-samples2.4.9是下载的))
mkdir -p /vdc/docker/fabric-offline/config/chaincode/fabcar

#宿主机执行:fabcar链码 → 已挂载的config/chaincode目录,容器内实时同步
cp -r /opt/docker/fabric-samples-2.4.9/chaincode/fabcar/javascript /vdc/docker/fabric-offline/config/chaincode/fabcar/

# 宿主机执行:检查复制后的链码文件
ls /vdc/docker/fabric-offline/config/chaincode/fabcar/javascript

这个fabcar链码存放目录要注意用自己服务器上的

fabric区块链复制示例文件

出现index.js等三个目录说明已经复制过去了

 

将我准备好的三个配置文件直接放进去/vdc/docker/fabric-offline/config里crypto-config.yaml,configtx.yaml,docker-compose.yaml

crypto-config.yaml

OrdererOrgs:- Name: OrdererDomain: example.comSpecs:- Hostname: orderer
PeerOrgs:- Name: Org1Domain: org1.example.comTemplate:Count: 1Users:Count: 1

configtx.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
---
Organizations:- &OrdererOrgName: OrdererMSPID: OrdererMSPMSPDir: /opt/gopath/src/github.com/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/mspPolicies:Readers:Type: SignatureRule: "OR('OrdererMSP.member')"Writers:Type: SignatureRule: "OR('OrdererMSP.member')"Admins:Type: SignatureRule: "OR('OrdererMSP.admin')"Endorsement:Type: SignatureRule: "OR('OrdererMSP.member')"OrdererEndpoints:- orderer.example.com:7050- &Org1Name: Org1MSPID: Org1MSPMSPDir: /opt/gopath/src/github.com/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/mspPolicies:Readers:Type: SignatureRule: "OR('Org1MSP.member')"Writers:Type: SignatureRule: "OR('Org1MSP.member')"Admins:Type: SignatureRule: "OR('Org1MSP.admin')"Endorsement:Type: SignatureRule: "OR('Org1MSP.member')"OrdererEndpoints:- orderer.example.com:7050AnchorPeers:- Host: peer0.org1.example.comPort: 7051Capabilities:Global: &ChannelCapabilitiesV2_0: trueOrderer: &OrdererCapabilitiesV2_0: trueApplication: &ApplicationCapabilitiesV2_0: true# 核心新增:Channel级默认策略(Fabric 2.4.9强制要求)
Channel: &ChannelDefaultsPolicies:Readers:Type: ImplicitMetaRule: "ANY Readers"Writers:Type: ImplicitMetaRule: "ANY Writers"Admins:Type: SignatureRule: "OR('Org1MSP.member')"Capabilities:<<: *ChannelCapabilitiesApplication: &ApplicationDefaultsOrganizations:Policies:Readers:Type: ImplicitMetaRule: "ANY Readers"Writers:Type: ImplicitMetaRule: "ANY Writers"Admins:Type: SignatureRule: "OR('Org1MSP.admin')"Endorsement:Type: SignatureRule: "OutOf(1, 'Org1MSP.member')"Capabilities:<<: *ApplicationCapabilitiesOrderer: &OrdererDefaultsOrdererType: soloAddresses:- orderer.example.com:7050BatchTimeout: 2sBatchSize:MaxMessageCount: 10AbsoluteMaxBytes: 99 MBPreferredMaxBytes: 512 KBOrganizations:Policies:Readers:Type: ImplicitMetaRule: "ANY Readers"Writers:Type: ImplicitMetaRule: "ANY Writers"Admins:Type: SignatureRule: "OR('OrdererMSP.admin', 'Org1MSP.admin')"BlockValidation:Type: ImplicitMetaRule: "ANY Writers"Profiles:OneOrgOrdererGenesis:<<: *ChannelDefaults  # 关联Channel级策略Capabilities:<<: *ChannelCapabilitiesOrderer:<<: *OrdererDefaultsOrganizations:- *OrdererOrgCapabilities:<<: *OrdererCapabilitiesConsortiums:SampleConsortium:Organizations:- *Org1OneOrgChannel:<<: *ChannelDefaults  # 关联Channel级策略(生成通道交易文件必须)Consortium: SampleConsortiumApplication:<<: *ApplicationDefaultsOrganizations:- *Org1Capabilities:<<: *ApplicationCapabilities

docker-compose.yaml

version: '2.4'
# 定义网络:避免IP/网络冲突
networks:config_fabric-network:name: config_fabric-networkdriver: bridgeipam:config:- subnet: 172.19.0.0/16  # 匹配当前服务器网段# 通用TLS配置模板:避免重复编写,Orderer/Peer统一引用
x-tls-common: &tls-commonCORE_PEER_TLS_ENABLED: "true"CORE_PEER_TLS_CERT_FILE: /etc/hyperledger/fabric/tls/server.crtCORE_PEER_TLS_KEY_FILE: /etc/hyperledger/fabric/tls/server.keyCORE_PEER_TLS_ROOTCERT_FILE: /etc/hyperledger/fabric/tls/ca.crtservices:# ========== Orderer节点(启用TLS,固定IP:172.19.0.3)==========orderer.example.com:image: hyperledger/fabric-orderer:2.4.9  # 离线镜像,无需修改container_name: orderer.example.comrestart: always  # 意外挂掉自动重启,提升稳定性environment:# 基础日志/监听配置- ORDERER_GENERAL_LOGLEVEL=info- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0- ORDERER_GENERAL_LISTENPORT=7050# 核心TLS配置(精准匹配生成的TLS证书)- ORDERER_GENERAL_TLS_ENABLED=true- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]# 创世块/MSP配置(匹配已生成的文件)- ORDERER_GENERAL_GENESISMETHOD=file- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/genesis.block- ORDERER_GENERAL_LOCALMSPID=OrdererMSP- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp# 挂载:精准对应你的本地目录,无需修改volumes:- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/genesis.block- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls:/var/hyperledger/orderer/tlsports:- 7050:7050  # 对外端口,和你之前一致networks:config_fabric-network:ipv4_address: 172.19.0.3  # 固定IP,Java代码无需修改# ========== Peer0节点(启用TLS,固定IP:172.19.0.4)==========peer0.org1.example.com:image: hyperledger/fabric-peer:2.4.9  # 离线镜像,无需修改container_name: peer0.org1.example.comrestart: always  # 意外挂掉自动重启depends_on:- orderer.example.com  # 先启动Orderer,再启动Peerenvironment:# 基础Peer配置【去掉所有-,改成映射格式,支持YAML锚点合并】CORE_VM_ENDPOINT: unix:///host/var/run/docker.sock
      CORE_PEER_ID: peer0.org1.example.comCORE_PEER_ADDRESS: peer0.org1.example.com:7051CORE_PEER_LOCALMSPID: Org1MSPCORE_PEER_MSPCONFIGPATH: /etc/hyperledger/fabric/mspCORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE: config_fabric-networkCORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052# 引入通用TLS配置<<: *tls-common# 挂载:精准对应本地目录,包含链码目录volumes:- /var/run/:/host/var/run/  # 对接宿主机Docker,用于启动链码容器- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls- ./channel-artifacts:/etc/hyperledger/fabric/channel-artifacts- ./chaincode:/etc/hyperledger/fabric/chaincode  # 链码目录,提前挂载ports:- 7051:7051  # Peer主端口- 7052:7052  # 链码通信端口,不可省略networks:config_fabric-network:ipv4_address: 172.19.0.4  # 固定IP,Java代码无需修改# ========== Tools工具容器(后续部署链码/操作通道专用,无需手动操作)==========fabric-tools:image: hyperledger/fabric-tools:2.4.9  # 离线镜像,无需修改container_name: fabric-toolsrestart: alwaystty: truestdin_open: trueenvironment:# 提前定义环境变量,后续命令直接引用,无需手动输超长路径- CHANNEL_NAME=mychannel- ORDERER_ADDRESS=orderer.example.com:7050- PEER0_ORG1_ADDRESS=peer0.org1.example.com:7051# TLS根证书路径(精准匹配挂载的证书)- TLS_ROOTCERT_ORDERER=/etc/hyperledger/fabric/orderer-tls/ca.crt- TLS_ROOTCERT_PEER0=/etc/hyperledger/fabric/peer0-tls/ca.crt# 挂载TLS证书/通道文件,方便后续操作volumes:- /var/run/:/host/var/run/- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls:/etc/hyperledger/fabric/orderer-tls- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/peer0-tls- ./channel-artifacts:/etc/hyperledger/fabric/channel-artifacts- ./chaincode:/etc/hyperledger/fabric/chaincode  # 挂载链码目录working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer  # 工具默认工作目录networks:- config_fabric-network

这里三个文件一定要放到这个config目录下并与其它三个目录平级,因为上述几个配置文件挂载时用了本地的一些相对路径进行挂载

配置文件放进去

 

2.创建区块+证书+通道交易文件生成

一键生成所有文件(证书 + 创世块 + 通道交易)
docker run -it --rm \
-v $(pwd)/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/crypto-config \
-v $(pwd)/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/channel-artifacts \
-v $(pwd)/crypto-config.yaml:/opt/gopath/src/github.com/hyperledger/fabric/crypto-config.yaml \
-v $(pwd)/configtx.yaml:/opt/gopath/src/github.com/hyperledger/fabric/configtx.yaml \
-w /opt/gopath/src/github.com/hyperledger/fabric \
hyperledger/fabric-tools:2.4.9 \
bash -c "
export FABRIC_CFG_PATH=/opt/gopath/src/github.com/hyperledger/fabric;
# 生成带TLS的证书
cryptogen generate --config=/opt/gopath/src/github.com/hyperledger/fabric/crypto-config.yaml;
# 生成创世块
configtxgen -profile OneOrgOrdererGenesis -outputBlock /opt/gopath/src/github.com/hyperledger/fabric/channel-artifacts/genesis.block -channelID system-channel;
# 生成通道交易文件
configtxgen -profile OneOrgChannel -outputCreateChannelTx /opt/gopath/src/github.com/hyperledger/fabric/channel-artifacts/mychannel.tx -channelID mychannel;
echo '✅ 所有带TLS的证书/通道文件生成完成!'
"

检查通道文件是否生成
ls channel-artifacts/

已经成功创建

创世区块生成成功

 

3.服务节点一键启动

注意也是在/vdc/docker/fabric-offline/config目录下执行
docker-compose up -d

docker-compose一键启动

服务都已正常启动

 

4.创建通道

在 /vdc/docker/fabric-offline/config 目录下执行
1. # 复制完整的crypto-config目录到fabric-tools容器
docker cp ./crypto-config fabric-tools:/etc/hyperledger/fabric/进入tools容器命令
docker exec -it fabric-tools bash2.进入fabric-tools 容器内,查找路径是否存在
find /etc/hyperledger/fabric -name "Admin@org1.example.com"3.验证 $ORDERER_CA 变量是否正确设置(证书)
echo $ORDERER_CA4. 如果输出是 /etc/hyperledger/fabric/orderer-tls/ca.crt,说明变量正确;如果是空的,重新设置
export ORDERER_CA=/etc/hyperledger/fabric/orderer-tls/ca.crt5.设置环境变量
# 设置正确的Admin MSP路径
export CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_LOCALMSPID="Org1MSP"6. 用正确的格式重新执行通道创建命令
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f /etc/hyperledger/fabric/channel-artifacts/mychannel.tx --tls true --cafile "${ORDERER_CA}"

重新创建通道并加入peer节点

 

5.将通道加入peer节点

#基础通道和Orderer配置(这一步是设置环境变量不然执行让peer0加入通道会报错)
export CHANNEL_NAME=mychannel
export ORDERER_CA=/etc/hyperledger/fabric/orderer-tls/ca.crt
# 2. Peer0的身份和网络配置
export CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/peer0-tls/ca.crt#让Peer0加入通道
peer channel join -b mychannel.block --tls true --cafile $ORDERER_CA# 查询Peer0已加入的通道
peer channel list

通道加入peer节点

通道已经成功加入了peer节点 mychannel

 

6.链码安装

链码又分为node.js链码和go链码,本质上链码部署流程都差不多,先用node.js链码进行安装

1. tools容器内执行:检查复制后的链码文件有没有复制进容器
ls /etc/hyperledger/fabric/chaincode/fabcar/javascript2.打包链码
peer lifecycle chaincode package fabcar.tar.gz \
--path /etc/hyperledger/fabric/chaincode/fabcar/javascript \
--lang node \
--label fabcar_1.03.安装链码
peer lifecycle chaincode install fabcar.tar.gz4.批准链码(链id记得换成自己的)
peer lifecycle chaincode approveformyorg \
-o orderer.example.com:7050 \
-C mychannel \
-n fabcar \
--version 1.0 \
--package-id fabcar_1.0:a656dc59c2488cdf7f14e68ee60c79ef0c0bc5f500789a33b33025ca65988a75 \
--sequence 1 \
--tls true \
--cafile $ORDERER_CA批准状态检查命令(Org1MSP对应的approvals列显示true,就能确认链码批准成功了)
peer lifecycle chaincode checkcommitreadiness \
-C mychannel \
-n fabcar \
--version 1.0 \
--sequence 1 \
--tls true \
--cafile $ORDERER_CA5.提交链码
peer lifecycle chaincode commit \
-o orderer.example.com:7050 \
-C mychannel \
-n fabcar \
--version 1.0 \
--sequence 1 \
--tls true \
--cafile $ORDERER_CA \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE

node.js链码安装命令

到这一步fabric区块链其实已经是成功部署了

7.区块链写入查询测试

这个写入测试车辆数据及查询方法是因为我们之前用的官方示例文件fabric-samples-2.4.9.tar,里面已经存在node.js及go链码的所有链码文件,有内置了这个车辆的上链及查询的方法,直接用这个测试即可

1.初始化账本(写入测试车辆数据)
peer chaincode invoke \
-o orderer.example.com:7050 \
-C mychannel \
-n fabcar \
-c '{"Args":["initLedger"]}' \
--tls true \
--cafile $ORDERER_CA \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE2. 验证链码查询功能
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

node.js链码测试

验证区块链数据上链及查询成功

 

其它

如果在安装过程中频繁出问题或环境被污染不如索性重头开始

删指定目录 + 停止并删除所有 Fabric 运行容器,镜像完全保留,执行完后环境回到干净状态# 1. 删除指定的/vdc/docker/fabric-offline/config目录
rm -rf /vdc/docker/fabric-offline/config
# 2. 停止所有运行中的Fabric容器(orderer/peer/tools)
docker stop $(docker ps -a | grep -E "orderer|peer|fabric-tools" | awk '{print $1}')
# 3. 删除所有已停止的Fabric容器
docker rm $(docker ps -a | grep -E "orderer|peer|fabric-tools" | awk '{print $1}')
# 4. 清理旧的链码容器/镜像(避免残留)
docker rm -f $(docker ps -a | grep "dev-" | awk '{print $1}')
docker rmi -f $(docker images | grep "dev-" | awk '{print $3}')
# 5. 清理Fabric相关的临时数据
rm -rf /vdc/docker/fabric-offline/*.block /vdc/docker/fabric-offline/*.tx /vdc/docker/fabric-offline/crypto-config删除fabric网络(如果网络是叫这个名字的话)
docker network rm config_fabric-network# 列出所有Docker网络
docker network ls# 查看每个网络的网段,找出与172.19.0.0/16(这是配置在上面文件得网段)重叠的网络
for net in $(docker network ls -q); do
echo "=== 网络ID: $net ===";
docker network inspect $net | grep -A 3 "Subnet";
done下载镜像并打包
docker save -o offline-images.tar \
hyperledger/fabric-ca:1.5.7 \
hyperledger/fabric-orderer:2.4.9 \
hyperledger/fabric-peer:2.4.9 \
hyperledger/fabric-tools:2.4.9 \
hyperledger/fabric-nodeenv:2.4 \
hyperledger/fabric-ccenv:2.4 \
hyperledger/fabric-baseos:2.4# 导入镜像到离线服务器docker
docker load -i offline-images.tar
peer chaincode invoke \  -o orderer.example.com:7050 \  -C mychannel \  -n fabcar \  -c '{"Args":["initLedger"]}' \  --tls true \  --cafile $ORDERER_CA \  --peerAddresses peer0.org1.example.com:7051 \  --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE
http://www.jsqmd.com/news/413496/

相关文章:

  • 2026超细粉碎设备厂家推荐:潍坊星尔机械设备科技,超微/气流粉碎机全系解决方案 - 品牌推荐官
  • 2026年光亮扁钢系列厂家实力推荐:苏州汇志金属制品有限公司全系产品供应,覆盖多领域需求 - 品牌推荐官
  • 2026螺旋输送机厂家推荐:无锡市长荣输送机械有限公司,多类型螺旋输送机全系供应 - 品牌推荐官
  • 开发者必知的 12 个核心架构概念:构建高可用分布式系统的基石
  • 2026年硝化细菌剂专业厂家推荐:武汉水之国环保科技,多类型硝化细菌产品全覆盖 - 品牌推荐官
  • 2026热压罐设备厂家推荐:山东茵泰利机械科技,碳纤维/大型/实验/真空热压罐全系供应 - 品牌推荐官
  • 检查是否有长时间运行的查询
  • 《周易》伏羲八卦演变过程
  • 2026年阻燃纱线厂家推荐:青岛裕晟邦纺织,晴氯纶/晴棉/天丝全系阻燃纱线供应 - 品牌推荐官
  • 2026年造粒机设备厂家推荐:常州君瑞杰机械设备有限公司,挤出/塑料/肥料/干粉造粒机全品类供应 - 品牌推荐官
  • 2026年滑环厂家推荐:杭州聚环机电科技,油路/水银/风力发电/盘式/导电滑环专业供应 - 品牌推荐官
  • 2026年定制/封闭式/11座/8座/电动/燃油/景区观光车推荐:重庆绿爵电动车全系供应 - 品牌推荐官
  • 【Linux】screen 命令创建会话 保持后台运行
  • 2026年挂具脱漆炉推荐:鱼台光华环保科技,原理/报价/定制全解析,环保设备优选 - 品牌推荐官
  • 2026年报警器厂家实力推荐:常州市武进悦达电声器材有限公司,全系特种机械/车辆报警器解决方案 - 品牌推荐官
  • 2026矿用工字钢及支架厂家推荐:唐山市舒达仓储供应20Mnk/11#/12#矿用工字钢及支护全系产品 - 品牌推荐官
  • 2026年废石墨回收厂家推荐:临漳县昊联碳素有限公司,废石墨方/粉/纸/块全品类回收 - 品牌推荐官
  • 2026支架水池厂家实力推荐:日照碧水湾泳池工程有限公司,多类型支架水池全场景覆盖 - 品牌推荐官
  • 2026废水除氟剂厂家推荐:巩义市永源净水材料有限公司,高效/活性/液体/深度除氟剂全系供应 - 品牌推荐官
  • 2026年矿用电机车厂家实力推荐:山东名舜机械制造,多型号井下/架线/防爆电机车供应 - 品牌推荐官
  • 2026年精密长轴/长轴加工/机械长轴厂家推荐:无锡杨楠精密机械制造有限公司全系供应 - 品牌推荐官
  • 2026年环保透水砖厂家推荐:佛山生态海绵城市科技发展有限公司全系产品解析 - 品牌推荐官
  • 【2025国内 iPaaS 主流厂商推荐】哪家好:专业深度测评
  • 2026年重庆自考本科及小自考官方助学点推荐:法商学校多元专业助力学历提升 - 品牌推荐官
  • 2026数控旋风铣床厂家推荐:南京创远旋铣装备制造有限公司,多系列旋铣装备定制化解决方案 - 品牌推荐官
  • 2026年武汉中职学校推荐:武汉东新电子技工学校,热门专业/升学率高/口碑优选 - 品牌推荐官
  • 农产品销售管理|基于java + vue农产品销售管理系统(源码+数据库+文档)
  • EI会议!IEEE出版 ▏2026年区块链技术与基础模型国际学术会议(BTFM 2026)
  • 2026年建房材料合金瓦厂家推荐:香河久工科技塑美/金属/复合树脂瓦合金瓦全系供应 - 品牌推荐官
  • 2026年家具定制企业推荐:天公家具厂全屋/客厅/布艺/真皮家具直销,15年荣誉认证 - 品牌推荐官