登录是信息系统的基本功能,本章将使用Java实现用户登录功能,并以三层结构重构登录功能。登录功能主要涉及Java如何与MySQL数据库交互。
0 环境
(1)JDK1.6+
(2)编辑器:Eclipse
(3)数据库驱动:mysql-connector-java-5.1.24-bin.jar
(4)读者具有Java、数据库基础
1 需求分析
我们需要使用MySQL建立一个数据库(demo),并在数据库中建立一张用户表(t_user),同时需要有一个登录界面。
当用户在登录界面输入用户名和密码,点击登录,程序应该在用户表中查找匹配的用户,如果存在,在控制台输出“登录中…”语句;如果不存在,提示错误信息。
2 建立测试数据
在MySQL中新建数据库demo,在demo中新建用户表t_user,其结构如下图所示。
插入一条测试数据,如下图所示。
3 Coding
编写登录界面代码,登录界面负责监听【登录】按钮是否被按下,如果按下,则连接demo数据库,并查找与输入的用户名和密码匹配的记录,如果查找成功,在控制台打印“登录…”语句。否则,在控制台打印提示错误信息。
代码清单1:LoginDig.java
public class LoginDig extends JFrame implements ActionListener{
/*
* 定义登录界面控件
*/
//定义用户静态标签
private JLabel lb_name;
//定义密码静态标签
private JLabel lb_psw;
//定义用户文本框
private JTextField txt_name;
//定义密码文本框
private JPasswordField txt_psw;
//定义登录按钮
private JButton btn_login;
//构造方法,初始化控件,将控件加入框架中
public LoginDig() {
//创建控件
lb_name = new JLabel("用户:");
txt_name = new JTextField(10);
lb_psw = new JLabel("密码:");
txt_psw = new JPasswordField(10);
btn_login = new JButton("登录");
//注册按钮事件,当点击按钮时,执行actionPerformed方法
btn_login.addActionListener(this);
//设置表格布局结构,3行2列
this.setLayout(new GridLayout(3, 2));
this.add(lb_name);
this.add(txt_name);
this.add(lb_psw);
this.add(txt_psw);
this.add(btn_login);
//显示框架
this.setVisible(true);
this.pack();
}
@Override
public void actionPerformed(ActionEvent arg0) {
//获取输入的用户名和密码
String name = txt_name.getText();
String password = txt_psw.getText();
try {
//加载Mysql驱动
Class.forName("com.mysql.jdbc.Driver");
//创建数据库连接
//数据库相关属性
String url = "jdbc:mysql://localhost/demo";
String user = "root";
String psw= "";
Connection conn = DriverManager.getConnection(url, user, psw);
//创建执行sql语句的statement对象
Statement stmt = conn.createStatement();
//执行sql语句,返回查询结果
String sql = "select * from t_user where name = '"
+ name + "' and password = '"
+ password + "'";
ResultSet rs = stmt.executeQuery(sql);
//如果存在表中存在和输入用户和密码匹配用户
if(rs.next()){
System.out.println("登录中...");
}else{
System.out.println("用户或密码错误!");
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试类,负责创建登录界面。
代码清单2:Test.java
public class test {
public static void main(String[] args) {
new LoginDig();
}
}
运行程序,登录界面如下所示。
输入不存在的用户或错误的密码;输入正确的用户和密码,将会在控制台看到相应的提示。
4 界面难于承受
在上面的代码清单1中,可以看到LoginDig类负责【UI(界面显示)】、【业务处理(组装SQL语句,依据数据库访问返回结果做处理)】、【数据库交互(连接数据库,访问数据)】三大功能。其逻辑关系如下图所示。
特别是数据库访问那一推凌乱的代码,让人昏昏欲睡,除了编写此代码的程序猿才有心情去看。
上面将三种不相关功能通过登录界面很紧密的关联在一起,【也就是说程序员既要懂界面美工,又要知道业务处理,且数据库知识也很厉害】。我们希望将界面中的三种不同的功能:界面、业务处理和数据库交互分离出来,让界面层只负责界面显示;让业务层专门处理和业务相关的事情;让数据库层专门处理数据库交互。下面将一步一步将登录界面中的三种功能解耦出来。
5 解耦数据库层
首先将那一堆难啃的数据库代码解耦出来,我们需要专门新建一个数据库助手类DBHelper,其负责所有数据库相关操作,并提供接口(方法)供界面层(登录界面)调用,其关系如下图所示。
依据上图分层要求,要将程序分为界面层、数据操作层,初步缓解LoginDig的烦恼,让其只负责界面显示与业务处理,抛弃那烦人的数据库交互代码。
将LoginDig中负责数据库操作的代码抽取出,编写数据库操作类DBHelper。
代码清单3:DBHelper.java
public class DBHelper {
//数据库相关属性
private String url = "jdbc:mysql://localhost/demo";
private String user = "root";
private String pwd = "";
//获取数据库连接
public Connection getConn() throws Exception{
Connection conn;
//加载Mysql驱动
Class.forName("com.mysql.jdbc.Driver");
//创建数据库连接
conn = DriverManager.getConnection(url, user, pwd);
//返回连接
return conn;
}
//依据用户名和密码查找用户,如果存在返回true,否则false
public Boolean findUser(String name, String password) throws Exception{
String sql = "select * from t_user where name = '"
+ name + "' and password = '"
+ password + "'";
//创建连接
Connection conn = getConn();
//创建执行sql语句statement对象
Statement stmt = conn.createStatement();
//依据sql语句获取结果集
ResultSet rs = stmt.executeQuery(sql);
//如果存在用户,返回true
if(rs.next()){
return true;
}else{
return false;
}
}
}
DBhelper类负责连接数据库,并提供数据库基本操作方法(创建连接、查找用户)供登录界面对象调用。此时,登录界面代码如代码清单4所示。
代码清单4:LoginDig.java
public class LoginDig extends JFrame implements ActionListener{
/*
* 定义登录界面控件
*/
//定义用户静态标签
private JLabel lb_name;
//定义密码静态标签
private JLabel lb_psw;
//定义用户文本框
private JTextField txt_name;
//定义密码文本框
private JPasswordField txt_psw;
//定义登录按钮
private JButton btn_login;
//构造方法,初始化控件,将控件加入框架中
public LoginDig() {
//创建控件
lb_name = new JLabel("用户:");
txt_name = new JTextField(10);
lb_psw = new JLabel("密码:");
txt_psw = new JPasswordField(10);
btn_login = new JButton("登录");
//注册按钮事件,当点击按钮时,执行actionPerformed方法
btn_login.addActionListener(this);
//设置表格布局结构,3行2列
this.setLayout(new GridLayout(3, 2));
this.add(lb_name);
this.add(txt_name);
this.add(lb_psw);
this.add(txt_psw);
this.add(btn_login);
//显示框架
this.setVisible(true);
this.pack();
}
@Override
public void actionPerformed(ActionEvent arg0) {
//获取输入的用户名和密码
String name = txt_name.getText();
String password = txt_psw.getText();
//创建数据库助手类
DBHelper db = new DBHelper();
//调用数据库助手提供的接口findUser,并将用户名和密码作为参数传递
try {
if(db.findUser(name, password)){
System.out.println("登录...");
}else{
System.out.println("用户不存在或密码错误!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在登录界面,当点击登录按钮,获取用户名和密码,调用数据库层方法,并依据返回的结果进行相应的业务处理。
目前登录界面代码立马靓仔多了,其只负责界面显示和业务处理,至于数据库相关处理都丢给了DBHelper对象负责。相当于完成登录功能这件事由一个人变成了两个人,其中一个专门负责和数据库交互。
6 解耦业务层
在界面层,我们希望其只负责界面显示,业务处理(login业务)应该由用户业务类(UserService)处理。这样登录功能就由三个人协力完成,各自负责自己擅长的事情,且出现错误也好定位是在那一层,缩小了找错范围。完成三层解耦的结构如下图所示。
将登录界面中负责登录业务的代码抽离出来,编写一个用户业务处理类,如代码清单5所示。
代码清单5:UserService.java
public class UserService {
// 负责处理登录业务
public void login(String name, String password) {
// 调用数据库层,处理登录
DBHelper db = new DBHelper();
// 调用数据库助手提供的接口findUser,并将用户名和密码作为参数传递
try {
if (db.findUser(name, password)) {
System.out.println("登录...");
} else {
System.out.println("用户不存在或密码错误!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
此时登录界面类如代码清单6所示。
代码清单6:LoginDig.java
public class LoginDig extends JFrame implements ActionListener{
/*
* 定义登录界面控件
*/
//定义用户静态标签
private JLabel lb_name;
//定义密码静态标签
private JLabel lb_psw;
//定义用户文本框
private JTextField txt_name;
//定义密码文本框
private JPasswordField txt_psw;
//定义登录按钮
private JButton btn_login;
//构造方法,初始化控件,将控件加入框架中
public LoginDig() {
//创建控件
lb_name = new JLabel("用户:");
txt_name = new JTextField(10);
lb_psw = new JLabel("密码:");
txt_psw = new JPasswordField(10);
btn_login = new JButton("登录");
//注册按钮事件,当点击按钮时,执行actionPerformed方法
btn_login.addActionListener(this);
//设置表格布局结构,3行2列
this.setLayout(new GridLayout(3, 2));
this.add(lb_name);
this.add(txt_name);
this.add(lb_psw);
this.add(txt_psw);
this.add(btn_login);
//显示框架
this.setVisible(true);
this.pack();
}
@Override
public void actionPerformed(ActionEvent arg0) {
//获取输入的用户名和密码
String name = txt_name.getText();
String password = txt_psw.getText();
//调用业务层
UserService userService = new UserService();
userService.login(name, password);
}
}