Excel生成Oracle數據庫表sql工具類


1.解決問題: 開發文檔中字段比較多的時候,建表sql(Oracle下划線命名規范)比較麻煩,容易出錯~~ (主要是懶)

  特意手寫一個工具,根據excel字段,生成建表的sql語句.

~~~末尾附GitHub傳送門~~~

 2.Java代碼

Excel頭:

public class ExcelHead {
    private String excelName;             //Excel名
    private String entityName;            //實體類屬性名
    private boolean required=false;      //值必填
get()/set()
}

 

Excel實體:

public class Excel {
    private String item;    //屬性列
    private String type;    //類型
    private String isNeed;  //是否必填
    private String annotation;  //注釋
    private Integer maxLength;  //最大長度

get()/set()
}

ExcelUtils工具類 :

(借鑒而來)

package com.utils;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ExcelUtils {
    private static final String FULL_DATA_FORMAT = "yyyy/MM/dd  HH:mm:ss";
    private static final String SHORT_DATA_FORMAT = "yyyy/MM/dd";


    /**
     * Excel表頭對應Entity屬性 解析封裝javabean
     *
     * @param classzz    類
     * @param in         excel流
     * @param fileName   文件名
     * @param excelHeads excel表頭與entity屬性對應關系
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> readExcelToEntity(Class<T> classzz, InputStream in, String fileName, List<ExcelHead> excelHeads) throws Exception {
        checkFile(fileName);    //是否EXCEL文件
        Workbook workbook = getWorkBoot(in, fileName); //兼容新老版本
        List<T> excelForBeans = readExcel(classzz, workbook, excelHeads);  //解析Excel
        return excelForBeans;
    }

    /**
     * 解析Excel轉換為Entity
     *
     * @param classzz  類
     * @param in       excel流
     * @param fileName 文件名
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> readExcelToEntity(Class<T> classzz, InputStream in, String fileName) throws Exception {
        return readExcelToEntity(classzz, in, fileName,null);
    }

    /**
     * 校驗是否是Excel文件
     *
     * @param fileName
     * @throws Exception
     */
    public static void checkFile(String fileName) throws Exception {
        if (!StringUtils.isEmpty(fileName) && !(fileName.endsWith(".xlsx") || fileName.endsWith(".xls"))) {
            throw new Exception("不是Excel文件!");
        }
    }

    /**
     * 兼容新老版Excel
     *
     * @param in
     * @param fileName
     * @return
     * @throws IOException
     */
    private static Workbook getWorkBoot(InputStream in, String fileName) throws IOException {
        if (fileName.endsWith(".xlsx")) {
            return new XSSFWorkbook(in);
        } else {
            return new HSSFWorkbook(in);
        }
    }

    /**
     * 解析Excel
     *
     * @param classzz    類
     * @param workbook   工作簿對象
     * @param excelHeads excel與entity對應關系實體
     * @param <T>
     * @return
     * @throws Exception
     */
    private static <T> List<T> readExcel(Class<T> classzz, Workbook workbook, List<ExcelHead> excelHeads) throws Exception {
        List<T> beans = new ArrayList<T>();
        int sheetNum = workbook.getNumberOfSheets();
        for (int sheetIndex = 0; sheetIndex < sheetNum; sheetIndex++) {
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            String sheetName=sheet.getSheetName();
            int firstRowNum = sheet.getFirstRowNum();
            int lastRowNum = sheet.getLastRowNum();
            Row head = sheet.getRow(firstRowNum);
            if (head == null)
                continue;
            short firstCellNum = head.getFirstCellNum();
            short lastCellNum = head.getLastCellNum();
            Field[] fields = classzz.getDeclaredFields();
            for (int rowIndex = firstRowNum + 1; rowIndex <= lastRowNum; rowIndex++) {
                Row dataRow = sheet.getRow(rowIndex);
                if (dataRow == null)
                    continue;
                T instance = classzz.newInstance();
                if(CollectionUtils.isEmpty(excelHeads)){  //非頭部映射方式,默認不校驗是否為空,提高效率
                    firstCellNum=dataRow.getFirstCellNum();
                    lastCellNum=dataRow.getLastCellNum();
                }
                for (int cellIndex = firstCellNum; cellIndex < lastCellNum; cellIndex++) {
                    Cell headCell = head.getCell(cellIndex);
                    if (headCell == null)
                        continue;
                    Cell cell = dataRow.getCell(cellIndex);
                    headCell.setCellType(Cell.CELL_TYPE_STRING);
                    String headName = headCell.getStringCellValue().trim();
                    if (StringUtils.isEmpty(headName)) {
                        continue;
                    }
                    ExcelHead eHead = null;
                    if (!CollectionUtils.isEmpty(excelHeads)) {
                        for (ExcelHead excelHead : excelHeads) {
                            if (headName.equals(excelHead.getExcelName())) {
                                eHead = excelHead;
                                headName = eHead.getEntityName();
                                break;
                            }
                        }
                    }
                    for (Field field : fields) {
                        if (headName.equalsIgnoreCase(field.getName())) {
                            String methodName = MethodUtils.setMethodName(field.getName());
                            Method method = classzz.getMethod(methodName, field.getType());
                            if (isDateFied(field)) {
                                Date date=null;
                                if(cell!=null){
                                    date=cell.getDateCellValue();
                                }
                                if (date == null) {
                                    volidateValueRequired(eHead,sheetName,rowIndex);
                                    break;
                                }
                                method.invoke(instance, cell.getDateCellValue());
                            } else {
                                String value = null;
                                if(cell!=null){
                                    cell.setCellType(Cell.CELL_TYPE_STRING);
                                    value=cell.getStringCellValue();
                                }
                                if (StringUtils.isEmpty(value)) {
                                    volidateValueRequired(eHead,sheetName,rowIndex);
                                    break;
                                }
                                method.invoke(instance, convertType(field.getType(), value.trim()));
                            }
                            break;
                        }
                    }
                }
                beans.add(instance);
            }
        }
        return beans;
    }
    /**
     * 是否日期字段
     *
     * @param field
     * @return
     */
    private static boolean isDateFied(Field field) {
        return (Date.class == field.getType());
    }
    /**
     * 空值校驗
     *
     * @param excelHead
     * @throws Exception
     */
    private static void volidateValueRequired(ExcelHead excelHead,String sheetName,int rowIndex) throws Exception {
        if (excelHead != null && excelHead.isRequired()) {
            throw new Exception("《"+sheetName+"》第"+(rowIndex+1)+"行:\""+excelHead.getExcelName() + "\"不能為空!");
        }
    }
    /**
     * 類型轉換
     *
     * @param classzz
     * @param value
     * @return
     */
    private static Object convertType(Class classzz, String value) {
        if (Integer.class == classzz || int.class == classzz) {
            return Integer.valueOf(value);
        }
        if (Short.class == classzz || short.class == classzz) {
            return Short.valueOf(value);
        }
        if (Byte.class == classzz || byte.class == classzz) {
            return Byte.valueOf(value);
        }
        if (Character.class == classzz || char.class == classzz) {
            return value.charAt(0);
        }
        if (Long.class == classzz || long.class == classzz) {
            return Long.valueOf(value);
        }
        if (Float.class == classzz || float.class == classzz) {
            return Float.valueOf(value);
        }
        if (Double.class == classzz || double.class == classzz) {
            return Double.valueOf(value);
        }
        if (Boolean.class == classzz || boolean.class == classzz) {
            return Boolean.valueOf(value.toLowerCase());
        }
        if (BigDecimal.class == classzz) {
            return new BigDecimal(value);
        }
       /* if (Date.class == classzz) {
            SimpleDateFormat formatter = new SimpleDateFormat(FULL_DATA_FORMAT);
            ParsePosition pos = new ParsePosition(0);
            Date date = formatter.parse(value, pos);
            return date;
        }*/
        return value;
    }
    /**
     * 獲取properties的set和get方法
     */
    static class MethodUtils {
        private static final String SET_PREFIX = "set";
        private static final String GET_PREFIX = "get";
        private static String capitalize(String name) {
            if (name == null || name.length() == 0) {
                return name;
            }
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        public static String setMethodName(String propertyName) {
            return SET_PREFIX + capitalize(propertyName);
        }
        public static String getMethodName(String propertyName) {
            return GET_PREFIX + capitalize(propertyName);
        }
    }
}

 

Constant常量 :

package com.utils;

public interface Constant {

    String pre = " create table <<tableName>> \n" +
            "(\n" +
            "<<itemContent>>  \n" +
            ")\n" +
            "/\n" +
            "comment on table <<tableName>> is '<<tableNameDesc>>'" +
            "\n" +
            "/\n" +
            "<<annotationContent>>";


    //oracle數據類型相關
    String NUMBER = "NUMBER";
    String VARCHAR2 = "VARCHAR2";
    String DATE = "DATE";
    String NOT_NULL = "not null";
    String STRING_MAX_LENGTH = "256";//默認字符串最大位數
    String ROW_PRE = "    ";//行開頭縮進

}

 

ChangeChar工具類 (駝峰轉下划線大寫) :
我的另一篇博客有 : https://www.cnblogs.com/coloz/p/10911174.html
ExcelToSql:( 處理Excel中數據,各種拼接替換模板和常量)
package com.utils;


import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;

import java.util.List;

public class ExcelToSql {


    /**
     * @param tableName
     * @param tableNameDesc
     * @param excelPath
     * @throws Exception
     */
    public static String createSql(String tableName, String tableNameDesc, String excelPath) throws Exception {
        //String tableName = "MY_USER";  //表名
        // String tableNameDesc = "我的用戶表";  //表名描述
        // String excelPath = "D:\\code\\excelToSql\\src\\main\\resources\\Excel.xlsx";
        File file = new File(excelPath); //文件位置
        FileInputStream fileInputStream = new FileInputStream(file);
        String name = file.getName();
        List<Excel> list = ExcelUtils.readExcelToEntity(Excel.class, fileInputStream, name);
        // System.out.println("list :" + list);
        String sqlStr = Constant.pre;  //總的部分,先添加前置部分
        String itemContent = "";  //具體表字段信息
        String annotationContent = "";  //后面注釋內容

        String rowModelEnd = ",\n"; //最后一行不加

        if (CollectionUtils.isNotEmpty(list)) {
            for (int i = 0; i < list.size(); i++) {
                //oracle
                Excel vo = list.get(i);
                if (vo != null) {

                    String item = vo.getItem();
                    String annotation = vo.getAnnotation();
                    String type = vo.getType(); //數據類型
                    String isNeed = vo.getIsNeed(); //是否必填
                    Integer maxLength = vo.getMaxLength(); //最大長度
                    if (StringUtils.isBlank(item)) {
                        continue; //列不存在直接跳過
                    }

                    String ITEM_LINE = ChangeChar.camelToUnderline(item, 2); //對應oracle數據庫列名轉大寫下划線

                    //用於替換sql語句中的占位 字符串<< >>
                    String itemNew = ITEM_LINE;  //oracle大寫
                    String annotationNew = annotation;
                    String typeNew = Constant.VARCHAR2;   //默認字符串類型
                    String isNeedNew = "";  //默認不必填
                    String maxLengthNew = ""; //最大長度


                    if (type.contains("int") || type.contains("Num") || type.contains("Int")
                            || type.contains("數") || type.contains("num")) {
                        typeNew = Constant.NUMBER;
                    } else if (type.contains("date") || type.contains("Date") || type.contains("日期")) {
                        typeNew = Constant.DATE;
                    }

                    if (isNeed.contains("是") || isNeed.contains("true") || isNeed.contains("True")) {
                        isNeedNew = Constant.NOT_NULL;
                    }
                    if (isNeed.contains("是") || isNeed.contains("true") || isNeed.contains("True")) {
                        isNeedNew = Constant.NOT_NULL;
                    }

                    //如果是字符串類型沒有指定長度,默認256
                    if (maxLength == null || maxLength < 0) {
                        if (typeNew.equals(Constant.VARCHAR2)) {
                            maxLengthNew = "(" + Constant.STRING_MAX_LENGTH + ")";
                        }
                    } else {
                        maxLengthNew = "(" + maxLength + ")";  //有值直接賦值
                    }
                    //默認值問題???

                    //列字段相關,行左端保持必要空格,方便格式對齊
                    String rowModel = Constant.ROW_PRE + "<<rowItem>>              <<dataType>><<(maxLength)>>       <<isNeed>>"; //maxlength有括號
                    if (i != (list.size() - 1)) {
                        rowModel += rowModelEnd;  //最后一行不加
                    }

                    rowModel = rowModel.replaceAll("<<rowItem>>", itemNew).
                            replaceAll("<<dataType>>", typeNew).
                            replace("<<(maxLength)>>", maxLengthNew).
                            replaceAll("<<isNeed>>", isNeedNew);

                    itemContent += rowModel;   //列拼接

                    //注釋相關
                    String rowAnnotation = "\n" +
                            "comment on column <<tableName>>.<<ITEM_LINE>> is '<<annotation>>'\n" +
                            "/";

                    rowAnnotation = rowAnnotation.replaceAll("<<tableName>>", tableName).
                            replaceAll("<<ITEM_LINE>>", ITEM_LINE).
                            replaceAll("<<annotation>>", annotationNew)
                    ;

                    annotationContent += rowAnnotation;  //注釋拼接
                }
            }
        }


        //替換一下表字段名和注釋部分
        sqlStr = sqlStr.replaceAll("<<itemContent>>", itemContent)
                .replaceAll("<<tableNameDesc>>", tableNameDesc)
                .replaceAll("<<annotationContent>>", annotationContent)
        ;

        sqlStr = sqlStr.replaceAll("<<tableName>>", tableName);
        System.out.println("-----------下面是生成表的sql--------------------------------------------------------");
        System.out.println(sqlStr);

        System.out.println("-----------sql結束----------------------------------------------------------------");
        return sqlStr;
    }

}

 

測試類:

 

package com;

import com.utils.ExcelToSql;

public class MainRun {
    public static void main(String[] args) throws Exception {
        /**
         * 本工具主要為EXCEL生成ORACLE數據庫建表sql
         * 第一步:修改resource文件夾下面Excel.xlsx內容(第一行不要修改),
         * item:列字段,    annotation:注釋,type:數據類型(Number/String/Date 默認String),maxLength:最大長度(字符串默認256),isNeed:是否必須(是/否)
         * 第二步:設置 下面的tableName, tableNameDesc,excelPath
         * 第三步:運行MainRun.java類下的main方法,控制台輸出sqls
         * 注意格式:只測試過excel里面(駝峰字段)--->生成表列都是(下划線大寫)
         *
         */


        String tableName = "MY_USER";  //表名,必填
        String tableNameDesc = "我的用戶表";  //表名,可以為空
        String excelPath = "D:\\code\\excelToSql\\src\\main\\resources\\Excel.xlsx"; //excel硬盤上路徑
        String sql = ExcelToSql.createSql(tableName, tableNameDesc, excelPath);

    }
}

 

 

總結 : 1. Oracle的SQL規范,對開發者來說也是一種比較好的約束和開發工作中需要考慮到的方面.

     2.使用一些比較方便的工具對開發者省時省力,避免重復的"CV"工作.

   3.本篇中使用的無非是使用sql模板,結合POI工具,對表字段內容進行替換和邏輯判斷,十分簡單.

   4.如果有實現Mysql版本對應的工具,歡迎留言交流分享~~~

 

GitHub傳送門:  https://github.com/ColoZhu/excelToSql

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM