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

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

java 复制代码
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));
            }
        }
    }
}
相关推荐
编程爱好者熊浪1 小时前
两次连接池泄露的BUG
java·数据库
TDengine (老段)3 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349843 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE3 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102164 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎4 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP4 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t4 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb
安当加密4 小时前
Nacos配置安全治理:把数据库密码从YAML里请出去
数据库·安全
测试老哥5 小时前
python+requests+excel 接口测试
自动化测试·软件测试·python·测试工具·测试用例·excel·接口测试