第13章 基于Java Swing的图书管理系统

13.1 需求分析

在当今社会,随着信息技术的不断发展,信息管理系统已经进入到了人类社会的各个领域,人们对于信息技术的掌握也越来越迅速。在图书管理的过程中也引入图书管理体系,图书管理系统将大大节省人力、物力、时间、金钱等资源,不仅方便了工作人员的管理,也增加了读者查找、借阅图书的便利。

在图书管理系统项目中主要讲解如何开发基于Java Swing的图书管理系统。该项目应满足以下需求。

● 统一友好的操作界面,具有良好的用户体验。

● 用户信息的注册、验证、登录功能。

● 用户通过图书名称模糊搜索相关图书。

● 用户借书功能。

● 用户还书功能。

● 设计后台管理,用于管理系统的各项基本数据,包括类别管理、书籍管理、用户管理。

● 系统运行安全稳定且响应及时。

13.2 功能结构

图书管理系统项目分为用户界面和管理员界面两个部分,用户界面的功能结构具体如下图。

管理员界面的功能结构具体如下图。

13.3 项目预览

首先进入图书管理系统的用户界面,用户界面主要功能包括借书、还书以及图书查询功能如右图。

在上图中,选择借阅信息区域中的一条数据,单击【还书】按钮,即可归还图书。

在上图中,选择书籍信息区域中的一条数据,单击【借书】按钮,即可借阅图书。

在上图中,用户还可以按书籍名称或者按作者查询图书。例如,按书籍名称查询图书,在文本框中输入书籍名称,单击【查询】按钮,即可获取书籍信息。

13.4 数据库设计

13.4.1 E-R图设计

在设计数据库之前,首先需要明确在图书管理系统项目中都有哪些实体对象。根据实体对象间的关系设计数据库。接下来介绍一种能描述实体对象关系的模型——E-R图。E-R图也称实体-联系图(Entity Relationship Diagram),它能直够直观地表示实体类型和属性之间的关联关系。

下面根据图书管理系统项目的需求,为本项目的核心实体对象设计E-R图,具体如下:

(1)用户实体(user)的E-R图。

(2)图书实体(book)的E-R图。

(3)图书类别实体(book_type)的E-R图。

(4)图书借阅详情实体(borrowdetail)的E-R图。

13.4.2 数据表结构

了解实体类的E-R图结构后,接下来根据E-R图设计数据表。在教材中,只提供数据表的表结构,读者可根据表结构自行编写SQL语句创建表,也可以执行配套的项目源码中的SQL语句创建表。

根据上一小节中的E-R图结构,项目中需要创建4个表,具体如下。

(1)用户表—user

user表用于保存图书管理系统用户以及管理员的信息。user表结构如下表。

字段名类型是否为空是否为主键说明
idint(11)用户表主键
usernamevarchar(255)用户名
passwordvarchar(255)用户密码
roleint(255)用户分类
sexvarchar(1)用户性别
phonechar(11)用户电话

(2)书籍表—book

book表用于保存图书管理系统的图书信息。book表结构如下表。

字段名类型是否为空是否为主键描述
idint(11)图书表主键
book_namevarchar(255)图书名称
type_idint(11)图书类别
authorvarchar(255)作者
publishvarchar(255)出版社
pricedouble(10)图书价格
numberint(11)图书数量
statusint(11)借阅状态
remarkvarchar(255)图书描述

(3)图书类别表—book_type

book_type表用于保存图书管理系统的图书类别信息。book_type表结构如下表。

字段名类型是否为空是否为主键描述
idint(11)图书类别表主键
type_namevarchar(255)类别名称
remarkvarchar(255)类别描述

(4)图书借阅详情表—borrowdetail

borrowetail表用于保存图书管理系统图书的借阅详情信息。borrowdetail表结构如下表。

字段名类型是否为空是否为主键描述
idint(11)订单表主键
user_idint(11)用户id
book_idint(11)图书id
statusint(11)借阅状态
borrow_timebigint(20)借阅时间
return_timebigint(20)归还时间

13.5 项目环境搭建

在开发功能模块之前,应该先进行项目环境及项目框架的搭建等工作,接下来分步骤讲解,在正式开发系统前应做的准备工作,具体如下。

(1)确定项目开发环境

● 操作系统:Windows10版本。

● Java开发包:JDK 8。

● 数据库:MySQL 5.7。

● 开发工具:IntelliJ IDEA 2019.3。

● 浏览器:谷歌浏览器。

(2)创建数据库表

在MySQL数据库中创建一个名称为bookmanager的数据库,并根据表结构在bookmanager数据库中创建相应的表。

/*
SQLyog Ultimate v10.42 
MySQL - 5.5.19 : Database - bookmanager
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`bookmanager` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;USE `bookmanager`;/*Table structure for table `book` */DROP TABLE IF EXISTS `book`;CREATE TABLE `book` (`id` int(11) NOT NULL AUTO_INCREMENT,`book_name` varchar(255) DEFAULT NULL,`type_id` int(11) DEFAULT NULL,`author` varchar(255) DEFAULT NULL,`publish` varchar(255) DEFAULT NULL,`price` double(10,2) DEFAULT NULL,`number` int(11) DEFAULT NULL,`status` int(11) DEFAULT '1' COMMENT '状态 1上架0下架',`remark` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;/*Data for the table `book` */insert  into `book`(`id`,`book_name`,`type_id`,`author`,`publish`,`price`,`number`,`status`,`remark`) values (4,'西游记',3,'吴承恩','机械工业出版社',23.00,213,1,'四大名著之一'),(6,'SpringCloud微服务架构开发',1,'黑马程序员','人民邮电出版社',28.00,20,1,'微服务实战开发'),(7,'水浒传',3,'施耐庵 ','人民文学出版社',29.00,30,1,'四大名著之一'),(8,'Java基础入门(第2版)',1,'黑马程序员','清华大学出版社',30.20,22,1,'提高Java编程功底必备'),(9,'中国文学编年史',2,'陈文新','湖南人民出版社',35.30,36,1,'中国文学编年史'),(10,'JavaWeb程序设计任务教程',1,'黑马程序员','人民邮电出版社',25.50,16,1,'学习JavaWeb的好帮手'),(11,'SSH框架整合实战教程',1,'传智播客高教产品研发部','清华大学出版社',59.00,12,1,'SSH项目开发实战'),(12,'朝花夕拾',3,'鲁迅','辽海出版社',44.60,30,1,'鲁迅小说全集系列'),(13,'彷徨',3,'鲁迅','辽海出版社',44.60,16,1,'鲁迅小说全集系列'),(14,'呐喊',3,'鲁迅','辽海出版社',44.50,16,1,'鲁迅小说全集系列'),(15,'阿Q正传',3,'鲁迅','辽海出版社',29.00,33,1,'鲁迅小说全集系列');/*Table structure for table `book_type` */DROP TABLE IF EXISTS `book_type`;CREATE TABLE `book_type` (`id` int(11) NOT NULL AUTO_INCREMENT,`type_name` varchar(255) DEFAULT NULL,`remark` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;/*Data for the table `book_type` */insert  into `book_type`(`id`,`type_name`,`remark`) values (1,'技术','技术类'),(2,'人文','人文类'),(3,'小说','人生情感小说');/*Table structure for table `borrowdetail` */DROP TABLE IF EXISTS `borrowdetail`;CREATE TABLE `borrowdetail` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL,`book_id` int(11) NOT NULL,`status` int(11) NOT NULL COMMENT '状态  1在借2已还',`borrow_time` bigint(20) DEFAULT NULL,`return_time` bigint(20) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;/*Data for the table `borrowdetail` */insert  into `borrowdetail`(`id`,`user_id`,`book_id`,`status`,`borrow_time`,`return_time`) values (1,1,2,2,1546414916391,1546414948498),(2,1,3,2,1546414932877,1556417443285),(3,1,2,2,1546416530026,1546416640210),(4,1,1,2,1546565100120,1556334334816),(5,1,4,1,1546565102870,NULL),(6,3,1,2,1546565519776,1556207839074),(7,3,4,1,1546565522374,NULL),(8,1,1,1,1556427836809,NULL),(9,4,3,1,1556433544156,NULL),(10,7,5,1,1556503388763,NULL),(11,8,5,2,1556507260569,1556507349243),(12,8,13,1,1556507333043,NULL),(13,8,14,1,1556507390633,NULL),(14,5,4,2,1556523317389,1556523338061),(15,5,12,1,1556523321541,NULL),(16,5,13,2,1556523324149,1556535561206),(17,5,10,1,1556535626582,NULL),(18,5,8,2,1556535629488,1556585064182),(19,5,6,1,1556539744896,NULL),(20,1,5,1,1556539946226,NULL),(21,9,2,2,1556583833816,1556583847518),(22,9,7,1,1556583838018,NULL),(23,5,14,1,1556585092996,NULL),(24,5,11,1,1556585100866,NULL),(25,1,12,1,1556845403233,NULL),(26,11,2,2,1561804768359,1561804772616);/*Table structure for table `user` */DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(255) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`role` int(255) DEFAULT NULL COMMENT '角色  1学生 2管理员',`sex` varchar(1) DEFAULT NULL,`phone` char(11) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;/*Data for the table `user` */insert  into `user`(`id`,`username`,`password`,`role`,`sex`,`phone`) values (1,'xkj','xkj123',1,'男','13195648799'),(2,'admin','111111',2,'男','13198645975'),(3,'徐某人','xkj123',1,'女','13195648529'),(4,'肖淼','sdf78978',1,'女','13195698458'),(5,'张军伟','zjw520',1,'女','13195689458'),(6,'杨帆','dfd757',1,'女','15246598568'),(7,'九头蛇','kkk111',1,'男','13194959879'),(8,'蔡佳铭','cjm7418',1,'女','13164649855'),(9,'杨飞龙','kj12345',1,'男','13195864589'),(11,'javaniu','111111',1,'男','13520109203');/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

(3)创建项目,引入JAR包

在IntelliJ IDEA中创建一个名称为myBookManager的Java工程,将项目所需JAR包导入到项目的WEB-INF/lib文件夹下。本项目使用jdbc连接数据库,因此需要MySQL驱动的JAR包。

本项目所需JAR包具体如下图。

(4)创建包

在工程的src文件夹下创建包,命名为cn.itcast.bookmanager,然后在cn.itcast.bookmanager包下创建4个子包,分别命名为dao、JFrame、model、utils,src目录结构如右图。

上图中各个包下的文件归类具体如下。

● dao包下的java文件为与数据库进行交互的类。

● JFrame包下的java文件为UI界面。

● model包下的java文件为实体类。

● utils包中的类为项目中所用到的工具类。

13.6 实体类设计

13.2节讲解了项目实体对象的划分和数据表的设计,针对每一个实体对象都要设计一个类。下面分别介绍项目实体类的设计。

(1)用户实体类

在model包下新建User类,用于描述用户实体。在User类中声明属性userId、userName、password、role、sex、phone,并编写属性对应的getter和setter方法。

package com.bookmanager.model;public class User {private Integer userId;private String userName;private String password;//角色  1普通  2管理员private Integer role;private String sex;private String phone;public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}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 Integer getRole() {return role;}public void setRole(Integer role) {this.role = role;}
}

(2)图书实体类

在model包下新建Book类,用于描述图书实体。在Book类中声明属性bookId、bookName、author、status、bookTypeId、publish、number、price、remark,并编写属性对应的getter和setter方法。

package com.bookmanager.model;public class Book {private Integer bookId;private String bookName;private String author;//状态 1上架  2下架private Integer status;private Integer bookTypeId;private String publish;//库存private Integer number;private double price;private String remark;public Integer getBookId() {return bookId;}public void setBookId(Integer bookId) {this.bookId = bookId;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}public Integer getBookTypeId() {return bookTypeId;}public void setBookTypeId(Integer bookTypeId) {this.bookTypeId = bookTypeId;}public String getPublish() {return publish;}public void setPublish(String publish) {this.publish = publish;}public Integer getNumber() {return number;}public void setNumber(Integer number) {this.number = number;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}

(3)图书类别实体类

在model包下新建BookType类,用于描述图书类别实体。在BookType类中声明属性typeId、typeName、remark,并编写属性对应的getter和setter方法。

package com.bookmanager.model;public class BookType {private Integer typeId;private String typeName;private String remark;public Integer getTypeId() {return typeId;}public void setTypeId(Integer typeId) {this.typeId = typeId;}public String getTypeName() {return typeName;}public void setTypeName(String typeName) {this.typeName = typeName;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}@Overridepublic String toString() {return this.typeName;}
}
package com.bookmanager.model;public class BookType {private Integer typeId;private String typeName;private String remark;public Integer getTypeId() {return typeId;}public void setTypeId(Integer typeId) {this.typeId = typeId;}public String getTypeName() {return typeName;}public void setTypeName(String typeName) {this.typeName = typeName;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}@Overridepublic String toString() {return this.typeName;}
}

(4)图书借阅详情实体类

在model包下新建BorrowDetail类,用于描述图书借阅详情。在BorrowDetail类中声明属性borrowId、userId、bookId、status、borrowTime、returnTime,并编写属性对应的getter和setter方法。

package com.bookmanager.model;public class BorrowDetail {private Integer borrowId;private Integer userId;private Integer bookId;//状态  1在借  2已还private Integer status;private Long borrowTime;private Long returnTime;public Integer getBorrowId() {return borrowId;}public void setBorrowId(Integer borrowId) {this.borrowId = borrowId;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public Integer getBookId() {return bookId;}public void setBookId(Integer bookId) {this.bookId = bookId;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}public Long getBorrowTime() {return borrowTime;}public void setBorrowTime(Long borrowTime) {this.borrowTime = borrowTime;}public Long getReturnTime() {return returnTime;}public void setReturnTime(Long returnTime) {this.returnTime = returnTime;}
}

13.7 工具类设计

(1)DbUitil类

在utils包下新建DbUtil类,用于获取数据库连接,DbUtil类具体实现如下。

package com.bookmanager.utils;import java.sql.DriverManager;
import com.mysql.jdbc.Connection;
public class DbUtil {private String dbDriver = "com.mysql.jdbc.Driver";private String dbUrl = "jdbc:mysql://localhost:3306/bookmanager?useUnicoder=true&characterEncoding=utf-8";private String dbUserName = "root";private String dbPassword = "admin";public Connection getConnection()throws Exception{Class.forName(dbDriver);Connection con = (Connection) DriverManager.getConnection(dbUrl,dbUserName,dbPassword);return con;}public void closeCon (Connection con)throws Exception {if(con!=null){con.close();}}}

上述代码中,第2~6行代码是创建JDBC所需的四个连接参数 ;第7~12行代码用于获取数据库连接;第13~18行代码用于关闭JDBC连接对象资源。

(2)toolUtil类

在utils包下新建toolUtil类,在该类中定义一些方法,用于判断字符串是否为空、获取当前时间、对时间进行格式化以及获取当前登录用户等。

package com.bookmanager.utils;import com.bookmanager.model.User;import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpSession;public class toolUtil {public static boolean isEmpty(String str){if(str != null && !"".equals(str.trim())){return false;}return true;}public static Long getTime(){long time = System.currentTimeMillis();return time;}public static String getDateByTime(Long time){SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String string = format.format(new Date(time));return string;}public static User getUser(HttpSession session){User user = (User) session.getAttribute("user");return user;}public static void setUser(HttpSession session,User user){session.setAttribute("user", user);}
}

上述代码中,第2~7行代码用于判断字符串是否为空;第8~11行代码用于获取当前时间;第12~17行代码用于对时间进行格式化;第18~21行代码用于获取当前登录用户;第22~24行代码用于设置用户登录。

到此,项目的前期准备就已经完成了,下面将针对用户界面和管理员界面的不同功能模块进行讲解。由于项目代码量大,而教材篇幅有限,在讲解功能模块时,只展示关键性的代码,详细代码请参见项目配套的源代码。

13.8 登录注册功能实现

13.8.1 实现用户注册功能

首次进入图书管理系统的用户需要先注册账号,用户只有在注册账号并登录后才可以借阅图书。图书管理系统项目的用户注册页面预览如下图。

1.编写注册页面

在JFrame包中新建RegFrm类,在RegFrm类中编写用户注册时需要填写的用户名、密码、手机号、性别等文本框及按钮组件。由于界面部分代码量较大,因此这里我们以密码为例进行讲解。

1 private JFrame jf;
2 private JTextField textField_1;
3 private JLabel passwordMes;
4 JLabel label_1 = new JLabel("密码:");
5 label_1.setForeground(Color.BLACK);
6 label_1.setFont(new Font("幼圆", Font.BOLD, 16));
7 label_1.setBounds(120, 108, 65, 40);
8 jf.getContentPane().add(label_1);     
9 textField_1 = new JTextField();
10 textField_1.setFont(new Font("Dialog", Font.BOLD, 14));
11 textField_1.setToolTipText("");
12 textField_1.setColumns(10);
13 textField_1.setBounds(198, 114, 164, 30); 
14 jf.getContentPane().add(textField_1);      

上述代码中,第4行代码创建了一个名为密码的lable;第5~7行代码是对lable设置颜色、字体、坐标、宽高;第8行代码将lable添加到面板中;第9行代码创建了一个文本框;第10~13行代码分别设置文本框中内容的字体、文本框的内容默认为空、文本框的长度、坐标以及宽高;第14行代码将文本框添加到面板中。

2.编写密码文本框的监听器

在界面中创建密码组件之后,需要编写一个监听器来监听密码文本框的动作。监听器的实现代码如下所示。

1 textField_1.addFocusListener(new FocusListener() {        
2   @Override
3    public void focusLost(FocusEvent e) {  
4       String pwd=textField_1.getText();
5       if(toolUtil.isEmpty(pwd)){
6          passwordMes.setText("密码不能为空");
7          passwordMes.setForeground(Color.RED);
8           }else{
9             boolean  flag=        
10         pwd.matches("^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$");
11 if(flag){
12            passwordMes.setText("√");
13            passwordMes.setForeground(Color.GREEN);
14         }else{
15           JOptionPane.showMessageDialog(null, "密码需为6-16位数字和字母
16           的组合");
17           passwordMes.setText("");
18          }  
19       }          
20    }
21 @Override
22 public void focusGained(FocusEvent e) {          
23 }
24 }); 

上述代码中,为密码文本框对象textField_1添加了监听器,在focusLost()函数中编写了密码文本框失去鼠标焦点时,对文本框中内容的校验逻辑。其中,第5~7行代码是判断密码是否为空,当密码为空时提示“密码不能为空”。第10行代码使用正则表达式定义密码的格式必须为6-16位的字母和数字的组合,若输入的密码不符合此规范,进行提示。

3.编写注册按钮的监听器

填写注册信息之后,单击【注册】按钮完成注册。在单击【注册】按钮后,注册按钮会对所填注册信息的正确性、完整性进行判断。【注册】按钮监听器实现代码如下所示。

1 button = new JButton("注册");
2     button.addActionListener(new ActionListener() {
3         public void actionPerformed(ActionEvent e) {
4           String code=textField_3.getText();
5           if(toolUtil.isEmpty(code)){
6             JOptionPane.showMessageDialog(null, "请输入验证码");
7           }else{
8              if(code.equalsIgnoreCase(vcode.getCode())){
9                  RegCheck(e);
10              }else{
11                JOptionPane.showMessageDialog(null, "验证码错误,请重新输入
12                ");   
13              } 
14          } 
15        }
16  });  
17 protected void RegCheck(ActionEvent e) { 
18     String username=textField.getText();
19     String password=textField_1.getText();
20     String phone=textField_2.getText();
21      String sex="";
22      if(rdbtnNewRadioButton.isSelected()){
23         sex=rdbtnNewRadioButton.getText(); 
24     }else{ 
25        sex=rdbtnNewRadioButton_1.getText();
26      } 
27     if (toolUtil.isEmpty(username) || 
28       toolUtil.isEmpty(password)||toolUtil.isEmpty(phone)) {
29          JOptionPane.showMessageDialog(null, "请输入相关信息"); 
30          return;
31       } 
32 User user = new User();
33     user.setUserName(username);
34     user.setPassword(password);
35     user.setSex(sex);
36     user.setPhone(phone);
37     user.setRole(1);
38     Connection con = null;
39     try { 
40       con = dbUtil.getConnection(); 
41        int i = userDao.addUser(con, user);
42        if (i == 2) {
43         JOptionPane.showMessageDialog(null, "该用户名已存在,请重新注册");
44        } else if (i == 0) {
45           JOptionPane.showMessageDialog(null, "注册失败"); 
46        } else {
47 JOptionPane.showMessageDialog(null, "注册成功");
48           jf.dispose();
49           new LoginFrm();
50        }
51     } catch (Exception e1) {
52        e1.printStackTrace();
53     } finally {
54         try {
55            dbUtil.closeCon(con);
56        } catch (Exception e1) {
57           e1.printStackTrace(); 
58       }
59      }      
60  }

上述代码中,第1行代码创建了一个注册按钮;第2~59行代码为【注册】按钮添加监听器,监听【注册】按钮的单击事件。当单击【注册】按钮时,监听器首先判断是否已经输入了验证码,若没有输入验证码,则提示“请输入验证码”;若已经输入验证码,则判断验证码的正确性,若验证码错误,则提示“验证码错误,请重新输入”;若验证码正确则判断用户名、密码、性别、手机号等信息是否填写完成,若填写完成,则从数据库中查询此用户名是否已经存在;若不存在,则提示“注册成功”,否则提示“该用户名已存在,请重新注册”。

4.编写dao层

在dao包中新建UserDao类,在UserDao类中编写addUser()方法,用于完成注册操作。addUser()方法的实现代码如下所示。

package com.bookmanager.Dao;import com.bookmanager.model.User;
import com.bookmanager.utils.toolUtil;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;import java.sql.ResultSet;
public class UserDao {public int addUser(Connection con,User user) throws Exception{//查询注册用户名是否存在String sql = "select * from user where userName=? ";PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql);pstmt.setString(1,user.getUserName());ResultSet rs = pstmt.executeQuery();if(rs.next()){return 2;}sql="insert into user (username,password,role,sex,phone) values (?,?,?,?,?)";PreparedStatement pstmt2=(PreparedStatement) con.prepareStatement(sql);pstmt2.setString(1, user.getUserName());pstmt2.setString(2, user.getPassword());pstmt2.setInt(3, user.getRole());pstmt2.setString(4,user.getSex());pstmt2.setString(5,user.getPhone());return pstmt2.executeUpdate();}
}

上述代码中,第3~10行代码是从数据库中查询是否存在此用户名的用户,若存在返回2;第11~20行代码是当没有在数据库查询到该用户时,向数据库插入用户信息。

注册页面完整代码如下

package com.bookmanager.JFrame;import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;import javax.swing.JTextField;import com.bookmanager.Dao.UserDao;
import com.bookmanager.model.User;
import com.bookmanager.utils.DbUtil;
import com.bookmanager.utils.toolUtil;
import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;import com.mysql.jdbc.Connection;import javax.swing.JRadioButton;
import javax.swing.JButton;import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.ImageIcon;/*** 注册页面*/
public class RegFrm extends JFrame {private JFrame jf;private JTextField textField;private JTextField textField_1;private JLabel label_2;private JTextField textField_2;private JLabel label_3;private JRadioButton rdbtnNewRadioButton_1;private JLabel usernameMes;private JLabel passwordMes;private JLabel phoneMes;private ValidCode vcode;private JLabel label_4;private JTextField textField_3;private JButton button;private JButton button_1;private JRadioButton rdbtnNewRadioButton;DbUtil dbUtil=new DbUtil();UserDao userDao=new UserDao();private JLabel lblNewLabel;private JLabel lblNewLabel_1;public RegFrm() {jf=new JFrame("用户注册");jf.getContentPane().setFont(new Font("幼圆", Font.BOLD, 16));jf.setBounds(600, 250,510, 410);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.getContentPane().setLayout(null);JLabel label = new JLabel("用户名:");label.setForeground(Color.BLACK);label.setFont(new Font("幼圆", Font.BOLD, 16));label.setBounds(110, 65, 75, 40);jf.getContentPane().add(label);textField = new JTextField();textField.setFont(new Font("幼圆", Font.BOLD, 14));textField.setForeground(Color.BLACK);textField.setColumns(10);textField.setBounds(198, 71, 164, 30);jf.getContentPane().add(textField);textField.addFocusListener(new FocusListener() {      @Overridepublic void focusGained(FocusEvent e) {}@Overridepublic void focusLost(FocusEvent e) {String text = textField.getText();if(toolUtil.isEmpty(text)){usernameMes.setText("用户名不能为空");usernameMes.setForeground(Color.RED);}else{usernameMes.setText("√");usernameMes.setForeground(Color.GREEN);}}});JLabel label_1 = new JLabel("密码:");label_1.setForeground(Color.BLACK);label_1.setFont(new Font("幼圆", Font.BOLD, 16));label_1.setBounds(120, 108, 65, 40);jf.getContentPane().add(label_1);textField_1 = new JTextField();textField_1.setFont(new Font("Dialog", Font.BOLD, 14));textField_1.setToolTipText("");textField_1.setColumns(10);textField_1.setBounds(198, 114, 164, 30);jf.getContentPane().add(textField_1);textField_1.addFocusListener(new FocusListener() {@Overridepublic void focusLost(FocusEvent e) {  String pwd=textField_1.getText();if(toolUtil.isEmpty(pwd)){passwordMes.setText("密码不能为空");passwordMes.setForeground(Color.RED);}else{boolean flag=pwd.matches("^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$");if(flag){passwordMes.setText("√");passwordMes.setForeground(Color.GREEN);}else{JOptionPane.showMessageDialog(null, "密码需为6-16位数字和字母的组合");passwordMes.setText("");}}}@Overridepublic void focusGained(FocusEvent e) {}});label_2 = new JLabel("手机号:");label_2.setForeground(Color.BLACK);label_2.setFont(new Font("幼圆", Font.BOLD, 16));label_2.setBounds(110, 150, 75, 40);jf.getContentPane().add(label_2);textField_2 = new JTextField();textField_2.setFont(new Font("Dialog", Font.BOLD, 14));textField_2.setColumns(10);textField_2.setBounds(198, 156, 164, 30);jf.getContentPane().add(textField_2);textField_2.addFocusListener(new FocusListener() {@Overridepublic void focusLost(FocusEvent e) {String phone=textField_2.getText();if(toolUtil.isEmpty(phone)){phoneMes.setText("手机号不能为空");phoneMes.setForeground(Color.RED);}else{boolean flag=phone.matches("^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$");if(flag){phoneMes.setText("√");phoneMes.setForeground(Color.GREEN);}else{JOptionPane.showMessageDialog(null, "请输入正确的手机号格式");phoneMes.setText("");}}}@Overridepublic void focusGained(FocusEvent e) {}});label_3 = new JLabel("性别:");label_3.setForeground(Color.BLACK);label_3.setFont(new Font("幼圆", Font.BOLD, 16));label_3.setBounds(123, 184, 65, 40);jf.getContentPane().add(label_3);rdbtnNewRadioButton = new JRadioButton("男");rdbtnNewRadioButton.setFont(new Font("幼圆", Font.BOLD, 16));rdbtnNewRadioButton.setBounds(198, 192, 58, 23);jf.getContentPane().add(rdbtnNewRadioButton);rdbtnNewRadioButton_1 = new JRadioButton("女");rdbtnNewRadioButton_1.setFont(new Font("幼圆", Font.BOLD, 16));rdbtnNewRadioButton_1.setBounds(287, 192, 65, 23);jf.getContentPane().add(rdbtnNewRadioButton_1);ButtonGroup bg=new ButtonGroup();bg.add(rdbtnNewRadioButton_1);bg.add(rdbtnNewRadioButton);usernameMes = new JLabel("");usernameMes.setFont(new Font("Dialog", Font.BOLD, 15));usernameMes.setBounds(372, 57, 122, 27);jf.getContentPane().add(usernameMes);passwordMes = new JLabel("");passwordMes.setFont(new Font("Dialog", Font.BOLD, 15));passwordMes.setBounds(372, 100, 122, 27);jf.getContentPane().add(passwordMes);phoneMes = new JLabel("");phoneMes.setFont(new Font("Dialog", Font.BOLD, 15));phoneMes.setBounds(372, 142, 122, 30);jf.getContentPane().add(phoneMes);vcode=new ValidCode();vcode.setLocation(293, 231);jf.getContentPane().add(vcode);label_4 = new JLabel("验证码:");label_4.setForeground(Color.BLACK);label_4.setFont(new Font("幼圆", Font.BOLD, 16));label_4.setBounds(110, 231, 75, 40);jf.getContentPane().add(label_4);textField_3 = new JTextField();textField_3.setColumns(10);textField_3.setBounds(198, 241, 83, 30);jf.getContentPane().add(textField_3);button = new JButton("注册");button.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {String code=textField_3.getText();if(toolUtil.isEmpty(code)){JOptionPane.showMessageDialog(null, "请输入验证码");}else{if(code.equalsIgnoreCase(vcode.getCode())){RegCheck(e);}else{JOptionPane.showMessageDialog(null, "验证码错误,请重新输入");}}}});button.setFont(new Font("幼圆", Font.BOLD, 15));button.setBounds(120, 299, 75, 30);jf.getContentPane().add(button);button_1 = new JButton("前往登录页面");button_1.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {jf.setVisible(false);new LoginFrm();}});button_1.setFont(new Font("幼圆", Font.BOLD, 15));button_1.setBounds(245, 299, 132, 30);jf.getContentPane().add(button_1);lblNewLabel_1 = new JLabel("用户注册");lblNewLabel_1.setFont(new Font("Dialog", Font.BOLD, 22));lblNewLabel_1.setBounds(184, 10, 122, 51);jf.getContentPane().add(lblNewLabel_1);lblNewLabel = new JLabel("");lblNewLabel.setForeground(Color.BLACK);lblNewLabel.setIcon(new ImageIcon(RegFrm.class.getResource("/tupian/regBG.png")));lblNewLabel.setBounds(0, 0, 494, 372);jf.getContentPane().add(lblNewLabel);jf.setVisible(true);jf.setResizable(true);}protected void RegCheck(ActionEvent e) {String username=textField.getText();String password=textField_1.getText();String phone=textField_2.getText();String sex="";if(rdbtnNewRadioButton.isSelected()){sex=rdbtnNewRadioButton.getText();}else{sex=rdbtnNewRadioButton_1.getText();}if (toolUtil.isEmpty(username) || toolUtil.isEmpty(password)||toolUtil.isEmpty(phone)) {JOptionPane.showMessageDialog(null, "请输入相关信息");return;}User user = new User();user.setUserName(username);user.setPassword(password);user.setSex(sex);user.setPhone(phone);user.setRole(1);Connection con = null;try {con = dbUtil.getConnection();int i = userDao.addUser(con, user);if (i == 2) {JOptionPane.showMessageDialog(null, "该用户名已存在,请重新注册");} else if (i == 0) {JOptionPane.showMessageDialog(null, "注册失败");} else {JOptionPane.showMessageDialog(null, "注册成功");jf.dispose();new LoginFrm();}} catch (Exception e1) {e1.printStackTrace();} finally {try {dbUtil.closeCon(con);} catch (Exception e1) {e1.printStackTrace();}}}public static void main(String[] args) {try {BeautyEyeLNFHelper.frameBorderStyle = BeautyEyeLNFHelper.FrameBorderStyle.generalNoTranslucencyShadow;BeautyEyeLNFHelper.launchBeautyEyeLNF();} catch (Exception e) {e.printStackTrace();}//new RegFrm();}
}

13.8.2 实现用户登录功能

用户注册成功之后,便可以在图书管理系统登录界面进行登录操作。图书管理系统前台系统登录模块流程如下图。

图书管理系统的登录页面如右图。

用户登录时需要输入用户名和密码,并选择登陆权限。接下来分步骤讲解用户登录功能的实现。

1.编写登录页面

在JFrame包中新建loginFrm类,在loginFrm类中编写用户登录时需要填写的用户名、密码、权限等文本框及下拉框组件,代码如下所示。

1 public class LoginFrm extends JFrame {
2 public static User currentUser;
3 private JFrame jf;
4 private JTextField userNameText;
5 private JTextField passwordText;
6 private JComboBox<String> comboBox;  
7   public LoginFrm(){            
8      jf=new JFrame("图书管理");
9      jf.getContentPane().setFont(new Font("幼圆", Font.BOLD, 14));
10      jf.setBounds(600, 250, 500, 467);
11 jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
12      jf.getContentPane().setLayout(null);      
13      JLabel lblNewLabel = new JLabel(new 
14      ImageIcon(LoginFrm.class.getResource("/tupian/bg2.png")));
15      lblNewLabel.setBounds(24, 10, 430, 218);
16      jf.getContentPane().add(lblNewLabel);      
17      JLabel label = new JLabel("用户名:");
18      label.setFont(new Font("幼圆", Font.BOLD, 14));
19      label.setBounds(129, 250, 60, 29);
20      jf.getContentPane().add(label);      
21      userNameText = new JTextField();
22      userNameText.setBounds(199, 252, 127, 25);
23      jf.getContentPane().add(userNameText);
24      userNameText.setColumns(10);      
25      JLabel label_1 = new JLabel("密码:");
26 label_1.setFont(new Font("幼圆", Font.BOLD, 14));
27      label_1.setBounds(144, 289, 45, 29);
28      jf.getContentPane().add(label_1);     
29      passwordText = new JPasswordField();
30      passwordText.setColumns(10);
31      passwordText.setBounds(199, 291, 127, 25);
32      jf.getContentPane().add(passwordText);
33      JLabel label_2 = new JLabel("权限:");
34      label_2.setFont(new Font("幼圆", Font.BOLD, 14));
35 label_2.setBounds(144, 328, 45, 29);
36      jf.getContentPane().add(label_2);      
37      comboBox = new JComboBox();
38      comboBox.setBounds(199, 332, 127, 25);
39      comboBox.addItem("用户");
40      comboBox.addItem("管理员");
41      jf.getContentPane().add(comboBox);     
42      JButton button = new JButton("登录");
43      button.setBounds(153, 377, 65, 29);
44      jf.getContentPane().add(button);   
45 } 
46 }

上述代码中,第8~41行代码用于创建标题、用户名、密码、权限的文本框及下拉框组件,并分别为这些组件设置字体、坐标、宽高,最后将这些组件添加到面板中。第42~44行代码创建登录按钮并将登录按钮添加到面板中。

2.编写登录按钮的监听器

用户在填写完登录信息后,单击【登录】按钮进行登录时,需要判断用户登录信息的正确性和完整性,这就要为【登录】按钮添加监听器。为【登录】按钮添加监听器的代码如下所示。

1 button.addActionListener(new ActionListener() {
2         public void actionPerformed(ActionEvent e) {
3            checkLogin(e);
4         }
5      });
6      UserDao userDao = new UserDao();
7      DbUtil dbUtil = new DbUtil();
8      protected void checkLogin(ActionEvent e) {
9           String userName = userNameText.getText();
10      String password = passwordText.getText();
11     int index = comboBox.getSelectedIndex();
12      if (toolUtil.isEmpty(userName) || toolUtil.isEmpty(password)) {
13        JOptionPane.showMessageDialog(null, "用户名和密码不能为空");
14        return;
15      }
16 User user = new User();
17      user.setUserName(userName);
18      user.setPassword(password);
19      if (index == 0) {
20        user.setRole(1);
21     } else {
22        user.setRole(2);
23    }
24     Connection con = null;
25     try { 
26       con = dbUtil.getConnection();
27       User login = userDao.login(con, user);
28       currentUser = login;
29 if (login == null) { 
30         JOptionPane.showMessageDialog(null, "登录失败"); 
31       } else {
32          // 权限 1普通 2管理员 
33          if (index == 0) {
34             // 学生
35             jf.dispose();
36              new UserMenuFrm();
37           } else {
38             // 管理员
39             jf.dispose();
40             new AdminMenuFrm();
41          }
42        }
43 } catch (Exception e21) {
44       e21.printStackTrace();
45       JOptionPane.showMessageDialog(null, "登录异常");
46     } finally {
47        try {
48           dbUtil.closeCon(con);
49       } catch (Exception e31) {
50           e31.printStackTrace();
51        } 
52 } 

上述代码中,第1~5行代码为【登录】按钮添加了监听器。第8~15行代码判断用户名和密码是否为空;第19~23行代码判断当前登录用户的权限。第24~52行代码从数据库中查询是否有此用户。若有此用户,判断用户的权限;若没有,则提示“登录失败”。若登录时出现异常,则提示“登录异常”。

3.编写Dao层

在UserDao类中添加login()方法,用于从数据库查询用户。login()方法的实现代码如下所示。

public User login(Connection con, User user)throws Exception {User resultUser = null;String sql = "select * from user where username=? and password=? and role = ?";PreparedStatement pstmt = (PreparedStatement) con.prepareStatement(sql);pstmt.setString(1,user.getUserName());pstmt.setString(2,user.getPassword());pstmt.setInt(3,user.getRole());ResultSet rs = pstmt.executeQuery();if(rs.next()){resultUser = new User();resultUser.setUserId(rs.getInt("id"));resultUser.setUserName(rs.getString("username"));resultUser.setSex(rs.getString("sex"));resultUser.setPhone(rs.getString("phone"));}return resultUser;
}

13.8 图书借还模块

在图书管理系统中,图书借还模块是必不可少的,也是最重要的模块之一。本节将学习图书管理系统项目的图书借还模块的实现。在开发图书借还模块之前,首先带领大家熟悉该模块实现的功能以及整个功能模块的处理流程。下面通过图书借还模块功能结构图来展示图书借还模块实现的所有功能,具体如右图。

图书借还功能的流程如下图。

13.8.1 实现用户借书功能

用户成功登录图书管理系统后,就可以借阅图书了。图书管理系统项目的用户借书页面预览如右图。

登录用户选中某一条图书信息,或者通过图书名称/作者名称查询图书并选中后,单击【借书】按钮,完成图书借阅。

接下来分步骤讲解借书功能的实现。

1.编写借书功能界面

在JFrame包中新建UserMenuFrm类,在UserMenuFrm类中编写书籍信息列表相关组件、图书查询相关组件、借书相关组件。由于界面部分代码量较大,这里我们只对核心代码进行讲解,核心代码如下所示。

1 panel_2 = new JPanel(); 
2        panel_2.setBorder(new TitledBorder(null, 
3      "\u4E66\u7C4D\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, 
4	   null, Color.RED));
5        panel_2.setBounds(23, 374, 651, 346);
6        jf.getContentPane().add(panel_2);
7        panel_2.setLayout(null);        
8        textField_1 = new JTextField(); 
9        textField_1.setColumns(10);
10        textField_1.setBounds(252, 23, 135, 27); 
11        panel_2.add(textField_1);       
12        button_1 = new JButton("查询");
13        button_1.setFont(new Font("幼圆", Font.BOLD, 16));
14        button_1.setBounds(408, 20, 93, 33); 
15 panel_2.add(button_1);         
16        comboBox = new JComboBox(); 
17        comboBox.setFont(new Font("幼圆", Font.BOLD, 15)); 
18        comboBox.setBounds(123, 26, 109, 24);
19        comboBox.addItem("书籍名称");
20        comboBox.addItem("书籍作者");
21        panel_2.add(comboBox);        
22        String[] BookTitle={"编号", "书名", "类型", "作者", "描述" }; 
23           /*具体的各栏行记录 先用空的二维数组占位*/
24            String[][] BookDates={}; 
25          /*然后实例化 上面2个控件对象*/ 
26            BookModel=new DefaultTableModel(BookDates,BookTitle);
27            BookTable=new JTable(BookModel); 
28            putDates(new Book());//获取数据库数据放置table中        
29 panel_2.setLayout(null);
30            JScrollPane jscrollpane1 = new JScrollPane();
31            jscrollpane1.setBounds(22, 74, 607, 250);
32            jscrollpane1.setViewportView(BookTable);
33            panel_2.add(jscrollpane1);
34            jf.getContentPane().add(panel_1);               
35            JPanel panel_3 = new JPanel();
36            panel_3.setBorder(new TitledBorder(null, "\u501F\u4E66", 
37            TitledBorder.LEADING, TitledBorder.TOP, null, Color.RED));
38            panel_3.setBounds(23, 730, 645, 87); 
39            jf.getContentPane().add(panel_3); 
40            panel_3.setLayout(null);               
41            JLabel label = new JLabel("编号:");
42            label.setFont(new Font("Dialog", Font.BOLD, 15));
43 label.setBounds(68, 31, 48, 33); 
44            panel_3.add(label);              
45            textField_2 = new JTextField(); 
46            textField_2.setEditable(false);
47             textField_2.setColumns(10);
48             textField_2.setBounds(126, 34, 135, 27); 
49             panel_3.add(textField_2);            
50             JLabel label_1 = new JLabel("书名:"); 
51             label_1.setFont(new Font("Dialog", Font.BOLD, 15)); 
52             label_1.setBounds(281, 31, 48, 33);
53 panel_3.add(label_1);            
54             textField_3 = new JTextField();
55             textField_3.setEditable(false);
56             textField_3.setColumns(10); 
57             textField_3.setBounds(339, 34, 135, 27);
58             panel_3.add(textField_3);               
59             JButton button_2 = new JButton("借书");
60         	    button_2.setFont(new Font("Dialog", Font.BOLD, 16)); 
61             button_2.setBounds(495, 31, 80, 33); 
62             panel_3.add(button_2); 

上述代码中,第1~21行代码用于创建图书查询的下拉框、文本框以及查询按钮,并为这些组件设置字体、坐标、宽高,最后将这些组件添加到面板中。第22~40行代码用于创建图书信息列表。其中,列表中的内容从数据库获取。第41~59行代码用于创建借书时用于显示所借图书的图书编号、图书名的文本框以及借书按钮,并将这些组件添加到到面板中。

2.编写借书按钮的监听器

用户选中需要借阅的书籍后,单击【借书】按钮进行借书。这时需要判断该用户是否已经借阅这本书,如果已经借阅,则提示“该书已在借,请先还再借”,否则提示“借书成功”。这就要为【借书】按钮添加监听器。为【借书】按钮添加监听器代码如下所示。

1 button_2.addActionListener(new ActionListener() {
2 public void actionPerformed(ActionEvent e) {
3            String bookId = textField_2.getText();
4            String bookName = textField_3.getText();
5            if (toolUtil.isEmpty(bookId) ||
6            toolUtil.isEmpty(bookName)) {
7            JOptionPane.showMessageDialog(null, "请选择相关书籍");
8            return;
9        }
10        BorrowDetail borrowDetail = new BorrowDetail();
11        borrowDetail.setUserId(LoginFrm.currentUser.getUserId());
12        borrowDetail.setBookId(Integer.parseInt(bookId));
13        borrowDetail.setStatus(1);
14        borrowDetail.setBorrowTime(toolUtil.getTime());
15        Connection con = null;
16 try {
17           con = dbUtil.getConnection();
18           //先查询是否有该书
19           ResultSet list = bdetailDao.list(con, borrowDetail);
20           while(list.next()){
21           	JOptionPane.showMessageDialog(null, "该书已在借, 请先还再借");
22                return;
23            }
24            int i = bdetailDao.add(con, borrowDetail);
25            if (i == 1) {
26                JOptionPane.showMessageDialog(null, "借书成功");
27                putDates(new BorrowDetail());
28            } else {
29                JOptionPane.showMessageDialog(null, "借书失败");
30            }
31 } catch (Exception e1) {
32            e1.printStackTrace();
33            JOptionPane.showMessageDialog(null, "借书异常");
34        }finally{
35            try {
36                dbUtil.closeCon(con);
37            } catch (Exception e1) {
38                e1.printStackTrace();
39            }
40        }
41    }
42 });
43  //从数据库获取书籍信息
44  private void putDates(Book book) {
45 DefaultTableModel model = (DefaultTableModel) BookTable.getModel();
46  model.setRowCount(0);
47      Connection con = null;
48      try { 
49        con = dbUtil.getConnection();
50         book.setStatus(1);
51         ResultSet list = bookDao.list(con, book);
52         while (list.next()) {
53            Vector rowData = new Vector();
54            rowData.add(list.getInt("id")); 
55            rowData.add(list.getString("book_name")); 
56            rowData.add(list.getString("type_name"));
57            rowData.add(list.getString("author")); 
58 rowData.add(list.getString("remark"));
59            model.addRow(rowData); 
60        }
61      } catch (Exception e) {
62        e.printStackTrace(); 
63     }finally{
64         try {
65            dbUtil.closeCon(con); 
66        } catch (Exception e) { 
67            e.printStackTrace();
68         }
69      }      
70  }

上述代码中,第2~9行代码是单击【借书】按钮后,若没有选中图书,则提示“请选择相关书籍”;第17~23行代码查询该图书是否已经被借阅,若已经被借阅,提示“该书已在借,请先还再借”;第24~42行代码将借书信息添加到数据库,添加成功则提示“借书成功”,此时会调用putDates()方法,将借书信息插入到数据库中。若添加失败,则提示“借书失败”。

3.编写Dao层

在dao包中创建BorrowDetailDao类,在BorrowDetailDao类中添加add()方法,用于将用户借书信息插入到对应的数据库表中。add()方法代码如下所示。

package com.bookmanager.Dao;import java.sql.ResultSet;import com.bookmanager.model.BorrowDetail;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;public class BorrowDetailDao {public int add(Connection con, BorrowDetail borrowDetail) throws Exception {String sql = "insert into borrowdetail (user_id,book_id,status,borrow_time) values (?,?,?,?)";PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql);pstmt.setInt(1, borrowDetail.getUserId());pstmt.setInt(2, borrowDetail.getBookId());pstmt.setInt(3, borrowDetail.getStatus());pstmt.setLong(4, borrowDetail.getBorrowTime());return pstmt.executeUpdate();}}

上述代码中,第3~11行代码是将一条借书信息中的用户id、图书id、图书状态、借阅时间等信息插入到数据库,并更新数据库。

13.8.2 实现用户还书功能

用户成功登录图书管理系统后,就可以进行还书操作了。图书管理系统项目的用户还书页面预览如下图。归还图书时,同样只需选中其中一条已借阅的图书信息,单击【还书】按钮,便可以完成图书的归还。

接下来分步骤讲解还书功能的实现。

1.编写还书功能界面

在UserMenuFrm类中编写用户借阅信息列表以及还书相关组件。这里我们只对核心代码进行讲解,核心代码如下所示。

1 JPanel panel_1 = new JPanel();
2      panel_1.setBorder(new 
3	 TitledBorder(UIManager.getBorder("TitledBorder.border"), 
4	 "\u501F\u9605\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, 
5	 null, new Color(255, 0, 0)));
6      panel_1.setBounds(23, 48, 651, 239);      
7       /*做一个表头栏数据  一维数组* */
8       String[] title={"编号", "书名", "状态", "借书时间", "还书时间"};
9      /*具体的各栏行记录 先用空的二维数组占位*/
10       String[][] dates={};
11       /*然后实例化 上面2个控件对象*/
12       model=new DefaultTableModel(dates,title);
13       table=new JTable();
14       table.setModel(model);       
15 putDates(new BorrowDetail());//获取数据库数据放置table中        
16       panel_1.setLayout(null);
17       JScrollPane jscrollpane = new JScrollPane();
18       jscrollpane.setBounds(20, 22, 607, 188);
19       jscrollpane.setViewportView(table);
20       panel_1.add(jscrollpane);
21        jf.getContentPane().add(panel_1);        
22        lblNewLabel_1 = new JLabel("New label");
23        lblNewLabel_1.setForeground(Color.RED);
24        lblNewLabel_1.setFont(new Font("Dialog", Font.BOLD, 18));
25        lblNewLabel_1.setBounds(315, 10, 197, 28); 
26        jf.getContentPane().add(lblNewLabel_1);
27        lblNewLabel_1.setText(LoginFrm.currentUser.getUserName());              
28        JPanel panel = new JPanel();
29 panel.setBorder(new 
30	   TitledBorder(UIManager.getBorder("TitledBorder.border"), 
31	   "\u8FD8\u4E66", 
32	   TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 0,
33 	   0)));
34        panel.setBounds(23, 294, 651, 70);
35        jf.getContentPane().add(panel);
36        panel.setLayout(null);        
37        JLabel lblNewLabel = new JLabel("编号:");
38        lblNewLabel.setBounds(90, 25, 51, 27);
39        panel.add(lblNewLabel);
40 lblNewLabel.setFont(new Font("幼圆", Font.BOLD, 16));         
41        textField = new JTextField();
42        textField.setBounds(145, 28, 116, 24); 
43        panel.add(textField); 
44        textField.setColumns(10);        
45        btnBackBook = new JButton("还书");
46        btnBackBook.setFont(new Font("Dialog", Font.BOLD, 15));
47        btnBackBook.setBounds(299, 25, 85, 31);
48        panel.add(btnBackBook); 

上述代码中,第8~20行代码是创建图书信息列表,其中,列表中的内容从数据库获取。第28~48行代码创建还书时用于显示所还图书的图书编号的文本框以及还书按钮,并将这些组件加入到面板中。

  1. 编写还书按钮的监听器

用户选中需要归还的图书后,单击【还书】按钮归还图书,还时需要判断该用户是否还书成功。这就要为【还书】按钮添加监听器。为【还书】按钮添加监听器的代码如下所示。

1 btnBackBook.addActionListener(new ActionListener() {
2           public void actionPerformed(ActionEvent e) {
3               String BorrowStr = textField.getText();
4               if (toolUtil.isEmpty(BorrowStr)) { 
5                 JOptionPane.showMessageDialog(null, "请选择未还的书籍"); 
6                 return;
7            }
8 BorrowDetail detail = new BorrowDetail(); 
9              detail.setBorrowId(Integer.parseInt(BorrowStr));
10              detail.setStatus(2);
11              detail.setReturnTime(toolUtil.getTime());
12              Connection con = null; 
13              try {
14                 con = dbUtil.getConnection();
15                 int i = bdetailDao.returnBook(con, detail);
16                  if (i == 1) {
17                     JOptionPane.showMessageDialog(null, "还书成功");
18                  } else { 
19                     JOptionPane.showMessageDialog(null, "还书失败");
20                  }
21               } catch (Exception e1) {
22                  e1.printStackTrace();
23 JOptionPane.showMessageDialog(null, "还书异常");
24               }finally{
25                  try { 
26                    dbUtil.closeCon(con);
27                  } catch (Exception e1) {
28                    e1.printStackTrace();
29                 }
30              }
31               putDates(new BorrowDetail());
32            } 
33        });            
34      jf.setVisible(true);
35      jf.setResizable(true);
36   }
37    });

上述代码中,第3~6行代码是单击【还书】按钮后,若没有选中图书,则提示“请选择未还的书籍”;第13~32行代码更新数据库的还书信息,更新成功则返回“还书成功”,否则返回“还书失败”。

3.编写Dao层

在BorrowDetailDao类中添加returnBook()方法,用于更新数据库中的图书借阅信息。returnBook()方法的实现代码如下所示。

public int returnBook(Connection con,BorrowDetail detail)throws Exception {String sql = "update borrowdetail set status = ? ,return_time = ? where id = ?";PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql);pstmt.setInt(1, detail.getStatus());pstmt.setLong(2, detail.getReturnTime());pstmt.setInt(3, detail.getBorrowId());return pstmt.executeUpdate();
}

13.9 书籍管理模块

书籍管理模块用于新增、修改图书,在开发图书的书籍管理模块之前,首先带领大家熟悉该模块实现的功能以及整个功能模块的处理流程。下面通过书籍管理模块功能结构图来展示书籍管理模块实现的所有功能。

13.9.1 实现书籍添加功能

以管理员用户登录,单击导航栏中的【书籍管理】按钮,选择类别添加,填写类书籍相关信息,然后单击【添加】按钮,便可以完成书籍的添加。书籍添加页面如下图。

从上图可以看出,管理员添加书籍需要填写书名、作者、出版社、价格、库存、类别、描述等相关信息,填写无误后单击【添加】按钮即可完成书籍的添加。

接下来分步骤讲解书籍添加功能的实现。

1.编写书籍添加功能界面

在JFrame包中新建AdminBookAdd类,在AdminBookAdd类中编写管理员添加图书时需要填写的书名、作者、出版社、价格、库存、类别、描述等文本框及按钮组件。组件添加代码如下所示。

1 JPanel panel = new JPanel();
2      panel.setBorder(new TitledBorder(null, 
3	 "\u4E66\u7C4D\u6DFB\u52A0", 
4      TitledBorder.LEADING, TitledBorder.TOP, null, Color.RED));
5      panel.setBounds(23, 21, 540, 275);
6      jf.getContentPane().add(panel);
7      panel.setLayout(null);      
8      JLabel lblNewLabel = new JLabel("书名:");
9      lblNewLabel.setFont(new Font("幼圆", Font.BOLD, 14));
10 lblNewLabel.setBounds(58, 31, 45, 27);
11 panel.add(lblNewLabel);      
12 textField = new JTextField();
13 textField.setBounds(101, 31, 129, 27);
14 panel.add(textField);
15 textField.setColumns(10);      
16 JLabel label = new JLabel("作者:");
17 label.setFont(new Font("幼圆", Font.BOLD, 14));
18 label.setBounds(294, 31, 45, 27);
19 panel.add(label);      
20 textField_1 = new JTextField();
21 textField_1.setColumns(10);
22 textField_1.setBounds(338, 31, 128, 27);
23 panel.add(textField_1);      
24 JLabel label_1 = new JLabel("出版社:");
25 label_1.setFont(new Font("幼圆", Font.BOLD, 14));
26 label_1.setBounds(43, 79, 60, 27);
27 panel.add(label_1);     
28 textField_2 = new JTextField();
29 textField_2.setColumns(10);
30 textField_2.setBounds(101, 79, 129, 27);
31 panel.add(textField_2);      
32 JLabel label_2 = new JLabel("库存:");
33 label_2.setFont(new Font("幼圆", Font.BOLD, 14));
34 label_2.setBounds(58, 125, 45, 27); 
35 panel.add(label_2);      
36 textField_3 = new JTextField(); 
37 textField_3.setColumns(10); 
38 textField_3.setBounds(101, 125, 129, 27);
39 panel.add(textField_3);     
40 JLabel label_3 = new JLabel("价格:"); 
41 label_3.setFont(new Font("幼圆", Font.BOLD, 14));
42 label_3.setBounds(294, 79, 45, 27);
43 panel.add(label_3);      
44 textField_4 = new JTextField();
45 textField_4.setColumns(10); 
46 textField_4.setBounds(337, 79, 129, 27); 
47 panel.add(textField_4);      
48 JLabel label_4 = new JLabel("类别:"); 
49 label_4.setFont(new Font("幼圆", Font.BOLD, 14));
50 label_4.setBounds(294, 125, 45, 27);
51 panel.add(label_4);      
52 JLabel label_5 = new JLabel("描述:");
53 label_5.setFont(new Font("幼圆", Font.BOLD, 14));
54 label_5.setBounds(58, 170, 45, 27);  
55 panel.add(label_5);     
56 textField_6 = new JTextField(); 
57 textField_6.setColumns(10);
58 textField_6.setBounds(101, 173, 365, 27); 
59 panel.add(textField_6);       
60 JButton btnNewButton = new JButton("添加");

上述代码中,第1~7行代码添加面板,并设置面板的大小、颜色等属性;第8~60行代码是创建书籍添加的文本框、下拉框、以及添加按钮,并为这些组件设置字体、坐标、宽高,最后将这些组件添加到面板中。最后将这些组件加入到面板中。

2.编写添加按钮的监听器

管理员填写完成书籍相关信息后,单击【添加】按钮添加书籍,这时需要判断管理员填写的书籍信息是否完整。这就要为【添加】按钮添加监听器。为【添加】按钮添加监听器的代码如下所示。

1 btnNewButton.addActionListener(new ActionListener() { 
2        public void actionPerformed(ActionEvent e) {
3           String bookName = textField.getText(); 
4           String author = textField_1.getText(); 
5           String publish = textField_2.getText(); 
6           String priceStr = textField_4.getText();
7           String numberStr = textField_3.getText(); 
8           String remark = textField_6.getText(); 
9          if (toolUtil.isEmpty(bookName) || toolUtil.isEmpty(author) 
10     || toolUtil.isEmpty(publish) || toolUtil.isEmpty(priceStr) 
11     || toolUtil.isEmpty(numberStr) || toolUtil.isEmpty(remark)) {
12            JOptionPane.showMessageDialog(null, "请输入相关内容");
13            return;
14       }
15 BookType selectedItem = (BookType) 
16		   comboBox.getSelectedItem();
17            Integer typeId = selectedItem.getTypeId();
18            int number;
19            double price;
20            try { 
21              number = Integer.parseInt(numberStr); 
22              price = new BigDecimal(priceStr).setScale(2, 
23			BigDecimal.ROUND_DOWN).doubleValue(); 
24           } catch (Exception e1) { 
25              JOptionPane.showMessageDialog(null, "参数错误");
26              return;
27            }
28            Book book = new Book();
29            book.setBookName(bookName);
30            book.setAuthor(author); 
31            book.setBookTypeId(typeId);
32            book.setNumber(number);
33            book.setPrice(price);
34            book.setPublish(publish);
35            book.setRemark(remark);
36            book.setStatus(1);
37            Connection con = null;  
38          try { 
39              con = dbUtil.getConnection(); 
40              int i = bookDao.add(con, book);
41 if (i == 1) { 
42                 JOptionPane.showMessageDialog(null, "添加成功");
43                  reset(); 
44              } else {
45                  JOptionPane.showMessageDialog(null, "添加失败"); 
46              }
47            } catch (Exception e1) {
48              e1.printStackTrace();
49              JOptionPane.showMessageDialog(null, "添加异常"); 
50           }
51         }
52   });

上述代码中,第9~14行代码判断所添加的书籍信息是否填写完整,若填写完整,则保存图书信息。第38~51行代码向数据库中插入图书信息,插入成功则提示“添加成功”,否则提示“添加失败”。

3.编写Dao层

在dao包中创建BookDao类,在BookDao类中添加add()方法,用于将书籍信息插入到对应的数据库表中。add()方法代码如下所示。

package com.bookmanager.Dao;import com.bookmanager.model.Book;
import com.bookmanager.utils.toolUtil;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;import java.sql.ResultSet;public class BookDao {// 图书添加public int add(Connection con, Book book)throws Exception{String sql="insert into book (book_name,type_id,author,publish,price,number,status,remark) values(?,?,?,?,?,?,?,?)";PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql);pstmt.setString(1, book.getBookName());pstmt.setInt(2, book.getBookTypeId());pstmt.setString(3, book.getAuthor());pstmt.setString(4, book.getPublish());pstmt.setDouble(5, book.getPrice());pstmt.setInt(6, book.getNumber());pstmt.setInt(7, book.getStatus());pstmt.setString(8, book.getRemark());return pstmt.executeUpdate();}}

13.9.2 实现书籍信息修改功能

以管理员用户登录,单击导航栏中的【书籍管理】按钮,选择【书籍修改】按钮,选中书籍信息中要修改的数据,修改之后,单击【修改】按钮,便可以完成书籍的修改。书籍修改页面如下图。

从上图可以看出,管理员可以修改图书的编号、书名、作者、出版社、价格、库存、类别、描述等相关信息。确认修改信息无误后,单击【修改】按钮即可完成书籍信息的修改。

接下来分步骤讲解书籍修改功能的实现。

1.编写书籍修改功能界面

在JFrame包中新建AdminBookEdit类,在AdminBookEdit类中编写修改书籍时需要填写的编号、书名、作者、出版社、价格、库存、类别、描述、【修改】按钮等文本框及按钮组件。组件添加代码如下所示。

 1 JPanel panel_1 = new JPanel(); 2    panel_1.setLayout(null);3     panel_1.setBorder(new 4   TitledBorder(UIManager.getBorder("TitledBorder.border"), 5 "\u4E66\u7C4D\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, 6  null, new Color(255, 0, 0)));7          panel_1.setBounds(20, 105, 541, 195);      8         /*做一个表头栏数据  一维数组 * */ 9    String[] title={"编号", "书名", "类别", "作者", "价格", "库存", "状态" };10     /*具体的各栏行记录 先用空的二维数组占位*/ 11      String[][] dates={}; 12     /*然后实例化 上面2个控件对象*/13      model=new DefaultTableModel(dates,title);  14      table=new JTable(model); 
15 putDates(new Book());//获取数据库数据放置table中   
16 panel_1.setLayout(null);
17       JScrollPane jscrollpane = new JScrollPane(); 
18       jscrollpane.setBounds(20, 22, 496, 154); 
19       jscrollpane.setViewportView(table); 
20       panel_1.add(jscrollpane);  
21       jf.getContentPane().add(panel_1); 
22       jf.getContentPane().add(panel_1);         
23     JPanel panel_2 = new JPanel();
24     panel_2.setBounds(20, 310, 541, 292);
25     jf.getContentPane().add(panel_2);
26     panel_2.setLayout(null);      
27     JLabel label = new JLabel("编号:");
28     label.setFont(new Font("幼圆", Font.BOLD, 14)); 
29     label.setBounds(58, 10, 45, 27);
30 panel_2.add(label);     
31     textField_1 = new JTextField(); 
32     textField_1.setColumns(10); 
33     textField_1.setBounds(101, 10, 129, 27);
34     panel_2.add(textField_1);      
35     JLabel label_1 = new JLabel("书名:");
36     label_1.setFont(new Font("幼圆", Font.BOLD, 14)); 
37     label_1.setBounds(294, 10, 45, 27);
38      panel_2.add(label_1);      
39      textField_2 = new JTextField();
40      textField_2.setColumns(10);
41      textField_2.setBounds(338, 10, 128, 27);
42      panel_2.add(textField_2);
43 JLabel label_2 = new JLabel("作者:"); 
44 label_2.setFont(new Font("幼圆", Font.BOLD, 14));
45      label_2.setBounds(58, 58, 45, 27);
46      panel_2.add(label_2);      
47      textField_3 = new JTextField();
48      textField_3.setColumns(10);
49      textField_3.setBounds(101, 58, 129, 27); 
50      panel_2.add(textField_3);       
51      JLabel label_3 = new JLabel("价格:");
52      label_3.setFont(new Font("幼圆", Font.BOLD, 14));
53      label_3.setBounds(58, 104, 45, 27);
54      panel_2.add(label_3);      
55      textField_4 = new JTextField();
56     textField_4.setColumns(10);
57 textField_4.setBounds(101, 104, 129, 27);
58 panel_2.add(textField_4);      
59     JLabel label_4 = new JLabel("出版:");
60     label_4.setFont(new Font("幼圆", Font.BOLD, 14));  
61     label_4.setBounds(294, 58, 45, 27); 
62     panel_2.add(label_4);     
63     textField_5 = new JTextField(); 
64     textField_5.setColumns(10); 
65     textField_5.setBounds(337, 58, 129, 27);
66     panel_2.add(textField_5);      
67     JLabel label_5 = new JLabel("类别:");  
68     label_5.setFont(new Font("幼圆", Font.BOLD, 14));  
69     label_5.setBounds(58, 189, 45, 27);  
70     panel_2.add(label_5);       
71     comboBox_1 = new JComboBox();
72 comboBox_1.setBounds(102, 190, 128, 26); 
73     //获取类别
74     getBookType(); 
75     panel_2.add(comboBox_1);      
76     JLabel label_6 = new JLabel("库存:");
77     label_6.setFont(new Font("幼圆", Font.BOLD, 14));
78     label_6.setBounds(294, 104, 45, 27); 
79     panel_2.add(label_6);      
80     textField_6 = new JTextField(); 
81     textField_6.setColumns(10); 
82     textField_6.setBounds(337, 104, 129, 27); 
83     panel_2.add(textField_6);      
84     JLabel label_7 = new JLabel("描述:");
85     label_7.setFont(new Font("幼圆", Font.BOLD, 14));
86 label_7.setBounds(58, 152, 45, 27);
87 panel_2.add(label_7);     
88     textField_7 = new JTextField(); 
89     textField_7.setColumns(10); 
90     textField_7.setBounds(101, 152, 365, 27); 
91     panel_2.add(textField_7);      
92     JLabel label_8 = new JLabel("状态:");
93     label_8.setFont(new Font("幼圆", Font.BOLD, 14));
94     label_8.setBounds(294, 190, 45, 27);
95     panel_2.add(label_8);      
96     comboBox_2 = new JComboBox(); 
97     comboBox_2.setBounds(338, 191, 128, 26);
98     comboBox_2.addItem("上架");
99     comboBox_2.addItem("下架"); 
100     panel_2.add(comboBox_2);      
101    JButton btnNewButton_1 = new JButton("修改");

上述代码中,第9~22行代码创建书籍信息列表,列表中的书籍信息从数据库中获取。第23~100行代码创建编号、书名、作者、出版社、价格、库存、类别、描述等的文本框组件,并分别为这些组件设置字体、坐标、宽高,最后将这些组件加入到面板中。第101行代码添加【修改】按钮。

2.编写修改按钮的监听器

管理员修改完成书籍相关信息后,单击【修改】按钮修改书籍信息,这时需要判断管理员填写的书籍信息是否完整。这就要为【修改】按钮添加监听器。为【修改】按钮添加监听器的代码如下所示。

1 btnNewButton_1.addActionListener(new ActionListener() { 
2       public void actionPerformed(ActionEvent e) { 
3            String bookName = textField_2.getText(); 
4            String author = textField_3.getText();
5            String publish = textField_5.getText();
6            String priceStr = textField_4.getText(); 
7            String numberStr = textField_6.getText();
8            String remark = textField_7.getText();
9            String bookId = textField_1.getText();
10       if (toolUtil.isEmpty(bookId) || toolUtil.isEmpty(bookName)
11            || toolUtil.isEmpty(author) || toolUtil.isEmpty(publish)  
12            || toolUtil.isEmpty(priceStr) ||toolUtil.isEmpty(numberStr)   
13            || toolUtil.isEmpty(remark)) {
14               JOptionPane.showMessageDialog(null, "请输入相关内容");
15               return;
16            }
17 BookType selectedItem = (BookType) 
18		   comboBox_1.getSelectedItem();
19            Integer typeId = selectedItem.getTypeId();
20            int index = comboBox_2.getSelectedIndex();
21            int number; 
22            double price;
23            try {
24               number = Integer.parseInt(numberStr);
25               price = new BigDecimal(priceStr).setScale(2, 
26               BigDecimal.ROUND_DOWN).doubleValue(); 
27            } catch (Exception e1) {
28               JOptionPane.showMessageDialog(null, "参数错误");  
29            	 return;
30            }
31 Book book = new Book();
32            book.setBookId(Integer.parseInt(bookId));  
33            book.setBookName(bookName);  
34            book.setAuthor(author);
35            book.setBookTypeId(typeId);
36            book.setNumber(number);
37            book.setPrice(price);
38            book.setPublish(publish);
39            book.setRemark(remark);
40            book.setStatus(1);
41            if (index == 0) {
42              book.setStatus(1);
43            } else if (index == 1) { 
44              book.setStatus(2);
45            } 
46 Connection con = null; 
47           try {
48              con = dbUtil.getConnection(); 
49              int i = bookDao.update(con, book); 
50              if (i == 1) {
51                  JOptionPane.showMessageDialog(null, "修改成功"); 
52              } else {
53                  JOptionPane.showMessageDialog(null, "修改失败");
54               }
55            } catch (Exception e1) {
56               e1.printStackTrace();
57               JOptionPane.showMessageDialog(null, "修改异常");
58            }finally{ 
59 try {  
60                dbUtil.closeCon(con); 
61              } catch (Exception e1) {  
62                e1.printStackTrace();
63               }
64            }
65            putDates(new Book());
66         }
67      });            

上述代码中,第10~16行代码判断填写的书籍信息是否填写完整,若填写完整,则保存图书信息。第48~66行代码更新数据库中的书籍信息,更新成功则提示“修改成功”,否则提示“修改失败”。

3.编写Dao层

在dao包中创建BookDao类,在BookDao类中添加update()方法,用于更新数据库中的图书信息。Update()方法代码如下所示。

//图书信息修改
public int update(Connection con,Book book)throws Exception{String sql="update book set book_name=?,type_id=?,author=?,publish=?,price=?,number=?,status=?,remark=? where id=?";PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql);pstmt.setString(1, book.getBookName());pstmt.setInt(2, book.getBookTypeId());pstmt.setString(3, book.getAuthor());pstmt.setString(4, book.getPublish());pstmt.setDouble(5, book.getPrice());pstmt.setInt(6, book.getNumber());pstmt.setInt(7, book.getStatus());pstmt.setString(8, book.getRemark());pstmt.setInt(9, book.getBookId());return pstmt.executeUpdate();
}

13.10 用户管理模块

用户管理模块用于管理普通用户信息和借阅信息。在开发图书的用户管理模块之前,首先带领大家熟悉该模块实现的功能以及整个功能模块的处理流程。下面通过用户管理模块的功能结构图来展示用户管理模块实现的所有功能,如下图。

13.10.1 实现用户信息修改功能

以管理员用户登录,单击导航栏中的【用户管理】按钮,选择其中一条用户信息,单击【修改】按钮,便可以完成用户信息的修改。用户信息修改页面如图。

从上图可以看出,管理员可以修改用户信息的编号、用户名、密码、性别、手机号等相关信息,确认修改信息无误后单击【修改】按钮即可完成用户信息的修改。

接下来分步骤实现用户信息修改功能。

1.用户信息修改功能界面

在JFrame包中新建AdminUserInfo类,在AdminUserInfo类中编写修改用户信息时需要填写的编号、用户名、密码、性别、手机号、【修改】按钮等文本框及按钮组件。组件添加代码如下所示。

1 JPanel panel_1 = new JPanel();
2      panel_1.setLayout(null);
3      panel_1.setBorder(new 
4	 TitledBorder(UIManager.getBorder("TitledBorder.border"), 
5	 "\u7528\u6237\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, 
6	    null, new Color(255, 0, 0)));
7         panel_1.setBounds(20, 94, 541, 195);      
8      //做一个表头栏数据  一维数组
9      String[] title={"编号","用户名","密码","性别","电话"}; 
10    /*具体的各栏行记录 先用空的二维数组占位*/ 
11    String[][] dates={}; 
12    /*然后实例化 上面2个控件对象*/
13    model=new DefaultTableModel(dates,title); 
14    table=new JTable(model);
15    putDates(new User());//获取数据库数据放置table中    
16 panel_1.setLayout(null); 
17    JScrollPane jscrollpane = new JScrollPane();
18    jscrollpane.setBounds(20, 22, 496, 154); 
19    jscrollpane.setViewportView(table);
20    panel_1.add(jscrollpane);
21    jf.getContentPane().add(panel_1);  
22    jf.getContentPane().add(panel_1);      
23    JPanel panel_2 = new JPanel();  
24    panel_2.setBorder(new TitledBorder(null, 
25"\u7528\u6237\u7F16\u8F91", TitledBorder.LEADING, TitledBorder.TOP, 
26 null, Color.RED)); 
27    panel_2.setBounds(20, 302, 540, 137);  
28    jf.getContentPane().add(panel_2); 
29    panel_2.setLayout(null);      
30    JLabel lblNewLabel_1 = new JLabel("编号:"); 
31 lblNewLabel_1.setFont(new Font("幼圆", Font.BOLD, 15));  
32    lblNewLabel_1.setBounds(49, 30, 48, 34); 
33    panel_2.add(lblNewLabel_1);       
34    textField_1 = new JTextField();
35    textField_1.setEditable(false);
36    textField_1.setBounds(103, 37, 66, 21);
37    panel_2.add(textField_1); 
38    textField_1.setColumns(10);      
39    JLabel label = new JLabel("用户名:");
40    label.setFont(new Font("幼圆", Font.BOLD, 15));
41    label.setBounds(187, 30, 66, 34);
42    panel_2.add(label);       
43    textField_2 = new JTextField(); 
44    textField_2.setColumns(10); 
45    textField_2.setBounds(259, 37, 93, 21); 
46 panel_2.add(textField_2);     
47    JLabel label_1 = new JLabel("密码:"); 
48    label_1.setFont(new Font("幼圆", Font.BOLD, 15)); 
49    label_1.setBounds(383, 30, 48, 34); 
50    panel_2.add(label_1);       
51    textField_3 = new JTextField();  
52    textField_3.setColumns(10);
53    textField_3.setBounds(437, 37, 93, 21);
54    panel_2.add(textField_3); 
55    btnNewButton_1.setFont(new Font("幼圆", Font.BOLD, 15)); 
56    btnNewButton_1.setBounds(422, 74, 87, 34); 
57    panel_2.add(btnNewButton_1);      
58    JLabel label_2 = new JLabel("性别:"); 
59    label_2.setFont(new Font("幼圆", Font.BOLD, 15)); 
60    label_2.setBounds(49, 74, 48, 34);
61 panel_2.add(label_2);      
62    textField_4 = new JTextField();   
63    textField_4.setColumns(10);  
64    textField_4.setBounds(103, 81, 66, 21);
65    panel_2.add(textField_4);      
66    JLabel label_3 = new JLabel("手机号:");  
67    label_3.setFont(new Font("幼圆", Font.BOLD, 15)); 
68    label_3.setBounds(187, 74, 66, 34); 
69    panel_2.add(label_3);       
70    JButton btnNewButton_1 = new JButton("修改"); 

上述代码中,第9~22行代码创建用户信息列表,列表中的用户信息从数据库中获取。第30~69行代码创建编号、用户名、密码、性别、手机号等文本框组件,并分别为这些组件设置字体、坐标、宽高,最后将这些组件加入到面板中。第70行代码添加【修改】按钮。

2.编写修改按钮的监听器

管理员修改完成用户相关信息后,单击【修改】按钮完成用户信息修改,这时需要判断管理员填写的用户信息是否完整。这就要为【修改】按钮添加监听器。为【修改】按钮添加监听器的代码如下所示。

1 btnNewButton_1.addActionListener(new ActionListener() {
2         public void actionPerformed(ActionEvent e) {
3           String userId = textField_1.getText(); 
4           String userName = textField_2.getText(); 
5           String password = textField_3.getText(); 
6           String sex=textField_4.getText();  
7          String phone=textField_5.getText(); 
8           if (toolUtil.isEmpty(userName) || 
9              toolUtil.isEmpty(password)||toolUtil.isEmpty(sex)||
10          toolUtil.isEmpty(phone)) { 
11           JOptionPane.showMessageDialog(null, "请输入相关信息");
12               return;
13       }
14 User user = new User(); 
15           user.setUserId(Integer.parseInt(userId)); 
16           user.setUserName(userName); 
17           user.setPassword(password); 
18           user.setSex(sex); 
19           user.setPhone(phone);  
20          Connection con = null; 
21           try {
22               con = dbUtil.getConnection(); 
23              int i = userDao.update(con, user); 
24              if (i == 1) { 
25                 JOptionPane.showMessageDialog(null, "修改成功"); 
26                 putDates(new User());    
27 } else { 
28                 JOptionPane.showMessageDialog(null, "修改失败");  
29             }
30            } catch (Exception e1) {  
31              e1.printStackTrace(); 
32              JOptionPane.showMessageDialog(null, "修改异常"); 
33          }finally{  
34            try {  
35                dbUtil.closeCon(con);  
36             } catch (Exception e1) {
37                 e1.printStackTrace();  
38             }  
39          }
40        }  
41    }); 

上述代码中,第8~19行代码判断填写的用户信息是否填写完整,若填写完整,则保存用户信息。第21~39行代码更新数据库中的用户信息,更新成功则提示“修改成功”,否则提示“修改失败”。

3.编写Dao层

在dao包中创建UserDao类,在UserDao类中添加update()方法,用于修改用户信息操作。update()方法代码如下所示。

public int update(Connection con,User user)throws Exception{String sql="update user set username=?,password=?,sex=?,phone=? where id=?";PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sql);pstmt.setString(1, user.getUserName());pstmt.setString(2, user.getPassword());pstmt.setString(3, user.getSex());pstmt.setString(4, user.getPhone());pstmt.setInt(5, user.getUserId());return pstmt.executeUpdate();
}

13.10.2 实现书籍借阅详情功能

以管理员用户登录,单击导航栏中的【用户管理】按钮,选择借阅信息,可以查看书籍的借阅信息。借阅信息页面如下图。

可以看出,管理员可以查看图书的借阅详情。接下来分步骤实现借阅信息管理功能的实现。

1.书籍借阅详情界面

在JFrame包中新建AdminBorrowInfo类,在AdminBorrowInfo类中编写书籍借阅详情信息列表,代码如下所示。

1 JPanel panel_1 = new JPanel();
2     panel_1.setBorder(new 
3     TitledBorder(UIManager.getBorder("TitledBorder.border"), 
4 "\u4E66\u7C4D\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, 
5 null, 
6 new Color(255, 0, 0)));
7      panel_1.setBounds(10, 10, 574, 350);
8       //做一个表头栏数据  一维数组
9     String[] title={"借书人","书名","状态","借书时间","还书时间"}; 
10     /*具体的各栏行记录 先用空的二维数组占位*/  
11     String[][] dates={};  
12 /*然后实例化 上面2个控件对象*/   
13     model=new DefaultTableModel(dates,title); 
14     table=new JTable(model); 
15     putDates(new BorrowDetail());//获取数据库数据放置table中 
16     panel_1.setLayout(null); 
17     JScrollPane jscrollpane = new JScrollPane(); 
18     jscrollpane.setBounds(20, 22, 538, 314); 
19     jscrollpane.setViewportView(table); 
20     panel_1.add(jscrollpane); 
21     jf.getContentPane().add(panel_1);

上述代码中,第1~7行代码用于添加面板,并设置面板大小、颜色等属性。第9~21行代码创建用户信息列表,列表中的用户信息从数据库中获取。

2.编写Dao层

在BorrowDetailDao 类中添加list()方法,用于获取图书借阅信息。list()方法代码如下所示。

public ResultSet list(Connection con, BorrowDetail borrowDetail)throws Exception{StringBuffer sb=new StringBuffer("SELECT bd.*,u.username,b.book_name from borrowdetail bd,user u,book b where u.id=bd.user_id and b.id=bd.book_id");if(borrowDetail.getUserId() != null){sb.append(" and u.id = ?");}if(borrowDetail.getStatus() != null){sb.append(" and bd.status = ?");}if(borrowDetail.getBookId() != null){sb.append(" and bd.book_id = ?");}sb.append("  order by bd.id");PreparedStatement pstmt=(PreparedStatement) con.prepareStatement(sb.toString());if(borrowDetail.getUserId() != null){pstmt.setInt(1, borrowDetail.getUserId());}if(borrowDetail.getStatus() != null && borrowDetail.getBookId() != null){pstmt.setInt(2, borrowDetail.getStatus());pstmt.setInt(3, borrowDetail.getBookId());}return pstmt.executeQuery();
}

类别管理模块用于添加图书类型、修改图书类型。下面通过类别管理模块功能结构图来展示书籍管理模块实现的所有功能,如右图。

在添加图书类别时,以管理员用户登录,单击导航栏中的【类别管理】按钮,选择类别添加,填写类别名称和类别说明后,单击【添加】按钮,便可以完成类别的添加。类别管理页面如右图。

在修改图书类别时,以管理员用户登录,单击导航栏中的【类别管理】按钮后,选择类别修改,选择类别信息中的其中一条数据,进行修改,修改完成后,单击【修改】按钮,便可以完成类别的修改。类别修改页面如右图。

类别管理模块的实现过程与书籍管理模块类似,具体实现过程请参考源代码,这里我们不做讲解。

13.11 本章小结

本章综合运用前面所讲的知识,设计了一个综合项目——图书管理系统,目的是帮助大家了解如何开发一个多模块多文件的Java程序。在开发这个程序时,首先将一个项目拆分成若干个小的模块,为每个模块实体设计E-R图和数据表;然后分别设计每个模块所需要的类;最后分步骤实现每个模块的功能。通过图书管理系统项目的学习,读者会对Java程序开发流程有个整体的认识,这对实际工作大有裨益。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/690505.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ART-Pi LoRa开发套件 不完全教程

1 前言 ART-Pi LoRa 开发套件(LSD4RFB-2EVKM0201)是利尔达科技与睿赛德科技联合出品的一套面向物联网开发者的 LoRa 产品原型设计工具包&#xff0c;搭配ART-Pi主板使用&#xff0c;支持利尔达全系 LoRa 节点与网关模块&#xff0c;拥有丰富的可选配件&#xff0c;用户 可按需…

C++6.0

思维导图 .编程题&#xff1a; 以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a;比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0…

【深入理解设计模式】单例设计模式

单例设计模式 概念&#xff1a; 单例模式&#xff08;Singleton Pattern&#xff09;是 Java 中最简单的设计模式之一。 单例设计模式是一种创建型设计模式&#xff0c;其主要目的是确保类在应用程序中的一个实例只有一个。这意味着无论在应用程序的哪个位置请求该类的实例&a…

IO 作业 24/2/19

1> 使用fread和fwrite完成两个文件的拷贝 #include <myhead.h> int main(int argc, const char *argv[]) {//定义被复制文件指针FILE *fp1NULL;if((fp1fopen("./111.bmp","r"))NULL){perror("error open");return -1;}//定义目标文件指…

Elasticsearch 与 OpenSearch:开源搜索技术的演进与选择

在2010年以Apache 2.0开源协议发布后&#xff0c;Elasticsearch迅速成为全球最受欢迎的企业搜索引擎。 Elasticsearch常与Logstash和Kibana一起部署&#xff0c;这一组合被称为 Elasitc Stack&#xff0c;用于启用日志分析用例&#xff0c;包括应用可观察性、安全日志分析和理解…

opencv计算机视觉

树莓派主机的无键盘解决 进入控制面板&#xff0c;更改适配器设置&#xff0c;WIFI属性&#xff0c;勾选 1.将网线两头分别接入树莓派和笔记本的网线接口 2.在无线连接属性那里勾选允许其他用户连接 3.运行cmd使用arp -a查看树莓派ip地址&#xff0c;或者使用ipscanner查看 cmd…

Springboot+vue的疫情信息管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的疫情信息管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的疫情信息管理系统&#xff0c;采用M&#xff08;model&a…

计算机专业必看的几部电影

计算机专业必看的几部电影 计算机专业必看的几部电影&#xff0c;就像一场精彩的编程盛宴&#xff01;《黑客帝国》让你穿越虚拟世界&#xff0c;感受高科技的魅力&#xff1b;《社交网络》揭示了互联网巨头的创业之路&#xff0c;《源代码》带你穿越时间解救世界&#xff0c;…

如何结合《ISO 55001资产管理-管理系统要求》,提升资产管理绩效

在当今竞争激烈的商业环境中&#xff0c;有效的资产管理对于组织的成功至关重要。ISO 55001标准为组织提供了一个框架&#xff0c;帮助其建立和维护一个高效的资产管理系统&#xff0c;从而实现更好地管理资产并提升业绩的目标。本文将探讨如何结合ISO 55001标准&#xff0c;以…

猫多喝水好吗?可以促进猫咪多喝水的主食分享

猫咪多喝水确实是有益的。适量的饮水对于猫咪的健康至关重要&#xff0c;有助于维持体液平衡、促进消化、减少便秘的风险&#xff0c;并对泌尿系统的健康起到保护作用。正常情况下&#xff0c;建议每公斤体重的猫每天摄入60-80毫升的水&#xff0c;除了与体重相关外&#xff0c…

python使用工厂模式和策略模式实现读文件、分析内容功能

当涉及到在 Python 中创建类以及使用设计模式来实现读取文件和分析内容的功能时&#xff0c;我们可以考虑使用工厂模式和策略模式的结合。下面是一个简单的示例&#xff0c;演示如何通过创建类和使用设计模式来实现这一功能&#xff1a; # 工厂模式&#xff1a;根据不同的分析…

【Linux系统化学习】深入理解文件系统(Ext2文件系统)

目录 前言 磁盘的物理结构 物理结构 磁头和盘片工作解析图 盘面区域划分图&#xff08;俯视盘面图&#xff09; 扇区的寻址、定位&#xff08;CHS定位&#xff09; 磁盘存储的逻辑抽象结构 LBA定址 文件系统 磁盘分区 EXT2文件系统 组块中的信息介绍 查看inode编号…

ComfyUI新宠,精准位置生成模型GLIGEN,附下载

GLIGEN 是一种在文本到图像模型中指定对象精确位置的直观方法。自带GUI&#xff0c;操作非常便利&#xff0c;可以精确控制要在什么位置画什么内容&#xff0c;比纯文字描述的RPG-DiffusionMaster更精确。 ComfyUI是一个基于节点的图形用户界面&#xff08;GUI&#xff09;工具…

【AI场景应用】智能电话机器人

从前有一个小型电商公司&#xff0c;每天都接收大量的客户咨询和订单确认电话。由于人手不足&#xff0c;公司的客服团队经常忙得不可开交。为了解决这个问题&#xff0c;他们引入了一位智能电话机器人&#xff0c;名叫小智。 小智是一位功能强大的机器人&#xff0c;他能够全…

助力智能化农田作物除草,基于轻量级YOLOv8n开发构建农田作物场景下玉米苗、杂草检测识别分析系统

在我们前面的系列博文中&#xff0c;关于田间作物场景下的作物、杂草检测已经有过相关的开发实践了&#xff0c;结合智能化的设备可以实现只能除草等操作&#xff0c;玉米作物场景下的杂草检测我们则少有涉及&#xff0c;这里本文的主要目的就是想要基于最新的YOLOv8下最轻量级…

33、IO/标准IO对图片操作练习及文件IO相关练习20240219

一、使用fread和fwrite完成两个图片文件的拷贝&#xff08;标准IO&#xff09;。 代码&#xff1a; #include<myhead.h>int main(int argc, const char *argv[]) {FILE *srcfpNULL;FILE *destfpNULL;if((srcfpfopen("./hongfeng.bmp","r"))NULL ||…

哪个电商抠图软件比较好用?这些软件也太好用了吧

当需要从原始场景中分离图片中的对象时&#xff0c;抠图变得尤为关键。对于电商从业者而言&#xff0c;抠图是不可或缺的步骤。手动抠图耗时费力&#xff0c;而利用一键抠图软件可以显著提高工作效率和质量。然而&#xff0c;市场上有众多抠图软件&#xff0c;其中哪些是真正好…

【已解决】windeployqt.exe此应用无法在你电脑上运行

遇到这种问题时&#xff0c;通常网络会给出右击程序的兼容性或者以管理员命令行身份运行该程序。但是本文想要告诉的是这个windeployqt.exe出现此应用无法在你电脑上运行问题出现时&#xff0c;如何解决&#xff1f; 解决方案 笔者出现的问题是这个exe大小变成0kb所以无法打…

【详细流程】vue+Element UI项目中使用echarts绘制圆环图 折线图 饼图 柱状图

vueElement UI项目中数据分析功能需要用到圆环图 折线图 饼图 柱状图等&#xff0c;可视化图形分析 安装流程及示例 1.安装依赖 npm install echarts --save2.在main.js中引入并挂载echarts import echarts from echarts Vue.prototype.$echarts echarts3.在需要使用echart…

VMware还原Windows11 ghost镜像

文章目录 环境步骤准备制作启动iso文件创建虚拟机启动虚拟机还原Windows 参考 环境 Windows 11 家庭中文版VMware Workstation 17 Pro石大师装机大师Windows 11 ghost系统镜像 步骤 准备 下载好Windows 11 ghost系统镜像&#xff0c;我下载的文件是 FQ_WIN11_X64_VDL_V2080…