咱們在以前的實現了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; }
咱們啓動項目
依次訪問基礎接口:
http://localhost:10086/tbUser/get/1
http://localhost:10086/tbUser/page?page=1&rows=10
http://localhost:10086/tbUser/list
(插入跟更新)
沒有id或id不存在,爲插入,http://localhost:10086/tbUser/save?username=張麻子&password=123
id已存在,則爲更新,注意:這裏的更新是你的字段是什麼jpa就幫你存什麼,若是想要實現只更新接參對象有值的字段,應該先用id去同步數據,再更新,
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); } } }
一、發現了一個問題,咱們在自動生成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); } }
代碼已經開源、託管到個人GitHub、碼雲: