總結:java小項目——圖書管理系統
一、用到的工具
1.eclipse+windowbuilder插件
二、涉及的知識點
1. MVC設計模式
2. Swing
3. JDBC+MySQL
三、框架搭建
按照MVC設計模式在eclipse中新建項目,導入項目中要用到的圖標,在數據庫中創建表(以及表之間的主外鍵關聯),用JDBC知識成功連接數據庫。
【JAVA%20MVC】
即把一個應用的輸入、處理、輸出流程按照Model、View、Controller的方式進行分離,這樣一個應用被分成三個層——模型層、視圖層、控制層。
M——Model(模型)。業務流程/狀態的處理以及業務規則的制定。把抽象的概念化成一個個類,例如User、Book、BookType。
V——View(視圖)。視圖接收來自Model的數據并顯示給用戶,以及將用戶界面的輸入數據和請求傳遞給Controller和Model。此部分用windowbuilder插件來實現。
C——Controller(控制器)。這部分主要是用來連接Model和View這兩部分,控制層收到請求后,%20并不處理業務信息,它只把用戶的信息傳遞給相應的Model,告訴模型做什么,選擇符合要求的View返回給用戶。關于用戶交互的操作的方法函數寫在這一部分。
——包com.BookManager.dao用來寫Controller這一模塊;
——包com.BookManager.model用來寫Model這一模塊;
——包com.BookManager.view用來寫View這一模塊;
另外,將多次使用的工具類都寫在com.BookManager.util包中,如數據庫連接、判斷字符串是否為空。
【包images】
下載好圖標后,新建一個images包,將復制好的圖標直接ctrl+v粘貼進來即可。包images用來存放項目中用到的圖標和圖片(http://www.easyicon.net/ )
【數據庫創建表】
1.【varchar】數據庫創建表時,對于userName等項應設置成varchar數據類型,char是定長的字符,varchar[n]存儲大小為輸入數據字節的實際長度,而不是%20n%20個字節。
2.【主外鍵關聯】
主鍵的主要作用是將記錄和存放在其他表中的數據進行關聯,在這一點上,主鍵是不同表中各記錄間的簡單指針,不能有重復的,不允許為空。
外鍵是另一表的主鍵,可以有重復,可以是空值,用來和其他表建立聯系用的。所以說,如果談到了外鍵,一定至少涉及兩張表。外鍵約束主要用來維護兩個表之間數據的一致性。
在SQLyog軟件中,點擊“架構設計器”拖動要關聯的兩張表,如下圖所示。
【JDBC】
1.【數據庫中創建表】t_User,設置用戶名及密碼。
2.【驅動】下載MySQL相應的驅動包,新建jdbc文件夾,將包復制粘貼到此文件夾中,然后Build%20Path—>Addto%20Build%20Path,就將此包添加到項目中了。
3.【按MySQL格式寫代碼】封裝DbUtil類。代碼中按下快捷鍵ctrl+shift+o要導入sql的包時,應選擇jdbc的接口——java.sql.Connection,如下圖所示。
四、代碼總結
<一>Model模塊
在Model中將抽象概念Book、BookType、User用代碼變量描述出來,即創建實體的描述。
Alt+Shift+s彈出自動生成語句的菜單(創建成員變量get()和set()方法)。
用到包裝類,以便能將基本類型當作對象處理。
【特別注意】構造方法中形參的每一項(順序)都要與數據庫中相應表中的欄目名稱和類型保持一致。
此外,BooType類中重寫了toString()的方法。因為把BookType類的對象當作參數傳進去后,顯示出來的并不是它里面的數據,而是它的地址。所以重寫toString()方法來顯示BookType類的對象里面的數據。
<二>Controller模塊
連接用戶輸入的數據和數據庫里面的數據的操作。在其他類中用到這些類的方法時,要先new相應的對象。
1.用戶登錄——UserDao.java
實現用戶登錄數據庫功能,即輸入用戶名和密碼,如果數據庫的t_user表中含有匹配的用戶名和密碼,就能登錄成功。所以,此方法應該為User類型,傳入參數為數據庫連接和用戶——public User login(Connection con, Useruser)throws Exception{}
·先定義變量sql,賦予MySQL的原始語句;
·調用PRepareStatement()來預處理sql;
·調用setString(),設置MySQL語句中占位符的內容;
·調用executeQuery();返回ResultSet結果集。【注意】調用此方法后,已經執行了sql語句的查詢功能,即比對查詢數據庫中是否有將要輸入(占位符)的數據。而數據的接收(輸入數據)是在View模塊中實現的,兩個模塊的變量相互呼應。
·判斷查詢數據庫的結果集是否含有輸入的記錄if(rs.next()),如果有,則實例化用戶對象,并對其記錄進行設置。
public class UserDao { public User login(Connection con,User user)throws Exception{ User resultUser = null; /** * PreparedStatement接口是Statementd的子接口,用于預編譯SQL語句。 * 預編譯后的SQL語句被存儲在PreparedStatement對象中, * 然后可以使用該對象多次高效率地執行該語句(比Statement的效率高)。 * * Statement執行SQL語句時不允許使用問號占位符參數 * PreparedStatement執行SQL語句時可以使用占位符,執行SQL語句之前必須為這些參數傳入參數值 * * PreparedStatement也提供了execute()、executeUpdate()、executeQuery()三個方法執行SQL語句, * 不過他們無需參數,因為PreparedStatement已經存儲了預編譯的SQL語句 */ String sql = "select*from t_user where userName=? and passWord=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, user.getUserName()); pstmt.setString(2, user.getPassword()); ResultSet rs = pstmt.executeQuery(); /** * 【注意】調用此方法后,已經執行了sql語句的查詢功能, * 即比對查詢數據庫中是否有將要輸入(占位符)的數據。 * 而數據的接收(輸入數據)是在View模塊中實現的, * 兩個模塊的變量相互呼應。 */ if(rs.next()){ resultUser = new User(); resultUser.setId(rs.getInt("id")); resultUser.setUserName(rs.getString("userName")); resultUser.setPassword(rs.getString("password")); } return resultUser; }}2.圖書類別操作——BookTypeDao.java
實現圖書類別的添加、刪除、查詢顯示和修改維護以及判斷此類別是否含有圖書。
【SQL語句拼接】因為是動態查詢,bookTypeName可能沒有值,因此涉及到判斷是否為空,所以要用“拼接”的方式來寫SQL語句——
·用StringBuffer暫存一下字符串;
·符合判斷條件時,用append拼接,拼接的SQL語句用and連接,之后再替換成where(因為在拼接的兩段SQL語句中,where的位置可能會造成多個if時的混亂,所以采用替換的方式來處理);
·用toString()將StringBuffer中的內容轉換成字符串,再將字符串內容的第一個and替換成where,即正式的SQL語句。
public ResultSet list(Connection con,BookType bookType) throws Exception{ StringBuffer sb = new StringBuffer("select*from t_bookType ");//用StringBuffer暫存一下字符串 if(StringUtil.isNotEmpty(bookType.getBookTypeName())){ //因為是動態查詢,bookTypeName可能沒有值,所以要用“拼接”的方式來寫SQL語句 sb.append(" and bookTypeName like '%" +bookType.getBookTypeName()+"%'"); } //先用toString()將StringBuffer中的內容轉換成字符串,再將字符串內容的第一個and替換成where,即正式的SQL語句 //在拼接的兩段SQL語句中,where的位置可能會造成多個if時的混亂,所以采用替換的方式來處理 PreparedStatement pstmt = con.prepareStatement(sb.toString().replaceFirst("and", "where")); return pstmt.executeQuery(); }3.圖書操作——BookDao.java
實現圖書的添加、查詢、刪除、修改。
兩個表的關聯查詢。
public class BookDao { /** * 圖書信息添加 * @param con * @param book * @return * @throws Exception */ public int add(Connection con , Book book)throws Exception{ String sql = "insert into t_book values(null,?,?,?,?,?,?)"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); /** * 【特別注意】對每一個"?"進行設置時都要與數據庫中t_book表中的欄目名稱和類型保持一致. * 比如: * 如果原t_book表中第6欄是price,則第六個"?"處就代表price,類型就是float, * 那么若執行pstmt.setString(6, book.getBookDesc());就會因為名稱和類型不一致而報錯 */ pstmt.setString(2, book.getAuthor()); pstmt.setString(3, book.getSex()); pstmt.setInt(4, book.getBookTypeId()); pstmt.setString(5, book.getBookDesc()); pstmt.setFloat(6, book.getPrice()); return pstmt.executeUpdate();//為什么不能方法返回值為void,并把return去掉—————— //executUpdate()本身返回int類型,返回受影響的記錄條數。 //也便于后面根據返回值而進一步判斷執行 } /** * 圖書信息查詢 * @param con * @param book * @return * @throws Exception */ public ResultSet list(Connection con ,Book book)throws Exception{ //t_book表中的id關聯到了t_bookType表的bookTypeId,所以要執行兩個表的關聯查詢 //t_book表的外鍵等于t_bookType表的主鍵 StringBuffer sb = new StringBuffer("select * from t_book b,t_bookType bt where b.bookTypeId=bt.id"); if(StringUtil.isNotEmpty(book.getBookName())){ sb.append(" and b.bookName like '%"+book.getBookName()+"%'");//like模糊查詢 } if(StringUtil.isNotEmpty(book.getAuthor())){ sb.append(" and b.author like '%"+book.getAuthor()+"%'");// '% "關鍵詞" %' 比如 '%java%' } //此時才表示用戶選中了圖書類別。(類別選擇框中“請選擇”的ID在BookManageInterFrm中已設為-1) if(book.getBookTypeId()!=null&&book.getBookTypeId()!=-1){ sb.append(" and b.bookTypeId="+book.getBookTypeId()); }// PreparedStatement pstmt = con.prepareStatement(sb.toString().replaceFirst("and", "where")); PreparedStatement pstmt = con.prepareStatement(sb.toString());//只能有一個where,所以不需要再把and替換成where return pstmt.executeQuery(); } /** * 圖書信息刪除 * @param con * @param id * @return * @throws Exception */ public int delete(Connection con ,String id)throws Exception{ String sql = "delete from t_book where id=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, id); return pstmt.executeUpdate(); } /** * 圖書信息修改 * @param con * @param book * @return * @throws Exception */ public int update(Connection con,Book book)throws Exception{ //要注意此處的順序要與數據庫中每一項的順序嚴格一致! String sql = "update t_book set bookName=?,author=?,sex=?,bookTypeId=?,bookDesc=?,price=?where id=?"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); pstmt.setString(2, book.getAuthor()); pstmt.setString(3, book.getSex()); pstmt.setInt(4, book.getBookTypeId()); pstmt.setString(5, book.getBookDesc()); pstmt.setFloat(6, book.getPrice()); pstmt.setInt(7, book.getId());//要注意sql語句中要有"where id=?" return pstmt.executeUpdate(); } }<三>View模塊
借助windowbuilder插件,新建類時new—>other—>windowbuilder
記得將窗體部件重命名,以便代碼中當作對象調用方法。并且相關部件要在開頭聲明(有些自動生成的代碼沒有在開頭申明需要手動調整完善)
【表格顯示查詢結果】拖入scrollPane,然后在它里面拖入Jtable,通過Jtable的model屬性設置表的標題與行列數,注意一定要與數據庫中的順序類型保持一致。
/** * 顯示結果表單 * @param book */ private void fillTable(Book book){ DefaultTableModel dtm = (DefaultTableModel) bookTable.getModel();//提前將table組件改名 dtm.setRowCount(0);//清空表單 Connection con = null; try{ con = dbUtil.getCon(); ResultSet rs = bookDao.list(con, book); while(rs.next()){ Vector v = new Vector(); v.add(rs.getInt("id")); v.add(rs.getString("bookName")); v.add(rs.getString("author")); v.add(rs.getString("sex")); v.add(rs.getString("bookTypeName"));//與數據庫的順序、名稱保持一致 v.add(rs.getString("bookDesc")); v.add(rs.getFloat("price")); dtm.addRow(v); } }catch(Exception e){ e.printStackTrace(); }finally{ try { dbUtil.closeCon(con); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }【初始化下拉框】
/** * 初始化下拉框 * @param type */ private void fillBookType(String type){ Connection con = null; try{ con = dbUtil.getCon(); ResultSet rs = bookTypeDao.list(con, new BookType()); //在選擇下拉框里添加未選擇時的"請選擇" if("search".equals(type)){ BookType bookType = new BookType(); bookType.setBookTypeName("請選擇"); bookType.setId(-1);//設置新添加的"請選擇"的ID為-1 this.s_bookTypeJcb.addItem(bookType);//將此項添加到下拉框中 } while(rs.next()){ BookType bookType = new BookType(); bookType.setBookTypeName(rs.getString("bookTypeName")); bookType.setId(rs.getInt("id")); if("search".equals(type)){ this.s_bookTypeJcb.addItem(bookType); }else if("modify".equals(type)){ this.bookTypeJcb.addItem(bookType); } } }catch(Exception e){ try { dbUtil.closeCon(con); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }【JRadioButton】要執行右鍵,setButtonGroup將兩個JRadioButton按鈕加入到一個組中,才能實現二選一(非此即彼)。
【表格點擊對應顯示】
/** * 表格行點擊事件處理 * 將選中的行的信息分別顯示到面板中相應的項里 * @param met */ private void bookTableMousePressed(MouseEvent met) { int row = this.bookTable.getSelectedRow();//獲取的是行號 //要與數據庫中的各項順序一致 this.idTXT.setText((Integer) bookTable.getValueAt(row, 0)+"");//【注意】id在fillTable方法中是getInt類型 //所以此處應為Integer類型,但是setText方法里面是String類型 //采取的辦法就是【(Integer)+""】形式來轉成String。否則報錯。 //下面Float同理 this.bookNameTXT.setText((String) bookTable.getValueAt(row, 1)); this.authorTXT.setText((String) bookTable.getValueAt(row, 2)); //"性別"是獲取后在選項前勾選的,不能直接設置文本顯示 String sex = (String) bookTable.getValueAt(row, 3); if("男".equals(sex)){ this.manJrb.setSelected(true); } if("女".equals(sex)){ this.femaleJrb.setSelected(true); } //"圖書類別"是下拉框顯示,也不能直接設置文本顯示 String bookTypeName = (String) bookTable.getValueAt(row, 4); int n = bookTypeJcb.getItemCount();//下拉框bookTypeJcb中有n個項 for(int i=0;i<n;i++){//遍歷n個項,如果其中第i項(item)的名稱與點擊行的bookTypeName相同,則下拉框顯示此i項 BookType item = (BookType) bookTypeJcb.getItemAt(i);//【注意】此處獲取的是圖書類別對象,不是圖書類別名稱 if(item.getBookTypeName().equals(bookTypeName)){ this.bookTypeJcb.setSelectedIndex(i);//下拉框顯示此i項 } } this.bookDescTXT.setText((String) bookTable.getValueAt(row, 5)); this.priceTXT.setText((Float) bookTable.getValueAt(row, 6)+""); }【圖書信息修改】/** * 圖書修改事件處理 * @param evt */ private void bookUpdateActionPerformed(ActionEvent evt) { String id = idTXT.getText();//因為id是int類型,所以創建對象時傳入參數要進行類型轉換Integer.parseInt(id) if(StringUtil.isEmpty(id)){ JOptionPane.showMessageDialog(null, "請選擇要修改的圖書"); return; } String bookName = this.bookNameTXT.getText(); String bookDesc = this.bookDescTXT.getText(); String author = this.authorTXT.getText(); String price = this.priceTXT.getText(); if(StringUtil.isEmpty(bookName)){ JOptionPane.showMessageDialog(null, "圖書名稱不能為空"); return;//不能少了return } if(StringUtil.isEmpty(author)){ JOptionPane.showMessageDialog(null, "圖書作者不能為空"); return;//不能少了return } if(StringUtil.isEmpty(price)){ JOptionPane.showMessageDialog(null, "圖書價格不能為空"); return;//不能少了return } String sex = ""; if(manJrb.isSelected()) sex = "男"; if(femaleJrb.isSelected()) sex = "女"; BookType bookType = (BookType) bookTypeJcb.getSelectedItem(); int bookTypeId = bookType.getId(); Book book = new Book( Integer.parseInt(id), bookName, author, sex, bookTypeId, bookDesc, Float.parseFloat(price) ); Connection con = null; try{ con = dbUtil.getCon(); int updateNum = bookDao.update(con, book); if(updateNum==1){ JOptionPane.showMessageDialog(null, "圖書修改成功"); resetValue(); this.fillTable(new Book());//實時修改刷新表單 }else{ JOptionPane.showMessageDialog(null, "圖書修改失敗"); } }catch(Exception e){ e.printStackTrace(); JOptionPane.showMessageDialog(null, "圖書修改失敗"); }finally{ try { dbUtil.closeCon(con); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void resetValue() { this.idTXT.setText(""); this.bookNameTXT.setText(""); this.authorTXT.setText(""); this.priceTXT.setText(""); this.bookDescTXT.setText(""); this.manJrb.setSelected(true); if(this.bookTypeJcb.getItemCount()>0)//圖書類別不為空 { this.bookTypeJcb.setSelectedIndex(0);//表單第一項選中 } }
新聞熱點
疑難解答