使用go语言来完成复杂excel表的导出导入

使用go语言来完成复杂excel表的导出导入(一)

1.复杂表的导入

   开发需求是需要在功能页面上开发一个excel文件的导入导出功能,这里的复杂指定是表内数据夹杂着一对多,多对一的形式,如下图所示。数据杂乱而且对应不统一。

在这里插入图片描述
首先我们先设计一个页面处理器,也就是一个前端页面用来上传要处理的excel文件,注意这里应该是可以处理多个Sheet,代码如下图。

func UploadPage(w http.ResponseWriter, r *http.Request) {if r.Method == http.MethodGet {// 渲染上传页面tmpl := template.Must(template.ParseFiles(filepath.Join("template", "index.html")))err := tmpl.Execute(w, nil)if err != nil {http.Error(w, fmt.Sprintf("Failed to render template: %v", err), http.StatusInternalServerError)}}
}

这段代码的主要作用就是用户在前端点击按钮之后,接收一个excel文件。接收文件之后,就进行处理。
首先就是先从上传的excel文件中获取所有的Sheet,然后再进行数据库的连接,
根据表的特性设计代码提取每一列的数据插入到数据库中,在这里为了确保插入时表的完整性需要使用数据库的事务,我还在这里添加了检查数据是否重复的报错功能,来确保数据行列中不会出现重复数据。代码如下,

func ImportData(w http.ResponseWriter, r *http.Request) {if r.Method != http.MethodPost {http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)return}// 从前端上传文件file, _, err := r.FormFile("excelFile")if err != nil {http.Error(w, fmt.Sprintf("Failed to get form file: %v", err), http.StatusInternalServerError)return}defer file.Close()// 打开 Excel 文件f, err := excelize.OpenReader(file)if err != nil {http.Error(w, fmt.Sprintf("Failed to open Excel file: %v", err), http.StatusInternalServerError)return}// 获取所有工作表名称sheetNames := f.GetSheetMap()if len(sheetNames) == 0 {http.Error(w, "No sheets found in Excel file", http.StatusInternalServerError)return}// 连接 MySQL 数据库dsn := "root:root@tcp(127.0.0.1:3306)/database_4"db, err := sql.Open("mysql", dsn)if err != nil {http.Error(w, fmt.Sprintf("Failed to connect to database: %v", err), http.StatusInternalServerError)return}defer db.Close()// 确保连接有效if err := db.Ping(); err != nil {http.Error(w, fmt.Sprintf("Failed to ping database: %v", err), http.StatusInternalServerError)return}for _, sheetName := range sheetNames {// 开始事务tx, err := db.Begin()if err != nil {http.Error(w, fmt.Sprintf("Failed to begin transaction: %v", err), http.StatusInternalServerError)return}// 读取工作表rows := f.GetRows(sheetName)if len(rows) == 0 {http.Error(w, fmt.Sprintf("No rows found in sheet: %v", sheetName), http.StatusInternalServerError)tx.Rollback()continue}// 使用 map 分别检查 SubSpanNumber 和 BeamNumber 的重复subSpanNumberSet := make(map[string]int)beamNumberSet := make(map[string]int)// 变量来跟踪当前的 spanNumber 和 beamNumbervar currentSpanNumber stringvar currentBeamNumber string// 跳过前两行for i, row := range rows[2:] {// 跳过空行if len(row) == 0 {continue}// 检查行的长度是否足够goif len(row) < 17 {log.Printf("Row %d does not have enough columns: %v", i+2, row)continue}// 提取每一列的数据id := row[0]bridgeName := row[1]centerPileNumber := row[2]beamType := row[3]subSpanNumber := row[4]spanNumber := row[5]beamNumber := row[6]designBeamLength, _ := strconv.ParseFloat(row[7], 64)designBeamHeight, _ := strconv.ParseFloat(row[8], 64)topPlateWidth, _ := strconv.ParseFloat(row[9], 64)bottomPlateWidth, _ := strconv.ParseFloat(row[10], 64)webThickness, _ := strconv.ParseFloat(row[11], 64)flangeThickness, _ := strconv.ParseFloat(row[12], 64)camber := row[13]expansionJointType := row[14]concreteStrength := row[15]concreteUsage, _ := strconv.ParseFloat(row[16], 64)// 如果 spanNumber 变化,重置 subSpanNumberSetif spanNumber != currentSpanNumber {subSpanNumberSet = make(map[string]int)currentSpanNumber = spanNumber}// 如果 beamNumber 变化,重置 beamNumberSetif beamNumber != currentBeamNumber {beamNumberSet = make(map[string]int)currentBeamNumber = beamNumber}// 跳过 spanNumber 为空格的检查,但仍保留其他数据插入if spanNumber != "" {// 检查 spanNumber 是否重复if _, found := subSpanNumberSet[spanNumber]; found {http.Error(w, fmt.Sprintf("在 %v 表 联跨编号列 第%d行出现数据重复: %v", sheetName, i+3, subSpanNumber), http.StatusInternalServerError)tx.Rollback()return}subSpanNumberSet[spanNumber] = i + 3 // 保存行号以便于调试}// 检查 BeamNumber 是否重复if _, found := beamNumberSet[beamNumber]; found {http.Error(w, fmt.Sprintf("在 %v 表 梁体编号列 第%d行出现数据重复: %v", sheetName, i+3, beamNumber), http.StatusInternalServerError)tx.Rollback()return}beamNumberSet[beamNumber] = i + 3 // 保存行号以便于调试// 插入数据到数据库query := `INSERT INTO bridge_data (id, bridge_name, center_pile_number, beam_type, sub_span_number, span_number, beam_number,design_beam_length, design_beam_height, top_plate_width, bottom_plate_width, web_thickness,flange_thickness, camber, expansion_joint_type, concrete_strength, concrete_usage, filename) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`_, err = tx.Exec(query, id, bridgeName, centerPileNumber, beamType, subSpanNumber, spanNumber, beamNumber,designBeamLength, designBeamHeight, topPlateWidth, bottomPlateWidth, webThickness,flangeThickness, camber, expansionJointType, concreteStrength, concreteUsage, sheetName)if err != nil {log.Printf("Failed to insert row %d: %v", i+3, err)http.Error(w, fmt.Sprintf("Failed to insert row %d: %v", i+3, err), http.StatusInternalServerError)tx.Rollback()return}}// 插入成功后,添加标志行currentTime := time.Now().Format(time.RFC3339)fileName := sheetNamestatus := "success"markQuery := `INSERT INTO process_mark (timestamp, filename, status) VALUES (?, ?, ?)`_, err = tx.Exec(markQuery, currentTime, fileName, status)if err != nil {log.Printf("Failed to insert process mark for sheet %s: %v", sheetName, err)http.Error(w, fmt.Sprintf("Failed to insert process mark for sheet %s: %v", sheetName, err), http.StatusInternalServerError)tx.Rollback()return}// 提交事务if err := tx.Commit(); err != nil {http.Error(w, fmt.Sprintf("Failed to commit transaction: %v", err), http.StatusInternalServerError)return}}fmt.Fprintln(w, "excel数据导入成功")
}

处理完成之后的效果就是(部分效果图)
在这里插入图片描述
**

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/35442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国90米分辨率可蚀性因子K数据

土壤可蚀性因子&#xff08;K&#xff09;数据&#xff0c;基于多种土壤属性数据计算&#xff0c;所用数据包括土壤黏粒含量&#xff08;%&#xff09;、粉粒含量&#xff08;%&#xff09;、砂粒含量&#xff08;%&#xff09;、土壤有机碳含量&#xff08;g/kg&#xff09;、…

[DALL·E 2] Hierarchical Text-Conditional Image Generation with CLIP Latents

1、目的 CLIP DDPM进行text-to-image生成 2、数据 (x, y)&#xff0c;x为图像&#xff0c;y为相应的captions&#xff1b;设定和为CLIP的image和text embeddings 3、方法 1&#xff09;CLIP 学习图像和文本的embedding&#xff1b;在训练prior和decoder时固定该部分参数 2&a…

开放式耳机什么牌子好一点?亲检的几款开放式蓝牙耳机推荐

不入耳的开放式耳机更好一些&#xff0c;不入耳式耳机佩戴更舒适&#xff0c;适合长时间佩戴&#xff0c;不会引起强烈的压迫感或耳部不适。不入耳式的设计不需要接触耳朵&#xff0c;比入耳式耳机更加卫生且不挑耳型&#xff0c;因此备受运动爱好者和音乐爱好者的喜爱。这里给…

周转车配料拣货方案

根据周转车安装的电子标签&#xff0c;被悬挂的扫码器扫到墨水屏显示的二维码&#xff0c;投屏发送配料拣货的数据。 方便快捷分拣物料

20240625(周二)欧美股市总结:标普纳指止步三日连跌,英伟达反弹6.8%,谷歌微软新高,油价跌1%

美联储理事鲍曼鹰派发声&#xff0c;若通胀没有持续改善将支持加息&#xff0c;加拿大5月CPI重新加速&#xff0c;对加拿大央行7月降息构成阻碍。美股走势分化&#xff0c;道指收跌近300点且六日里首跌&#xff0c;英伟达市值重上3.10万亿美元&#xff0c;芯片股指显著反弹1.8%…

想要用tween实现相机的移动,three.js渲染的canvas画布上相机位置一点没动,如何解决??

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

第1章 物联网模式简介---独特要求和体系结构原则

物联网用例的独特要求 物联网用例往往在功耗、带宽、分析等方面具有非常独特的要求。此外&#xff0c;物联网实施的固有复杂性&#xff08;一端的现场设备在计算上受到挑战&#xff0c;另一端的云容量几乎无限&#xff09;迫使架构师做出艰难的架构决策和实施选择。可用实现技…

【自动调参】年化29.3%,最大回撤18.5%​:lightGBM的参数优化

原创文章第570篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 研报复现继续&#xff1a;【研报复现】年化27.1%&#xff0c;人工智能多因子大类资产配置策略之benchmark 昨天调了一版参数&#xff0c;主要是lambda_l1, lambda_l2&#xff0c;防…

Vmvare12安装CentOS7.6

Vmvare12安装 注意事项 安装完成以后有这两个虚拟网卡。 CentOS官网镜像地址 https://www.centos.org/download/mirrors/Vmvare安装CentOS7.6 创建虚拟机 安装CentOS7.6 选择桌面版 磁盘分区 上述是确认使用自动分区。 设置密码 设置license information 欢迎页面 CentOS7…

宝兰德受邀出席华为开发者大会2024,携手共绘基础软件新篇章

6月21日-23日&#xff0c;华为开发者大会&#xff08;HDC 2024&#xff09;在东莞松山湖举行&#xff0c;作为全球开发者的年度盛会&#xff0c;本次大会汇聚了众多业界精英与前沿技术。华为分享了HarmonyOS、盘古大模型、昇腾AI云服务、GaussDB数据库、自研仓颉编程语言等最新…

【IM即时通信 功能介绍】客户端用户在线状态订阅

本文档旨在介绍客户端用户在线状态订阅功能&#xff0c;该功能允许开发者通过 SDK 接口实时监控和接收指定用户的在线或离线状态变更通知。这一功能对于需要实时交流、状态同步或用户活动监控的应用场景至关重要。 功能特点 实时状态通知 跨平台通知&#xff1a;订阅成功后&…

使用 MediaPipe 实现实时手部追踪和手势识别 | Rerun展示

点击下方卡片&#xff0c;关注“小白玩转Python”公众号 在本文中&#xff0c;我将展示一个使用 MediaPipe Python 和 Rerun SDK 进行手部追踪和手势识别的示例。如果您有兴趣深入了解并扩展您的知识&#xff0c;我将指导您如何安装 MediaPipe Python 和 Rerun SDK 来进行手部追…

Linux部署SVN

一.下载与安装 &#xff08;1&#xff09;yum安装 yum install subversion &#xff08;2&#xff09;源文件编译安装 ①下载svn源文件 subversion-xxx.tar.gz&#xff08;subversion 源文件&#xff09; subversion-deps-xxx.tar.gz&#xff08;subversion依赖文件&…

项目四 OpenStack身份管理

任务一 理解身份服务 1.1 •Keystone的基本概念 • 认证 &#xff08; Authentication &#xff09; —— 确认用户身份的过程 &#xff0c;又称身份验证 。 • 凭证 &#xff08; Credentials &#xff09; —— 又 称凭据&#xff0c;是用于 确认用户身份的数据 。 • 令牌…

短视频最佳时长:成都柏煜文化传媒有限公司

探索时间与内容之间的完美平衡 成都柏煜文化传媒有限公司 在数字媒体日益繁荣的今天&#xff0c;短视频已成为人们获取信息、娱乐休闲的重要形式。然而&#xff0c;关于短视频的最佳时长&#xff0c;一直是一个备受争议的话题。本文将探讨短视频时长的各种考量因素&#xff0…

MySQL报错Duplicate entry ‘0‘ for key ‘PRIMARY‘

报错现场 现象解释 因为你在插入时没有给 Customer.Id 赋值&#xff0c;MySQL 会倾向于赋值为 NULL。但是主键不能为 NULL&#xff0c;所以 MySQL 帮了你一个忙&#xff0c;将值转换为 0。这样&#xff0c;在第二次插入时就会出现冲突&#xff08;如果已经有一条记录为 0&…

微服务——服务治理

目录 1 什么是服务治理&#xff1f;2 为什么需要服务治理&#xff1f;3 服务治理的关键点3.1 服务注册与发现3.2 负载均衡3.3 容错与熔断3.4 服务监控与告警3.5 服务配置管理 4 示例说明5 总结 1 什么是服务治理&#xff1f; 简单来说&#xff0c;服务治理就是对微服务架构中的…

iptables(11)target(SNAT、DNAT、MASQUERADE、REDIRECT)

简介 前面我们已经介绍了ACCEPT、DROP、REJECT、LOG,这篇文章我们介绍SNAT、DNAT、MASQUERADE、REDIRECT,这几个参数的定义我们在上篇文章中都有介绍,我这里再列出回顾一下 DNAT(目标地址转换)和 SNAT(源地址转换) 原理:修改数据包的源或目标 IP 地址。通常用于 NAT(…

小迪安全v2023笔记 1-18

小迪安全v2023笔记 1-18 棱角社区 文章目录 1. 基础入门1. 正向shell与反向shell2. web应用3. 抓包&#xff0c;封包&#xff0c;协议&#xff0c;app&#xff0c;小程序&#xff0c;pc应用&#xff0c;web应用 2. 信息打点1. 常见信息获取2. 文件泄露3. 常见阻碍4. CDN绕过&a…

Stable Diffusion——SDXL 1.0原理解析

1. SDXL 1.0 简介 SDXL 1.0是Stability AI推出的新基础模型&#xff0c;作为Stable Diffusion的大幅改进版本&#xff0c;它是一个用于文本到图像合成的潜在扩散模型&#xff08;LDM&#xff09;。作为Stable Diffusion的最新进化&#xff0c;它正在超越其前身&#xff0c;并与…