第 32 章 - Go语言 部署与运维
在Go语言的应用开发中,部署与运维是一个非常重要的环节。它不仅关系到应用能否顺利上线,还直接影响到应用的性能、安全性和可维护性。以下是根据您的需求整理的关于Go语言应用的打包和发布、容器化部署、监控和日志管理的相关内容。
1. 应用的打包和发布
打包
- 静态编译:Go语言支持跨平台编译,可以使用
GOOS
和GOARCH
环境变量指定目标操作系统和架构。例如,要为Linux x86_64系统编译一个静态二进制文件,可以执行:GOOS=linux GOARCH=amd64 go build -o myapp .
- 资源文件打包:如果应用依赖于外部资源文件(如配置文件、静态文件等),可以使用第三方工具如
go-bindata
将这些文件嵌入到二进制文件中,方便发布和部署。
发布
- 版本控制:使用Git等版本控制系统来管理代码变更,确保每次发布的版本都是可追溯的。
- 持续集成/持续部署(CI/CD):利用Jenkins、GitHub Actions、GitLab CI等工具实现自动化构建、测试和部署流程,提高效率并减少人为错误。
2. 容器化部署
- Dockerfile:编写Dockerfile定义应用运行所需的环境,包括基础镜像、安装依赖、复制应用文件等步骤。例如:
FROM golang:1.17-alpine AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/app . CMD ["./app"]
- Docker Compose:对于多服务应用,可以使用Docker Compose来管理服务间的依赖关系,简化本地开发环境搭建。
- Kubernetes:在生产环境中,推荐使用Kubernetes进行容器集群管理和调度,以实现高可用性和弹性伸缩。
3. 监控和日志
- 日志管理:使用
logrus
等库来格式化输出日志信息,并通过日志级别控制输出量。生产环境中应将日志发送到集中式日志管理系统,如ELK Stack或Loki。 - 性能监控:可以通过Prometheus搭配Golang客户端库(如
prometheus/client_golang
)收集应用指标数据,设置警报规则以便及时发现和处理问题。 - 健康检查:在应用中实现HTTP接口供外部调用,用于检查应用的状态是否正常。这对于Kubernetes中的自动恢复机制尤为重要。
案例及源代码
假设我们有一个简单的Web服务,该服务提供了一个返回当前时间的API。下面是一些关键部分的示例代码:
main.go
package mainimport ("fmt""net/http""time"
)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Current time is %s", time.Now().Format(time.RFC3339))})http.ListenAndServe(":8080", nil)
}
Dockerfile
FROM golang:1.17-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
监控和日志
可以添加对logrus
和prometheus
的支持,以便更好地监控应用状态和性能。这通常涉及到修改main.go
以包含相应的库初始化和指标收集逻辑。
4. 监控和日志管理
日志管理
-
日志格式化:使用
logrus
库可以方便地格式化日志输出,支持多种日志级别(如Debug、Info、Warn、Error等)。package mainimport (log "github.com/sirupsen/logrus" )func main() {log.Info("This is an info message")log.Warn("This is a warning message")log.Error("This is an error message") }
-
日志输出:可以将日志输出到标准输出(stdout)、文件、甚至是远程日志服务器。
log.SetOutput(os.Stdout)
-
集中式日志管理:使用ELK Stack(Elasticsearch、Logstash、Kibana)或Loki等工具集中管理日志,便于搜索和分析。
- ELK Stack:Logstash负责收集日志,Elasticsearch存储日志,Kibana提供可视化界面。
- Loki:轻量级的日志聚合系统,适合Kubernetes环境。
性能监控
-
Prometheus:使用Prometheus进行性能监控,可以收集各种指标(如请求延迟、QPS等)。
- 客户端库:使用
prometheus/client_golang
库在应用中暴露指标。 - 中间件:可以使用中间件(如
promhttp
)来自动收集HTTP请求的指标。
package mainimport ("net/http""github.com/prometheus/client_golang/prometheus""github.com/prometheus/client_golang/prometheus/promhttp" )var requestCounter = prometheus.NewCounterVec(prometheus.CounterOpts{Name: "http_requests_total",Help: "Total number of HTTP requests.",},[]string{"code"}, )func init() {prometheus.MustRegister(requestCounter) }func handler(w http.ResponseWriter, r *http.Request) {// Your application logic herew.Write([]byte("Hello, world!"))requestCounter.WithLabelValues(http.StatusOK).Inc() }func main() {http.HandleFunc("/", handler)http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8080", nil) }
- 客户端库:使用
-
Grafana:使用Grafana可视化Prometheus收集的数据,创建仪表板监控应用的性能。
5. 安全性
-
输入验证:对用户输入进行严格的验证,防止SQL注入、XSS等攻击。
func validateInput(input string) error {if len(input) > 100 {return errors.New("input too long")}// Additional validation logicreturn nil }
-
HTTPS:使用TLS证书启用HTTPS,保护数据传输的安全。
certFile := "path/to/cert.pem" keyFile := "path/to/key.pem" http.ListenAndServeTLS(":443", certFile, keyFile, nil)
-
身份验证和授权:实现身份验证(如JWT)和授权(如RBAC)机制,保护敏感操作。
- JWT:使用
jwt-go
库生成和验证JSON Web Tokens。 - RBAC:基于角色的访问控制,限制不同角色的权限。
- JWT:使用
6. 高可用性和容错
-
负载均衡:使用Nginx或HAProxy等工具实现负载均衡,提高应用的可用性和性能。
upstream myapp {server 192.168.1.1:8080;server 192.168.1.2:8080; }server {listen 80;location / {proxy_pass http://myapp;} }
-
自动扩展:在Kubernetes中使用Horizontal Pod Autoscaler (HPA) 根据CPU或内存使用率自动扩展Pod数量。
apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata:name: myapp spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: myappminReplicas: 2maxReplicas: 10metrics:- type: Resourceresource:name: cputarget:type: UtilizationaverageUtilization: 50
-
故障恢复:配置Kubernetes的Pod和Deployment策略,确保应用在出现故障时能够自动重启和恢复。
7. 持续集成/持续部署 (CI/CD)
- GitHub Actions:使用GitHub Actions实现自动化构建、测试和部署流程。
name: CI/CD Pipelineon:push:branches: [ main ]pull_request:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- name: Checkout codeuses: actions/checkout@v2- name: Set up Gouses: actions/setup-go@v2with:go-version: 1.17- name: Buildrun: go build -o myapp .- name: Testrun: go test -v ./...- name: Docker Loginuses: docker/login-action@v1with:username: ${{ secrets.DOCKER_USERNAME }}password: ${{ secrets.DOCKER_PASSWORD }}- name: Build and push Docker imagerun: |docker build -t myapp:latest .docker push myapp:latest- name: Deploy to Kubernetesuses: kubernetes-sigs/kustomize-github-actions/deploy@v1with:kubernetes-context: ${{ secrets.KUBE_CONTEXT }}kustomization-directory: k8s
8. 示例项目结构
一个典型的Go语言Web应用项目结构可能如下所示:
myapp/
├── cmd/
│ └── myapp/
│ └── main.go
├── internal/
│ ├── handlers/
│ │ └── handler.go
│ ├── middleware/
│ │ └── middleware.go
│ └── models/
│ └── model.go
├── pkg/
│ └── utils/
│ └── utils.go
├── Dockerfile
├── go.mod
├── go.sum
├── k8s/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── hpa.yaml
├── .github/
│ └── workflows/
│ └── ci-cd.yml
└── README.md
结论
通过上述内容,您可以更好地理解和实践Go语言应用的部署与运维。从打包和发布、容器化部署,到监控和日志管理、安全性、高可用性和容错,再到CI/CD,每个环节都至关重要。
9. 安全性增强
认证和授权
- OAuth2 和 OpenID Connect:使用OAuth2协议进行认证和授权,OpenID Connect是基于OAuth2的标准化身份层。
- OAuth2 Provider:可以使用Keycloak、Auth0等开源或商业服务作为OAuth2提供商。
- 中间件:使用中间件(如
oauth2-proxy
)保护应用的API端点。
package mainimport ("net/http""github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options""github.com/oauth2-proxy/oauth2-proxy/pkg/logger""github.com/oauth2-proxy/oauth2-proxy/pkg/oauthproxy" )func main() {config := options.Options{ClientID: "your-client-id",ClientSecret: "your-client-secret",RedirectURL: "http://localhost:8080/oauth2/callback",Provider: "google",CookieSecret: "your-cookie-secret",}proxy, err := oauthproxy.NewOAuthProxy(config)if err != nil {logger.Fatalf("Failed to create OAuth proxy: %v", err)}http.Handle("/", proxy)http.HandleFunc("/protected", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Protected content"))})http.ListenAndServe(":8080", nil) }
安全头设置
- Security Headers:使用中间件设置HTTP安全头,如Content-Security-Policy、X-Frame-Options等。
package mainimport ("net/http""github.com/unrolled/secure" )func main() {secureMiddleware := secure.New(secure.Options{AllowedHosts: []string{"example.com"},SSLRedirect: true,STSSeconds: 315360000,STSIncludeSubdomains: true,STSPreload: true,FrameDeny: true,ContentTypeNosniff: true,BrowserXssFilter: true,ContentSecurityPolicy: "default-src 'self'",})http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello, world!"))})http.ListenAndServe(":8080", secureMiddleware.Handler(http.DefaultServeMux)) }
10. 性能优化
代码优化
-
基准测试:使用
go test -bench .
进行基准测试,找出性能瓶颈。package mainimport "testing"func BenchmarkMyFunction(b *testing.B) {for i := 0; i < b.N; i++ {MyFunction()} }
-
性能剖析:使用
pprof
进行性能剖析,分析CPU和内存使用情况。package mainimport (_ "net/http/pprof""net/http" )func main() {go func() {http.ListenAndServe("localhost:6060", nil)}()// Your application logichttp.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello, world!"))})http.ListenAndServe(":8080", nil) }
数据库优化
- 索引优化:合理使用索引,避免全表扫描。
- 连接池:使用数据库连接池(如
sqlx
)管理数据库连接,提高性能。package mainimport ("database/sql""fmt"_ "github.com/go-sql-driver/mysql" )func main() {db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true")if err != nil {panic(err)}defer db.Close()db.SetMaxOpenConns(100)db.SetMaxIdleConns(10)rows, err := db.Query("SELECT * FROM users")if err != nil {panic(err)}defer rows.Close()for rows.Next() {var id intvar name stringif err := rows.Scan(&id, &name); err != nil {panic(err)}fmt.Println(id, name)} }
11. 微服务架构
服务拆分
- 领域驱动设计(DDD):根据业务领域将应用拆分为多个微服务。
- API网关:使用API网关(如Kong、Traefik)统一管理微服务的入口。
# Kong API Gateway configuration services:- name: user-serviceurl: http://user-service:8080routes:- name: user-routepaths: ["/users"]
服务发现和注册
- Consul:使用Consul进行服务发现和注册。
package mainimport ("context""fmt""time"consul "github.com/hashicorp/consul/api" )func main() {config := consul.DefaultConfig()client, err := consul.NewClient(config)if err != nil {panic(err)}service := &consul.AgentServiceRegistration{ID: "user-service-1",Name: "user-service",Address: "127.0.0.1",Port: 8080,Check: &consul.AgentServiceCheck{HTTP: "http://127.0.0.1:8080/health",Interval: 10 * time.Second,Timeout: 5 * time.Second,DeregisterCriticalServiceAfter: 1 * time.Minute,},}if err := client.Agent().ServiceRegister(service); err != nil {panic(err)}defer client.Agent().ServiceDeregister("user-service-1")http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("User service is running"))})http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK)})http.ListenAndServe(":8080", nil) }
12. 服务网格
Istio
- Istio:使用Istio作为服务网格,提供流量管理、安全性和可观测性。
-
安装Istio:
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.10.0 sh - cd istio-1.10.0 export PATH=$PWD/bin:$PATH istioctl install --set profile=demo -y
-
部署应用:
apiVersion: apps/v1 kind: Deployment metadata:name: myapplabels:app: myapp spec:replicas: 2selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- name: myappimage: your-docker-imageports:- containerPort: 8080 --- apiVersion: v1 kind: Service metadata:name: myapplabels:app: myapp spec:ports:- port: 80targetPort: 8080selector:app: myapp --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata:name: myapp spec:hosts:- "myapp.example.com"http:- route:- destination:host: myappport:number: 80
-
13. 最佳实践
代码质量
- 代码审查:定期进行代码审查,确保代码质量和一致性。
- 代码规范:使用
golint
、go vet
等工具检查代码风格和潜在问题。golint ./... go vet ./...
测试
-
单元测试:编写单元测试,确保每个函数的行为符合预期。
package mainimport ("testing" )func TestMyFunction(t *testing.T) {result := MyFunction()if result != expected {t.Errorf("Expected %v, got %v", expected, result)} }
-
集成测试:编写集成测试,确保各个组件协同工作。
package mainimport ("net/http""net/http/httptest""testing" )func TestIntegration(t *testing.T) {ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Hello, world!"))}))defer ts.Close()resp, err := http.Get(ts.URL)if err != nil {t.Fatal(err)}defer resp.Body.Close()if resp.StatusCode != http.StatusOK {t.Errorf("Expected status %v, got %v", http.StatusOK, resp.StatusCode)} }
结论
通过上述内容,您可以进一步提升Go语言应用的部署与运维水平。从安全性增强、性能优化,到微服务架构和服务网格,每个环节都有其独特的挑战和解决方案。希望这些内容能帮助您构建更加健壮、高效和可扩展的应用。
相关文章:
第 32 章 - Go语言 部署与运维
在Go语言的应用开发中,部署与运维是一个非常重要的环节。它不仅关系到应用能否顺利上线,还直接影响到应用的性能、安全性和可维护性。以下是根据您的需求整理的关于Go语言应用的打包和发布、容器化部署、监控和日志管理的相关内容。 1. 应用的打包和发布…...

噪杂环境离线语音通断器效果展示
介于之前的离线语音通断器模块的使用环境大部分为噪音比较小的环境中,部分客户对环境提出了更高的要求,能在噪杂、室外或者有一定的噪音的车内使用的模块开发需求被提高到了一个新的层次。最近找到某些能支持室外噪杂环境使用的芯片和模组,打…...
【django】扩展
1. Promise 1.1 对象和状态 是什么?是前端开发时js中的一个对象(包裹)。【对象】【异步请求】# 对象中有一个状态的值,status # 创建对象,不赋值,statuspendding let v1 new Promise(function(resolve, …...

逆向破解识别基础
找main函数: (使用OllyDbg软件) 方法一: 因为main函数需要三个参数,所以遇到三个参数加一个调用,那么可能是main函数。 方法二: 如果main函数中有字符串或者调用函数等一些唯一标识&#x…...
MFC 下拉框显示问题和控件自适应窗口大小
在mfc开发过程中,遇到了下拉框的两个问题,现在记录一下 1、把下拉框点开显示不全我放进去的多条文本 解决办法:把鼠标放到下拉框的倒三角去点一下,鼠标就会变成双向箭头,或者先选中一下下拉框再把鼠标移动到倒三角上去…...

Docker 的存储驱动及其优缺点
Docker 的存储驱动是容器文件系统的关键组成部分,决定了容器镜像和数据的存储方式。以下是常见的存储驱动及其优缺点: 1. OverlayFS/Overlay2 简介: Overlay 是现代 Linux 文件系统中一种高效的联合文件系统,Overlay2 是其改进版本࿰…...
单片机系统的性能指标有哪些?
单片机系统的性能指标涵盖了多个方面,这些指标共同决定了系统的整体性能。以下是单片机系统中常见的性能指标: 1. 处理器性能指标 1.1 时钟频率(Clock Frequency) 定义:处理器内核工作的时钟频率,通常以…...
波点音乐自动点击
波点音乐 import uiautomator2 as u2 import time import sys import os# 动态点击时间,打印剩余时间 def dynamic_sleep(seconds):wait_time secondsfor i in range(wait_time):print(f"Waiting... {wait_time - i} seconds remaining")sys.stdout.flu…...
HTTP 消息结构
HTTP 消息结构 1. 引言 超文本传输协议(HTTP)是互联网上应用最广泛的协议之一,它定义了客户端和服务器之间交换数据的格式和规则。HTTP消息是客户端和服务器之间通信的基本单位,包括请求消息和响应消息两种类型。本文将详细介绍HTTP消息的结构,包括其组成部分和格式。 …...

ESP32学习笔记_Bluetooth(1)——蓝牙技术与 BLE 通信机制简介
摘要(From AI): 这篇笔记详细讲解了蓝牙技术的分类、核心架构和通信流程,重点介绍了低功耗蓝牙(BLE)的协议栈、角色划分及连接机制,结合拓扑示例清晰阐述了蓝牙网络配置和操作过程 前言:本文档是本人在《ESP32-C3 物联…...

C0034.在Ubuntu中安装的Qt路径
Qt安装路径查询 在终端输入qmake -v如上中/usr/lib/x86_64-linux-gnu就是Qt的安装目录;...

jdbc学习——SQL注入
SQL注入介绍 SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。 用户登录的本质:执行下面的sql语句 select * from tb_user where username zhangsan and password 123; 发生sql注入的本质 解决SQL注入的方…...

JavaEE-线程安全专题
文章目录 线程安全概述线程安全引入线程不安全原因概述 线程是随机调度的 线程安全概述 线程安全引入 线程安全问题是整个多线程专题的最核心也是最重要的章节, 如果不理解线程的安全, 是无法写出正确的多线程的代码的, 我们之前所写的代码都是在单一的线程环境之下写出的 “…...

Android 设备使用 Wireshark 工具进行网络抓包
背景 电脑和手机连接同一网络,想使用wireshark抓包工具抓取Android手机网络日志,有以下两种连接方法: Wi-Fi 网络抓包。USB 网络共享抓包。需要USB 数据线将手机连接到电脑,并在开发者模式中启用 USB 网络共享。 查看设备连接信…...

物联网无线局域网WiFi开发(一):WiFi智能家居解决方案
一、WiFi智能家居硬件设计 (一)WiFi智能家居硬件方案 (二)硬件选型方案 二、WiFi开发环境搭建 (一)开发环境搭建 虚拟机lubuntu VirtualBox下载地址:https://www.virtualbox.org/wiki/Downl…...

GMAN解读(论文+代码)
一、注意力机制 注意力机制与传统的卷积神经网络不同的是,前者擅长捕获全局依赖和长程关系,权重会动态调整。而后者对于所有特征都使用同一个卷积核。关于更多注意力机制内容,详见: 注意力机制、自注意力机制、多头注意力机制、通…...
速盾:ddos防御手段哪种比较好?高防cdn怎么样?
DDoS(分布式拒绝服务)攻击是一种威胁网络安全的常见攻击手段。为了保护网站和服务器免受DDoS攻击的影响,许多安全专家和公司开发了各种防御手段。在这篇文章中,我们将重点讨论一种常见的DDoS防御手段——高防CDN(内容分…...

Spring:AOP切入点表达式
对于AOP中切入点表达式,我们总共会学习三个内容,分别是语法格式、通配符和书写技巧。 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法切入点表达式:要进行增强的方法的描述方式 对于切入点的描述,我们其实是有两中方式的&a…...

《文件操作》
一 . 文本文件和二进制文件 根据数据的组织形式,数据文件被分为了二进制文件和文本文件 数据在内存中是以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件。 如果要求在外存上以ASCII 码的形式存储,则需要再存…...
python特殊字符序列
字符 描述 \A 只匹配字符串的开始 \b 匹配一个单词边界 \B 匹配一个单词的非边界 \d 匹配任意十进制数字字符,等价于r[0-9] \D 匹配任意非十进制数字字符,等价于r[^0-9]’ \s 匹配任意空格字符(空格符、tab制表符、换…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...