這是這個學期Java實訓課的課程設計,實訓的主要內容的JDBC連接操縱數據庫,選取駕考試題管理作為項目命題,總的來說這個項目很簡單,就是最基本的增刪查改。同樣的這次也是選用JavaFx做UI端,感覺雖然JavaFx沒有MFC那樣所見即所得,但自己也摸索了一些形式,配合支持FXML的JavaFX Scene Builder ,再加上點CSS,感覺像是在做網頁?博客大部分內容直接摘自實訓報告吧,當時為了湊字數,啰里啰嗦說了一堆廢話,湊合看吧。
github地址https://github.com/wkfvawl/JavaFX-DrivingTestMS
一、系統描述
隨着我國社會的不斷進步和發展,越來越多的家庭擁有汽車,人們把駕駛汽車作為外出游玩,上下班的第一選擇,因而大眾對駕駛技能考試的熱情越來越高漲,開發本系統的主要目的是為了給准備駕駛技能考試科目一、科目四的考生構建一個能夠進行增刪查改的數據庫。由於科目一和科目四只有單選題和判斷題,因而本數據庫只需要根據單選題和判斷題的特征,抽象出兩張表即可。
本駕考試題管理系統是一個管理試題資源的工具軟件,采用模塊化思想,基於Windows環境和Java平台提供的Derby數據庫,使用IDEA軟件作為開發環境,系統包括單選題管理和判斷題管理兩大功能模塊,每個大模塊下又包含添加試題、更新試題、刪除試題和查詢試題這四個子模塊。這樣的模塊化結構一方面可以減少各個模塊之間的依賴,降低系統開發的復雜度;另一方面也便於之后系統的維護和功能升級。
二、總體結構
1、系統結構設計
2、數據庫結構設計
本系統設計了2個表,抽象為兩個對象,繪制E-R圖。
ChoiceQuestion表:
用於記錄選擇題信息和答案
Number:題目編號
Content:題目內容
Pic:圖片名稱
Answer:正確答案
optionA:選項A
optionB:選項B
optionC:選項C
optionD:選項D
TFQuestion表:
用於記錄判斷題信息和答案
Number:題目編號
Content:題目內容
Pic:圖片名稱
Answer:正確答案
optionT:選項1
optionF:選項2
SQL建表語句如下:
create table ChoiceQuestion (number char(10) primary key,content varchar(100),pic varchar(50),optionA varchar(50),optionB varchar(50),optionC varchar(50),optionD varchar(50),answer char(2) ); create table TFQuestion (number char(10) primary key,content varchar(100),pic varchar(50),optionA char(6) default '正確',optionB char(6) default '錯誤',answer char(2) );
三、功能描述
(1)用戶根據單選題的格式,依照相應的規范進行單選題的增添、修改、刪除和查詢,輸入信息不規范會有信息提示窗口。
(2)用戶根據查詢子模塊的查詢功能,依照查詢得到題目記錄,有選擇地進行修改和刪除。
實現原理
用戶在前端JavaFX界面上輸入信息,觸發事件處理,將輸入的數據傳輸到業務層,通過DAO模式,對Derby數據庫進行增刪查改。而進行數據庫操作的關鍵是JDBC,可以為多種關系型數據庫DBMS提供統一的訪問方式,主要目的是用Java來操作數據庫。
JDBC API主要負責三個功能:(1)與數據庫建立連接(2)發送SQL語句給數據庫(3)數據庫將結果返回
四、相關類的實現
這里主要介紹選擇題和判斷題的兩個實體類ChoiceQuestion、TrueFalseQuestion還有對應的兩個數據庫操作DAO類ChoiceQuestionDao、TFQuestionDao,以及封裝好的數據庫配置類DBUtils。
ChoiceQuestion類
package pojo; public class ChoiceQuestion { String number;//題目編號 String content;//題目內容 String pic;//圖片名稱 String optionA;//選項 String optionB; String optionC; String optionD; String answer;//正確答案 public ChoiceQuestion(String number, String content, String pic, String optionA, String optionB, String optionC, String optionD, String answer) { this.number = number; this.content = content; this.pic = pic; this.optionA = optionA; this.optionB = optionB; this.optionC = optionC; this.optionD = optionD; this.answer = answer; } public ChoiceQuestion() { } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getPic() { return pic; } public void setPic(String pic) { this.pic = pic; } public String getOptionA() { return optionA; } public void setOptionA(String optionA) { this.optionA = optionA; } public String getOptionB() { return optionB; } public void setOptionB(String optionB) { this.optionB = optionB; } public String getOptionC() { return optionC; } public void setOptionC(String optionC) { this.optionC = optionC; } public String getOptionD() { return optionD; } public void setOptionD(String optionD) { this.optionD = optionD; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } @Override public String toString() { return "ChoiceQuestion{" + "number='" + number + '\'' + ", content='" + content + '\'' + ", pic='" + pic + '\'' + ", optionA='" + optionA + '\'' + ", optionB='" + optionB + '\'' + ", optionC='" + optionC + '\'' + ", optionD='" + optionD + '\'' + ", answer='" + answer + '\'' + '}'; } }
TrueFalseQuestion類
package pojo; public class TrueFalseQuestion { String number;//題目編號 String content;//題目內容 String pic;//圖片名稱 String optionT;//選項 String optionF; String answer;//正確答案 public TrueFalseQuestion(String number, String content, String pic, String optionT, String optionF, String answer) { this.number = number; this.content = content; this.pic = pic; this.optionT = optionT; this.optionF = optionF; this.answer = answer; } public TrueFalseQuestion() { } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getPic() { return pic; } public void setPic(String pic) { this.pic = pic; } public String getOptionT() { return optionT; } public void setOptionT(String optionT) { this.optionT = optionT; } public String getOptionF() { return optionF; } public void setOptionF(String optionF) { this.optionF = optionF; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } @Override public String toString() { return "TrueFalseQuestion{" + "number='" + number + '\'' + ", content='" + content + '\'' + ", pic='" + pic + '\'' + ", optionT='" + optionT + '\'' + ", optionF='" + optionF + '\'' + ", answer='" + answer + '\'' + '}'; } }
ChoiceQuestionDao類
package dao; import pojo.ChoiceQuestion; import util.DBUtils; import java.sql.*; import java.util.ArrayList; public class ChoiceQuestionDao { private static Connection connection = DBUtils.getConnection(); public static boolean ChoiceItemInsert(ChoiceQuestion cq) { PreparedStatement preparedStatement; String sql = "insert into ChoiceQuestion(number,content,pic,optionA,optionB,optionC,optionD,answer) values(?,?,?,?,?,?,?,?)"; try { if (cq != null) { preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, cq.getNumber()); preparedStatement.setString(2, cq.getContent()); preparedStatement.setString(3, cq.getPic()); preparedStatement.setString(4, cq.getOptionA()); preparedStatement.setString(5, cq.getOptionB()); preparedStatement.setString(6, cq.getOptionC()); preparedStatement.setString(7, cq.getOptionD()); preparedStatement.setString(8, cq.getAnswer()); //修改表中的內容executeUpdate返回值是一個整數 return preparedStatement.executeUpdate() > 0; } } catch (SQLException e) { e.printStackTrace(); } return false; } public static boolean ChoiceItemDelete(String number) throws SQLException { PreparedStatement preparedStatement; String sql = "delete from ChoiceQuestion where number = ?"; PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); int result = pst.executeUpdate();//返回值表示受到影響的行數 if(result>0) { return true; } return false; } //單個具體查找,根據題目編號 public static ChoiceQuestion ChoiceItemQuerySingle(String number) throws SQLException { String sql = "select * from ChoiceQuestion where number = ?"; //要執行的SQL PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); ResultSet rs = pst.executeQuery();//創建數據對象,注意預定義語句上允許帶參數 ChoiceQuestion cq = new ChoiceQuestion(); while (rs.next()){ cq.setNumber(rs.getString(1)); cq.setContent(rs.getString(2)); cq.setPic(rs.getString(3)); cq.setOptionA(rs.getString(4)); cq.setOptionB(rs.getString(5)); cq.setOptionC(rs.getString(6)); cq.setOptionD(rs.getString(7)); cq.setAnswer(rs.getString(8)); System.out.println(cq.toString()); } return cq;//返回查找到的單選題目 } public static ArrayList<ChoiceQuestion> ChoiceItemQuery() { String sql = "select * from ChoiceQuestion"; //要執行的SQL ArrayList<ChoiceQuestion> acq=new ArrayList(); try { Statement stmt = connection.createStatement(); //創建Statement對象 ResultSet rs = stmt.executeQuery(sql);//創建數據對象 while (rs.next()){ ChoiceQuestion cq = new ChoiceQuestion(); cq.setNumber(rs.getString(1)); cq.setContent(rs.getString(2)); cq.setPic(rs.getString(3)); cq.setOptionA(rs.getString(4)); cq.setOptionB(rs.getString(5)); cq.setOptionC(rs.getString(6)); cq.setOptionD(rs.getString(7)); cq.setAnswer(rs.getString(8)); acq.add(cq); System.out.println(cq.toString()); } } catch (SQLException e) { e.printStackTrace(); } return acq;//返回ArrayList<ChoiceQuestion> } }
TFQuestionDao類
package dao; import pojo.TrueFalseQuestion; import util.DBUtils; import java.sql.*; import java.util.ArrayList; public class TFQuestionDao { private static Connection connection = DBUtils.getConnection(); public static boolean TFItemInsert(TrueFalseQuestion tfq) { System.out.println(tfq.toString()); PreparedStatement preparedStatement; String sql = "insert into TFQuestion(number,content,pic,optionA,optionB,answer) values(?,?,?,?,?,?)"; try { if (tfq != null) { preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, tfq.getNumber()); preparedStatement.setString(2, tfq.getContent()); preparedStatement.setString(3, tfq.getPic()); preparedStatement.setString(4, tfq.getOptionT()); preparedStatement.setString(5, tfq.getOptionF()); preparedStatement.setString(6, tfq.getAnswer()); //修改表中的內容executeUpdate返回值是一個整數 return preparedStatement.executeUpdate() > 0; } } catch (SQLException e) { e.printStackTrace(); } return false; } public static boolean TFItemDelete(String number) throws SQLException { PreparedStatement preparedStatement; String sql = "delete from TFQuestion where number = ?"; PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); int result = pst.executeUpdate();//返回值表示受到影響的行數 if(result>0) { return true; } return false; } //單個具體查找,根據題目編號 public static TrueFalseQuestion TFItemQuerySingle(String number) throws SQLException { String sql = "select * from TFQuestion where number = ?"; //要執行的SQL PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); ResultSet rs = pst.executeQuery();//創建數據對象,注意預定義語句上允許帶參數 TrueFalseQuestion tfq = new TrueFalseQuestion(); while (rs.next()){ tfq.setNumber(rs.getString(1)); tfq.setContent(rs.getString(2)); tfq.setPic(rs.getString(3)); tfq.setOptionT(rs.getString(4)); tfq.setOptionF(rs.getString(5)); tfq.setAnswer(rs.getString(6)); System.out.println(tfq.toString()); } return tfq;//返回查找到的單選題目 } public static ArrayList<TrueFalseQuestion> TFItemQuery() { String sql = "select * from TFQuestion"; //要執行的SQL ArrayList<TrueFalseQuestion> atfq=new ArrayList(); try { Statement stmt = connection.createStatement(); //創建Statement對象 ResultSet rs = stmt.executeQuery(sql);//創建數據對象 while (rs.next()){ TrueFalseQuestion tfq = new TrueFalseQuestion(); tfq.setNumber(rs.getString(1)); tfq.setContent(rs.getString(2)); tfq.setPic(rs.getString(3)); tfq.setOptionT(rs.getString(4)); tfq.setOptionF(rs.getString(5)); tfq.setAnswer(rs.getString(6)); atfq.add(tfq); System.out.println(tfq.toString()); } } catch (SQLException e) { e.printStackTrace(); } return atfq;//返回ArrayList<TrueFalseQuestion> } }
package dao; import pojo.TrueFalseQuestion; import util.DBUtils; import java.sql.*; import java.util.ArrayList; public class TFQuestionDao { private static Connection connection = DBUtils.getConnection(); public static boolean TFItemInsert(TrueFalseQuestion tfq) { System.out.println(tfq.toString()); PreparedStatement preparedStatement; String sql = "insert into TFQuestion(number,content,pic,optionA,optionB,answer) values(?,?,?,?,?,?)"; try { if (tfq != null) { preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, tfq.getNumber()); preparedStatement.setString(2, tfq.getContent()); preparedStatement.setString(3, tfq.getPic()); preparedStatement.setString(4, tfq.getOptionT()); preparedStatement.setString(5, tfq.getOptionF()); preparedStatement.setString(6, tfq.getAnswer()); //修改表中的內容executeUpdate返回值是一個整數 return preparedStatement.executeUpdate() > 0; } } catch (SQLException e) { e.printStackTrace(); } return false; } public static boolean TFItemDelete(String number) throws SQLException { PreparedStatement preparedStatement; String sql = "delete from TFQuestion where number = ?"; PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); int result = pst.executeUpdate();//返回值表示受到影響的行數 if(result>0) { return true; } return false; } //單個具體查找,根據題目編號 public static TrueFalseQuestion TFItemQuerySingle(String number) throws SQLException { String sql = "select * from TFQuestion where number = ?"; //要執行的SQL PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,number); ResultSet rs = pst.executeQuery();//創建數據對象,注意預定義語句上允許帶參數 TrueFalseQuestion tfq = new TrueFalseQuestion(); while (rs.next()){ tfq.setNumber(rs.getString(1)); tfq.setContent(rs.getString(2)); tfq.setPic(rs.getString(3)); tfq.setOptionT(rs.getString(4)); tfq.setOptionF(rs.getString(5)); tfq.setAnswer(rs.getString(6)); System.out.println(tfq.toString()); } return tfq;//返回查找到的單選題目 } public static ArrayList<TrueFalseQuestion> TFItemQuery() { String sql = "select * from TFQuestion"; //要執行的SQL ArrayList<TrueFalseQuestion> atfq=new ArrayList(); try { Statement stmt = connection.createStatement(); //創建Statement對象 ResultSet rs = stmt.executeQuery(sql);//創建數據對象 while (rs.next()){ TrueFalseQuestion tfq = new TrueFalseQuestion(); tfq.setNumber(rs.getString(1)); tfq.setContent(rs.getString(2)); tfq.setPic(rs.getString(3)); tfq.setOptionT(rs.getString(4)); tfq.setOptionF(rs.getString(5)); tfq.setAnswer(rs.getString(6)); atfq.add(tfq); System.out.println(tfq.toString()); } } catch (SQLException e) { e.printStackTrace(); } return atfq;//返回ArrayList<TrueFalseQuestion>
DBUtils類
package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; //數據庫工具類 public class DBUtils { private static Connection connection; private static String dirverName = "org.apache.derby.jdbc.EmbeddedDriver"; private static String uri = "jdbc:derby:MyDB/DrivingTest;create=true"; //這里將Derby數據庫創建到本項目的目錄下 //加載數據 庫驅動 public DBUtils() { super(); try { Class.forName(dirverName); } catch (Exception e) { System.out.print("數據庫驅動加載異常" + e); } } //獲取數據庫連接對象 public static Connection getConnection() { try { if (connection == null) { connection = DriverManager.getConnection(uri);//Derby數據庫建立連接 } } catch (SQLException e) { System.out.println("連接數據庫異常" + e); } return connection; } }
五、界面設計
本系統的圖形界面使用JavaFX開發,可以使用FXML編寫,該語言是基於XML的標記語言,用於定義用戶界面,容易開發與維護。可以通過使用層疊樣式表CSS,輕松定制。
本項目的面板結構
單選題管理界面
單選題添加界面:
單選題更新界面:
單選題刪除界面:
單選題查詢界面:
判斷題管理界面
判斷題添加界面:
判斷題更新界面:
判斷題刪除界面:
判斷題查詢界面:
六、程序設計
該系統的項目程序代碼在伴隨本文檔的壓縮包中給出,本系統開發環境為Windows10,開發軟件為idea,並在eclipse下測試通過。這個給出描述本程序的文件目錄樹結構。
其中MyDB下的DrivingTest為本項目的Derby數據庫,本項目主要位於src目錄下,其中pojo下的ChoiceQuestion和TrueFalseQuestion為單選題和判斷題的兩個試題類;dao包下是用於單選題和判斷題用於數據庫操作的類;sample包用於生成圖形界面和事物處理;util包下的DBUtils用於數據庫驅動配置等。
七、總結
本次Java實訓課的主要內容是通過JDBC來操作數據庫,完成一個簡單的駕考試題管理系統,了解了Apache Derby這樣一個與平台無關的Java數據庫,學會了兩種操作Derby數據庫的方式,通過本地連接和網絡連接。之后通過一系列基礎的查詢操作、更新操作、添加和刪除操作,基本掌握了JDBC操作數據庫的流程。
本系統就是以Java實訓周中所學到的知識設計,GUI圖形用戶界面使用JavaFX技術編寫,界面使用少量的CSS層疊樣式表來進行渲染,增強美感。數據持久層采用DAO模式,將數據庫操作進行封裝,把數據訪問和業務邏輯進行分離,在原則上降低了代碼的耦合性,提高了代碼擴展性和系統的可移植性。最后通過關系型數據庫Derby完成對駕考試題的存儲。
本系統主要的目的是方便駕考考生和教練管理出現在駕駛技能考試上科目一、科目四的單選題和判斷題,讓用戶輕松管理試題,但本項目依舊存在着許多的不足和可再提升、改進的空間,主要體現在下面幾個方面:
(1) 本項目由於開發時間緊迫,在界面設計上過於簡單,功能過少。可以在后序的改進中引入一些可視化的圖表。
(2) 選取的數據庫Derby有一些不足,Derby的定位是嵌入式小型數據庫,在本項目這種事務並不復雜的應用上還是很不錯的,但也經常有連接失敗和安全性不足等問題。