眾所周知,我們平常在做專案的時候,資料庫中複雜的表和列導致我們手寫很破煩的實體類,雖然都是工具生成,但是屬性多了,也會感覺到很破煩!!!今天我們來做一個簡單的資料庫表生成相應的實體類!!!
主要依據四條sql語句:
# 查詢所有的資料庫
SELECT schema_name FROM information_schema.SCHEMATA;
# 查詢資料庫中表的名字
SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'students';
# 獲取列名和型別
SELECT column_name,data_type FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'students' AND table_name='score';
# 查詢外來鍵關聯表和外來鍵列名
SELECT column_name, referenced_table_name FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema = 'scott' AND table_name='emp'
AND constraint_name = (SELECT constraint_name FROM TABLE_CONSTRAINTS WHERE table_schema = 'scott' AND table_name='emp' AND constraint_type='Foreign key');
複製程式碼
1、建立並匯入properties配置檔案和jar包
- 1、在專案下建立proFile資料夾,匯入DBCP連線池配置檔案mysql.dbcp.properties
程式碼如下:
########DBCP配置檔案##########
#非自動提交
defaultAutoCommit=false
#驅動名
driverClassName=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://127.0.0.1:3306/information_schema
#使用者名稱
username=root
#密碼
password=6831245
#初始連線數
initialSize=1
#最大活躍數
maxTotal=30
#最大空閒數
maxIdle=10
#最小空閒數
minIdle=1
#最長等待時間(毫秒)
maxWaitMillis=5000
#程式中的連線不使用後是否被連線池回收(該版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#連線在所指定的秒數內未使用才會被刪除(秒)
removeAbandonedTimeout=5
#連線程式碼
#Properties ps = new Properties();
#使用類載入器在專案的src目錄下載入指定檔名的檔案,來封裝輸入流
#InputStream fis =ConnUtil.class.getClassLoader().getResourceAsStream("dbcp.properties");
#也可以使用檔案輸入流載入專案路徑下的檔案,封裝為檔案輸入流物件鍵盤輸入物件
#FileInputStream fis = new FileInputStream("專案下檔案路徑/mysql.dbcp.properties");
#ps.load(fis);
#DataSource ds = BasicDataSourceFactory.createDataSource(ps);
#conn = ds.getConnection();
複製程式碼
- 2、匯入4個相關jar包
2、建立MVC結構的專案結構
3、建立view層
程式碼如下: MainView.java
package com.yueqian.entityCreater.view;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.yueqian.entityCreater.controller.MainViewLis;
import com.yueqian.entityCreater.model.dao.DBDao;
public class MainView extends JFrame{
//建立資料庫選擇下拉框
private JComboBox<String> dbBox = null;
//建立資料庫表的列表
private JList<String> tabLis = null;
//建立生成實體類按鈕
private JButton createBtn = null;
//獲取所有資料庫名稱
private Vector<String> dbNames = null;
//獲取所有表名稱
private Vector<String> tabNames = null;
public MainView() {
super("Entity Creater");
this.setSize(280,300);
this.setLocationRelativeTo(null);
//新增元件
addComponent();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
private void addComponent() {
dbNames = DBDao.getInstance().getDbNames();
//建立資料庫下拉框
dbBox = new JComboBox<String>(dbNames);
//建立皮膚
JPanel dbPan = new JPanel(new FlowLayout(FlowLayout.LEFT,10,10));
//新增標籤到皮膚
dbPan.add(new JLabel("資料庫名稱:"));
//新增資料庫下拉選單框
dbPan.add(dbBox);
//新增皮膚到北部
this.add(dbPan,BorderLayout.NORTH);
tabNames = DBDao.getInstance().getTableNames(dbNames.get(0));
//新增表名資訊到展示列表
this.tabLis = new JList<String>(tabNames);
//建立表名皮膚 (使用邊界佈局管理器)
JPanel tabPan = new JPanel(new BorderLayout());
//產生邊線
tabPan.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),"表資訊:"));
//將表格列表包裹進皮膚中,有滾動條
JScrollPane js = new JScrollPane(tabLis);
tabPan.add(js);
//將表格皮膚新增到視窗
this.add(tabPan);
//構造按鈕
createBtn = new JButton("生成Entity");
//建立按鈕皮膚
JPanel btnPan = new JPanel(new FlowLayout(FlowLayout.LEADING,10,10));
//將按鈕新增到按鈕皮膚
btnPan.add(createBtn);
//新增皮膚到南部
this.add(btnPan,BorderLayout.SOUTH);
//新增監聽器
MainViewLis mvLis = new MainViewLis(this);
this.dbBox.addItemListener(mvLis);
this.createBtn.addActionListener(mvLis);
}
public JComboBox<String> getDbBox() {
return dbBox;
}
public void setDbBox(JComboBox<String> dbBox) {
this.dbBox = dbBox;
}
public JList<String> getTabLis() {
return tabLis;
}
public void setTabLis(JList<String> tabLis) {
this.tabLis = tabLis;
}
public Vector<String> getDbNames() {
return dbNames;
}
public void setDbNames(Vector<String> dbNames) {
this.dbNames = dbNames;
}
public Vector<String> getTabNames() {
return tabNames;
}
public void setTabNames(Vector<String> tabNames) {
this.tabNames = tabNames;
}
}
複製程式碼
4、建立DBCPProUtil類(配置檔案連線池連線資料庫)
程式碼如下: DBCPProUtil.java
package com.yueqian.entityCreater.util;
/**
* 配置檔案方式連線池工具類
* @author LinChi
*
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
public class DBCPProUtil {
private static BasicDataSource bs;
/**
* 配置檔案方式連線資料庫
* @return
*/
public static Connection getConnection() {
//建立類載入器方式檔案輸入流物件
FileInputStream fis = null;
if(bs == null) {
//建立屬性物件 從屬性檔案建立屬性資訊
Properties ps = new Properties();
try {
//將屬性檔案封裝成檔案輸入流
//可以使用檔案輸入流載入專案路徑下的檔案,封裝為檔案輸入流物件鍵盤輸入物件
// fis = new FileInputStream("dbproperties/mysql.dbcp.properties");
//也可以使用類載入器在專案的src目錄下載入指定檔名的檔案,來封裝輸入流
//注意:使用類載入機制記載配置檔案,配置檔案必須為src目錄下
// fis = DBCPProUtil.class.getClassLoader().getResourceAsStream("mysql.dbcp.properties");
fis = new FileInputStream("proFile/mysql.dbcp.properties");
//讓屬性檔案通過屬性物件讀取檔案輸入流中的屬性資訊
ps.load(fis);
//使用DBCP工廠類建立核心類BasicDataSource,將屬性檔案物件出入
//自動設定屬性資訊配置資料來源 (工廠模式)
//注意:屬性檔案中的key大小寫是固定的,利用反射自動獲取key值
bs = BasicDataSourceFactory.createDataSource(ps);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
return bs.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 關閉連線池物件
*/
public static void closeDbcp() {
if(bs != null) {
try {
bs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 關閉資料庫
* @param conn 連線
* @param st 處理sql物件
* @param rs 查詢結果集
*/
public static void closeAll(Connection conn,Statement st,ResultSet rs) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(st != null) {
try {
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
複製程式碼
5、建立Model層
1、建立持久層
程式碼如下: DBDao.java
package com.yueqian.entityCreater.model.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.swing.JOptionPane;
import com.yueqian.entityCreater.util.DBCPProUtil;
/**
* 資料持久層
* @author LinChi
*
*/
public class DBDao {
//使用單例模式
private static DBDao dbDao = null;
private DBDao() {
}
public static DBDao getInstance() {
if(dbDao == null) {
dbDao = new DBDao();
}
return dbDao;
}
/**
* 查詢所有資料庫名
*/
public Vector<String> getDbNames(){
//建立vector
Vector<String> vector = new Vector<String>();
//建立sql語句
String sql = "SELECT schema_name FROM information_schema.SCHEMATA";
//獲得連線
Connection conn = DBCPProUtil.getConnection();
//判斷是否連線成功
if(conn == null) {
JOptionPane.showMessageDialog(null, "資料庫連線失敗,請檢查連線檔案,在proFile/mysql.dbcp.properties中!","錯誤",JOptionPane.ERROR_MESSAGE);
return vector;
}
//建立預處理sql物件
PreparedStatement pst = null;
//執行結果集
ResultSet rs = null;
try {
pst = conn.prepareStatement(sql);
rs = pst.executeQuery();
while(rs.next()) {
vector.add(rs.getString(1));
}
//提交事務
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
//回滾事務
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
DBCPProUtil.closeAll(conn, pst, rs);
}
return vector;
}
/**
* 查詢指定資料庫中表的名字
*/
public Vector<String> getTableNames(String dbName){
//建立vector
Vector<String> vector = new Vector<String>();
//建立sql語句
String sql = "SELECT table_name FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?";
//獲得連線
Connection conn = DBCPProUtil.getConnection();
//判斷是否連線成功
if(conn == null) {
JOptionPane.showMessageDialog(null, "資料庫連線失敗,請檢查連線檔案,在proFile/mysql.dbcp.properties中!","錯誤",JOptionPane.ERROR_MESSAGE);
return vector;
}
//建立預處理sql物件
PreparedStatement pst = null;
//設定引數
//執行結果集
ResultSet rs = null;
try {
pst = conn.prepareStatement(sql);
pst.setString(1, dbName);
rs = pst.executeQuery();
while(rs.next()) {
vector.add(rs.getString(1));
}
//提交事務
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
//回滾事務
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
DBCPProUtil.closeAll(conn, pst, rs);
}
return vector;
}
/**
* 查詢指定資料庫中列的資訊
*/
public Map<String,String> getTabColumns(String dbName,String tabName){
//建立Map
Map<String,String> map = new HashMap<String,String>();
//建立sql語句
String sql = "SELECT column_name,data_type FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND table_name=?";
//獲得連線
Connection conn = DBCPProUtil.getConnection();
//判斷是否連線成功
if(conn == null) {
JOptionPane.showMessageDialog(null, "資料庫連線失敗,請檢查連線檔案,在proFile/mysql.dbcp.properties中!","錯誤",JOptionPane.ERROR_MESSAGE);
return map;
}
//建立預處理sql物件
PreparedStatement pst = null;
//執行結果集
ResultSet rs = null;
try {
pst = conn.prepareStatement(sql);
pst.setString(1, dbName);
pst.setString(2,tabName);
rs = pst.executeQuery();
while(rs.next()) {
map.put(rs.getString(1),rs.getString(2));
}
//提交事務
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
//回滾事務
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
DBCPProUtil.closeAll(conn, pst, rs);
}
return map;
}
}
複製程式碼
2、建立實體類工具
程式碼如下:CreateEntityUtil.java
package com.yueqian.entityCreater.model.dao;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Map;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
* 建立實體類工具
* @author LinChi
*
*/
public class CreateEntityUtil {
private static final String SPACE =" ";
public static void writerEntityFile(String tabName,Map<String, String> colMap) {
//建立輸出檔案
File outputDir = new File("output");
//判斷檔案是否存在
if(!outputDir.isDirectory()) {
outputDir.mkdir();
}
//獲得類名
String classStr = getClassStr(tabName,colMap);
//獲取檔名
String fileName = getClassName(tabName)+".java";
//建立寫出檔案
File javaFile = new File(outputDir,fileName);
//判斷檔案是否存在並覆蓋
if(javaFile.exists()) {
if(JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(null,"所選"+fileName+"檔案已經存在,是否覆蓋?","提示",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE)) {
return;
}
}
//輸出流
FileOutputStream out = null;
OutputStreamWriter osw = null;
try {
out = new FileOutputStream(javaFile);
osw = new OutputStreamWriter(out);
osw.write(classStr.toCharArray());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(osw != null) {
try {
osw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(out!=null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 獲取所有Map字元
* @param tabName
* @param colMap
* @return
*/
private static String getClassStr(String tabName, Map<String, String> colMap) {
//獲取類名
String className = getClassName(tabName);
//定義儲存資料的StringBuffer
StringBuffer sb = new StringBuffer();
//定義getset方法
StringBuffer sbuf = new StringBuffer();
sb.append("public class ").append(className).append(" {").append("\r\n");
for ( Map.Entry<String, String> entry: colMap.entrySet()) {
//獲取列的型別
String dbType = entry.getValue();
//將列的型別轉換為java型別
String javaType = getJavaType(dbType);
//獲取列名
String dbName = entry.getKey();
//將列名轉換為屬性名
String filedName = getColumnName(dbName);
sb.append(SPACE).append("private ").append(javaType).append(" ").append(filedName).append(";\r\n");
//新增get和set方法
sbuf.append(getMethod(filedName,javaType));
sbuf.append(setMethod(filedName, javaType));
}
sb.append(sbuf).append("}\r\n");
return sb.toString();
}
/**
* 新增get方法
*/
private static String getMethod(String fieldName,String javaType) {
if(isStringEntity(fieldName,javaType)) {
return "";
}
StringBuffer sb = new StringBuffer();
sb.append(SPACE).append("public ").append(javaType).append(" get");
//將屬性名首字母大寫
sb.append(String.valueOf(fieldName.charAt(0)).toUpperCase());
//判斷屬性名是否為1個字元
if(fieldName.length() != 1) {
sb.append(fieldName.substring(1));
}
sb.append("() {\r\n").append(SPACE);
sb.append(SPACE).append("return this.").append(fieldName).append(";\r\n");
sb.append(SPACE).append("}\r\n");
return sb.toString();
}
/**
* set方法
*/
private static String setMethod(String fieldName,String javaType) {
if(isStringEntity(fieldName,javaType)) {
return "";
}
StringBuffer sb = new StringBuffer();
sb.append(SPACE).append("public void set").append(String.valueOf(fieldName.charAt(0)).toUpperCase());
if(fieldName.length() != 1) {
sb.append(fieldName.substring(1));
}
sb.append("(").append(javaType).append(SPACE).append(fieldName).append("){\r\n");
sb.append(SPACE).append(SPACE).append("this.").append(fieldName).append(" = ").append(fieldName).append(";\r\n");
sb.append(SPACE).append("}\r\n");
return sb.toString();
}
/**
* 將dbType轉換為javaType
* @param dbType
* @return
*/
private static String getJavaType(String dbType) {
if("int".equalsIgnoreCase(dbType) || "Integer".equalsIgnoreCase(dbType)) {
return "Integer";
}
if("float".equalsIgnoreCase(dbType) || "double".equalsIgnoreCase(dbType) || "decimal".equalsIgnoreCase(dbType)) {
return "Double";
}
if("varchar".equalsIgnoreCase(dbType) || "char".equalsIgnoreCase(dbType)) {
return "String";
}
if("date".equalsIgnoreCase(dbType) || "datetime".equalsIgnoreCase(dbType)) {
return "java.util.date";
}
return "";
}
/**
* 根據表名獲取類名
* @param tabName
* @return
*/
private static String getClassName(String tabName) {
if(isStringEntity(tabName)) {
return "";
}
//將表中帶_的字元去掉
tabName = getColumnName(tabName);
//將首字母大寫
String firstStr = String.valueOf(tabName.charAt(0)).toUpperCase();
//判斷是否單個字元為表名
if(tabName.trim().length() == 1) {
return firstStr+"Entity";
}
return firstStr+tabName.substring(1)+"Entity";
}
/**
* 將列名轉換為屬性名
* @param tabName
* @return
*/
private static String getColumnName(String colName) {
if(isStringEntity(colName)) {
return "";
}
//將所有欄位名轉換為小寫
colName = colName.toLowerCase();
StringBuffer sb = new StringBuffer();
for (int i = 0;i<colName.length();i++) {
String charStr = String.valueOf(colName.charAt(i));
if("_".equals(charStr)) {
i++;
//過濾是否以_結尾
if(i>=colName.length()) {
break;
}
charStr = String.valueOf(colName.charAt(i)).toUpperCase();
}
sb.append(charStr);
}
return sb.toString();
}
private static boolean isStringEntity(String ...colName) {
for(int i = 0;i<colName.length;i++) {
if(colName[i] == null || colName[i].trim().length()<=0) {
return true;
}
}
return false;
}
}
複製程式碼
6、建立controller層
建立監聽器
程式碼如下:MainViewLis.java
package com.yueqian.entityCreater.controller;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.swing.JOptionPane;
import com.yueqian.entityCreater.model.dao.CreateEntityUtil;
import com.yueqian.entityCreater.model.dao.DBDao;
import com.yueqian.entityCreater.view.MainView;
/**
* 主視窗監聽器
* @author LinChi
*
*/
public class MainViewLis implements ActionListener,ItemListener{
private MainView mainView;
public MainViewLis(MainView mainView) {
super();
this.mainView = mainView;
}
/**
* 變更所選內容
*/
@Override
public void itemStateChanged(ItemEvent e) {
//獲取資料庫名稱
String dbName = mainView.getDbBox().getSelectedItem().toString();
//獲取該庫對應的表資訊
Vector<String> tableNames = DBDao.getInstance().getTableNames(dbName);
//清理mainView上的表資訊
mainView.getTabNames().clear();
//將選擇的表的資訊新增到視窗中
mainView.getTabNames().addAll(tableNames);
//重新整理重繪資料表列表
mainView.getTabLis().repaint();
}
@Override
public void actionPerformed(ActionEvent e) {
//獲取資料庫名
String dbName = mainView.getDbBox().getSelectedItem().toString();
//獲取表名
List<String> tableList = mainView.getTabLis().getSelectedValuesList();
//判斷是否選擇表檔案
if(tableList.isEmpty()) {
JOptionPane.showMessageDialog(null, "請先選擇需要匯出的表!","錯誤",JOptionPane.ERROR_MESSAGE);
return;
}
//根據表名稱和庫名稱獲取列資訊 Map<表名,Map<列名,列型別>>
Map<String,Map<String,String>> map = new HashMap<String,Map<String,String>>();
//迴圈取出所有選擇的表的列資訊
for (String tableName : tableList) {
Map<String,String> tabColMap = DBDao.getInstance().getTabColumns(dbName,tableName);
map.put(tableName, tabColMap);
}
//迴圈輸出entity
for(Map.Entry<String,Map<String,String>> entrty:map.entrySet()) {
CreateEntityUtil.writerEntityFile(entrty.getKey(), entrty.getValue());
}
JOptionPane.showMessageDialog(null,"執行完畢!");
}
}
複製程式碼
7、建立程式入口類
程式碼如下:App.java
package com.yueqian.entityCreater.app;
import com.yueqian.entityCreater.view.MainView;
public class App {
public static void main(String[] args) {
new MainView();
}
}
複製程式碼
8、效果圖
選擇資料庫
一鍵生成 生成實體類如下:9、將專案導成jar檔案,方便執行
- 1、專案右鍵-> Export -> Runnable JAR file ->選擇位置finash
- 2、將proFile資料夾複製到和jar包平級的位置(資料夾下有properties配置檔案)
- 3、如果匯出的是jar包,則可直接執行
- 4、如果是壓縮檔案,則新建文字->字尾名改為.bat(批處理檔案),內容寫入java -jar entityCreater.jar,記得按個回車
- 5、執行批處理檔案即可執行
好了!小夥伴們,今天的分享就到此了!這兒沒有按照查詢到外來鍵生成相應的實體類,將外來鍵對應的實體類通過屬性傳遞。後面會逐步新增此功能,感興趣的小夥伴可以自己評論新增哦!這樣我們就不用自己手寫煩人的實體類了!!!