将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 小时前
Vue3 + Element Plus 项目中日期时间处理的最佳实践与数据库设计规范
数据库·设计规范
白鹭2 小时前
MySQL源码部署(rhel7)
数据库·mysql
666和7772 小时前
Struts2 工作总结
java·数据库
还听珊瑚海吗2 小时前
SpringMVC(一)
数据库
星期天要睡觉4 小时前
MySQL 综合练习
数据库·mysql
Y4090014 小时前
数据库基础知识——聚合函数、分组查询
android·数据库
JosieBook5 小时前
【数据库】MySQL 数据库创建存储过程及使用场景详解
数据库·mysql
处女座_三月5 小时前
改 TDengine 数据库的时间写入限制
数据库·sql·mysql