天天看點

java根據mysql資料庫表簡單生成增删改查

寫作背景

換了家公司後,公司裡沒有公共的代碼生成工具。每次來個新需求,從建表到實體Bean、dao、service等等這樣一直做重複的工作會比較煩躁又很費時間。于是自己想寫一個玩玩,這裡說明一下,公司技術選型為springboot + jdbc templates沒有使用到像mybatis等orm架構,是以不需要生成mapper.xml檔案。

代碼執行個體

package com.chenyulian.util;

import java.io.*;
import java.sql.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.text.MessageFormat.format;


/**
 * @author 沉魚
 * @date 2018/3/18 15:51
 */
public class GenerateJavaFileUtils {
    // 定義資料庫常用類型
    private static final String TYPE_CHAR = "char";

    private static final String TYPE_DATE = "date";

    private static final String TYPE_TIMESTAMP = "timestamp";

    private static final String TYPE_INT = "int";

    private static final String TYPE_BIGINT = "bigint";

    private static final String TYPE_TEXT = "text";

    private static final String TYPE_BIT = "bit";

    private static final String TYPE_DECIMAL = "decimal";

    private static final String TYPE_BLOB = "blob";

    // 配置檔案存放位址
    private static final String PACKAGEPATH = "D:\\workspace\\entity\\";

    private static final String BEAN_PATH = PACKAGEPATH + "entity_bean";

    private static final String SERVICE_PATH = PACKAGEPATH + "entity_service";

    private static final String MAPPER_PATH = PACKAGEPATH + "entity_mapper";

    private static final String XML_PATH = PACKAGEPATH + "entity_mapper/xml";

    // 配置檔案包名稱 , 這些值需要根據各自的項目配置
    private static final String MODULENAME = "com.chenyulian";

    private static final String BEAN_PACKAGE = MODULENAME + ".entity";

    private static final String MAPPER_PACKAGE = MODULENAME + ".dao";

    private static final String SERVICE_PACKAGE = MODULENAME + ".service";

    private static final String SERVICEIMPL_PACKAGE = MODULENAME + ".service.impl";


    // 配置資料庫連接配接資訊
    private static final String DRIVERNAME = "com.mysql.jdbc.Driver";

    private static final String USER = "root";

    private static final String PASSWORD = "123456";

    private static final String URL = "jdbc:mysql://localhost:3306/chenyulian?characterEncoding=utf8&useSSL=false&serverTimezone=UTC";

    // 方法統一命名
    private static final String save = "insert";

    private static final String update = "updateById";

    private static final String countTotalNum = "count";

    private static final String queryById = " selectById";

    private static final String delete = "deleteById";

    // sql語句
    private static final String showTablesName = "show tables"; // 擷取資料庫的所有表名

    private static final String showTablesInfo = "show table status"; // 擷取資料庫的所有表詳情資訊(包括注釋)

    private static final String showFields = "show full fields from "; // 擷取指定表的所有字段詳情

    // 定義系統中使用到的全局變量
    private String tableName;

    private String beanName;

    private String serviceName;

    private String serviceImplName;

    private String controllerName;

    private String lowerBeanName;

    private String mapperName;

    private List columns = new ArrayList<>();

    private List types = new ArrayList<>();

    private List comments = new ArrayList<>();

    private Connection conn;

    // 常用的配置項
    /** 用于指定生成類檔案的表, 當值為空時會将資料庫的所有表都生成類檔案 */
    private static final String TABLE_NAME = "gift";

    /** 表名中的這些值将不會轉換為類名的一部分 */
    private static final String[] TABLE_PREFIXS = {"app","lms","wms","zwms", "v2"};

    /**
     * 删除指定目錄下所有檔案,若目錄不存在則建立該目錄
     */
    private static void mkdirs(Runtime runtime) throws IOException {
        File file = new File(PACKAGEPATH);
        if (file.exists()) {
            runtime.exec("cmd /c del /q/a/f/s "+ file.getAbsolutePath());
        }
        file.mkdirs();
    }

    /**
     * 擷取連接配接
     */
    private void initConnection() throws ClassNotFoundException, SQLException {
        Class.forName(DRIVERNAME);
        conn = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    /**
     * 擷取所有的表名
     */
    private List<String> getTables() throws SQLException {
        List<String> tables = new ArrayList<>();
        PreparedStatement pstate = conn.prepareStatement(showTablesName);
        ResultSet results = pstate.executeQuery();
        while (results.next()) {
            String tableName = results.getString();
            // if ( tableName.toLowerCase().startsWith("yy_") ) {
            tables.add(tableName);
            // }
        }
        return tables;
    }

    /**
     * 根據表名生成實體類名稱及所有相關的檔案名
     */
    private void initNameByTable(String table) {
        tableName = table;
        beanName = getBeanName(table);
        lowerBeanName = lowerCaseFirstLitter(beanName);
        mapperName = beanName + "Mapper";
        serviceName = beanName + "Service";
        serviceImplName = serviceName + "Impl";
    }

    /**
     * 根據表名擷取實體類名
     */
    private String getBeanName(String table) {
        StringBuilder entityName = new StringBuilder(table.length());
        String tableLower = table.toLowerCase();
        String[] tables = tableLower.split("_");
        String temp = null;
        for (int i = ; i < tables.length; i++) {
            temp = tables[i].trim();
            if(canUseTemp(temp)){
                entityName.append(upperCaseFirstLitter(temp));
            }
        }
        return entityName.toString();
    }

    /**
     * 判斷表名字首是否要加到實體類名上
     */
    private Boolean canUseTemp(String temp) {
        if(isEmpty(temp)){
            return false;
        }
        for(String tablePrefix: TABLE_PREFIXS){
            if (tablePrefix.equalsIgnoreCase(temp)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 擷取實體類屬性的資料類型
     */
    private String processType(String type) {
        if (type.indexOf(TYPE_CHAR) > -) {
            return "String";
        } else if (type.indexOf(TYPE_BIGINT) > -) {
            return "Long";
        } else if (type.indexOf(TYPE_INT) > -) {
            return "Integer";
        } else if (type.indexOf(TYPE_DATE) > -) {
            return "Date";
        } else if (type.indexOf(TYPE_TEXT) > -) {
            return "String";
        } else if (type.indexOf(TYPE_TIMESTAMP) > -) {
            return "Date";
        } else if (type.indexOf(TYPE_BIT) > -) {
            return "Boolean";
        } else if (type.indexOf(TYPE_DECIMAL) > -) {
            return "BigDecimal";
        } else if (type.indexOf(TYPE_BLOB) > -) {
            return "byte[]";
        }
        return null;
    }

    /**
     * 将字段名轉換為實體類的屬性名
     */
    private String processField(String field) {
        StringBuilder sb = new StringBuilder(field.length());
        String[] fields = field.split("_");
        sb.append(fields[]);
        for (int i = ; i < fields.length; i++) {
            sb.append(upperCaseFirstLitter(fields[i].trim()));
        }
        return sb.toString();
    }

    /**
     * 建構類上面的注釋
     */
    private void buildClassComment(BufferedWriter bw, String text) throws IOException {
        bw.newLine();
        bw.newLine();
        bw.write("/**");
        bw.newLine();
        bw.write(" * " + text);
        bw.newLine();
        bw.write(" */");
    }

    /**
     * 建構方法上面的注釋
     */
    private void buildMethodComment(BufferedWriter bw, String text) throws IOException {
        bw.newLine();
        bw.write("\t/**" + text + "*/");
    }

    /**
     * 生成實體類
     */
    private void buildEntityBean(List<String> columns, List<String> types, List<String> comments, String tableComment)
            throws IOException {
        instanceFolder(BEAN_PATH);
        BufferedWriter bw = instanceBufferedWriter(BEAN_PATH, beanName + ".java");
        writeBeanHead(tableComment, bw);
        writeBeanColumns(columns, types, comments, bw);
        writeGetSetMethod(columns, types, bw);
        writeEnd(bw);
    }

    /**
     * 寫類結尾處代碼
     */
    private void writeEnd(BufferedWriter bw) throws IOException {
        bw.newLine();
        bw.write("}");
        bw.newLine();
        bw.flush();
        bw.close();
    }

    /**
     * 寫實體類的get,set方法
     */
    private void writeGetSetMethod(List<String> columns, List<String> types, BufferedWriter bw) throws IOException {
        String uppperField = null;
        String lowerField = null;
        String tempType = null;
        for (int i = ; i < columns.size(); i++) {
            tempType = processType(types.get(i));
            lowerField = processField(columns.get(i));
            uppperField = upperCaseFirstLitter(lowerField);
            bw.newLine();
            bw.write("\tpublic void set" + uppperField + "(" + tempType + " " + lowerField + "){");
            bw.newLine();
            bw.write("\t\tthis." + lowerField + " = " + lowerField + ";");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();
            bw.newLine();
            bw.write("\tpublic " + tempType + " get" + uppperField + "(){");
            bw.newLine();
            bw.write("\t\treturn this." + lowerField + ";");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();
        }
        bw.newLine();
        bw.newLine();
    }

    /**
     * 寫實體類屬性代碼
     */
    private void writeBeanColumns(List<String> columns, List<String> types, List<String> comments, BufferedWriter bw)
            throws IOException {
        for (int i = ; i < columns.size(); i++) {
            if (isNotEmpty(comments.get(i))) {
                bw.write("\t/**" + comments.get(i) + "*/");
                bw.newLine();
            }
            bw.write("\tprivate " + processType(types.get(i)) + " " + processField(columns.get(i)) + ";");
            bw.newLine();
            bw.newLine();
        }
        bw.newLine();
    }

    /**
     * 寫實體類頭部代碼
     */
    private void writeBeanHead(String tableComment, BufferedWriter bw) throws IOException {
        bw.write("package " + BEAN_PACKAGE + ";");
        bw.newLine();
        bw.write("import java.io.Serializable;");
        bw.newLine();
        bw.write("import java.util.Date;");
        bw.newLine();
        buildClassComment(bw, tableComment + "實體類");
        bw.newLine();
        bw.write("public class " + beanName + " implements Serializable {");
        bw.newLine();
    }

    /**
     * 根據路徑建立檔案及輸出流
     */
    private BufferedWriter instanceBufferedWriter(String parent, String child) throws FileNotFoundException {
        File beanFile = new File(parent, child);
        return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
    }

    /**
     * 根據路徑建立目錄
     */
    private void instanceFolder(String folderPath) {
        File folder = new File(folderPath);
        if (!folder.exists()) {
            folder.mkdir();
        }
    }


    /**
     * 建構方法代碼
     *
     * @param comment 方法注釋
     * @param returnType 方法傳回類型
     * @param name 方法名
     * @param param 方法參數
     */
    private void buildMethod(BufferedWriter bw, String comment, String returnType, String name, String param) throws IOException{
        buildMethodComment(bw, comment);
        bw.newLine();
        String result = format("\t{0} {1}({2});", returnType, name, param);
        bw.write(result);
        bw.newLine();
    }

    /**
     * 建構Dao檔案
     */
    private void buildMapper() throws IOException {
        instanceFolder(MAPPER_PATH);
        BufferedWriter bw = instanceBufferedWriter(MAPPER_PATH, mapperName + ".java");
        writeMapperHead(bw);
        writeMethod(bw);
        writeEnd(bw);
    }

    /**
     * 寫Mapper及Service中方法代碼
     */
    private void writeMethod(BufferedWriter bw) throws IOException {
        buildMethod(bw, "查詢(根據主鍵ID查詢", beanName, queryById, "String id");
        buildMethod(bw, "删除(根據主鍵ID删除)", "int", delete, "String id");
        buildMethod(bw, "添加", "int", save, beanName + " " + lowerBeanName);
        buildMethod(bw, "修改", "int", update, beanName + " " + lowerBeanName);
    }

    /**
     * 寫Mapper類頭部代碼
     */
    private void writeMapperHead(BufferedWriter bw) throws IOException {
        bw.write("package " + MAPPER_PACKAGE + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
        bw.newLine();
        bw.write("import java.util.List;");
        bw.newLine();
        bw.write("import java.util.Map;");
        bw.newLine();
        bw.write("import org.apache.ibatis.annotations.Param;");
        buildClassComment(bw, mapperName + "資料庫操作接口類");
        bw.newLine();
        bw.write("public interface " + mapperName + "{");
        bw.newLine();
    }

    /**
     * 建構Service檔案
     */
    private void buildServie() throws IOException {
        instanceFolder(SERVICE_PATH);
        BufferedWriter bw = instanceBufferedWriter(SERVICE_PATH, serviceName + ".java");
        writeServiceHead(bw);
        writeMethod(bw);
        writeEnd(bw);
    }

    /**
     * 寫service接口頭部代碼
     */
    private void writeServiceHead(BufferedWriter bw) throws IOException {
        bw.write("package " + SERVICE_PACKAGE + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
        bw.newLine();
        bw.write("import java.util.List;");
        bw.newLine();
        bw.write("import java.util.Map;");
        bw.newLine();
        bw.write("import org.apache.ibatis.annotations.Param;");
        buildClassComment(bw, serviceName + "資料庫操作接口類");
        bw.newLine();
        bw.write("public interface " + serviceName + " {");
        bw.newLine();
    }

    /**
     * 建構ServiceImpl檔案
     */
    private void buildServieImpl() throws IOException {
        instanceFolder(SERVICE_PATH);
        BufferedWriter bw = instanceBufferedWriter(SERVICE_PATH, serviceImplName + ".java");
        writeServiceImplHead(bw);
        writeServieImplMethod(bw);
        writeEnd(bw);
    }

    /**
     * 寫serveImpl中的方法
     */
    private void writeServieImplMethod(BufferedWriter bw) throws IOException {
        String lowerMapperName = lowerCaseFirstLitter(mapperName);
        buildServiceImplMethod(bw, beanName, queryById, "String id", lowerMapperName);
        buildServiceImplMethod(bw, "int", delete, "String id", lowerMapperName);
        buildServiceImplMethod(bw, "int", save, beanName + " " + lowerBeanName, lowerMapperName);
        buildServiceImplMethod(bw, "int", update, beanName + " " + lowerBeanName, lowerMapperName);
    }

    /**
     * 寫serveImpl中的方法
     */
    private void buildServiceImplMethod(BufferedWriter bw, String returnType, String name, String param, String lowerMapperName) throws IOException {
        bw.write("\[email protected]");
        bw.newLine();
        bw.write(format("\tpublic {0} {1}({2})", returnType, name, param));
        bw.write("{");
        bw.newLine();
        bw.write(format("\t\treturn {0}.{1}({2});", lowerMapperName, name.trim(), param.split(" ")[]));
        bw.newLine();
        bw.write("\t}");
        bw.newLine();
        bw.newLine();
    }

    /**
     * 寫serviceImpl頭部代碼
     */
    private void writeServiceImplHead(BufferedWriter bw) throws IOException {
        String lowerMapperName = lowerCaseFirstLitter(mapperName);
        bw.write("package " + SERVICEIMPL_PACKAGE + ";");
        bw.newLine();
        bw.newLine();
        bw.write("import java.util.List;");
        bw.newLine();
        bw.write("import org.springframework.beans.factory.annotation.Autowired;");
        bw.newLine();
        bw.write("import org.springframework.stereotype.Service;");
        bw.newLine();
        bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
        bw.newLine();
        buildClassComment(bw, serviceImplName + "資料庫操作接口類");
        bw.newLine();
        bw.newLine();
        bw.write("@Service");
        bw.newLine();
        bw.write("public class " + serviceImplName + " implements " + serviceName + " {");
        bw.newLine();
        bw.newLine();
        bw.write("\[email protected]");
        bw.newLine();
        bw.write("\tprivate " + mapperName + " " + lowerMapperName + ";");
        bw.newLine();
        bw.newLine();
    }

    /**
     * 擷取所有的資料庫表名及注釋
     */
    private Map<String,String> getTableComment() throws SQLException {
        Map maps = new HashMap<>();
        //全部表
        PreparedStatement pstate = conn.prepareStatement(showTablesInfo);
        ResultSet results = pstate.executeQuery();
        while (results.next()) {
            String tableName = results.getString("NAME");
            String comment = results.getString("COMMENT");
            maps.put(tableName, comment);
        }
        return maps;
    }

    public static Boolean isEmpty(String str) {
        return null == str || "".equals(str);
    }

    public static Boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * 将字元串首字母小寫
     */
    public static String lowerCaseFirstLitter(String str) {
        if(isEmpty(str)){
            return "";
        }else {
            return str.substring(, ).toLowerCase() + str.substring();
        }
    }

    /**
     * 将字元串首字母大寫
     */
    public static String upperCaseFirstLitter(String str) {
        if(isEmpty(str)){
            return "";
        }else {
            return str.substring(, ).toUpperCase() + str.substring();
        }
    }


    /**
     * 根據某一個表生成實體類,service,mapper
     */
    private void generateByTable(Map tableComments, String table) throws SQLException, IOException {
        columns.clear();
        types.clear();
        comments.clear();
        PreparedStatement pstate = conn.prepareStatement(showFields + table);
        ResultSet results = pstate.executeQuery();
        while (results.next()) {
            columns.add(results.getString("FIELD"));
            types.add(results.getString("TYPE"));
            comments.add(results.getString("COMMENT"));
        }
        initNameByTable(table);
        String tableComment = (String) tableComments.get(table);
        buildEntityBean(columns, types, comments, tableComment);
        buildMapper();
        buildServie();
        buildServieImpl();
    }

    /**
     * 擷取所有的表資訊并循環生成相應檔案
     */
    public void generate() throws ClassNotFoundException, SQLException, IOException {
        initConnection();
        Map<String,String> tableComments = getTableComment();
        if(isNotEmpty(TABLE_NAME)){
            generateByTable(tableComments, TABLE_NAME);
        }else {
            List<String> tables = getTables();
            for (String table : tables) {
                generateByTable(tableComments, table);
            }
        }
        conn.close();
    }   
}
           

測試

執行這個main方法後,後彈出下面的圖

public static void main(String[] args) {
        try {
            Runtime runtime = Runtime.getRuntime();
            mkdirs(runtime);
            new GenerateJavaFileUtils().generate();
            // 自動打開生成檔案的目錄
            runtime.exec("cmd /c start explorer " + PACKAGEPATH);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
           
java根據mysql資料庫表簡單生成增删改查