SpringBoot系列——Spring-Data-JPA(究極進化版) 自動生成單表基礎增、刪、改、查接口

  前言

  咱們在以前的實現了springboot與data-jpa的增、刪、改、查簡單使用(請戳:SpringBoot系列——Spring-Data-JPA),並實現了升級版(請戳:SpringBoot系列——Spring-Data-JPA(升級版)),在基礎版、升級版中,咱們實現了單表的基礎get、save(插入/更新)、list、page、delete接口,並寫了一套通用common代碼,每一個單表去繼承從而實現這套基礎接口、同時,咱們使用用Vo去接收、傳輸數據,實體負責與數據庫表映射。html

  可是,單表增、刪、改、查基礎功能類似,代碼高度類似,咱們新增一個單表操做的步驟:複製、粘貼、修改文件夾、文件名、類名、修改傳參實體對象...,爲了實現快速開發,咱們在前面兩個版本的基礎上,使用代碼自動生成一套單表的基礎增、刪、改、查接口前端

 

   代碼編寫

  首先咱們先建立一個新的工程項目,實現一套common代碼,以便單表直接繼承java

  CodeDOM.java是一個比較大的類,由於我把全部的東西都丟在了裏面...,接下來咱們拆分講解一下步驟(文末貼出CodeDOM.java完整代碼)mysql

  首先定義幾個屬性,構造函數傳入表名,基礎路徑基於表名進行賦值git

    /**
     * 表名
     */
    private String tableName;

    /**
     * 基礎路徑
     */
    private String basePackage_;
    private String package_;
    private String basePath;

  構造函數github

    /**
     * 構造參數,出入表名
     */
    private CodeDOM(String tableName) {
        this.tableName = tableName;
        basePackage_ = "cn\\huanzi\\springbootjpa\\";
        package_ = basePackage_ + StringUtil.camelCaseName(tableName).toLowerCase() + "\\";
        //System.getProperty("user.dir") 獲取的是項目所在路徑,若是咱們是子項目,則須要添加一層路徑
        basePath = System.getProperty("user.dir") + "\\src\\main\\java\\" + package_;
    }

 

  查詢表信息

  首先要鏈接數據庫,鏈接數據使用jdbc進行鏈接web

    /**
     * 數據鏈接相關
     */
    private static final String URL = "jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "123456";
    private static final String DRIVERCLASSNAME = "com.mysql.jdbc.Driver";
    /**
     * JDBC鏈接數據庫工具類
     */
    private static class DBConnectionUtil {

        static {
            // 一、加載驅動
            try {
                Class.forName(DRIVERCLASSNAME);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        /**
         * 返回一個Connection鏈接
         *
         * @return
         */
        public static Connection getConnection() {
            Connection conn = null;
            // 二、鏈接數據庫
            try {
                conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return conn;
        }

        /**
         * 關閉Connection,Statement鏈接
         *
         * @param conn
         * @param stmt
         */
        public static void close(Connection conn, Statement stmt) {
            try {
                conn.close();
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        /**
         * 關閉Connection,Statement,ResultSet鏈接
         *
         * @param conn
         * @param stmt
         * @param rs
         */
        public static void close(Connection conn, Statement stmt, ResultSet rs) {
            try {
                close(conn, stmt);
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

  獲取數據表的表機構信息(本系列用的是MySQL數據庫),經過查詢 information_schema 表,SQL:ajax

select column_name,data_type,column_comment,column_key,extra from information_schema.columns where table_name=?

  建立一個表結構對象,而後封裝一下方法:spring

    /**
     * 表結構行信息實體類
     */
    private class TableInfo {
        private String columnName;
        private String dataType;
        private String columnComment;
        private String columnKey;
        private String extra;

        TableInfo() {
        }

        String getColumnName() {
            return columnName;
        }

        void setColumnName(String columnName) {
            this.columnName = columnName;
        }

        String getDataType() {
            return dataType;
        }

        void setDataType(String dataType) {
            this.dataType = dataType;
        }

        String getColumnComment() {
            return columnComment;
        }

        void setColumnComment(String columnComment) {
            this.columnComment = columnComment;
        }

        String getColumnKey() {
            return columnKey;
        }

        void setColumnKey(String columnKey) {
            this.columnKey = columnKey;
        }

        String getExtra() {
            return extra;
        }

        void setExtra(String extra) {
            this.extra = extra;
        }
    }
    /**
     * 獲取表結構信息
     *
     * @return list
     */
    private List<TableInfo> getTableInfo() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        ArrayList<TableInfo> list = new ArrayList<>();
        try {
            conn = DBConnectionUtil.getConnection();
            String sql = "select column_name,data_type,column_comment,column_key,extra from information_schema.columns where table_name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, tableName);
            rs = ps.executeQuery();
            while (rs.next()) {
                TableInfo tableInfo = new TableInfo();
                //列名,所有轉爲小寫
                tableInfo.setColumnName(rs.getString("column_name").toLowerCase());
                //列類型
                tableInfo.setDataType(rs.getString("data_type"));
                //列註釋
                tableInfo.setColumnComment(rs.getString("column_comment"));
                //主鍵
                tableInfo.setColumnKey(rs.getString("column_key"));
                //主鍵類型
                tableInfo.setExtra(rs.getString("extra"));
                list.add(tableInfo);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            assert rs != null;
            DBConnectionUtil.close(conn, ps, rs);
        }
        return list;
    }

 

  那麼oracle應該怎麼查呢?sql

--表結構信息
select * from user_tab_columns where table_name='TB_USER'
--表字段註釋
select * from user_col_comments  where table_name='TB_USER'
--表註釋
select * from user_tab_comments  where table_name='TB_USER'

  咱們看一下系統都提供有哪些表,這...太多了

 

  數據處理

  數據處理,好比數據字段類型轉成java類型、字段的下劃線轉駝峯等,咱們封裝一下工具類:

    /**
     * 字符串處理工具類
     */
    private static class StringUtil {
        /**
         * 數據庫類型->JAVA類型
         *
         * @param dbType 數據庫類型
         * @return JAVA類型
         */
        private static String typeMapping(String dbType) {
            String javaType = "";
            if ("int|integer".contains(dbType)) {
                javaType = "Integer";
            } else if ("float|double|decimal|real".contains(dbType)) {
                javaType = "Double";
            } else if ("date|time|datetime|timestamp".contains(dbType)) {
                javaType = "Date";
            } else {
                javaType = "String";
            }
            return javaType;
        }

        /**
         * 駝峯轉換爲下劃線
         */
        public static String underscoreName(String camelCaseName) {
            StringBuilder result = new StringBuilder();
            if (camelCaseName != null && camelCaseName.length() > 0) {
                result.append(camelCaseName.substring(0, 1).toLowerCase());
                for (int i = 1; i < camelCaseName.length(); i++) {
                    char ch = camelCaseName.charAt(i);
                    if (Character.isUpperCase(ch)) {
                        result.append("_");
                        result.append(Character.toLowerCase(ch));
                    } else {
                        result.append(ch);
                    }
                }
            }
            return result.toString();
        }

        /**
         * 首字母大寫
         */
        public static String captureName(String name) {
            char[] cs = name.toCharArray();
            cs[0] -= 32;
            return String.valueOf(cs);

        }

        /**
         * 下劃線轉換爲駝峯
         */
        public static String camelCaseName(String underscoreName) {
            StringBuilder result = new StringBuilder();
            if (underscoreName != null && underscoreName.length() > 0) {
                boolean flag = false;
                for (int i = 0; i < underscoreName.length(); i++) {
                    char ch = underscoreName.charAt(i);
                    if ("_".charAt(0) == ch) {
                        flag = true;
                    } else {
                        if (flag) {
                            result.append(Character.toUpperCase(ch));
                            flag = false;
                        } else {
                            result.append(ch);
                        }
                    }
                }
            }
            return result.toString();
        }
    }

 

  文件處理

  文件處理好比建立文件夾、文件,將字符寫入文件等,咱們先獲取一下基礎路徑,並封裝一下文件工具類:

    /**
     * file工具類
     */
    private static class FileUtil {
        /**
         * 建立文件
         *
         * @param pathNameAndFileName 路徑跟文件名
         * @return File對象
         */
        private static File createFile(String pathNameAndFileName) {
            File file = new File(pathNameAndFileName);
            try {
                //獲取父目錄
                File fileParent = file.getParentFile();
                if (!fileParent.exists()) {
                    fileParent.mkdirs();
                }
                //建立文件
                if (!file.exists()) {
                    file.createNewFile();
                }
            } catch (Exception e) {
                file = null;
                System.err.println("新建文件操做出錯");
                e.printStackTrace();
            }
            return file;
        }

        /**
         * 字符流寫入文件
         *
         * @param file         file對象
         * @param stringBuffer 要寫入的數據
         */
        private static void fileWriter(File file, StringBuffer stringBuffer) {
            //字符流
            try {
                FileWriter resultFile = new FileWriter(file, true);//true,則追加寫入 false,則覆蓋寫入
                PrintWriter myFile = new PrintWriter(resultFile);
                //寫入
                myFile.println(stringBuffer.toString());

                myFile.close();
                resultFile.close();
            } catch (Exception e) {
                System.err.println("寫入操做出錯");
                e.printStackTrace();
            }
        }
    }

 

  

  建立代碼

  根據咱們項目的路徑規範,代碼編寫規範,咱們定義好文件的模板,並封裝成對應的方法

    /**
     * 建立pojo實體類
     */
    private void createPojo(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "pojo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ".java");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "pojo;\n" +
                        "\n" +
                        "import lombok.Data;\n" +
                        "import javax.persistence.*;\n" +
                        "import java.io.Serializable;\n" +
                        "import java.util.Date;\n" +
                        "\n" +
                        "@Entity\n" +
                        "@Table(name = \"" + tableName + "\")\n" +
                        "@Data\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " implements Serializable {\n"
        );
        //遍歷設置屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                stringBuffer.append("    @Id\n");
            }
            //自增
            if ("auto_increment".equals(tableInfo.getExtra())) {
                stringBuffer.append("    @GeneratedValue(strategy= GenerationType.IDENTITY)\n");
            }
            stringBuffer.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
        }
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }
    /**
     * 建立vo類
     */
    private void createVo(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "vo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo.java");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "vo;\n" +
                        "\n" +
"import "+ basePackage_.replaceAll("\\\\", ".") +" common.pojo.PageCondition;"+ "import lombok.Data;\n" + "import java.io.Serializable;\n" + "import java.util.Date;\n" + "\n" + "@Data\n" + "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo extends PageCondition implements Serializable {\n" ); //遍歷設置屬性 for (TableInfo tableInfo : tableInfos) { stringBuffer.append(" private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n"); } stringBuffer.append("}"); FileUtil.fileWriter(file, stringBuffer); }
    /**
     * 建立repository類
     */
    private void createRepository(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "repository\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "repository;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.repository.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import org.springframework.stereotype.Repository;\n" +
                        "\n" +
                        "@Repository\n" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository extends CommonRepository<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }
    /**
     * 建立service類
     */
    private void createService(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "\n" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service extends CommonService<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);

        //Impl
        File file1 = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl.java");
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1.append(
                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "repository." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
                        "import org.springframework.stereotype.Service;\n" +
                        "import org.springframework.transaction.annotation.Transactional;\n" +
                        "import javax.persistence.EntityManager;\n" +
                        "import javax.persistence.PersistenceContext;\n" +
                        "\n" +
                        "@Service\n" +
                        "@Transactional\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl extends CommonServiceImpl<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> implements " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service{"
        );
        stringBuffer1.append("\n\n");
        stringBuffer1.append(
                "    @PersistenceContext\n" +
                        "    private EntityManager em;\n");

        stringBuffer1.append("" +
                "    @Autowired\n" +
                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository " + StringUtil.camelCaseName(tableName) + "Repository;\n");
        stringBuffer1.append("}");
        FileUtil.fileWriter(file1, stringBuffer1);
    }
    /**
     * 建立controller類
     */
    private void createController(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "controller\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "controller;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.controller.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "service." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
                        "import org.springframework.web.bind.annotation.*;\n" +
                        "\n" +
                        "@RestController\n" +
                        "@RequestMapping(\"/" + StringUtil.camelCaseName(tableName) + "/\")\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller extends CommonController<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("" +
                "    @Autowired\n" +
                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service " + StringUtil.camelCaseName(tableName) + "Service;\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }

   須要注意的是:目前生成的pojo的主鍵,只用了@Id聲明該屬性爲表主鍵,尚缺一個主鍵生成策略,這個須要根據本身的狀況來選擇主鍵生成策略

  PS:缺乏主鍵生成策略或者設置錯誤將會出現如下問題:

  程序不報錯,JPA查詢出來的數據長度正常,內容都是重複的,但mysql數據庫運行查詢語句結果正常

    /*
        JPA提供的四種主鍵生成策略
        GenerationType.TABLE:使用一個特定的數據庫表格來保存主鍵。 
        GenerationType.SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。 
        GenerationType.IDENTITY:主鍵由數據庫自動生成(主要是自動增加型) 
        GenerationType.AUTO:主鍵由程序控制。
     */
    @GeneratedValue(strategy = GenerationType.IDENTITY)

 

  提供一個方法讓外部直接調用

    /**
     * 快速建立,供外部調用,調用以前先設置一下項目的基礎路徑
     */
    private String create() {
        List<TableInfo> tableInfo = getTableInfo();
        createPojo(tableInfo);
        createVo(tableInfo);
        createRepository(tableInfo);
        createService(tableInfo);
        createController(tableInfo);
        return tableName + " 後臺代碼生成完畢!";
    }

 

  效果演示

  main方法運行

    public static void main(String[] args) {
        String[] tables = {"tb_user"};
        for (int i = 0; i < tables.length; i++) {
            String msg = new CodeDOM(tables[i]).create();
            System.out.println(msg);
        }
    }

 

   生成代碼

  咱們查看一下生成的代碼

package cn.huanzi.springbootjpa.tbuser.pojo;

import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name = "tb_user")
@Data
public class TbUser implements Serializable {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;//表id

    private String username;//用戶名

    private String password;//密碼

    private Date created;//建立時間

    private Integer descriptionId;//關聯詳情id

}
package cn.huanzi.springbootjpa.tbuser.vo;

import lombok.Data;
import java.io.Serializable;
import java.util.Date;

@Data
public class TbUserVo extends PageCondition implements Serializable {
    private Integer id;//表id

    private String username;//用戶名

    private String password;//密碼

    private Date created;//建立時間

    private Integer descriptionId;//關聯詳情id

}
package cn.huanzi.springbootjpa.tbuser.repository;

import cn.huanzi.springbootjpa.common.repository.*;
import cn.huanzi.springbootjpa.tbuser.pojo.TbUser;
import org.springframework.stereotype.Repository;

@Repository
public interface TbUserRepository extends CommonRepository<TbUser, Integer> {
}
package cn.huanzi.springbootjpa.tbuser.service;

import cn.huanzi.springbootjpa.common.service.*;
import cn.huanzi.springbootjpa.tbuser.pojo.TbUser;
import cn.huanzi.springbootjpa.tbuser.vo.TbUserVo;

public interface TbUserService extends CommonService<TbUserVo, TbUser, Integer> {
}
package cn.huanzi.springbootjpa.tbuser.service;

import cn.huanzi.springbootjpa.common.service.*;
import cn.huanzi.springbootjpa.tbuser.pojo.TbUser;
import cn.huanzi.springbootjpa.tbuser.vo.TbUserVo;
import cn.huanzi.springbootjpa.tbuser.repository.TbUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Service
@Transactional
public class TbUserServiceImpl extends CommonServiceImpl<TbUserVo, TbUser, Integer> implements TbUserService{

    @PersistenceContext
    private EntityManager em;
    @Autowired
    private TbUserRepository tbUserRepository;
}
package cn.huanzi.springbootjpa.tbuser.controller;

import cn.huanzi.springbootjpa.common.controller.*;
import cn.huanzi.springbootjpa.tbuser.pojo.TbUser;
import cn.huanzi.springbootjpa.tbuser.vo.TbUserVo;
import cn.huanzi.springbootjpa.tbuser.service.TbUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/tbUser/")
public class TbUserController extends CommonController<TbUserVo, TbUser, Integer> {
    @Autowired
    private TbUserService tbUserService;
}

  咱們啓動項目

  依次訪問基礎接口:

  get接口

  http://localhost:10086/tbUser/get/1

 

  page接口

  http://localhost:10086/tbUser/page?page=1&rows=10

  

   list接口

  http://localhost:10086/tbUser/list

 

 

 

  save接口

  (插入跟更新)

  沒有id或id不存在,爲插入,http://localhost:10086/tbUser/save?username=張麻子&password=123

  id已存在,則爲更新,注意:這裏的更新是你的字段是什麼jpa就幫你存什麼,若是想要實現只更新接參對象有值的字段,應該先用id去同步數據,再更新,

 

  delete接口

  http://localhost:10086/tbUser/delete/15

  擴展

  一、有一些同窗會發現,代碼生成後idea並無幫咱們掃描出來,這時候咱們能夠手動去刷新一下,對着咱們的項目右鍵,而後刷新

  二、我的以爲代碼生成用groovy更加合適,只是我如今對它的語法使用還不熟悉,後面咱們能夠嘗試一下使用groovy來生成代碼,在idea裏使用groovy生成代碼:

  groovy文件的位置:

  使用方法:用idea的datebase鏈接數據庫後,對着表右擊

 

  後記

  這套代碼的風格是單表繼承通用CRUD、分頁、排序接口,在啓動類的同級目錄下面,按一張表一個目錄分層級存放文件,技術選型:springboot + thymeleaf + springdata-jpa + mysql,pojo實體對象負責ORM框架與數據庫的映射,vo對象負責接參、傳參,vo與pojo經過CopyUtil工具類進相互轉換

  一人挖井,全村喝水;有了這一套基礎代碼跟代碼自動生成單表基礎增、刪、改、查接口,咱們的開發效率大大提升

 

  完整代碼

package cn.huanzi.qch.springbootjpa.util;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 自動生成代碼
 */
public class CodeDOM {

    /**
     * 構造參數,出入表名
     */
    private CodeDOM(String tableName) {
        this.tableName = tableName;
        basePackage_ = "cn\\huanzi\\qch\\springbootjpa\\";
        package_ = basePackage_ + StringUtil.camelCaseName(tableName).toLowerCase() + "\\";
        //System.getProperty("user.dir") 獲取的是項目所在路徑,若是咱們是子項目,則須要添加一層路徑
        basePath = System.getProperty("user.dir") + "\\springboot-jpa\\src\\main\\java\\" + package_;
    }

    /**
     * 數據鏈接相關
     */
    private static final String URL = "jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "123456";
    private static final String DRIVERCLASSNAME = "com.mysql.jdbc.Driver";
    /**
     * 表名
     */
    private String tableName;

    /**
     * 基礎路徑
     */
    private String basePackage_;
    private String package_;
    private String basePath;

    /**
     * 建立pojo實體類
     */
    private void createPojo(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "pojo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ".java");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "pojo;\n" +
                        "\n" +
                        "import lombok.Data;\n" +
                        "import javax.persistence.*;\n" +
                        "import java.io.Serializable;\n" +
                        "import java.util.Date;\n" +
                        "\n" +
                        "@Entity\n" +
                        "@Table(name = \"" + tableName + "\")\n" +
                        "@Data\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + " implements Serializable {\n"
        );
        //遍歷設置屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                stringBuffer.append("    @Id\n");
            }
            //自增
            if ("auto_increment".equals(tableInfo.getExtra())) {
                stringBuffer.append("    @GeneratedValue(strategy= GenerationType.IDENTITY)\n");
            }
            stringBuffer.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
        }
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }

    /**
     * 建立vo類
     */
    private void createVo(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "vo\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo.java");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "vo;\n" +
                        "\n" +
                        "import "+ basePackage_.replaceAll("\\\\", ".") +" common.pojo.PageCondition;"+
                        "import lombok.Data;\n" +
                        "import java.io.Serializable;\n" +
                        "import java.util.Date;\n" +
                        "\n" +
                        "@Data\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo extends PageCondition implements Serializable {\n"
        );
        //遍歷設置屬性
        for (TableInfo tableInfo : tableInfos) {
            stringBuffer.append("    private " + StringUtil.typeMapping(tableInfo.getDataType()) + " " + StringUtil.camelCaseName(tableInfo.getColumnName()) + ";//" + tableInfo.getColumnComment() + "\n\n");
        }
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }

    /**
     * 建立repository類
     */
    private void createRepository(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "repository\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "repository;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.repository.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import org.springframework.stereotype.Repository;\n" +
                        "\n" +
                        "@Repository\n" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository extends CommonRepository<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }

    /**
     * 建立service類
     */
    private void createService(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "\n" +
                        "public interface " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service extends CommonService<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);

        //Impl
        File file1 = FileUtil.createFile(basePath + "service\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl.java");
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1.append(
                "package " + package_.replaceAll("\\\\", ".") + "service;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.service.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "repository." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
                        "import org.springframework.stereotype.Service;\n" +
                        "import org.springframework.transaction.annotation.Transactional;\n" +
                        "import javax.persistence.EntityManager;\n" +
                        "import javax.persistence.PersistenceContext;\n" +
                        "\n" +
                        "@Service\n" +
                        "@Transactional\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "ServiceImpl extends CommonServiceImpl<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> implements " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service{"
        );
        stringBuffer1.append("\n\n");
        stringBuffer1.append(
                "    @PersistenceContext\n" +
                        "    private EntityManager em;\n");

        stringBuffer1.append("" +
                "    @Autowired\n" +
                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Repository " + StringUtil.camelCaseName(tableName) + "Repository;\n");
        stringBuffer1.append("}");
        FileUtil.fileWriter(file1, stringBuffer1);
    }

    /**
     * 建立controller類
     */
    private void createController(List<TableInfo> tableInfos) {
        File file = FileUtil.createFile(basePath + "controller\\" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller.java");
        StringBuffer stringBuffer = new StringBuffer();
        String t = "String";
        //遍歷屬性
        for (TableInfo tableInfo : tableInfos) {
            //主鍵
            if ("PRI".equals(tableInfo.getColumnKey())) {
                t = StringUtil.typeMapping(tableInfo.getDataType());
            }
        }
        stringBuffer.append(
                "package " + package_.replaceAll("\\\\", ".") + "controller;\n" +
                        "\n" +
                        "import " + basePackage_.replaceAll("\\\\", ".") + "common.controller.*;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "pojo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ";\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "vo." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo;\n" +
                        "import " + package_.replaceAll("\\\\", ".") + "service." + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
                        "import org.springframework.web.bind.annotation.*;\n" +
                        "\n" +
                        "@RestController\n" +
                        "@RequestMapping(\"/" + StringUtil.camelCaseName(tableName) + "/\")\n" +
                        "public class " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Controller extends CommonController<" + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Vo, " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + ", " + t + "> {"
        );
        stringBuffer.append("\n");
        stringBuffer.append("" +
                "    @Autowired\n" +
                "    private " + StringUtil.captureName(StringUtil.camelCaseName(tableName)) + "Service " + StringUtil.camelCaseName(tableName) + "Service;\n");
        stringBuffer.append("}");
        FileUtil.fileWriter(file, stringBuffer);
    }

    /**
     * 獲取表結構信息
     *
     * @return list
     */
    private List<TableInfo> getTableInfo() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        ArrayList<TableInfo> list = new ArrayList<>();
        try {
            conn = DBConnectionUtil.getConnection();
            String sql = "select column_name,data_type,column_comment,column_key,extra from information_schema.columns where table_name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, tableName);
            rs = ps.executeQuery();
            while (rs.next()) {
                TableInfo tableInfo = new TableInfo();
                //列名,所有轉爲小寫
                tableInfo.setColumnName(rs.getString("column_name").toLowerCase());
                //列類型
                tableInfo.setDataType(rs.getString("data_type"));
                //列註釋
                tableInfo.setColumnComment(rs.getString("column_comment"));
                //主鍵
                tableInfo.setColumnKey(rs.getString("column_key"));
                //主鍵類型
                tableInfo.setExtra(rs.getString("extra"));
                list.add(tableInfo);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            assert rs != null;
            DBConnectionUtil.close(conn, ps, rs);
        }
        return list;
    }

    /**
     * file工具類
     */
    private static class FileUtil {
        /**
         * 建立文件
         *
         * @param pathNameAndFileName 路徑跟文件名
         * @return File對象
         */
        private static File createFile(String pathNameAndFileName) {
            File file = new File(pathNameAndFileName);
            try {
                //獲取父目錄
                File fileParent = file.getParentFile();
                if (!fileParent.exists()) {
                    fileParent.mkdirs();
                }
                //建立文件
                if (!file.exists()) {
                    file.createNewFile();
                }
            } catch (Exception e) {
                file = null;
                System.err.println("新建文件操做出錯");
                e.printStackTrace();
            }
            return file;
        }

        /**
         * 字符流寫入文件
         *
         * @param file         file對象
         * @param stringBuffer 要寫入的數據
         */
        private static void fileWriter(File file, StringBuffer stringBuffer) {
            //字符流
            try {
                FileWriter resultFile = new FileWriter(file, false);//true,則追加寫入 false,則覆蓋寫入
                PrintWriter myFile = new PrintWriter(resultFile);
                //寫入
                myFile.println(stringBuffer.toString());

                myFile.close();
                resultFile.close();
            } catch (Exception e) {
                System.err.println("寫入操做出錯");
                e.printStackTrace();
            }
        }
    }

    /**
     * 字符串處理工具類
     */
    private static class StringUtil {
        /**
         * 數據庫類型->JAVA類型
         *
         * @param dbType 數據庫類型
         * @return JAVA類型
         */
        private static String typeMapping(String dbType) {
            String javaType = "";
            if ("int|integer".contains(dbType)) {
                javaType = "Integer";
            } else if ("float|double|decimal|real".contains(dbType)) {
                javaType = "Double";
            } else if ("date|time|datetime|timestamp".contains(dbType)) {
                javaType = "Date";
            } else {
                javaType = "String";
            }
            return javaType;
        }

        /**
         * 駝峯轉換爲下劃線
         */
        public static String underscoreName(String camelCaseName) {
            StringBuilder result = new StringBuilder();
            if (camelCaseName != null && camelCaseName.length() > 0) {
                result.append(camelCaseName.substring(0, 1).toLowerCase());
                for (int i = 1; i < camelCaseName.length(); i++) {
                    char ch = camelCaseName.charAt(i);
                    if (Character.isUpperCase(ch)) {
                        result.append("_");
                        result.append(Character.toLowerCase(ch));
                    } else {
                        result.append(ch);
                    }
                }
            }
            return result.toString();
        }

        /**
         * 首字母大寫
         */
        public static String captureName(String name) {
            char[] cs = name.toCharArray();
            cs[0] -= 32;
            return String.valueOf(cs);

        }

        /**
         * 下劃線轉換爲駝峯
         */
        public static String camelCaseName(String underscoreName) {
            StringBuilder result = new StringBuilder();
            if (underscoreName != null && underscoreName.length() > 0) {
                boolean flag = false;
                for (int i = 0; i < underscoreName.length(); i++) {
                    char ch = underscoreName.charAt(i);
                    if ("_".charAt(0) == ch) {
                        flag = true;
                    } else {
                        if (flag) {
                            result.append(Character.toUpperCase(ch));
                            flag = false;
                        } else {
                            result.append(ch);
                        }
                    }
                }
            }
            return result.toString();
        }
    }

    /**
     * JDBC鏈接數據庫工具類
     */
    private static class DBConnectionUtil {

        {
            // 一、加載驅動
            try {
                Class.forName(DRIVERCLASSNAME);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        /**
         * 返回一個Connection鏈接
         *
         * @return
         */
        public static Connection getConnection() {
            Connection conn = null;
            // 二、鏈接數據庫
            try {
                conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return conn;
        }

        /**
         * 關閉Connection,Statement鏈接
         *
         * @param conn
         * @param stmt
         */
        public static void close(Connection conn, Statement stmt) {
            try {
                conn.close();
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        /**
         * 關閉Connection,Statement,ResultSet鏈接
         *
         * @param conn
         * @param stmt
         * @param rs
         */
        public static void close(Connection conn, Statement stmt, ResultSet rs) {
            try {
                close(conn, stmt);
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 表結構行信息實體類
     */
    private class TableInfo {
        private String columnName;
        private String dataType;
        private String columnComment;
        private String columnKey;
        private String extra;

        TableInfo() {
        }

        String getColumnName() {
            return columnName;
        }

        void setColumnName(String columnName) {
            this.columnName = columnName;
        }

        String getDataType() {
            return dataType;
        }

        void setDataType(String dataType) {
            this.dataType = dataType;
        }

        String getColumnComment() {
            return columnComment;
        }

        void setColumnComment(String columnComment) {
            this.columnComment = columnComment;
        }

        String getColumnKey() {
            return columnKey;
        }

        void setColumnKey(String columnKey) {
            this.columnKey = columnKey;
        }

        String getExtra() {
            return extra;
        }

        void setExtra(String extra) {
            this.extra = extra;
        }
    }

    /**
     * 快速建立,供外部調用,調用以前先設置一下項目的基礎路徑
     */
    private String create() {
        List<TableInfo> tableInfo = getTableInfo();
        createPojo(tableInfo);
        createVo(tableInfo);
        createRepository(tableInfo);
        createService(tableInfo);
        createController(tableInfo);
        System.out.println("生成路徑位置:" + basePath);
        return tableName + " 後臺代碼生成完畢!";
    }

    public static void main(String[] args) {
        String[] tables = {"tb_description"};
        for (String table : tables) {
            String msg = new CodeDOM(table).create();
            System.out.println(msg);
        }
    }
}
CodeDOM

 

  補充

  一、發現了一個問題,咱們在自動生成controller裏有個地方是寫死的...

  改一下,順便升級一下CodeDOM類,我已經更新了博客文章,如今你看的文章已是正確的,且是升級後的版本。 

 

  二、有細心園友發現咱們漏貼了CommonController的代碼,咱們在這裏補貼一下,另外說一下,其餘的common代碼在jpa升級版中 SpringBoot系列——Spring-Data-JPA(升級版),但裏面當時咱們只寫了service層、repository層的通用代碼,以及通信對象和實體與Vo轉換工具等其餘公用代碼,controller是在本文才加上去的。

/**
 * 通用Controller
 *
 * @param <V> 實體類Vo
 * @param <E> 實體類
 * @param <T> id主鍵類型
 */
public class CommonController<V, E,T> {

    @Autowired
    private CommonService<V, E,T> commonService;
    
    /*
        CRUD、分頁、排序測試
     */
    //    @PostMapping("page")
    @RequestMapping("page")
    public Result<PageInfo<V>> page(V entityVo) {
        return commonService.page(entityVo);
    }

    //    @PostMapping("list")
    @RequestMapping("list")
    public Result<List<V>> list(V entityVo) {
        return commonService.list(entityVo);
    }

    //    @GetMapping("get/{id}")
    @RequestMapping("get/{id}")
    public Result<V> get( @PathVariable("id") T id) {
        return commonService.get(id);
    }

    //    @PostMapping("save")
    @RequestMapping("save")
    public Result<V> save( V entityVo) {
        return commonService.save(entityVo);
    }

    //    @GetMapping("delete/{id}")
    @RequestMapping("delete/{id}")
    public Result<T> delete( @PathVariable("id") T id) {
        /*
        批量刪除
        @DeleteMapping("deleteBatch")
        public Result<T> deleteBatch(@RequestBody List<String> ids){}
        前端調用:
        $.ajax({
            url: ctx + "deleteBatch",
            type: "DELETE",
            data: JSON.stringify([id1,id2]),
            dataType: "JSON",
            contentType: 'application/json',
            success: function (data) { 

            }
        });
         */
        return commonService.delete(id);
    }
}
CommonController

 

  代碼開源

  代碼已經開源、託管到個人GitHub、碼雲:

  GitHub:https://github.com/huanzi-qch/springBoot

  碼雲:https://gitee.com/huanzi-qch/springBoot

相關文章
相關標籤/搜索