前期準備<br />首先要先明確有個大體的思路,要實現什麼樣的功能,了解完成整個模塊要運用到哪些方面的知識,以及從做的過程中去發現自己的不足。技術方面的進步大都都需要從實踐中出來的。
功能:用戶註冊功能+系統登錄功能+生成驗證碼
知識:窗體設計、數據庫設計、JavaBean封裝屬性、JDBC實現對數據庫的連接、驗證碼(包括彩色驗證碼)生成技術,還有就些比如像使用正則表達式校驗用戶註冊信息、隨機獲得字符串、對文本可用字符數的控制等
設計的模塊預覽圖:
彩色驗證碼預覽圖:
所用數據庫:MySQL
數據庫設計
創建一個數據庫db_database01,其中包含一個表格tb_user,用來保存用戶的註冊的數據。
其中包含4個字段
id int(11)
username varchar(15)
password varchar(20)
email varchar(45)
MySQL語句可以這樣設計:
create schema db_database01;use db_database01;create table tb_user(id int(11) not null auto_increment primary key,username varchar(15) not null,password varchar(20) not null,email varchar(45) not null);insert into tb_user values(1,"lixiyu","lixiyu",[email protected]);
這樣把lixiyu作為用戶名。
select語句檢查一下所建立的表格:
編寫JavaBean封裝用戶屬性
package com.lixiyu.model;public class User {private int id;// 編號private String username;// 用戶名private String password;// 密碼private String email;// 電子郵箱public int getId() {return id; }public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password; }public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}}
編寫JDBC工具類
將與數據庫操作相關的代碼放置在DBConfig接口和DBHelper類中
DBConfig接口用於保存數據庫、用戶名和密碼信息代碼:
package com.lixiyu.util;public interface DBConfig {String databaseName = "db_database01";// 數據庫名稱String username = "root";// 數據庫用戶名String password = "lixiyu";// 數據庫密碼}
為簡化JDBC開發,DBHelper使用了了Commons DbUtil組合。
DBHelper類繼承了DBConfig接口,該類中包含4種方法:
(1)getConnection()方法:獲得數據庫連接,使用MySQL數據源來簡化編程,避免因加載數據庫驅動而發生異常。
(2)exists()方法:判斷輸入的用戶名是否存在。
(3)check()方法:當用戶輸入用戶名和密碼,查詢使用check()方法是否正確。
(4)save()方法:用戶輸入合法註冊信息後,,將信息進行保存。
詳細代碼:
package com.lixiyu.util;import java.sql.Connection;import java.sql.SQLException;import java.util.Arrays;import java.util.List;import org.apache.commons.dbutils.DbUtils;import org.apache .commons.dbutils.QueryRunner;import org.apache.commons.dbutils.ResultSetHandler;import org.apache.commons.dbutils.handlers.ColumnListHandler;import org.apache.commons.dbutils.handlers.ScalarHandler;import org.apache.commons .lang.StringEscapeUtils;import com.lixiyu.model.User;import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;public class DBHelper implements DBConfig { /* * 使用MySQL數據源獲得數據庫連接對象* * @return:MySQL連接對象,如果獲得失敗返回null */ public static Connection getConnection() { MysqlDataSource mds = new MysqlDataSource();// 創建MySQL數據源mds.setDatabaseName(databaseName);// 設置數據庫名稱mds.setUser(username); // 設置數據庫用戶名mds.setPassword(password);// 設置數據庫密碼try { return mds.getConnection();// 獲得連接} catch (SQLException e) { e.printStackTrace(); } return null;//如果獲取失敗就返回null } /* * 判斷指定用戶名的用戶是否存在* * @return:如果存在返回true,不存在或者查詢失敗返回false */ public static boolean exists(String username) { QueryRunner runner = new QueryRunner();// 創建QueryRunner對象String sql = "select id from tb_user where username = '" + username + "';";// 定義查詢語句Connection conn = getConnection();// 獲得連接ResultSetHandler<List< Object>> rsh = new ColumnListHandler();// 創建結果集處理類try { List<Object> result = runner.query(conn, sql, rsh);// 獲得查詢結果if (result.size() > 0 ) {// 如果列表中存在數據return true;// 返回true } else {// 如果列表中沒有數據return false;// 返回false } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtils.closeQuietly(conn);// 關閉連接} return false;// 如果發生異常返回false } /* * 驗證用戶名和密碼是否正確使用Commons Lang組件轉義字符串避免SQL注入* * @return:如果正確返回true,錯誤返回false */ public static boolean check(String username, char[] password) { username = StringEscapeUtils.escapeSql(username);// 將用戶輸入的用戶名轉義QueryRunner runner = new QueryRunner();/ / 創建QueryRunner對象String sql = "select password from tb_user where username = '" + username + "';";// 定義查詢語句Connection conn = getConnection();// 獲得連接ResultSetHandler<Object> rsh = new ScalarHandler( );// 創建結果集處理類try { String result = (String) runner.query(conn, sql, rsh);// 獲得查詢結果char[] queryPassword = result.toCharArray();// 將查詢到得密碼轉換成字符數組if (Arrays.equals(password, queryPassword)) {// 如果密碼相同則返回true Arrays.fill(password, '0');// 清空傳入的密碼Arrays.fill(queryPassword, ' 0');// 清空查詢的密碼return true; } else {// 如果密碼不同則返回false Arrays.fill(password, '0');// 清空傳入的密碼Arrays.fill(queryPassword, '0 ');// 清空查詢的密碼return false; } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtils.closeQuietly(conn);// 關閉連接} return false;// 如果發生異常返回false } /* * 保存用戶輸入的註冊信息* * @return:如果保存成功返回true,保存失敗返回false */ public static boolean save(User user) { QueryRunner runner = new QueryRunner();// 創建QueryRunner對象String sql = "insert into tb_user (username, password, email) values (?, ?, ?);";// 定義查詢語句Connection conn = getConnection();// 獲得連接Object[] params = { user.getUsername (), user.getPassword(), user.getEmail() };// 獲得傳遞的參數try { int result = runner.update(conn, sql, params);// 保存用戶if (result > 0) {/ / 如果保存成功返回true return true; } else {// 如果保存失敗返回false return false; } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtils.closeQuietly(conn);// 關閉連接} return false;// 如果發生異常返回false }}
系統登錄
1.1窗體設計
使用BoxLayout佈局,將控件排列方式設置從上至下:
複製代碼代碼如下:contentPane.setLayout(new BoxLayout(contentPane,BoxLayout.PAGE_AXIS));
窗體使用了標籤、文本域、密碼域和按鈕等控件實現代碼:
public class login extends JFrame{private static final long serialVersionUID = -4655235896173916415L;private JPanel contentPane;private JTextField usernameTextField;private JPasswordField passwordField;private JTextField validateTextField;private String randomText;public static void main(String args[]){try {UIManager. setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");} catch (Throwable e) {e.printStackTrace();}EventQueue.invokeLater(new Runnable(){public void run(){try{ login frame=new login();frame.setVisible(true);}catch(Exception e){e.printStackTrace();}}});}public login(){setTitle("系統登錄");setDefaultCloseOperation(JFrame .EXIT_ON_CLOSE);contentPane=new JPanel();setContentPane(contentPane);contentPane.setLayout(new BoxLayout(contentPane,BoxLayout.PAGE_AXIS));JPanel usernamePanel=new JPanel();contentPane.add(usernamePanel);JLabel usernameLable=new JLabel("/u7528/u6237/u540D/uFF1A");usernameLable.setFont(new Font("微軟雅黑", Font.PLAIN, 15));usernamePanel.add(usernameLable);usernameTextField=new JTextField();usernameTextField .setFont(new Font("微軟雅黑", Font.PLAIN, 15));usernamePanel.add(usernameTextField);usernameTextField.setColumns(10);JPanel passwordPanel = new JPanel();contentPane.add(passwordPanel);JLabel passwordLabel = new JLabel("/u5BC6 /u7801/uFF1A");passwordLabel.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordPanel.add(passwordLabel);passwordField = new JPasswordField(); passwordField.setColumns(10);passwordField.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordPanel.add(passwordField);JPanel validatePanel = new JPanel();contentPane.add(validatePanel); JLabel validateLabel = new JLabel("/u9A8C/u8BC1/u7801/uFF1A");validateLabel.setFont(new Font("微軟雅黑", Font.PLAIN, 15));validatePanel.add(validateLabel);validateTextField = new JTextField ();validateTextField.setFont(new Font("微軟雅黑", Font.PLAIN, 15));validatePanel.add(validateTextField);validateTextField.setColumns(5);randomText = RandomStringUtils.randomAlphanumeric(4);CAPTCHALabel label = new CAPTCHALabel(randomText);//隨機驗證碼label.setFont(new Font("微軟雅黑", Font.PLAIN, 15));validatePanel.add(label);JPanel buttonPanel=new JPanel();contentPane.add (buttonPanel);JButton submitButton=new JButton("登錄");submitButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_submitButton_actionPerformed(e);}});submitButton.setFont(new Font("微軟雅黑", Font.PLAIN, 15));buttonPanel.add(submitButton);JButton cancelButton=new JButton("退出");cancelButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){do_cancelButton_actionPerformed( e);}});cancelButton.setFont(new Font("微軟雅黑",Font.PLAIN,15));buttonPanel.add(cancelButton);pack();// 自動調整窗體大小setLocation(com. lixiyu.util.SwingUtil.centreContainer(getSize()));// 讓窗體居中顯示}
窗體居中顯示:
public class SwingUtil {/** 根據容器的大小,計算居中顯示時左上角坐標** @return 容器左上角坐標*/public static Point centreContainer(Dimension size) {Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize() ;// 獲得屏幕大小int x = (screenSize.width - size.width) / 2;// 計算左上角的x坐標int y = (screenSize.height - size.height) / 2;// 計算左上角的y坐標return new Point(x, y);// 返回左上角坐標}}
1.2獲取及繪製驗證碼
public class CAPTCHALabel extends JLabel {private static final long serialVersionUID = -963570191302793615L;private String text;// 用於保存生成驗證圖片的字符串public CAPTCHALabel(String text) {this.text = text;setPreferredSize(new Dimension(60, 36));// 設置標籤的大小}@Overridepublic void paint(Graphics g) {super.paint(g);// 調用父類的構造方法g.setFont(new Font("微軟雅黑", Font. PLAIN, 16));// 設置字體g.drawString(text, 5, 25);// 繪製字符串}}
*彩色驗證碼:
public class ColorfulCAPTCHALabel extends JLabel {private static final long serialVersionUID = -963570191302793615L;private String text;// 用於保存生成驗證圖片的字符串private Color[] colors = { Color.BLACK, Color.BLUE, Color.CYAN, Color .DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,Color.PINK, Color.RED, Color.WHITE, Color.YELLOW };// 定義畫筆顏色數組public ColorfulCAPTCHALabel(String text) {this.text = text;setPreferredSize(new Dimension(60, 36));// 設置標籤的大小}@Overridepublic void paint(Graphics g) {super.paint(g);// 調用父類的構造方法g.setFont(new Font("微軟雅黑", Font.PLAIN, 16));// 設置字體for (int i = 0; i < text.length(); i++) {g.setColor(colors[ RandomUtils.nextInt(colors.length)]);g.drawString("" + text.charAt(i), 5 + i * 13, 25);// 繪製字符串}}}
1.3非空校驗
if (username.isEmpty()) {// 判斷用戶名是否為空JOptionPane.showMessageDialog(this, "用戶名不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (new String( password).isEmpty()) {// 判斷密碼是否為空JOptionPane.showMessageDialog(this, "密碼不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (validate.isEmpty()) {// 判斷驗證碼是否為空JOptionPane.showMessageDialog(this, "驗證碼不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}
1.4合法性校驗
if (!DBHelper.exists(username)) {// 如果用戶名不存在則進行提示JOptionPane.showMessageDialog(this, "用戶名不存在!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if ( !DBHelper.check(username, password)) {// 如果密碼錯誤則進行提示JOptionPane.showMessageDialog(this, "密碼錯誤!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (!validate.equals (randomText)) {// 如果校驗碼不匹配則進行提示JOptionPane.showMessageDialog(this, "驗證碼錯誤!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}
1.5顯示主窗體
EventQueue.invokeLater(new Runnable() {@Overridepublic void run() {try {MainFrame frame = new MainFrame();// 創建主窗體frame.setVisible(true);// 設置主窗體可見} catch (Exception e) {e.printStackTrace();}}});dispose();// 將登錄窗體銷毀}
設計主窗體(比較簡單這個):
public MainFrame() {setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 設置單擊關閉窗體按鈕時執行的操作setSize(450, 300);// 設置窗體大小contentPane = new JPanel();// 創建面板contentPane .setLayout(new BorderLayout(0, 0));// 設置面板佈局使用邊界佈局setContentPane(contentPane);// 應用面板JLabel tipLabel = new JLabel("恭喜您成功登錄系統!");// 創建標籤tipLabel .setFont(new Font("微軟雅黑", Font.PLAIN, 40));// 設置標籤字體contentPane.add(tipLabel, BorderLayout.CENTER);// 應用標籤setLocation(SwingUtil.centreContainer(getSize()) );// 讓窗體居中顯示}
用戶註冊
1.1窗體設計
public class Register extends JFrame {/****/private static final long serialVersionUID = 2491294229716316338L;private JPanel contentPane;private JTextField usernameTextField;private JPasswordField passwordField1;private JPasswordField passwordField2;private JTextField emailTextField;private JLabel tipLabel = new JLabel();/ / 顯示提示信息/*** Launch the application.*/public static void main(String[] args) {try {UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");} catch (Throwable e) {e.printStackTrace();}EventQueue.invokeLater(new Runnable() {@Overridepublic void run() {try {Register frame = new Register();frame.setVisible(true);} catch (Exception e ) {e.printStackTrace();}}});}/*** Create the frame.*/public Register() {setTitle("/u7528/u6237/u6CE8/u518C");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); contentPane = new JPanel();setContentPane(contentPane);contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.PAGE_AXIS));JPanel usernamePanel = new JPanel();contentPane.add(usernamePanel);JLabel usernameLabel = new JLabel("/ u7528 /u6237 /u540D/uFF1A");usernameLabel.setFont(new Font("微軟雅黑", Font.PLAIN, 15));usernamePanel.add(usernameLabel);usernameTextField = new JTextField();usernameTextField.setToolTipText(" /u8BF7/u8F93/u51655~15/u4E2A/u7531/u5B57/u6BCD/u6570/u5B57/u4E0B/u5212/u7EBF/u7EC4/u6210/u7684/u5B57/u7B26/u4E32");AbstractDocument doc = (AbstractDocument) usernameTextField.getDocument ();doc.setDocumentFilter(new DocumentSizeFilter(15));// 限製文本域內可以輸入字符長度為15doc.addDocumentListener(new DocumentSizeListener(tipLabel, 15));usernameTextField.setFont(new Font("微軟雅黑", Font.PLAIN, 15));usernamePanel.add(usernameTextField);usernameTextField.setColumns(10);JPanel passwordPanel1 = new JPanel();contentPane.add(passwordPanel1);JLabel passwordLabel1 = new JLabel("/u8F93/u5165/u5BC6 /u7801/uFF1A");passwordLabel1.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordPanel1.add(passwordLabel1);passwordField1 = new JPasswordField();doc = (AbstractDocument) passwordField1.getDocument ();doc.setDocumentFilter(new DocumentSizeFilter(20));// 限制密碼域內可以輸入字符長度為20doc.addDocumentListener(new DocumentSizeListener(tipLabel, 20));passwordField1.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordField1.setColumns(10);passwordPanel1.add(passwordField1);JPanel passwordPanel2 = new JPanel();contentPane.add(passwordPanel2);JLabel passwordLabel2 = new JLabel("/u786E/u8BA4/u5BC6 /u7801/uFF1A");passwordLabel2.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordPanel2.add(passwordLabel2);passwordField2 = new JPasswordField();doc = (AbstractDocument) passwordField2.getDocument ();doc.setDocumentFilter(new DocumentSizeFilter(20));// 限制密碼域內可以輸入字符長度為20doc.addDocumentListener(new DocumentSizeListener(tipLabel, 20));passwordField2.setFont(new Font("微軟雅黑", Font.PLAIN, 15));passwordField2.setColumns(10);passwordPanel2.add(passwordField2);JPanel emailPanel = new JPanel();contentPane.add(emailPanel);JLabel emailLabel = new JLabel("/u7535/u5B50/u90AE /u7BB1/uFF1A");emailLabel.setFont(new Font("微軟雅黑", Font.PLAIN, 15));emailPanel.add(emailLabel);emailTextField = new JTextField();doc = (AbstractDocument) emailTextField.getDocument ();doc.setDocumentFilter(new DocumentSizeFilter(45));// 限製文本域內可以輸入字符長度為45doc.addDocumentListener(new DocumentSizeListener(tipLabel, 45));emailTextField.setFont(new Font("微軟雅黑", Font.PLAIN, 15));emailPanel.add(emailTextField);emailTextField.setColumns(10);JPanel buttonPanel = new JPanel();contentPane.add(buttonPanel);JButton submitButton = new JButton("/u63D0/u4EA4") ;submitButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_submitButton_actionPerformed(e);}});buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));tipLabel.setFont(new Font( "微軟雅黑", Font.PLAIN, 15));buttonPanel.add(tipLabel);Component glue = Box.createGlue();buttonPanel.add(glue);submitButton.setFont(new Font("微軟雅黑", Font.PLAIN, 15));buttonPanel.add(submitButton);JButton cancelButton = new JButton("/u53D6/u6D88");cancelButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_cancelButton_actionPerformed(e );}});cancelButton.setFont(new Font("微軟雅黑", Font.PLAIN, 15));buttonPanel.add(cancelButton);pack();// 自動調整窗體大小setLocation(SwingUtil.centreContainer (getSize()));// 讓窗體居中顯示}
1.2用DocumentFilter限製文本可用字符數
public class DocumentSizeFilter extends DocumentFilter {private int maxSize;// 獲得文本的最大長度public DocumentSizeFilter(int maxSize) {this.maxSize = maxSize;// 獲得用戶輸入的最大長度}@Overridepublic void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {if ((fb.getDocument().getLength() + string.length()) <= maxSize) {// 如果插入操作完成後小於最大長度super.insertString(fb, offset , string, attr);// 調用父類中的方法} else {Toolkit.getDefaultToolkit().beep();// 發出提示聲音}}@Overridepublic void replace(FilterBypass fb, int offset, int length, String text , AttributeSet attrs) throws BadLocationException {if ((fb.getDocument().getLength() + text.length() - length) <= maxSize) {// 如果替換操作完成後小於最大長度super.replace(fb, offset , length, text, attrs);// 調用父類中的方法} else {Toolkit.getDefaultToolkit().beep();// 發出提示聲音}}}
1.3用DocumentListener接口實現顯示文本控件已用字符
public class DocumentSizeListener implements DocumentListener {private JLabel tipLabel;private int maxSize;public DocumentSizeListener(JLabel tipLabel, int maxSize) {this.tipLabel = tipLabel;this.maxSize = maxSize;}@Overridepublic void insertUpdate(DocumentEvent e) {setTipText(e) ;}@Overridepublic void removeUpdate(DocumentEvent e) {setTipText(e);}@Overridepublic void changedUpdate(DocumentEvent e) {setTipText(e);}private void setTipText(DocumentEvent e) {Document doc = e.getDocument();/ / 獲得文檔對象tipLabel.setForeground(Color.BLACK);// 設置字體顏色if (doc.getLength() > (maxSize * 4 / 5)) {// 如果已輸入字符長度大於最大長度的80%tipLabel. setForeground(Color.RED);// 使用紅色顯示提示信息} else {tipLabel.setForeground(Color.BLACK);// 使用黑色顯示提示信息}tipLabel.setText("提示信息:" + doc.getLength() + "/" + maxSize);}}
1.4非空校驗
if (username.isEmpty()) {// 判斷用戶名是否為空JOptionPane.showMessageDialog(this, "用戶名不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (new String( password1).isEmpty()) {// 判斷密碼是否為空JOptionPane.showMessageDialog(this, "密碼不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (new String(password2). isEmpty()) {// 判斷確認密碼是否為空JOptionPane.showMessageDialog(this, "確認密碼不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}if (email.isEmpty()) { // 判斷電子郵箱是否為空JOptionPane.showMessageDialog(this, "電子郵箱不能為空!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}
1.5使用正則表達式校驗字符串(合法性校驗)
// 校驗用戶名是否合法if (!Pattern.matches("//w{5,15}", username)) {JOptionPane.showMessageDialog(this, "請輸入合法的用戶名!", "警告信息" , JOptionPane.WARNING_MESSAGE);return;}// 校驗兩次輸入的密碼是否相同if (!Arrays.equals(password1, password2)) {JOptionPane.showMessageDialog(this, "兩次輸入的密碼不同!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}// 校驗電子郵箱是否合法if (!Pattern.matches("//w+@//w+//.//w+", email)) {JOptionPane.showMessageDialog (this, "請輸入合法的電子郵箱!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}// 校驗用戶名是否存在if (DBHelper.exists(username)) {JOptionPane.showMessageDialog(this, "用戶名已經存在", "警告信息", JOptionPane.WARNING_MESSAGE);return;}
1.6保存註冊信息
User user = new User();user.setUsername(username);user.setPassword(new String(password1));user.setEmail(email);Arrays.fill(password1, '0');// 清空保存密碼的字符數組Arrays.fill(password2, '0');// 清空保存密碼的字符數組if (DBHelper.save(user)) {JOptionPane.showMessageDialog(this, "用戶註冊成功!", "提示信息", JOptionPane .INFORMATION_MESSAGE);return;} else {JOptionPane.showMessageDialog(this, "用戶註冊失敗!", "警告信息", JOptionPane.WARNING_MESSAGE);return;}}
至此,一個簡單而有完整的登陸註冊模塊就完成了。
以上就是本文的全部內容,希望大家可以喜歡。