Java实现将Excel中的数据导入到oracle数据库中

前言

·场景:需要将excel中的数据导入到oracle数据库中
·问题:虽然PL/SQL中有一个ODBC import工具可以实现场景中描述的需求,但是如果excel中存在合并单元格的情况存在或者空行等情况,该工具就不是特别的好用,需要自己提前手动处理好excel文件
·需要解决:

  • 1.自动识别和填充合并单元格的内容 (代码核心价值)
  • 2.识别空行并将之排除
  • 3.将数据插入到指定数据库

代码实现

/**
 * 用于将excle表中得数据插入到指定数据库中
 * 前提条件:指定好excel文件路径,sheet表名称,数据库信息(表名称,连接地址,账号密码)
 * 输出:数据将插入到指定得表中
 * 存在价值:可以解决excel表中合并单元格得问题 会自动识别和填充合并单元格中每格得内容
 * 注意:如果整行为空 将不插入数据库
 */
public class ExcelJDBC {
    private static String oracleTable; //插入得表名称
    private static String sheetName; //sheet表名称
    private static String oracleUrl; //连接地址
    private static String user; //用户名
    private static String passWord; //密码
    private static String excelPath; //excel文件路径
    
    public ExcelJDBC(String p_oracleTable,String p_sheetName,String p_oracleUrl,String p_user,String p_passWord,String p_excelPath){
        this.oracleTable = p_oracleTable;
        this.sheetName = p_sheetName;
        this.oracleUrl = p_oracleUrl;
        this.user = p_user;
        this.passWord = p_passWord;
        this.excelPath = p_excelPath;
    }
    
    //总的一个执行逻辑方法
    public void excelDeal() throws SQLException, IOException {
            File xlsFile = new File(excelPath);//excel路径
            // 获得工作簿
            Workbook workbook = WorkbookFactory.create(xlsFile);
            // 获得工作表个数
            int sheetCount = workbook.getNumberOfSheets();
            // 获取工作表
            Sheet sheet = workbook.getSheet(sheetName);
            // 获得行数
            int rows = sheet.getLastRowNum() + 1;
            // 获得列数,先获得一行,再得到该行列数
            org.apache.poi.ss.usermodel.Row tmp = sheet.getRow(0);
            if (tmp == null) {
                System.out.println("首行没有数据");
                return;
            }
            int cols = (tmp).getPhysicalNumberOfCells();//获取列数
            String[][] cellsTemp = new String[rows][cols];//用于保存数据
            // 读取数据
            for (int row = 1; row < rows; row++) {
                org.apache.poi.ss.usermodel.Row r = sheet.getRow(row);
                for (int col = 0; col < cols; col++) {
                    //判断是否为合并单元格
                    Result resultTemp = isMergedRegion(sheet, row, col);
                    //获取单元格内容
                    String content = r.getCell(col) == null ? "" : r.getCell(col).toString();
                    //如果这个单元格是合并单元格且没有被赋值 则说明这个单元格是第一个
                    if (resultTemp.merged) {
                        String sTemp = cellsTemp[row][col];
                        
                        //不等于null则说明这个是合并单元格 且已经被附过值
                        if (sTemp != null) {
                            continue;
                        }
                        
                        //获取合并的行数和列数
                        int colnum = resultTemp.endCol - resultTemp.startCol;
                        int rownum = resultTemp.endRow - resultTemp.startRow;
                        
                        //这个不等于0 则说明是向下合并单元格
                        if (colnum != 0) {
                            for (int j = 0; j <= colnum; j++) {
                                cellsTemp[row][col + j] = content;
                            }
                        }
                        //这个不等于0 则说明横向合并单元格
                        if (rownum != 0) {
                            for (int j = 0; j <= rownum; j++) {
                                cellsTemp[row + j][col] = content;
                            }
                        }
                        //如果都不为0 那么就说明跨行跨列合并单元格
                        if (colnum != 0 && rownum != 0) {
                            for (int j = 1; j <= colnum; j++) {
                                for (int p = 1; p <= rownum; p++) {
                                    cellsTemp[row + p][col + j] = content;
                                }
                            }
                        }
                    } else {
                        cellsTemp[row][col] = content;
                    }
                }
            }
            //控制台打印出数据
            //printData(cellsTemp);
            //执行sql,将数据插入到数据库
            StringBuilder sb = runSql(cellsTemp);
            System.out.println("未成功执行数据为:" + sb.toString());
            System.out.println("操作结束");
        }
        
        //region 以下为被调用的方法
        
        /**
         * 打印数据
         * @param p_Data data
         */
        public static void printData(String[][] p_Data){
            for (int k = 0; k < p_Data.length; k++){
                for (int q = 0; q < p_Data[k].length; q++){
                    System.out.printf("%10s", p_Data[k][q]);
                }
                System.out.println();
            }
        }
        
        /**
         * 判断是否为合并单元格
         * @param sheet 表
         * @param row 所在行
         * @param column 所在列
         * @return
         */
        private static Result isMergedRegion(Sheet sheet, int row, int column) {
            int sheetMergeCount = sheet.getNumMergedRegions();
            for (int i = 0; i < sheetMergeCount; i++) {
                CellRangeAddress range = sheet.getMergedRegion(i);
                int firstColumn = range.getFirstColumn();
                int lastColumn = range.getLastColumn();
                int firstRow = range.getFirstRow();
                int lastRow = range.getLastRow();
                if (row >= firstRow && row <= lastRow) {
                    if (column >= firstColumn && column <= lastColumn) {
                        return new Result(true, firstRow + 1, lastRow + 1, firstColumn + 1, lastColumn + 1);
                    }
                }
            }
            return new Result(false, 0, 0, 0, 0);
        }
        
        /**
         * 获取oracle数据库连接
         * @return
         */
        public static Connection getConnection() {
            Connection connection = null;// 创建一个数据库连接
            try
            {
                // 加载Oracle驱动程序
                Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
                System.out.println("开始尝试连接数据库!");
                String url = "jdbc:oracle:thin:@" + oracleUrl;//Oracle的默认数据库名
                connection = DriverManager.getConnection(url, user, passWord);// 获取连接
                System.out.println("数据库连接成功!");
                return connection;
            }
            catch (Exception e)
            {
                e.printStackTrace();
                return null;
            }
        }
        
        /**
         * 拼接并执行sql语句
         * @param p_Data
         * @return 执行异常的sql语句
         */
        public static StringBuilder runSql(String[][] p_Data) throws SQLException {
            List<String> sqlList = new ArrayList<>();
            StringBuilder errorSql = new StringBuilder();
            for (int k = 0; k < p_Data.length; k++){
                String _value = "";
                int emptyNum = 0;//一行中含有空值得数量
                for (int q = 0; q < p_Data[k].length; q++){
                    _value += "'" + p_Data[k][q] + "',";
                    if(p_Data[k][q] == null || p_Data[k][q] == "") emptyNum++;
                }
                _value = _value.substring(0,_value.lastIndexOf(","));
                if(emptyNum == p_Data[k].length) continue;//如果整行为空 则不进行插入动作
                sqlList.add("insert into " + oracleTable + " values(" + _value + ")");
            }
            Connection con = getConnection();
            for (String s:
                    sqlList) {
                Statement statement = con.createStatement();
                int modifyNum = statement.executeUpdate(s);
                if(modifyNum == 0){
                    errorSql.append(s);
                }
                System.out.println("成功执行得sql语句为:" + s);
            }
            return errorSql;
        }
        
        /**
         * 内部类
         */
        static class  Result{
            public boolean merged;//是否为合并单元格 true-shi,false-fou
            public int startRow;//开始的行
            public int endRow;//结束的行
            public int startCol;//开始的列
            public int endCol;//结束的列
            public Result(boolean merged,int startRow,int endRow
                    ,int startCol,int endCol){
                this.merged = merged;
                this.startRow = startRow;
                this.endRow = endRow;
                this.startCol = startCol;
                this.endCol = endCol;
            }
        }
        
        //endregion
}
复制代码

使用方法:
1.声明类对象ExcelJDBC
2.调用方法excelDeal即可
示例如下:

public static void main(String args[]) throws IOException, SQLException {
        //region 以下内容需要使用者根据实际情况进行更改
        String oracleTable = "tableName";//插入得表名称,例:HANTEST
        String sheetName = "sheetName";//sheet表名称,例:Sheet1
        String oracleUrl = "ip:port:dataName";//数据库连接地址,例:127.0.0.1:1521:orcl
        String user = "ueserName";//数据库用户名,例:root
        String passWord = "passWord";//数据库密码,例:root123
        String excelPath = "excelPath";//excel文件路径,例:D:\\Han\\test.xlsx
        //endregion
        
        //声明对象 传入参数
        ExcelJDBC excelJDBC = new ExcelJDBC(oracleTable,sheetName,oracleUrl,user,passWord,excelPath);
        调用方法 执行操作
        excelJDBC.excelDeal();
    }
复制代码

实际使用效果对比

使用的excel表格结构:

数据库原始表结构:

使用PL/SQL的ODBC import工具的数据库导入效果:

使用 上述程序数据库导入效果:

结语

由于在工作中接到相关的任务,在手动导入数据时十分痛苦。故写了上述程序以此来解放劳动力,时间上耗时5H左右。所以会在代码规范,程序性能的方面上有些纰漏,望读者在使用的过程中可以根据实际来自我优化。
这篇文章适用于希望快速解决问题人群,避免重复造轮子。

转载请备明出处,LOVE & PEACE ! --- By HAN

猜你喜欢

转载自juejin.im/post/5e81b97b6fb9a03c5b2fb224