前期准备
首先要先明确有个大体的思路,要实现什么样的功能,了解完成整个模块要运用到哪些方面的知识,以及从做的过程中去发现自己的不足。技术方面的进步大都都需要从实践中出来的。
功能:用户注册功能+系统登录功能+生成验证码
知识:窗体设计、数据库设计、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",lixiyu419@gmail.com);
这样把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布局,将控件排列方式设置从上至下:
窗体使用了标签、文本域、密码域和按钮等控件
实现代码:
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;}}
至此,一个简单而有完整的登陆注册模块就完成了。
以上就是本文的全部内容,希望大家可以喜欢。
新闻热点
疑难解答