Maven + MyBatis + JavaFX——班级通讯录系统
闲来无事,将之前没写完的一篇文章重新写一下。本文是对基于Maven + MyBatis + JavaFX 编写的一个班级通讯录系统的介绍。其主要界面如图所示。
一、开发环境
名称 | 开发环境 |
---|---|
编辑器 | IDEA2021.1 |
界面设计工具 | JavaFx SenceBuilder 2.0 |
JDK版本 | 1.8.0_251 |
数据库 | MySQL 8.0.23 |
mysql-connector-java | 8.0.23 |
mybatis | 3.5.7 |
lombok | 1.18.22 |
二、UI 设计
我使用JavaFx SenceBuilder 2.0来设计项目界面。
创建好 .fxml 文件后,使用ScenceBuilder打开就可以根据自己的需求设计界面。
2.1 主界面设计
主界面设计如图所示。主界面包括 多个 Container,以及各种视图,包括Button、Label、TextField、TableView、TableColumn等。本节介绍几个主要小视图的使用。
学习 JavaFX 可以去 JavaFX 中文文档学习
2.1.1 Button
JavaFX API中的Button类用来处理当用户点击一个按钮时执行一个动作(Action)。Button类继承自Labeled类,它可以显示文本,图像,或两者兼而有之。
可以在右边设计其 fx:id ,如我设置为check。同时也可以使用 On Action 来设置其行为,其中是其行为的方法名。
使用 fx:id 在 Java 中的响应如下:
check.setOnAction(e -> {
// 执行体
});
2.1.2 TextField
TextField 类实现了一个接收和显示文本输入的UI组件。它提供了从用户接收文本输入的功能。这个类和另一个文本输入组件PasswordField一样,都继承自 TextInput 类。TextInput 类是 JavaFX API中所有文本组件的超类。
可以通过 Prompt Text 设置灰色的提示文字,通过 Editable 可以设置是否可以编辑。
同样地,可以通过 fx:id 来对其进行操作,若设置其 fx:id 为 checkID
其获取文本的代码如下:
checkID.getText()
其设置文本的代码如下:
checkID.setText()
2.1.3 TableView
TableView 是一个表格视图,它可以包括多列 TableColumn,即多列表格。
它是一个相对比较复杂点的视图,具体的设置见项目代码。其数据关联设置如下,其中的 “id”、“name”等是Student类的属性,其逻辑是获取一个学生List数据 students,并通过各个属性关联到相应列。
if (students != null) {
list.addAll(students);
idCol.setCellValueFactory(
new PropertyValueFactory<>("id")
);
nameCol.setCellValueFactory(
new PropertyValueFactory<>("name")
);
genderCol.setCellValueFactory(
new PropertyValueFactory<>("sex")
);
classCol.setCellValueFactory(
new PropertyValueFactory<>("classNum")
);
phoneCol.setCellValueFactory(
new PropertyValueFactory<>("phone")
);
mailCol.setCellValueFactory(
new PropertyValueFactory<>("mail")
);
addressCol.setCellValueFactory(
new PropertyValueFactory<>("address")
);
deleteCol.setCellValueFactory(
new PropertyValueFactory<>("deleteButton")
);
updateCol.setCellValueFactory(
new PropertyValueFactory<>("editButton")
);
tableView.setItems(list);
}
每一行的删除和修改按钮是自己定义在 Student中的,每一个student 对象都带有这两个按钮。
2.2 添加界面
添加界面是添加学生的地方,可以输入学生各种信息。其具体布局如是:
2.2.1 ChoiceBox
这里新增加了一个视图,用于选择性别。其选项的添加无法在 ScenceBuilder中完成。
可以参考:1、fxml中设置添加链接描述 2、Java中设置
,其代码如是,我使用自己定义的枚举类,同时设置TableView类型为String
addGender.getItems().addAll(GenderType.getGenders());
// GenderType 是枚举类
// GenderType.getGenders() 返回 ArrayList<String>
2.3 修改界面
修改界面和添加界面差不多,其如图所示:
三、数据库设计
由于功能简单,只设计了一个 student 表,其包括 id、name、gender、classNum、phone、mail和address这七个字段,id是主键,设置了自增长。
字段 | 类型 | 说明 |
---|---|---|
id | int | 学生ID自增 |
name | varchar | 姓名 |
gender | tinyint | 性别:0男生,1女生,2其他; [0,128) |
classNum | tinyint | 班级,[1, 128) |
phone | varchar | 电话号码 |
varchar | 邮箱 | |
address | varchar | 家庭住址 |
3.1 MyBatis
使用 MyBatis 来连接 MySQL数据库,相应的maven 依赖如下:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
同时需要编写 MyBatis 配置文件,我在 resources 里添加了 MyBatis-Config.xml ,其内容如下,需要结合自己的数据库用户名和链接修改。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="Student" type="com.yfengl.addressBook.entity.Student"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/address_book?serverTimezone=UTC"/>
<!-- 配置数据库用户名和密码 -->
<property name="username" value="root"/>
<property name="password" value="123456"/>
<!-- 配置数据库用户名和密码 -->
</dataSource>
</environment>
</environments>
<!-- 配置mapper文件位置 -->
<mappers>
<mapper resource="mappers/StudentDao.xml"/>
</mappers>
<!-- 配置mapper文件位置 -->
</configuration>
3.1.1 MyBatis Generate 插件
使用idea 的插件可以自动生成 mapper文件和实体类,省去了繁杂的SQL的编写。
3.1.2 MyBatisUtils
MyBatisUtils 是一个 MyBatis 连接的工具类,可以省去一些反复的代码,其如下:
public class MyBatisUtils {
private static SqlSessionFactory sessionFactory = null;
/*
* 创建本地线程变量,为每一个线程独立管理一个session对象 每一个线程只有且仅有单独且唯一的一个session对象
* 加上线程变量对session进行管理,可以保证线程安全,避免多实例同时调用同一个session对象
* 每一个线程都会new一个线程变量,从而分配到自己的session对象
*/
private static ThreadLocal<SqlSession> threadlocal = new ThreadLocal<SqlSession>();
// 创建sessionFactory对象,因为整个应用程序只需要一个实例对象,故用静态代码块
static {
try {
Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回sessionFactory对象 工厂对象
*
* @return sessionFactory
*/
public static SqlSessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* 新建session会话,并把session放在线程变量中
*/
private static void newSession() {
// 打开一个session会话
SqlSession session = sessionFactory.openSession();
// 将session会话保存在本线程变量中
threadlocal.set(session);
}
/**
* 返回session对象
* @return session
*/
public static SqlSession getSession(){
//优先从线程变量中取session对象
SqlSession session = threadlocal.get();
//如果线程变量中的session为null,
if(session==null){
//新建session会话,并把session放在线程变量中
newSession();
//再次从线程变量中取session对象
session = threadlocal.get();
}
return session;
}
/**
* 关闭session对象,并从线程变量中删除
*/
public static void closeSession(){
//读取出线程变量中session对象
SqlSession session = threadlocal.get();
//如果session对象不为空,关闭sessoin对象,并清空线程变量
if(session!=null){
session.close();
threadlocal.set(null);
}
}
}
每次连接后需要 closeSession,放在 finally 代码块每次都会执行,参考如下:
sqlSession = MyBatisUtils.getSession();
studentDao = sqlSession.getMapper(StudentDao.class);
Student student = null;
try {
student = studentDao.selectByPrimaryKey(id);
sqlSession.commit();
} catch (Exception e) {
sqlSession.rollback();
} finally {
MyBatisUtils.closeSession();
}
四、代码设计
4.1 实体类 Student
Student类除了数据库相应的字段,还有几个其他字段,@Data 是 Lombok 的注解,可以自动生成一些getter和setter或构造函数。
其中sex是为了从数据库中存储的数字转化为字符串,它与gender都是指性别。
@Data
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 学生id或编号,自增长
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 性别:0男生,1女生,2其他
* ;<128;>=0
*/
private Integer gender;
/**
* 性别:男生,女生,其他
* 用于从数字gender获取汉字性别
*/
private String sex;
/**
* 班级,数字
* <128;>0
*/
private Integer classNum;
/**
* 手机号,11位
*/
private String phone;
/**
* 邮箱
*/
private String mail;
/**
* 家庭住址
*/
private String address;
private SimpleObjectProperty<DeleteButton> deleteButton;
private SimpleObjectProperty<EditButton> editButton;
private final AddressList addressList = new AddressList();
public String getSex() {
return GenderType.valueOf(gender).getGender();
}
public void setSex(String sex) {
this.sex = GenderType.valueOf(gender).getGender();
}
}
4.2 性别 GenderType
枚举类,定义性别
public enum GenderType {
MAN(0, "男"),
WOMAN(1, "女"),
OTHER(2, "其他"),
;
private final Integer key;
private final String gender;
GenderType(Integer key, String gender) {
this.key = key;
this.gender = gender;
}
public Integer getKey() {
return this.key;
}
public String getGender() {
return this.gender;
}
public static ArrayList<String> getGenders(){
ArrayList<String> genders = new ArrayList<>();
GenderType[] genderTypes = GenderType.values();
int i = 0;
for (GenderType genderType : genderTypes) {
genders.add(genderType.getGender());
}
return genders;
}
public static GenderType valueOf(Integer key) {
GenderType[] genderTypes = values();
for (GenderType genderType : genderTypes) {
if (genderType.key == key) return genderType;
}
return null;
}
public static GenderType getGenderTypeByGender(String gender) {
GenderType[] genderTypes = values();
for (GenderType genderType : genderTypes) {
if (genderType.gender == gender) return genderType;
}
return null;
}
}
五、项目源代码
项目Github地址:https://github.com/yfengl/AddressBook