将Excel文件的两个表格经过验证后分别读取到Excel表和数据库

news2024/11/16 5:42:44

 遍历读取数据,建两个表,负责人和业主表,业主表有外键,负责人表添加手机号正则验证负责人和业主的正确数据添加到数据库,错误的添加到Excel表负责人错误信息,业主错误信息


package excel;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class ExcelDataProcessorDemo2 {

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        try {
            // 读取并处理所有表的数据
            Map<String, List<Map<String, String>>> sheetDataMap = readAndProcessAllSheets("D:\\javaIO\\demo.xlsx");

            // 获取并打印所有表的数据
            processAndPrintSheetData(sheetDataMap);

            // 验证数据
            //有效负责人
            List<Map<String, String>> validResponsibleData = new ArrayList<>();
            //无效负责人
            List<Map<String, String>> invalidResponsibleData = new ArrayList<>();
            //有效业主
            List<Map<String, String>> validOwnerData = new ArrayList<>();
            //无效业主
            List<Map<String, String>> invalidOwnerData = new ArrayList<>();


            validateData(sheetDataMap.get("负责人"), validResponsibleData, invalidResponsibleData,validResponsibleData,true);

            //数据 有效 无效 如果这个地方有效负责人为空了,还需要进行业主信息判断么? 肯定四不需要啊 所以进行非空判断
            if (CollectionUtils.isNotEmpty(validResponsibleData)){
                validateData(sheetDataMap.get("业主信息"), validOwnerData, invalidOwnerData,validResponsibleData,false);

            } else {
                //负责人为空了 业主信息应该时全部为错误信息啊 找不到负责人
                ///。。。。。。。。。。。。。
                log.error("找不到负责人");
            }

            // 插入数据库
            insertIntoDatabase(validResponsibleData, validOwnerData);

            // 写入错误数据到新的Excel文件
            writeInvalidDataToExcel(invalidResponsibleData, invalidOwnerData);

            long endTime = System.currentTimeMillis();
            log.info("Total time taken: {} ms", (endTime - startTime));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取并处理所有表的数据
     *
     * @param filePath Excel文件路径
     * @return 包含所有表数据的Map
     */
    public static Map<String, List<Map<String, String>>> readAndProcessAllSheets(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {

            Map<String, List<Map<String, String>>> sheetDataMap = new HashMap<>();
            //遍历所有表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                //获取表对象
                Sheet sheet = workbook.getSheetAt(i);
                //获取表名
                String sheetName = sheet.getSheetName();
                //读取数据
                List<Map<String, String>> sheetData = readSheet(sheet);
                //将数据放入Map中
                sheetDataMap.put(sheetName, sheetData);
            }
            //最后返回map集合
            return sheetDataMap;
        } catch (IOException e) {
            log.error("Error reading sheets: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 读取单个表的数据
     * @param sheet 表对象
     * @return 包含表数据的List
     */
    public static List<Map<String, String>> readSheet(Sheet sheet) {
        List<Map<String, String>> data = new ArrayList<>();
        // 获取表头行
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            throw new IllegalStateException("Header row is null");
        }
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue; // 跳过空行
            }
            Map<String, String> rowMap = new HashMap<>();
            // 增强for得到每一列的值
            for (Cell cell : row) {
                if (cell == null) {
                    continue; // 跳过空单元格
                }
                // 获取表头
                Cell headerCell = headerRow.getCell(cell.getColumnIndex());
                if (headerCell == null) {
                    continue; // 跳过不存在的表头
                }
                String columnName = headerCell.getStringCellValue();
                String cellValue = getCellValue(cell);
                rowMap.put(columnName, cellValue);
            }

            data.add(rowMap);
        }

        return data;
    }

    /**
     * 打印所有表的数据
     *
     * @param sheetDataMap 包含所有表数据的Map
     */
    public static void processAndPrintSheetData(Map<String, List<Map<String, String>>> sheetDataMap) {
        for (Map.Entry<String, List<Map<String, String>>> entry : sheetDataMap.entrySet()) {
            String sheetName = entry.getKey();
            List<Map<String, String>> sheetData = entry.getValue();
            log.info("{} 表大小: {}", sheetName, sheetData.size());
            sheetData.forEach(row -> log.info("Row: {}", row));
        }
    }

    /**
     * 获取单元格的值
     *
     * @param cell 单元格对象
     * @return 单元格的值
     */
    private static String getCellValue(Cell cell) {
        if (cell == null) {
            return ""; // 或者返回其他默认值
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    /**
     * 验证数据
     *
     * @param sheetData 表数据
     * @param validData 有效数据列表
     * @param invalidData 无效数据列表
     * @param validResponsibleData 有效负责人数据列表
     */
    private static void validateData(List<Map<String, String>> sheetData, List<Map<String, String>> validData,
                                     List<Map<String, String>> invalidData, List<Map<String, String>> validResponsibleData,
                                     boolean isResponsibleData) {
        // 遍历表数据,如果是有效数据,则添加到有效数据列表中,否则添加到无效数据列表中
        for (Map<String, String> row : sheetData) {
            if (isResponsibleData) {
                // 处理负责人数据
                if (isValidResponsiblePerson(row)) {
                    validData.add(row);
                } else {
                    invalidData.add(row);
                }
            } else {
                // 处理业主数据
                if (CollectionUtils.isEmpty(validResponsibleData)) {
                    // 如果没有有效负责人数据,直接判断为无效
                    invalidData.add(row);
                } else {
                    // 使用有效负责人信息集合和遍历中的业主信息进行判断
                    if (isValidOwner(validResponsibleData, row)) {
                        validData.add(row);
                    } else {
                        invalidData.add(row);
                    }
                }
            }
        }
    }

    /**
     * 验证负责人信息是否有效
     *
     * @param row 单行数据
     * @return 是否有效
     */
    private static boolean isValidResponsiblePerson(Map<String, String> row) {
        // 验证手机号
        String phoneNumber = row.get("联系方式");
        if (!isValidPhoneNumber(phoneNumber)) {
            return false;
        }

//        // 验证邮箱
//        String email = row.get("邮箱");
//        if (!isValidEmail(email)) {
//            return false;
//        }
//
//        // 验证时间
//        String time = row.get("时间");
//        if (!isValidTime(time)) {
//            return false;
//        }

        return true;
    }

    /**
     * 验证业主信息是否有效
     *
     * @param row 单行数据
     * @return 是否有效
     */
    private static boolean isValidOwner(  List<Map<String, String>> validResponsibleData,Map<String, String> row) {
        for (Map<String, String> firstSheetRow : validResponsibleData) {
            //比较当前行与第一张表的每一行,如果匹配,则将当前行的负责人信息添加到 row 中,并返回 true。
            if (firstSheetRow.get("项目").equals(row.get("项目")) &&
                    firstSheetRow.get("楼栋").equals(row.get("楼栋")) &&
                    firstSheetRow.get("单元").equals(row.get("单元"))) {
                row.put("负责人", firstSheetRow.get("负责人"));
                return true;
            }
        }
        return false;
    }

    /**
     * 验证手机号是否有效
     *
     * @param phoneNumber 手机号
     * @return 是否有效
     */
    private static boolean isValidPhoneNumber(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.isEmpty()) {
            return false;
        }
        //以1开头,第二位为3-9,后面是9位数
        String phoneRegex = "^1[3-9]\\d{9}$";
        // 使用正则表达式验证
        return phoneNumber.matches(phoneRegex);
    }

    /**
     * 验证邮箱是否有效
     *
     * @param email 邮箱
     * @return 是否有效
     */
    private static boolean isValidEmail(String email) {
        if (email == null || email.isEmpty()) {
            return false;
        }
        //[A-Za-z0-9+_.-]+ 匹配一个或多个字母、数字、加号、点号、下划线或减号。
        // @ 匹配一个字符,后面是域名,域名可以是多个字母、数字、点号或减号。
        String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
        return email.matches(emailRegex);
    }

    /**
     * 验证时间格式是否有效
     *
     * @param time 时间
     * @return 是否有效
     */
    private static boolean isValidTime(String time) {
        if (time == null || time.isEmpty()) {
            return false;
        }
        // yyyy-MM-dd HH:mm:ss
        String timeRegex = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$";
        return time.matches(timeRegex);
    }


    /**
     * 将有效数据插入数据库
     * @param validResponsibleData 有效的负责人数据
     * @param validOwnerData 有效的业主数据
     */
    private static void insertIntoDatabase(List<Map<String, String>> validResponsibleData, List<Map<String, String>> validOwnerData) {
        String url = "jdbc:mysql://localhost:3306/excel?serverTimezone=UTC";
        String user = "root";
        String password = "root";
        // 加载驱动
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            insertResponsibleData(conn, validResponsibleData);
            insertOwnerData(conn,validOwnerData);
        } catch (SQLException e) {
            log.error("Error inserting data into database: {}", e.getMessage());
        }
    }

    /**
     * 插入负责人数据到数据库
     *
     * @param conn 数据库连接
     * @param validResponsibleData 有效的负责人数据
     * @throws SQLException SQL异常
     */
    private static void insertResponsibleData(Connection conn, List<Map<String, String>> validResponsibleData) throws SQLException {
        String sql = "INSERT INTO responsible (responsible_name, phone, email, create_time) VALUES (?, ?, ?, ?)";
        // 使用 PreparedStatement 执行批量插入
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            for (Map<String, String> row : validResponsibleData) {
                pstmt.setString(1, row.get("负责人"));
                pstmt.setString(2, row.get("联系方式"));
                pstmt.setString(3, row.get("邮箱"));
                pstmt.setString(4, row.get("时间"));
                //将当前设置的参数添加到批处理命令中,添加到批处理队列中,以便后续一次性执行所有批处理命令。
                pstmt.addBatch();
            }
            pstmt.executeBatch();
        }
    }

    /**
     * 插入业主数据到数据库
     *
     * @param conn 数据库连接
     * @param validOwnerData 有效的业主数据
     * @throws SQLException SQL异常
     */
    private static void insertOwnerData(Connection conn, List<Map<String, String>> validOwnerData) throws SQLException {
        String sql = "INSERT INTO owner (owner_name,project, building, unit,floor,room_number,owner_id,responsible_id) VALUES (?, ?, ?, ?,?,?,?,?)";
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            for (Map<String, String> row : validOwnerData) {
                pstmt.setString(1, row.get("业主姓名"));
                pstmt.setString(2, row.get("项目"));
                pstmt.setString(3, row.get("楼栋"));
                pstmt.setString(4, row.get("单元"));
                pstmt.setString(5, row.get("楼层"));
                pstmt.setString(6, row.get("房号"));
                pstmt.setString(7,row.get("编号"));
                // 获取或插入负责人的 ID 那个地方加过之后 这个就有值了
                int responsibleId = getOrCreateResponsibleId(conn, row.get("负责人"));
                //如果这个地方返回值为0了,代表你业主验证的时候没有验证对

                pstmt.setInt(8, responsibleId);
                pstmt.addBatch();
            }
            pstmt.executeBatch();
        }
    }
    private static int getOrCreateResponsibleId(Connection conn, String responsibleName) throws SQLException {
        //那个地方有值 这个地方就一定会有值 不会返回0
        String selectSql = "SELECT responsible_id FROM responsible WHERE responsible_name = ?";
        try (PreparedStatement selectStmt = conn.prepareStatement(selectSql)) {
            selectStmt.setString(1, responsibleName);
            try (ResultSet rs = selectStmt.executeQuery()) {
                if (rs.next()) {
                    return rs.getInt("responsible_id");
                }
            }
        }
        return 0;
    }
    /**
     * 将无效数据写入新的Excel文件
     *
     * @param invalidResponsibleData 无效的负责人数据
     * @param invalidOwnerData 无效的业主数据
     */
    private static void writeInvalidDataToExcel(List<Map<String, String>> invalidResponsibleData, List<Map<String, String>> invalidOwnerData) {
        try (Workbook workbook = new XSSFWorkbook()) {
            // 创建负责人表
            Sheet responsibleSheet = workbook.createSheet("无效负责人数据");
            createSheetWithHeader(responsibleSheet, invalidResponsibleData);

            // 创建业主表
            Sheet ownerSheet = workbook.createSheet("无效业主数据");
            createSheetWithHeader(ownerSheet, invalidOwnerData);

            try (FileOutputStream fos = new FileOutputStream("D:\\javaIO\\invalidData.xlsx")) {
                workbook.write(fos);
            } catch (IOException e) {
                e.printStackTrace();
                System.err.println("写入文件时发生错误: " + e.getMessage());
            }
        } catch (IOException e) {
            log.error("Error writing results to Excel: {}", e.getMessage());
        }
    }

    /**
     * 创建带有表头的表
     *
     * @param sheet 表对象
     * @param data 表数据
     */
    private static void createSheetWithHeader(Sheet sheet, List<Map<String, String>> data) {
        if (data.isEmpty()) {
            return;
        }

        Row headerRow = sheet.createRow(0);
        int columnIndex = 0;
        for (String key : data.get(0).keySet()) {
            headerRow.createCell(columnIndex++).setCellValue(key);
        }

        int rowIndex = 1;
        for (Map<String, String> row : data) {
            Row dataRow = sheet.createRow(rowIndex++);
            columnIndex = 0;
            for (String key : row.keySet()) {
                dataRow.createCell(columnIndex++).setCellValue(row.get(key));
            }
        }
    }
}

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

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

相关文章

Java篇String类的常见方法

目录 一. String类的概念 1.1 String类的特性 二. 字符串的构造方式 三. 常用方法 3.1 字符串查找 3.2 字符串转换 3.3 字符串比较 3.3.1 equals( )方法 3.3.2 compare To( )方法 3.3.3 compare ToIgnoreCase( )方法 3.4 字符串替换 3.4.1 replace( )方法 3.4.2 r…

「QT」文件类 之 QDataStream 数据流类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定制…

MySQL45讲 第二十三讲 是怎么保证数据不丢的?

文章目录 MySQL45讲 第二十三讲 是怎么保证数据不丢的&#xff1f;一、binlog 写入机制&#xff08;一&#xff09;事务执行与 binlog cache&#xff08;二&#xff09;事务提交与 binlog 文件写入 二、redo log 写入机制&#xff08;一&#xff09;事务执行与 redo log buffer…

pgaudit插件-pgslq

使用pgaudit插件 一.介绍 postgresql可以通过log_statementall 提供日志审计&#xff0c;但是无法详细的提供日志信息&#xff0c;使用ogaudit能够提供详细的会话和对象审计日志&#xff0c;是PG的一个扩展插件 注意&#xff1a;pgAudit可能会生成大量日志。请谨慎确定要在您…

系统掌握大语言模型提示词 - 从理论到实践

以下是我目前的一些主要个人标签&#xff1a; 6 年多头部大厂软件开发经验&#xff1b;1 年多 AI 业务应用经验&#xff0c;拥有丰富的业务提示词调优经验和模型微调经验。信仰 AGI&#xff0c;已经将 AI 通过自定义 Chatbot /搭建 Agent 融合到我的工作流中。头部大厂技术大学…

Vue 项目打包后环境变量丢失问题(清除缓存),区分.env和.env.*文件

Vue 项目打包后环境变量丢失问题&#xff08;清除缓存&#xff09;&#xff0c;区分.env和.env.*文件 问题背景 今天在导报项目的时候遇到一个问题问题&#xff1a;在开发环境中一切正常&#xff0c;但在打包后的生产环境中&#xff0c;某些环境变量&#xff08;如 VUE_APP_B…

群控系统服务端开发模式-应用开发-前端菜单功能开发

今天优先开发菜单及角色&#xff0c;明天将开发岗位配置、级别配置等功能。具体看下图 而前端的路由不需要手动添加&#xff0c;是依据数据库里面存储的路径。 一、添加视图 在根目录下src文件夹下views文件夹下permission文件夹下menu文件夹下&#xff0c;新建index.vue&…

数据结构Python版

2.3.3 双链表 双链表和链表一样&#xff0c;只不过每个节点有两个链接——一个指向后一个节点&#xff0c;一个指向前一个节点。此外&#xff0c;除了第一个节点&#xff0c;双链表还需要记录最后一个节点。 每个结点为DLinkNode类对象&#xff0c;包括存储元素的列表data、…

【HarmonyOS学习日志(8)】UIAbility,HAP,AbilityStage组件及其生命周期

基本概念 UIAbility组件是一种包含UI的应用组件&#xff0c;主要用于和用户交互。 在项目创建时&#xff0c;系统默认生成的EntryAbility类继承了UIAbility类。 ExtensionAbility组件&#xff1a;是基于特定场景&#xff08;例如服务卡片、输入法等&#xff09;提供的应用组件…

【Linux】多线程(中)

目录 一、线程互斥 1.1 互斥概念 1.2 互斥量mutex 1.3 互斥量相关API &#xff08;1&#xff09;初始化互斥量 &#xff08;2&#xff09;销毁互斥量 &#xff08;3&#xff09;互斥量加锁和解锁 1.4 互斥量原理 1.5 重入和线程安全 二、死锁 2.1 概念 2.2 造成死锁…

【数字图像处理+MATLAB】基于 Sobel 算子计算图像梯度并进行边缘增强:使用 imgradientxy 函数

引言 在图像处理中&#xff0c;边缘通常是图像中像素强度变化最大的地方&#xff0c;这种变化可以通过计算图像的梯度来量化。梯度是一个向量&#xff0c;它的方向指向像素强度增加最快的方向&#xff0c;它的大小&#xff08;或者说幅度&#xff09;表示像素强度增加的速度。…

Nuxt.js 应用中的 schema:beforeWrite 事件钩子详解

title: Nuxt.js 应用中的 schema:beforeWrite 事件钩子详解 date: 2024/11/14 updated: 2024/11/14 author: cmdragon excerpt: schema:beforeWrite 钩子是 Vite 提供的一个功能强大的生命周期钩子,允许开发者在 JSON Schema 被写入之前执行自定义操作。利用这个钩子,您可以…

k8s服务内容滚动升级以及常用命令介绍

查看K8S集群所有的节点信息 kubectl get nodes 删除K8S集群中某个特定节点 kubectl delete nodes/10.0.0.123 获取K8S集群命名空间 kubectl get namespace 获取K8S所有命名空间的那些部署 kubectl get deployment --all-namespaces 创建命名空间 web界面上看到的效果,但是…

MinIo在Ubantu和Java中的整合

1.MinIo在Ubantu中的部署 首先准备好一台已经安装好Ubantu系统的服务器 MinIO是一个开源的对象存储服务器&#xff0c;兼容Amazon S3&#xff0c;性能卓越&#xff0c;适合存储非结构化数据&#xff0c;例如照片、视频、日志文件、备份和容器镜像等。 1&#xff1a;更新系统…

设计模式-参考的雷丰阳老师直播课

一般开发中使用的模式为模版模式策略模式组合&#xff0c;模版用来定义骨架&#xff0c;策略用来实现细节。 模版模式 策略模式 与模版模式特别像&#xff0c;模版模式会定义好步骤定义好框架&#xff0c;策略模式定义小细节 入口类 使用模版模式策略模式开发支付 以上使用…

【LeetCode】【算法】53. 最大子数组和

LeetCode 53. 最大子数组和 题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。子数组是数组中的一个连续部分。 思路 思路&#xff1a;动态规划秒了 具体递推式如…

供应SW6301V单C口多协议升降压移动电源IC

1. 概述 SW6301V 是一款高集成度的单 C 口多协议升降压移动电源 SOC。集成双向升降压控制器&#xff0c;支持 2~6 节 电池串联&#xff0c;提供 100W 功 率 输 入 输 出 &#xff1b; 支 持 C 口 快 充 输入输出 &#xff1b; 支 持UFCS/PPS/PD/SVOOC/VOOC/SCP/FCP/QC/AFC/BC…

C++常用的新特性-->day06

时间间隔duration duration表示一段时间间隔&#xff0c;用来记录时间长度&#xff0c;可以表示几秒、几分钟、几个小时的时间间隔。duration的原型如下 // 定义于头文件 <chrono> template<class Rep,class Period std::ratio<1> > class duration;Rep&…

Cyberchef配合Wireshark提取并解析TCP/FTP流量数据包中的文件

前一篇文章中讲述了如何使用cyberchef提取HTTP/TLS数据包中的文件,详见《Cyberchef配合Wireshark提取并解析HTTP/TLS流量数据包中的文件》,链接这里,本文讲述下如何使用cyberchef提取FTP/TCP数据包中的文件。 FTP 是最为常见的文件传输协议,和HTTP协议不同的是FTP协议传输…

性能面向下一代PCIe Gen 5,G991B322HR、G99L12312HR 安费诺ExtremePort™ Swift连接器支持内部I/O应用

前言 为了在网络设备和服务器上提供更高速度和更小尺寸的解决方案&#xff0c;Amphenol开发了ExtremePort™ Swift连接器&#xff0c;适用于PCIe Gen5 NRZ 32GT/s、UPI 2.0 24GT/s、24Gb/s SAS信号。 G991B322HR G9912312HR G9912322HR G9914312HR G991B312HR G991C312HR G99…