目录

 1.需求分析

1.1 功能需求

1.2 性能需求

1.3 可靠性和可用性需求

1.4 错误处理需求

1.5 将来可能要提出的需求

1.6建立数据模型——ER图

2.概要设计

2.1 设计哈希表的抽象数据类型定义:

2.2本程序模块结构

3.详细设计

3.1 模块功能设计

3.2人机界面设计

3.3算法设计

3.4数据设计

4.调试分析

4.1遇到的问题:

4.2解决方法:

4.3经验和体会:

5.用户手册

5.1概述

5.2系统要求

5.3安装与配置

5.4运行程序

5.5使用说明

5.6注意事项

6.测试结果

6.1登录模块

6.2员工管理模块

6.3部门管理模块

7.项目结构及源码分享

7.1项目结构

7.2源码分享(文件从上往下)

7.2.1MessageConstant.java

7.2.2Dept.java

7.2.3Employee.java

7.2.4User.java

7.2.5MyHashMap.java

7.2.6AddDeptUI.java

7.2.7AddEmpUI.java

7.2.8DeptUI.java

7.2.9EditDeptUI.java

7.2.10EditEmpUI.java

7.2.11EmpUI.java

7.2.12LoginUI.java

7.2.13MainUI.java

7.2.14RegisterUI.java

7.2.15EmpApp.java

7.2.16Dept.csv

7.2.17Emps.csv

7.2.18User.csv

7.3文件资源

8.说明


 1.需求分析

1.1 功能需求

1.1.1登录信息模块:

    用户登录:用户在登录界面输入账户名和密码,系统验证输入的信息与存储在 `User.csv` 文件中的管理员信息是否匹配。若匹配,跳转到主界面;若不匹配,弹出提示框告知用户登录失败。

    用户注册:提供注册按钮,点击后跳转到注册界面,实现新用户的注册功能。

    数据存储:从 `User.csv` 文件读取管理员账户名和密码信息到哈希表 `userMap` 中,用于登录验证;登录信息发生变化时(如新增用户注册),可将哈希表中的数据写回 `User.csv` 文件。

1.1.2员工管理模块:

    数据展示:从 `Emps.csv` 文件读取员工信息到哈希表 `employeeMap` 中,并以表格形式展示在 `EmpUI` 界面上,表格包含员工 ID、姓名、性别、出生年月、工作年月、学历、部门、住址、电话等字段。

    新增员工:在 `EmpUI` 界面提供“新增员工”按钮,点击后弹出新增员工窗口(`AddEmpUI`),用于添加新员工信息。

    查询员工:在 `EmpUI` 界面提供搜索框和“查询员工”按钮,用户输入姓名进行模糊查询,系统在哈希表中匹配员工信息并展示在表格中;若未找到匹配信息,弹出提示框告知用户。

    排序员工:在 `EmpUI` 界面提供排序下拉列表框,可按员工姓名进行升序(a -> z)或降序(z -> a)排序,排序后刷新表格展示。

    编辑员工:在表格上右键点击某一员工行,弹出右键菜单,选择“编辑”可打开编辑窗口(`EditEmpUI`)对该员工信息进行修改。

    删除员工:在表格上右键点击某一员工行,弹出右键菜单,选择“删除”,弹出确认对话框,确认后从哈希表和表格中删除该员工信息,并将更新后的数据写回 `Emps.csv` 文件。

1.1.3部门管理模块:

    数据展示:从 `Dept.csv` 文件读取部门信息到哈希表 `deptMap` 中,并以表格形式展示在 `DeptUI` 界面上,表格包含部门 ID、部门名称、负责人、成立日期等字段。

    新增部门:在 `DeptUI` 界面提供“新增部门”按钮,点击后弹出新增部门窗口(`AddDeptUI`),用于添加新部门信息。

    查询部门:在 `DeptUI` 界面提供搜索框和“查询部门”按钮,用户输入部门名称进行模糊查询,系统在哈希表中匹配部门信息并展示在表格中;若未找到匹配信息,弹出提示框告知用户。

    排序部门:在 `DeptUI` 界面提供排序下拉列表框,可按部门名称进行升序(a -> z)或降序(z -> a)排序,排序后刷新表格展示。

    编辑部门:在表格上右键点击某一部门行,弹出右键菜单,选择“编辑”可打开编辑窗口(`EditDeptUI`)对该部门信息进行修改。

    删除部门:在表格上右键点击某一部门行,弹出右键菜单,选择“删除”,弹出确认对话框,确认后从哈希表和表格中删除该部门信息,并将更新后的数据写回 `Dept.csv` 文件。

1.2 性能需求

响应时间:对于常见操作,如登录、查询、排序等,系统应在短时间内(如不超过 3 秒)给出响应,以提供流畅的用户体验。

数据加载:在启动系统或切换界面时,加载员工和部门信息的时间应尽量短,尤其是在数据量较大的情况下,需优化文件读取和数据处理逻辑,确保界面能快速展示数据。

1.3 可靠性和可用性需求

数据可靠性:系统应保证数据的完整性和准确性,在数据读取、写入和修改操作时,需进行错误处理,防止数据丢失或损坏。例如,在写入文件失败时,应弹出提示框告知用户,并保留原有数据。

系统可用性:系统应具备较高的可用性,确保在正常使用情况下,不会频繁出现崩溃或无响应的情况。在出现异常情况(如文件损坏、内存不足等)时,应提供合理的错误提示,引导用户进行相应处理,尽量保证系统的部分功能仍可使用。

1.4 错误处理需求

文件操作错误:在读取或写入 `User.csv`、`Emps.csv`、`Dept.csv` 文件时,若发生文件不存在、读写权限不足等错误,应捕获异常并弹出相应的错误提示框,告知用户错误原因,如“文件不存在,请检查文件路径”或“写入文件失败,可能是权限不足”。

输入验证错误:在用户进行登录、注册、新增员工或部门等操作时,应对用户输入进行合法性验证。例如,登录时账户名或密码为空,应弹出提示框告知用户“请输入账户名和密码”;新增员工时,若关键信息(如员工 ID、姓名等)为空,也应提示用户输入完整信息。

其他运行时错误:对于其他可能出现的运行时错误(如哈希表操作异常、界面组件初始化失败等),应捕获异常并记录错误日志(若有日志功能),同时向用户弹出友好的错误提示框,告知用户系统出现问题,并建议用户重试或联系管理员。

1.5 将来可能要提出的需求

权限管理:增加不同用户角色(如管理员、普通员工)及其权限设置,不同角色可进行的操作(如新增、编辑、删除等)有所限制。

数据统计与分析:对员工和部门信息进行统计分析,如统计各部门员工数量、各学历层次员工分布等,并以图表形式展示统计结果。

1.6建立数据模型——ER图

图1-1 员工和部门关系ER图

图1-2 登录关系ER图

2.概要设计

2.1 设计哈希表的抽象数据类型定义:

ADT MyHashMap {
数据对象:D={ (ki, vi) | ki∈KeySet, vi∈ValueSet, i=1…n, n≥0 }
数据关系:R={<ei, ej> | ei, ej∈D, i≠j, ei.key ≠ ej.key}

基本操作:
MyHashMap()
操作结果:创建一个空的哈希表,初始容量为16,负载因子为0.75。

put(K key, V value)
操作结果:将键key和值value插入到哈希表中。如果键key已存在,则更新对应的值为value。如果插入后哈希表的元素数量超过扩容阈值,则进行扩容。

get(K key)
操作结果:根据键key返回对应的值。如果键不存在,则返回null。
remove(K key)
操作结果:根据键key移除对应的条目,并返回该条目的值。如果键不存在,则返回null。

size()
操作结果:返回哈希表中条目的数量。

values()
操作结果:返回哈希表中所有值的列表。

keys()
操作结果:返回哈希表中所有键的列表。

sortByNameAsc(MyHashMap<String, V> map)
操作结果:返回键按升序排序后的键数组。

sortByNameDesc(MyHashMap<String, V> map)
操作结果:返回键按降序排序后的键数组。

}ADT MyHashMap;

2.2本程序模块结构

① 登录模块

② 员工界面管理模块

③ 部门界面管理模块

④ 哈希表数据结构类型模块

  

图2-1 员工管理系统功能结构图

3.详细设计

3.1 模块功能设计

3.1.1哈希表模块

①哈希表设计概述

数据结构:使用数组 table 来存储哈希表的桶(bucket),每个桶是一个链表,用于解决哈希冲突。

初始容量:初始容量为 16,定义为 INITIAL_CAPACITY。

负载因子:负载因子为 0.75,定义为 LOAD_FACTOR。当哈希表中的元素数量达到扩容阈值(容量 * 负载因子)时,会进行扩容。

②哈希函数

哈希函数 hash (除留余数法)用于计算键的哈希值,并确定键值对在哈希表中的存储位置。

③哈希冲突解决

哈希冲突通过链地址法(separate chaining)解决。当多个键映射到同一个桶时,这些键值对以链表的形式存储在该桶中。

在插入操作 put 中,如果发现桶中已有元素(即发生哈希冲突),会遍历链表查找是否存在相同的键。如果存在,则更新值;否则,将新的键值对添加到链表末尾。

3.1.2登录模块

功能说明:

注册功能:新用户默认没有账户,进行注册后将账号存入账号文件user.csv中,每次系统启动都会加载这份文件并填入哈希表,只要注册一次,无论程序是否关闭不影响账号信息

登录功能:程序启动后,user.csv文件加载到哈希表中,账号作为哈希表的键,密码作为哈希表的值,根据用户输入的账号名称来在哈希表中进行键值匹配,匹配成功则登录成功,匹配失败则弹出登录错误。

图3-1 登录模块流程图

3.1.3员工信息管理模块

功能说明:

① 员工信息的增删改查

添加员工:用户可以通过表单输入员工的详细信息(如 ID、姓名、性别、出生年月、工作年月、学历、部门、住址、电话),其中部门的选择是从部门哈希表中读取的,部门的数量变化会影响新增员工页面的选择。点击“添加”按钮后,系统会验证输入是否合法,然后将新员工信息保存到内存中的 employeeMap 中,并刷新表格显示。同时,系统会将新的员工信息写入文件,以实现持久化存储。

删除员工:用户可以选择表格中的某一行,点击“删除”按钮后,系统会弹出确认对话框,询问用户是否确定删除。如果用户确认删除,系统会从 employeeMap 中移除对应的员工信息,并刷新表格显示。同时,系统会更新文件中的员工信息。

修改员工:用户可以选择表格中的某一行,点击“编辑”按钮后,系统会打开一个编辑窗口,允许用户修改员工的详细信息。修改完成后,点击“保存”按钮,系统会更新 employeeMap 中的员工信息,并刷新表格显示。同时,系统会将更新后的员工信息写入文件。

查询员工:用户可以在搜索框中输入员工的姓名或部分姓名,点击“查询”按钮后,系统会在 employeeMap 中查找匹配的员工信息,并在表格中显示结果。

如果没有找到匹配的员工,系统会弹出提示框,告知用户未找到相关记录。

员工排序:系统提供了两种排序方式:按员工名字的字典顺序进行升序排序(AZ)或降序排序(ZA)。用户可以通过点击表格标题栏中的“姓名”列来切换排序方式。

② 员工信息的持久化

保存员工信息:每次对员工信息进行添加、删除或修改操作后,系统会自动将最新的员工信息写入文件,确保数据不会丢失。

加载员工信息:程序启动时,系统会从文件中读取员工信息,并将其加载到 employeeMap 中,以便用户可以立即查看和操作这些数据。

③ 用户界面优化

表格展示:使用 JTable 组件展示员工信息,表格列包括员工 ID、姓名、性别、出生年月、工作年月、学历、部门、住址、电话等。表格支持排序功能,用户可以点击排序对名字进行升序或降序排序。

搜索功能:提供一个搜索框,用户可以在其中输入员工的姓名或部分姓名,系统会实时过滤表格中的数据,显示匹配的员工信息。如果用户清空搜索框,表格会恢复显示所有员工信息。

右键菜单:当用户右键点击表格中的某一行时,会弹出一个上下文菜单,提供“编辑”、“删除”等操作选项,方便用户快速操作。

④ 数据验证

必填项验证:在添加或修改员工信息时,系统会检查所有必填项(如姓名、性别、出生年月、工作年月、学历、部门、住址、电话)是否已填写。如果用户未填写必填项,系统会弹出提示框,要求用户补充完整信息。

图3-2 员工信息管理模块流程图

3.1.4部门信息管理模块

①添加部门

用户操作:用户可以通过表单输入部门的详细信息,包括部门 ID、名称、负责人、创建时间。点击“添加”按钮后,系统会验证输入是否合法,确保所有必填项已填写且没有空。如果验证通过,系统会将新部门信息保存到部门哈希表中中,并刷新表格显示。同时,系统会将新的部门信息写入文件,以实现持久化存储。

②删除部门

用户操作:用户可以选择表格中的某一行,右键点击该行并选择“删除部门”选项,或者直接点击表格上方的“删除”按钮。系统会弹出确认对话框,询问用户是否确定删除该部门。如果用户确认删除,系统会从哈希表中移除对应的部门信息,并刷新表格显示。同时,系统会更新文件中的部门信息。

③修改部门

用户操作:用户可以选择表格中的某一行,右键点击该行并选择“编辑部门”选项,或者直接点击表格上方的“编辑”按钮。系统会打开一个编辑窗口,允许用户修改部门的详细信息,如名称、负责人、描述等。修改完成后,点击“保存”按钮,系统会更新哈希表中的部门信息,并刷新表格显示。同时,系统会将更新后的部门信息写入文件。

④查询部门

用户操作:用户可以在搜索框中输入部门的名称或部分名称,点击“查询”按钮后,系统会在哈希表中查找匹配的部门信息,并在表格中显示结果。如果用户清空搜索框,表格会恢复显示所有部门信息。如果找到匹配的部门,系统会在表格中显示查询结果。如果没有找到匹配的部门,系统会弹出提示框,告知用户“未找到相关记录”。

⑤部门排序

用户操作:系统提供了两种排序方式:按部门名称的字典顺序进行升序排序(A-Z)或降序排序(Z-A)。用户可以通过点击表格标题栏中的“名称”列来切换排序方式。

系统响应:

点击“名称”列后,系统会根据当前的排序方式重新排列表格中的部门记录,并在表格中实时显示排序结果。

⑥部门信息的持久化

(1)保存部门信息

自动保存:

每次对部门信息进行添加、删除或修改操作后,系统会自动将最新的部门信息写入文件,确保数据不会丢失。文件格式为 CSV

(2)加载部门信息

自动加载:程序启动时,系统会从文件中读取部门信息,并将其加载到部门哈希表中,以便用户可以立即查看和操作这些数据。

⑦数据验证

(1)必填项验证

输入验证:

在添加或修改部门信息时,系统会检查所有必填项(如名称、负责人)是否已填写。如果用户未填写必填项,系统会弹出提示框,要求用户补充完整信息。

系统还会验证输入的数据格式是否正确,例如,部门名称不能包含特殊字符,负责人姓名不能为空等。

(2)关联数据验证

员工关联:

在删除部门时,系统会检查该部门下是否有员工。如果该部门下有员工,系统会弹出提示框,告知用户“该部门下有员工,无法直接删除”。

用户可以选择将员工转移到其他部门后再进行删除操作,或者取消删除操作。

图3-3 部门信息管理模块流程图

3.2人机界面设计

本系统的人机界面基于 Java 的 Swing 组件库构建,提供了一个图形用户界面(GUI),使用户可以通过直观的可视化操作进行员工和部门的管理。主界面采用菜单栏和表格视图相结合的设计,用户可以通过点击菜单项或右键点击表格中的行来执行各种管理和调试任务,如添加、修改、删除员工信息和部门信息。这种设计不仅简化了用户的操作流程,还确保了系统的高效性和易用性。

图3-4 登陆界面

图3-5 注册界面

图3-6 员工管理界面

图3-7 部门管理界面

图3-8 新增员工界面

图3-9 新增部门界面

图3-10 编辑部门界面

图3-11 编辑员工界面

3.3算法设计

3.3.1数据结构选择

(一)哈希表

① 用途:本系统使用哈希表(MyHashMap)来存储部门(Dept)和员工(Employee)信息,以实现高效的数据查找、插入和删除操作。哈希表的键为部门名称(String)或员工姓名(String),值为对应的部门对象(Dept)或员工对象(Employee)。

② 优势:在大规模数据存储和频繁数据访问场景下,哈希表能够快速定位和操作数据,极大提高系统性能。例如,在根据部门名称查询部门信息或根据员工姓名查询员工信息时,哈希表可迅速返回结果。

(二)表格模型(DefaultTableModel)

① 用途:用于在图形用户界面(GUI)中展示部门和员工信息。表格模型存储了表格的列名、数据行等信息,并负责与界面表格组件(JTable)交互,实现数据的可视化展示。

② 优势:方便与 Swing 组件结合,实现直观的数据呈现。开发人员可轻松将数据模型中的数据更新同步到界面表格,同时表格的交互操作(如排序、选择等)也能及时反馈到数据模型。

(三)文件存储

① 用途:系统使用 CSV(逗号分隔值)文件来持久化存储部门、员工和管理员信息。在程序运行时,从文件中读取数据加载到内存中的哈希表,数据更新后,再将哈希表中的数据写回文件保存。

② 优势:CSV 文件格式简单,易于理解和编辑,适合存储结构化数据。与数据库相比,文件存储无需复杂的数据库管理系统配置,降低系统复杂度和部署成本,适用于小型或简单数据存储需求。

3.3.2核心算法

(一)哈希表操作算法

①put方法(插入数据):

根据输入的键计算哈希值,确定在哈希表中的存储位置。若该位置为空,则直接插入新元素;若已存在元素,则遍历链表,若找到相同键,则更新对应值,否则将新元素插入链表头部。

②get方法(获取数据):

计算键的哈希值,定位到哈希表中的存储位置,然后遍历链表查找对应键的值,若找到则返回,否则返回 null。

③remove方法(删除数据):

计算键的哈希值,找到存储位置后,遍历链表,若找到对应键的元素,则删除该元素,并调整链表结构。

(二)排序算法

① sortByNameAsc和sortByNameDesc方法(按姓名排序):

使用java.text.Collator类实现中文字符串的拼音排序。先获取哈希表中所有键(员工姓名),将其转换为数组,然后定义比较器。比较器先按姓氏拼音排序,若姓氏相同,则按姓名后续字符拼音排序。最后使用Arrays.sort方法对数组进行排序,升序或降序由比较器逻辑决定。

(三)文件读写算法

① writeDeptToFile、writeEmployeesToFile和writeUsersToFile方法(写入文件):

遍历哈希表,将每个对象的属性值以逗号分隔的形式拼接成字符串,然后写入文件。每行表示一个对象的信息。

② readDeptFromFile、readEmployeesFromFile和readUsersFromFile方法(读取文件):

从文件中逐行读取数据,按逗号分隔每行字符串,根据数据创建对应的对象(部门、员工或管理员),并将对象添加到哈希表中,以指定属性作为键。

(四)用户界面交互算法

① 添加部门 / 员工操作

   算法思路:在图形用户界面中,用户输入部门或员工信息后,点击添加按钮。系统获取输入框中的文本,创建对应的部门或员工对象,将其添加到哈希表中,并更新界面表格显示。同时,将新数据写入文件保存。

   流程

a. 用户在界面输入信息。

b. 点击添加按钮触发事件监听器。

c. 事件监听器获取输入信息,创建对象,添加到哈希表。

d. 调用refreshTable方法更新表格显示。

e. 调用相应的writeToFile方法将数据写入文件。

② 编辑部门 / 员工操作

   算法思路:用户在表格中右键点击某行数据,选择编辑选项,弹出编辑窗口。窗口中显示该行数据的原始信息,用户修改后点击保存按钮。系统更新哈希表中的对象信息,刷新表格显示,并将更新后的数据写入文件。

   流程

a. 用户右键点击表格行,选择编辑。

b. 弹出编辑窗口,显示原始数据。

c. 用户修改信息,点击保存按钮触发事件监听器。

d. 事件监听器获取新信息,更新哈希表中的对象。

e. 调用refreshTable方法更新表格。

f. 调用writeToFile方法保存数据。

③ 删除部门 / 员工操作

   算法思路:用户在表格中右键点击某行数据,选择删除选项,弹出确认对话框。用户确认后,系统从哈希表中删除对应对象,更新表格显示,并将更新后的数据写入文件。

   流程

a. 用户右键点击表格行,选择删除。

b. 弹出确认对话框,用户确认。

c. 系统根据选中行数据获取键,从哈希表中删除对象。

d. 调用refreshTable方法更新表格。

e. 调用writeToFile方法保存数据。

④ 查询部门 / 员工操作

   算法思路:用户在查询输入框中输入关键词,点击查询按钮。系统根据关键词在哈希表中查找匹配数据,将结果显示在表格中。若未找到匹配数据,则弹出提示框。

   流程

a. 用户在查询输入框输入关键词。

b. 点击查询按钮触发事件监听器。

c. 事件监听器获取关键词,遍历哈希表查找匹配数据。

d. 若找到,将匹配数据添加到表格模型显示;若未找到,弹出提示框。

⑤ 排序操作

   算法思路:用户在排序下拉框中选择排序方式(如按姓名升序、降序等),系统根据选择调用相应的排序方法对哈希表中的数据进行排序,然后更新表格显示。

   流程

a. 用户选择排序方式。

b. 下拉框触发事件监听器。

c. 事件监听器根据选择调用排序方法(如sortByNameAsc或sortByNameDesc)。

d.  排序方法对哈希表数据排序后,调用refreshTablesort方法更新表格显示。

3.4数据设计

数据设计基于两个核心实体:员工(Employee)和部门(Dept),它们通过部门名称进行关联。每个员工属于一个特定的部门,并且系统不允许删除含有员工的部门以确保数据完整性。员工和部门的信息分别存储在两个自定义的哈希表 MyHashMap 中,即 employeeMap 和 deptMap,这两个哈希表使用字符串作为键(分别是员工姓名和部门名称),并分别映射到 Employee 和 Dept 对象。这些对象的属性(如员工的姓名、性别、出生年月等,以及部门的负责人、成立日期等)被用于构建图形用户界面中的表格视图(JTable),并通过CSV文件持久化存储。系统提供了增删改查功能,允许用户对员工和部门信息进行管理,并支持根据名称进行排序和搜索。此外,为了保证用户体验,还实现了右键菜单以提供快捷操作,如编辑和删除记录。

4.调试分析

4.1遇到的问题:

4.1.1启动页面时数据的读入问题,无法保障每次的数据都及时更新至csv文件中和页面表格中?

4.1.2我们设计了员工管理和部门管理,如何将员工和部门进行关联是之前面临的问题?

4.1.3在碰到多种非法输入的情况,如何控制程序不挂掉,增强程序的健壮性?

4.2解决方法:

4.2.1程序启动时,直接读取csv文件至哈希表中,每次做增删改查操作时,都调用读入操作将最新的哈希表读入csv文件,并及时刷新页面。

4.2.2将员工类EmpUI和部门类DeptUI中的哈希表分别设置为静态类型的变量,在新增员工的界面类中可以直接调用部门类的哈希表来进行查找有哪些部门,新增员工的界面类中就可以通过一个下拉框展示可以选择的部门。

4.2.3对于各种非法的输入,做异常处理抛给界面显示以提醒用户相关的问题。

4.3经验和体会:

数据持久化的重要性:及时将内存中的数据持久化到文件中,避免因程序崩溃或意外关闭导致数据丢失。对于关键业务系统,数据的完整性和一致性至关重要。

操作后的即时反馈:每次操作后及时刷新页面,给用户清晰的操作反馈,增强用户体验。用户可以看到他们的操作结果,减少困惑和误操作的可能性。

性能优化:虽然每次操作后都写入文件可以确保数据一致性,但频繁的文件操作可能会影响性能。可以通过批量处理或延迟写入(如每隔一定时间或达到一定操作次数后再写入)来优化性能,同时保持数据的相对一致性。

模块化设计的优势:通过将员工和部门的数据结构设计为静态哈希表,实现了模块之间的数据共享,简化了系统的复杂度。这种设计使得不同模块之间可以方便地访问和操作公共数据,减少了重复代码的编写。

双向关联的设计思路:员工和部门之间的双向关联设计不仅提高了查询效率,还增强了系统的灵活性。例如,可以通过员工快速找到所属部门,也可以通过部门快速找到所有员工。这种设计在实际业务场景中非常实用,特别是在需要统计分析时。

数据冗余与优化:虽然双向关联可以提高查询效率,但也可能导致一定程度的数据冗余。为了避免冗余数据带来的维护成本,建议在设计时仔细权衡,确保数据的一致性和完整性。

异常处理的重要性:良好的异常处理机制是程序健壮性的基础。通过捕获和处理异常,程序可以在遇到错误时优雅地恢复,而不是直接崩溃。这不仅提升了用户体验,也减少了系统维护的成本。

输入验证的最佳实践:在用户输入数据时,提前进行合法性检查是非常重要的。通过在前端和后端双重验证,可以有效防止非法数据进入系统,减少潜在的安全风险和逻辑错误。

日志记录的价值:日志记录不仅是调试工具,更是系统运维的重要手段。通过记录用户的操作行为,开发者可以更好地了解系统的使用情况,及时发现和解决问题。此外,日志还可以作为审计依据,确保系统的合规性和安全性。

5.用户手册

5.1概述

本用户手册旨在为用户提供详细的指导,帮助您顺利从 Gitee 拉取并使用 IntelliJ IDEA 编译和运行员工管理系统。该系统包括以下模块:

①登录模块:用户通过登录验证后进入系统。

②员工信息管理模块:提供员工信息的增删改查和排序功能。

③部门信息管理模块:提供部门信息的增删改查和排序功能。

5.2系统要求

在安装和运行本系统之前,请确保您的计算机满足以下要求:

①操作系统:Windows 10/11, macOS, 或 Linux。

②Java 版本:Java 8 或更高版本(建议使用最新版本)。

③开发环境:IntelliJ IDEA(社区版或专业版)。

④Git 客户端:确保已安装 Git 客户端,并配置好 Git 环境变量。

5.3安装与配置

5.3.1从 Gitee 拉取项目

①安装 Git 客户端:

如果您尚未安装 Git,请访问 [Git 官方网站](https://gitscm.com/) 下载并安装适合您操作系统的 Git 客户端。

安装完成后,打开命令提示符(Windows)或终端(macOS/Linux),输入 `git version` 验证安装是否成功。

②克隆项目仓库:

打开命令提示符(Windows)或终端(macOS/Linux),导航到您希望保存项目的目录。例如: C:\path\to\your\directory使用以下命令从 Gitee 克隆员工管理系统的项目仓库:

git clone https://gitee.com/jinxiaoliang/employeemanagementsystem.git

克隆完成后,项目文件将保存在 `employeemanagementsystem` 文件夹中。

5.3.2导入项目到 IntelliJ IDEA

①启动 IntelliJ IDEA:打开 IntelliJ IDEA,选择“Open”或“Import Project”。

②导入项目:导航到克隆下来的 `employeemanagementsystem` 文件夹,选择该文件夹并点击“OK”。IntelliJ IDEA 将自动检测并导入项目。如果提示选择项目 SDK,请选择已安装的 Java 版本(建议使用最新版本)。

③配置项目依赖:项目使用了 Maven构建工具,IntelliJ IDEA 会自动下载并配置所需的依赖库。请等待依赖库下载完成。

5.4运行程序

5.4.1使用 IntelliJ IDEA 运行

①启动程序:在 IntelliJ IDEA 中,点击顶部菜单栏的“Run” , 程序将启动,并显示登录界面。

②调试程序:如果您需要调试程序,可以在代码中设置断点,然后点击“Run” > “Debug 'EmployeeManagementSystem'”。IntelliJ IDEA 将以调试模式启动程序,允许您逐步执行代码并检查变量值

5.5使用说明

5.5.1登录模块

①启动程序后,您将看到登录界面。

②输入您的用户名和密码,点击“登录”按钮。

③如果用户名和密码正确,您将进入系统主界面;否则,系统会提示您重新输入。

④如果你没有账号,点击注册按钮跳转到注册页面先进行账号的注册

5.5.2员工信息管理模块

员工信息管理模块提供了以下功能:

增加员工信息

删除员工信息

修改员工信息

查询员工信息

按条件排序

(1)增加员工信息

①在主界面选择“员工信息管理” > “增加员工信息”。

②输入员工的详细信息,包括员工ID,姓名、性别、出生年月、工作年月、学历、部门、住址和电话。

③点击“保存”按钮,数据将保存到Emp.csv文件中。

(2)删除员工信息

①选择要删除的员工行:使用鼠标滚动并找到您想要删除的员工记录所在的行。将鼠标悬停在该行上,确保选中了正确的员工记录。

②右键点击并选择删除:右键点击选中的员工行,弹出一个上下文菜单。在菜单中选择“删除员工信息”选项。

③确认删除操作:系统会弹出一个确认对话框,提示您是否确定要删除该员工的信息。仔细阅读确认提示,确保您确实想要删除该员工的记录。如果确认删除,请点击“确认”按钮;如果您决定取消删除操作,请点击“取消”按钮。

(3)修改员工信息

①选择要修改的员工行:使用鼠标滚动并找到您想要修改的员工记录所在的行。将鼠标悬停在该行上,确保选中了正确的员工记录。

②右键点击并选择编辑:右键点击选中的员工行,弹出一个上下文菜单。在菜单中选择“修改员工信息”选项。

③查看并修改员工信息:系统将弹出一个编辑窗口,显示该员工的当前信息(如姓名、性别、出生年月、工作年月、学历、部门、住址和电话等)。根据需要修改相应的字段。您可以更改任何需要更新的信息,如部门、职位、联系方式等。

④保存修改:修改完信息后,点击“保存”按钮。系统会将更新后的信息保存到数据库中,并在表格中实时反映修改结果。

(4)查询员工信息

①在主界面选择“员工信息管理” > “查询员工信息”。

②您可以根据姓名字段进行查询。

③输入查询条件后,点击“查询”按钮。

④系统将显示符合条件的员工信息列表。

(5)按条件排序

①在主界面选择“员工信息管理” > “按条件排序”。

②选择排序方式(升序或降序)。

③点击“排序”按钮,系统将根据选择的条件对员工信息进行排序,并显示结果。

5.5.3部门信息管理模块

部门信息管理模块提供了以下功能:

增加部门信息

删除部门信息

修改部门信息

查询部门信息

按条件排序

(1)增加部门信息

①在主界面选择“部门信息管理” > “增加部门信息”。

②输入部门的名称、负责人、联系电话等信息。

③点击“保存”按钮,系统将自动为部门分配唯一的 ID,并将数据保存到数据库中。

(2)删除部门信息

①选择要删除的部门行:使用鼠标滚动并找到您想要删除的部门记录所在的行。将鼠标悬停在该行上,确保选中了正确的部门记录。

②右键点击并选择删除:右键点击选中的部门行,弹出一个上下文菜单。在菜单中选择“删除部门信息”选项。

③确认删除操作:系统会弹出一个确认对话框,提示您是否确定要删除该部门的信息。仔细阅读确认提示,确保您确实想要删除该部门的记录。如果确认删除,请点击“确认”按钮;如果您决定取消删除操作,请点击“取消”按钮。

(3)修改部门信息

①选择要修改的部门行:使用鼠标滚动并找到您想要修改的部门记录所在的行。将鼠标悬停在该行上,确保选中了正确的部门记录。

②右键点击并选择编辑:右键点击选中的部门行,弹出一个上下文菜单。在菜单中选择“修改部门信息”选项。

③查看并修改部门信息:系统将弹出一个编辑窗口,显示该部门的当前信息(如名称、负责人、描述等)。根据需要修改相应的字段。您可以更改任何需要更新的信息,如部门名称、负责人、描述等。

④保存修改:修改完信息后,点击“保存”按钮。系统会将更新后的信息保存到Dept.csv文件中,并在表格中实时反映修改结果。

(4)查询部门信息

①在主界面选择“部门信息管理” > “查询部门信息”。

②系统会提示您选择查询条件,您可以根据部门名称字段进行查询。

③输入查询条件后,点击“查询”按钮。

④系统将显示符合条件的部门信息列表。

(5)按条件排序

①在主界面选择“部门信息管理” > “按条件排序”。

②选择排序方式(升序或降序)。

③点击“排序”按钮,系统将根据选择的条件对部门信息进行排序,并显示结果。

5.6注意事项

路径要求:系统对文件路径没有特殊要求,但建议将项目文件夹保存在一个容易访问的目录中,避免使用过长或包含特殊字符的路径。

备份数据:定期备份员工和部门数据,以防止数据丢失。您可以手动导出数据并保存到安全的位置。

权限问题:如果在运行程序时遇到权限问题,请确保您有足够的权限访问和写入指定的文件夹。

6.测试结果

6.1登录模块

6.1.1登录操作

①输入:

  账户名:李

密码:123

测试结果:登录成功

②输入账户名:李

密码:1234

测试结果:登录失败

图6-1 登录失败弹窗

6.1.2注册操作:

①输入:

  账户名:jxl

密码:123

测试结果:注册成功

②输入:

  账户名:(没有输入)

密码:(没有输入)

测试结果:注册失败

图6-2 用户注册失败弹窗

6.2员工管理模块

6.2.1新增员工

①输入:

图6-3 新增员工正确输入窗口

测试结果:新增成功

②输入:

图6-4 新增员工错误输入窗口

测试结果:新增失败

图6-5 输入错误警告弹窗

6.2.2删除员工

①输入:

图6-6 确认是否删除员工弹窗

测试结果:删除成功

6.2.3修改员工

①输入:

图6-7 编辑员工信息窗口进行修改

测试结果:修改成功

6.2.4查询员工:

①输入:周

图6-8 输入字段进行查询

测试结果:查询成功

图6-9 输入字段查询成功展示的数据

②输入:周停

图6-10 输入字段进行查询

测试结果:查询失败

图6-11 查询失败弹窗

6.2.5排序员工

①输入:按升序进行排

图6-12 选择升序进行排序

测试结果:排序成功

图6-13 员工数据成功排序

②输入:按降序进行排

图6-14 选择降序进行排序

测试结果:

图6-15 员工数据成功排序

6.3部门管理模块

6.3.1新增部门

①输入:

图6-16 正确输入部门数据

测试结果:新增成功

②输入:

图6-17 非法输入部门数据

测试结果:新增失败

图6-18 异常输入弹窗

6.3.2删除部门

①输入:删除某个部门

图6-19 非法删除有员工的部门的警告弹窗

测试结果:删除失败

6.3.3修改部门

①输入:

图6-20 修改部门的弹窗

测试结果:修改成功

6.3.4查询部门:

①输入:市场

测试结果:查询成功

6-21 查询成功回显的数据

②输入:市场部门

图6-22 输入数据表中没有的数据

测试结果:查询失败

图6-23 未查询到的警告弹窗

6.3.5排序部门

①输入:按升序进行排

图6-24 选择按部门名称升序排序

测试结果:

图6-25 成功对部门进行排序

②输入:按降序进行排

图6-26 选择按部门名称降序排序

测试结果:

图6-27 成功对部门进行排序

7.项目结构及源码分享

7.1项目结构

本项目是采用idea进行开发的,项目的文件结构图如下:

 图7-1 项目结构图

7.2源码分享(文件从上往下)

7.2.1MessageConstant.java

这个我本来是打算用来封装一些常量类来用,便于修改,后面没时间就没弄了,也没加到项目里,大家可以参考一下,可加可不加

package com.jxl_dyw.constant;

public class MessageConstant {
    //"提示"
    public static final String TIP = "提示";

    //"请填写所有必填项!"
    public static final String FILL_ALL_REQUIRED_ITEMS = "请填写所有必填项!";

    //"出生年月格式不正确,请输入yyyy-MM-dd格式!
    public static final String BIRTHDAY_FORMAT_ERROR = "出生年月格式不正确,请输入yyyy-MM-dd格式!";

    //"工作年月格式不正确,请输入yyyy-MM-dd格式!"
    public static final String WORKDAY_FORMAT_ERROR = "工作年月格式不正确,请输入yyyy-MM-dd格式!";
}

7.2.2Dept.java

package com.jxl_dyw.entity;

/**
 * 部门
 */
public class Dept {
    // 部门编号
    private String DeptId;
    // 部门名称
    private String DeptName;
    //部门创建人
    private String BuildPeople;
    //部门创建时间
    private String BuildTime;

    public Dept() {
    }

    public Dept(String deptId, String deptName, String buildPeople, String buildTime) {
        DeptId = deptId;
        DeptName = deptName;
        BuildPeople = buildPeople;
        BuildTime = buildTime;
    }

    public String getDeptId() {
        return DeptId;
    }

    public void setDeptId(String deptId) {
        DeptId = deptId;
    }

    public String getDeptName() {
        return DeptName;
    }

    public void setDeptName(String deptName) {
        DeptName = deptName;
    }

    public String getBuildPeople() {
        return BuildPeople;
    }

    public void setBuildPeople(String buildPeople) {
        BuildPeople = buildPeople;
    }

    public String getBuildTime() {
        return BuildTime;
    }

    public void setBuildTime(String buildTime) {
        BuildTime = buildTime;
    }
}

7.2.3Employee.java

package com.jxl_dyw.entity;

/**
 * 员工类
 */
public class Employee {
    //员工ID、姓名、性别、出生年月、工作年月、学历、职务、住址、电话
    private String EmpId;
    private String name;
    private String sex;
    private String birthday;
    private String workday;
    private String education;
    private String position;
    private String address;
    private String phone;

    public Employee() {
    }

    public Employee(String empId, String name, String sex, String birthday, String workday, String education, String position, String address, String phone) {
        EmpId = empId;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.workday = workday;
        this.education = education;
        this.position = position;
        this.address = address;
        this.phone = phone;
    }

    public String getEmpId() {
        return EmpId;
    }

    public void setEmpId(String empId) {
        EmpId = empId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getWorkday() {
        return workday;
    }

    public void setWorkday(String workday) {
        this.workday = workday;
    }

    public String getEducation() {
        return education;
    }

    public void setEducation(String education) {
        this.education = education;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

7.2.4User.java

package com.jxl_dyw.entity;

/**
 * 管理员
 */
public class User {
    //用户名
    private String username;
    //密码
    private String password;
    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    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;
    }
}

7.2.5MyHashMap.java

package com.jxl_dyw.hashMap;

import java.util.*;

public class MyHashMap<K, V> {
    // 初始容量为16
    private static final int INITIAL_CAPACITY = 16;
    // 负载因子为0.75
    private static final float LOAD_FACTOR = 0.75f;

    // 哈希表数组
    private Entry<K, V>[] table;
    // 哈希表元素数量
    private int size;
    // 扩容阈值
    private int threshold;

    // 构造函数,初始化哈希表
    public MyHashMap() {
        table = new Entry[INITIAL_CAPACITY];
        size = 0;
        threshold = (int) (INITIAL_CAPACITY * LOAD_FACTOR);
    }

    // 内部类,表示哈希表中的一个条目
    private static class Entry<K, V> {
        final K key;
        V value;
        Entry<K, V> next;

        Entry(K key, V value, Entry<K, V> next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

    // 计算键的哈希值
    private int hash(Object key) {
        return (key == null) ? 0 : Math.abs(key.hashCode() % table.length);
    }

    // 插入键值对到哈希表中
    public void put(K key, V value) {
        int index = hash(key);
        Entry<K, V> newEntry = new Entry<>(key, value, null);

        // 如果桶为空,直接放入新条目
        if (table[index] == null) {
            table[index] = newEntry;
        } else {
            // 否则,遍历链表查找是否存在相同键,如果存在则更新值
            Entry<K, V> current = table[index];
            while (current.next != null) {
                if (current.key.equals(key)) {
                    current.value = value;
                    return;
                }
                current = current.next;
            }
            if (current.key.equals(key)) {
                current.value = value;
            } else {
                current.next = newEntry;
            }
        }

        size++;
        // 如果超过扩容阈值,进行扩容
        if (size >= threshold) {
            resize();
        }
    }

    // 根据键获取值
    public V get(K key) {
        int index = hash(key);
        Entry<K, V> entry = table[index];

        // 遍历链表查找键,找到则返回值
        while (entry != null) {
            if (entry.key.equals(key)) {
                return entry.value;
            }
            entry = entry.next;
        }

        return null;
    }

    // 根据键移除条目
    public V remove(K key) {
        int index = hash(key);
        Entry<K, V> previous = null;
        Entry<K, V> current = table[index];

        // 遍历链表查找键,找到则移除条目
        while (current != null) {
            if (current.key.equals(key)) {
                if (previous == null) {
                    table[index] = current.next;
                } else {
                    previous.next = current.next;
                }
                size--;
                return current.value;
            }
            previous = current;
            current = current.next;
        }

        return null;
    }

    // 扩容哈希表
    private void resize() {
        Entry<K, V>[] oldTable = table;
        table = new Entry[oldTable.length * 2];
        size = 0;
        threshold = (int) (table.length * LOAD_FACTOR);

        // 重新插入旧表中的所有条目到新表中
        for (Entry<K, V> entry : oldTable) {
            while (entry != null) {
                put(entry.key, entry.value);
                entry = entry.next;
            }
        }
    }

    // 获取哈希表中条目的数量
    public int size() {
        return size;
    }

    // 获取哈希表中所有的值
    public List<V> values() {
        List<V> values = new ArrayList<>();
        for (Entry<K, V> entry : table) {
            while (entry != null) {
                values.add(entry.value);
                entry = entry.next;
            }
        }
        return values;
    }

    // 获取哈希表中所有的键
    public List<K> keys() {
        List<K> keys = new ArrayList<>();
        for (Entry<K, V> entry : table) {
            while (entry != null) {
                keys.add(entry.key);
                entry = entry.next;
            }
        }
        return keys;
    }

    // 按照员工姓名的姓氏进行升序排序,姓氏相同则按后续字符排序
    public String[] sortByNameAsc(MyHashMap<String, V> map) {
        List<String> keys = map.keys();
        String[] sortedKeys = keys.toArray(new String[0]);

        // 使用 Collator 确保中文字符按照拼音排序
        Comparator<String> nameComparator = new Comparator<String>() {
            //使其适应中文环境
            private final java.text.Collator collator = java.text.Collator.getInstance(Locale.CHINA);

            @Override
            public int compare(String o1, String o2) {
                // 分割姓名为姓和名
                String surname1 = o1.split("")[0];
                String surname2 = o2.split("")[0];

                // 首先按姓氏排序
                int surnameComparison = collator.compare(surname1, surname2);
                if (surnameComparison != 0) {
                    return surnameComparison;
                }

                // 如果姓氏相同,则按后续字符排序
                return collator.compare(o1, o2);
            }
        };

        // 对键数组进行排序
        Arrays.sort(sortedKeys, nameComparator);
        return sortedKeys;
    }

    // 按照员工姓名的姓氏进行降序排序,姓氏相同则按后续字符排序
    public String[] sortByNameDesc(MyHashMap<String, V> map) {
        List<String> keys = map.keys();
        String[] sortedKeys = keys.toArray(new String[0]);

        // 使用 Collator 确保中文字符按照拼音排序
        Comparator<String> nameComparator = new Comparator<String>() {
            private final java.text.Collator collator = java.text.Collator.getInstance(Locale.CHINA);

            @Override
            public int compare(String o1, String o2) {
                // 分割姓名为姓和名
                String surname1 = o1.split("")[0];
                String surname2 = o2.split("")[0];

                // 首先按姓氏排序
                int surnameComparison = collator.compare(surname1, surname2);
                if (surnameComparison != 0) {
                    return -surnameComparison; // 降序
                }

                // 如果姓氏相同,则按后续字符排序
                return -collator.compare(o1, o2); // 降序
            }
        };

        // 对键数组进行排序
        Arrays.sort(sortedKeys, nameComparator);
        return sortedKeys;
    }
}

7.2.6AddDeptUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Dept;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

/**
 * 新增部门的UI界面
 */
public class AddDeptUI {

    public AddDeptUI() {
        // 创建 JFrame
        JFrame frame = new JFrame("编辑部门");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 关闭时只关闭当前窗口,不退出整个程序
        frame.setSize(800, 600); // 增大窗口尺寸
        frame.setLocationRelativeTo(null); // 居中显示窗口

        // 使用 GridBagLayout 进行布局
        frame.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10); // 增大组件之间的间距

        // 创建一个面板用于存放所有输入字段
        JPanel inputPanel = new JPanel(new GridBagLayout());
        gbc.gridx = 0;
        gbc.gridy = 0;

        // 设置全局字体,使所有组件的文字更大
        Font font = new Font("宋体", Font.PLAIN, 18);

        // 创建组件并添加到面板
        JLabel deptIdLabel = new JLabel("部门编号:");
        JTextField deptIdField = new JTextField(20);
        deptIdLabel.setFont(font);
        deptIdField.setFont(font);
        addComponent(inputPanel, deptIdLabel, deptIdField, gbc);

        JLabel deptNameLabel = new JLabel("部门名称:");
        JTextField deptNameField = new JTextField(20);
        deptNameLabel.setFont(font);
        deptNameField.setFont(font);
        addComponent(inputPanel, deptNameLabel, deptNameField, gbc);

        JLabel buildPeopleLabel = new JLabel("负责人:");
        JTextField buildPeopleField = new JTextField(20);
        buildPeopleLabel.setFont(font);
        buildPeopleField.setFont(font);
        addComponent(inputPanel, buildPeopleLabel, buildPeopleField, gbc);

        JLabel buildTimeLabel = new JLabel("成立日期:");
        JTextField buildTimeField = new JTextField(20);
        buildTimeLabel.setFont(font);
        buildTimeField.setFont(font);
        addComponent(inputPanel, buildTimeLabel, buildTimeField, gbc);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton addButton = new JButton("添加");
        addButton.setFont(font); // 设置按钮字体
        buttonPanel.add(addButton);

        // 添加按钮点击事件监听器
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取输入的部门信息
                String deptId = deptIdField.getText().trim();
                String deptName = deptNameField.getText().trim();
                String buildPeople = buildPeopleField.getText().trim();
                String buildTime = buildTimeField.getText().trim();
                // 判断部门编号是否为纯数字
                if (!deptId.matches("\\d+")) {
                    JOptionPane.showMessageDialog(frame, "部门编号必须为纯数字!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //对日期输入的格式进行验证
                if (!buildTime.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "日期格式不正确,请输入yyyy-MM-dd格式的日期!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 验证输入是否为空
                if (deptId.isEmpty() || deptId.isEmpty() || deptName.isEmpty() || buildPeople.isEmpty() || buildTime.isEmpty()) {
                    JOptionPane.showMessageDialog(frame, "请填写所有必填项!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                // 创建 Dept 对象
                Dept dept = new Dept(deptId, deptName, buildPeople, buildTime);

                // 判断部门是否已经存在,如果存在则不允许添加
                if (DeptUI.getDeptMap().get(dept.getDeptName())!=null) {
                    JOptionPane.showMessageDialog(frame, "该部门已存在,请重新输入!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 将 Dept 对象添加到哈希表中,以部门的名字作为键
                DeptUI.getDeptMap().put(dept.getDeptName(), dept);

                // 刷新部门表格
                DeptUI.refreshTable();

                // 将部门信息写入文件
                try {
                    DeptUI.writeDeptToFile(DeptUI.filePath);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(frame, "保存部门信息失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // 清空输入框
                deptIdField.setText("");
                deptNameField.setText("");
                buildPeopleField.setText("");
                buildTimeField.setText("");

                // 关闭页面
                frame.dispose();
            }
        });

        // 将输入面板和按钮面板添加到主窗口
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2; // 占两列
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        frame.add(inputPanel, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1; // 占一列
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weighty = 0.1;
        frame.add(buttonPanel, gbc);

        // 设置窗口可见
        frame.setVisible(true);
    }

    // 辅助方法:添加标签和输入框到面板
    private void addComponent(JPanel panel, JLabel label, JComponent textField, GridBagConstraints gbc) {
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(label, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        panel.add(textField, gbc);
    }


}

7.2.7AddEmpUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Employee;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

public class AddEmpUI extends JFrame {
    public AddEmpUI() {
        // 创建 JFrame
        JFrame frame = new JFrame("新增员工");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 关闭时只关闭当前窗口,不退出整个程序
        frame.setSize(800, 600); // 增大窗口尺寸
        frame.setLocationRelativeTo(null); // 居中显示窗口

        // 使用 GridBagLayout 进行布局
        frame.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10); // 增大组件之间的间距

        // 创建一个面板用于存放所有输入字段
        JPanel inputPanel = new JPanel(new GridBagLayout());
        gbc.gridx = 0;
        gbc.gridy = 0;

        // 设置全局字体,使所有组件的文字更大
        Font font = new Font("宋体", Font.PLAIN, 18);

        // 创建组件并添加到面板
        JLabel empIdLabel = new JLabel("员工ID:");
        JTextField empIdField = new JTextField(20);
        empIdLabel.setFont(font);
        empIdField.setFont(font);
        addComponent(inputPanel, empIdLabel, empIdField, gbc);

        JLabel nameLabel = new JLabel("姓名:");
        JTextField nameField = new JTextField(20);
        nameLabel.setFont(font);
        nameField.setFont(font);
        addComponent(inputPanel, nameLabel, nameField, gbc);

        JLabel sexLabel = new JLabel("性别:");
        JTextField sexField = new JTextField(20);
        sexLabel.setFont(font);
        sexField.setFont(font);
        addComponent(inputPanel, sexLabel, sexField, gbc);

        JLabel birthdayLabel = new JLabel("出生年月:");
        JTextField birthdayField = new JTextField(20);
        birthdayLabel.setFont(font);
        birthdayField.setFont(font);
        addComponent(inputPanel, birthdayLabel, birthdayField, gbc);

        JLabel workdayLabel = new JLabel("工作年月:");
        JTextField workdayField = new JTextField(20);
        workdayLabel.setFont(font);
        workdayField.setFont(font);
        addComponent(inputPanel, workdayLabel, workdayField, gbc);

        JLabel educationLabel = new JLabel("学历:");
        JTextField educationField = new JTextField(20);
        educationLabel.setFont(font);
        educationField.setFont(font);
        addComponent(inputPanel, educationLabel, educationField, gbc);

        // 部门标签
        JLabel positionLabel = new JLabel("部门:");
        positionLabel.setFont(font);
        //获取部门哈希表中所有的键
        String[] departments = DeptUI.getDeptMap().keys().toArray(new String[0]);
        // 创建下拉框,并添加预定义的部门选项
        JComboBox<String> positionComboBox = new JComboBox<>(departments);
        positionComboBox.setFont(font);
        // 将标签和下拉框添加到面板中
        addComponent(inputPanel, positionLabel, positionComboBox, gbc);

        JLabel addressLabel = new JLabel("住址:");
        JTextField addressField = new JTextField(20);
        addressLabel.setFont(font);
        addressField.setFont(font);
        addComponent(inputPanel, addressLabel, addressField, gbc);

        JLabel phoneLabel = new JLabel("电话:");
        JTextField phoneField = new JTextField(20);
        phoneLabel.setFont(font);
        phoneField.setFont(font);
        addComponent(inputPanel, phoneLabel, phoneField, gbc);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton addButton = new JButton("添加");
        addButton.setFont(font); // 设置按钮字体
        buttonPanel.add(addButton);

        // 添加按钮点击事件监听器
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取输入的员工信息
                String empId = empIdField.getText().trim();
                String name = nameField.getText().trim();
                String sex = sexField.getText().trim();
                String birthday = birthdayField.getText().trim();
                String workday = workdayField.getText().trim();
                String education = educationField.getText().trim();
                String position = positionComboBox.getSelectedItem().toString();
                String address = addressField.getText().trim();
                String phone = phoneField.getText().trim();
                //验证输入出生日期格式
                if (!birthday.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "出生年月格式不正确,请输入yyyy-MM-dd格式!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //验证输入工作日期格式
                if (!workday.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "工作年月格式不正确,请输入yyyy-MM-dd格式!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 验证输入是否为空
                if (empId.isEmpty() || name.isEmpty() || sex.isEmpty() || birthday.isEmpty() || workday.isEmpty() ||
                        education.isEmpty() || position.isEmpty() || address.isEmpty() || phone.isEmpty()) {
                    JOptionPane.showMessageDialog(frame, "请填写所有必填项!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                // 创建 Employee 对象
                Employee employee = new Employee(empId, name, sex, birthday, workday, education, position, address, phone);
                //如果员工名称已存在,则提示不可添加
                if (EmpUI.getEmployeeMap().get(employee.getName()) != null) {
                    JOptionPane.showMessageDialog(frame, "员工已存在,请勿重复添加!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 将 Employee 对象添加到哈希表中,以员工的名字作为键
                EmpUI.getEmployeeMap().put(employee.getName(), employee);
                //刷新表格
                EmpUI.refreshTable();
                //将员工信息写入文件
                try {
                    EmpUI.writeEmployeesToFile(EmpUI.filePath);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }

                // 清空输入框
                empIdField.setText("");
                nameField.setText("");
                sexField.setText("");
                birthdayField.setText("");
                workdayField.setText("");
                educationField.setText("");
                positionComboBox.setSelectedItem("");
                addressField.setText("");
                phoneField.setText("");
                //关闭页面
                frame.dispose();
            }
        });

        // 将输入面板和按钮面板添加到主窗口
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2; // 占两列
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        frame.add(inputPanel, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1; // 占一列
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weighty = 0.1;
        frame.add(buttonPanel, gbc);

        // 设置窗口可见
        frame.setVisible(true);
    }

    // 辅助方法:添加标签和输入框到面板
    private void addComponent(JPanel panel, JLabel label, JComponent textField, GridBagConstraints gbc) {
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(label, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        panel.add(textField, gbc);
    }

}

7.2.8DeptUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Dept;
import com.jxl_dyw.entity.Employee;
import com.jxl_dyw.hashMap.MyHashMap;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;

/**
 * 部门类型的UI界面
 */
public class DeptUI extends JPanel {
    private JTable departmentTable;
    private static DefaultTableModel tableModel;
    // 部门信息文件路径
    static String filePath = "src/main/resources/Dept.csv";
    private static MyHashMap<String, Dept> deptMap=new MyHashMap<>();

    public static MyHashMap<String, Dept> getDeptMap() {
        return deptMap;
    }

    public DeptUI() throws IOException {
        setLayout(new BorderLayout());
        // 从文件中读取部门数据
        readDeptFromFile(filePath);
        // 创建表格模型
        String[] columnNames = {"ID", "部门名称", "负责人", "成立日期"};
        tableModel = new DefaultTableModel(columnNames, 0); // 初始化为空表格

        // 读取哈希表的数据,并将对象中的数据添加到表格中
        for (Dept dept : deptMap.values()) {
            Object[] rowData = {
                    dept.getDeptId(),
                    dept.getDeptName(),
                    dept.getBuildPeople(),
                    dept.getBuildTime()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }

        // 创建表格
        departmentTable = new JTable(tableModel);
        JScrollPane scrollPane = new JScrollPane(departmentTable);
        add(scrollPane, BorderLayout.CENTER);

        // 创建顶部栏
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

        // 查询按钮
        JButton checkButton = new JButton("查询部门");
        // 搜索框
        JTextField searchField = new JTextField(20);
        JButton addButton = new JButton("新增部门");
        //排序下拉列表框
        JComboBox<String> comboBox = new JComboBox<>();
        comboBox.addItem("默认");
        comboBox.addItem("部门名称a->z升序");
        comboBox.addItem("部门名称z->a降序");


        topPanel.add(checkButton);
        topPanel.add(searchField);
        topPanel.add(addButton);
        topPanel.add(comboBox);

        add(topPanel, BorderLayout.NORTH);

        // 调整表格的行高
        for (int row = 0; row < departmentTable.getRowCount(); row++) {
            departmentTable.setRowHeight(30); // 调整行高以适应按钮
            //设置表格的字体
            departmentTable.setFont(new Font("宋体", Font.PLAIN, 14));
        }
        addButton.addActionListener(e -> {
            AddDeptUI addDeptUI = new AddDeptUI();
        });

        //为下拉框的选项添加事件监听器
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Object selected = comboBox.getSelectedItem();
                if (selected.equals("部门名称a->z升序")) {
                    //按姓名a->z升序
                    Object[] sortAsc = deptMap.sortByNameAsc(deptMap);
                    String[] stringSortAsc = Arrays.copyOf(sortAsc, sortAsc.length, String[].class);
                    refreshTablesort(stringSortAsc);

                    //刷新表格

                } else if (selected.equals("部门名称z->a降序")) {
                    //按姓名z->a降序
                    Object[] sortDesc = deptMap.sortByNameDesc(deptMap);
                    String[] stringSortDesc = Arrays.copyOf(sortDesc, sortDesc.length, String[].class);
                    refreshTablesort(stringSortDesc);

                    //刷新表格

                }else {
                    refreshTable();
                }
            }
        });

        // 为查询按钮添加事件监听器
        checkButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String searchName = searchField.getText().trim();

                // 清空表格
                tableModel.setRowCount(0);

                if (searchName.isEmpty()) {
                    refreshTable();
                } else {
                    boolean found = false;
                    for (Dept dept : deptMap.values()) {
                        if (dept.getDeptName().contains(searchName)) {
                            Object[] rowData = {
                                    dept.getDeptId(),
                                    dept.getDeptName(),
                                    dept.getBuildPeople(),
                                    dept.getBuildTime()
                            };
                            tableModel.addRow(rowData);
                            found = true;
                        }
                    }
                    if (!found) {
                        JOptionPane.showMessageDialog(DeptUI.this, "未找到匹配的部门", "查询结果", JOptionPane.WARNING_MESSAGE);
                    }
                }
            }
        });
       // 添加鼠标右键菜单
        departmentTable.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    int row = departmentTable.rowAtPoint(e.getPoint());
                    if (row >= 0) {
                        showPopupMenu(e, row);
                    }
                }
            }
        });
    }

    // 刷新排序后的表格
    private void refreshTablesort(String []keys) {
        // 清空表格
        tableModel.setRowCount(0);

        // 遍历哈希表,将每个员工的信息添加到表格中
        for (String key: keys) {
            Object[] rowData = {
                    deptMap.get(key).getDeptId(),
                    deptMap.get(key).getDeptName(),
                    deptMap.get(key).getBuildPeople(),
                    deptMap.get(key).getBuildTime()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }
    }

    // 显示鼠标右键菜单
    private void showPopupMenu(MouseEvent e, int row) {
        JPopupMenu popupMenu = new JPopupMenu();

        JMenuItem editItem = new JMenuItem("编辑");
        editItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取选中的行数据
                String deptName = (String) tableModel.getValueAt(row, 1);
                Dept dept = deptMap.get(deptName);

                // 弹出编辑窗口
                new EditDeptUI(dept);
            }
        });
        popupMenu.add(editItem);

        JMenuItem deleteItem = new JMenuItem("删除");
        deleteItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取选中的行数据
                String deptName = (String) tableModel.getValueAt(row, 1);
                Dept dept = deptMap.get(deptName);

                // 弹出确认对话框
                int confirm = JOptionPane.showConfirmDialog(DeptUI.this, "确定要删除部门 " + dept.getDeptName() + " 吗?", "确认删除", JOptionPane.YES_NO_OPTION);
                //如果该部门下有员工,则不能删除
                if (hasEmployee(deptName)) {
                    JOptionPane.showMessageDialog(DeptUI.this, "该部门下有员工,不能删除", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                if (confirm == JOptionPane.YES_OPTION) {
                    // 删除部门
                    deptMap.remove(deptName);
                    tableModel.removeRow(row);

                    // 将新的数据写入文件中
                    try {
                        writeDeptToFile(filePath);
                    } catch (IOException ex) {
                        JOptionPane.showMessageDialog(DeptUI.this, "保存部门信息失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                    }
                }
            }
        });
        popupMenu.add(deleteItem);

        popupMenu.show(e.getComponent(), e.getX(), e.getY());
    }

    //判断该部门是否有员工
    public static boolean hasEmployee(String deptName) {
        for (Employee emp : EmpUI.getEmployeeMap().values()) {
            if (emp.getPosition().equals(deptName)) {
                return true;
            }
        }
        return false;
    }

    //将哈希表中的数据写入到CSV文件中
    public static void writeDeptToFile(String filePath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {

            // 遍历哈希表,将每个员工的信息写入CSV文件
            for (Dept dept : deptMap.values()) {
                writer.write(String.join(",",
                        dept.getDeptId(),
                        dept.getDeptName(),
                        dept.getBuildPeople(),
                        dept.getBuildTime()
                ));
                writer.newLine();
            }
        }
    }


    // 刷新表格,重新加载哈希表中的数据
    public static void refreshTable() {
        loadDeptDataToTable();
    }


    // 从哈希表中加载员工数据到表格
    private static void loadDeptDataToTable() {
        // 清空表格
        tableModel.setRowCount(0);

        // 遍历哈希表,将每个员工的信息添加到表格中
        for (Dept dept : deptMap.values()) {
            Object[] rowData = {
                    dept.getDeptId(),
                    dept.getDeptName(),
                    dept.getBuildPeople(),
                    dept.getBuildTime()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }
    }

    // 读取 CSV 文件并将数据添加到 employeeMap 中
    public void readDeptFromFile(String filePath) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                // 按逗号分隔每一行
                String[] fields = line.split(",");

                // 创建 Employee 对象
                Dept dept = new Dept(
                        fields[0],
                        fields[1],
                        fields[2],
                        fields[3]
                );

                // 将 dept对象添加到哈希表中,以部门的名字作为键
                deptMap.put(dept.getDeptName(), dept);
            }
        }
    }
}

7.2.9EditDeptUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Dept;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

public class EditDeptUI {


    public  EditDeptUI(Dept dept) {
        // 创建 JFrame
        JFrame frame = new JFrame("编辑部门");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 关闭时只关闭当前窗口,不退出整个程序
        frame.setSize(800, 600); // 增大窗口尺寸
        frame.setLocationRelativeTo(null); // 居中显示窗口

        // 使用 GridBagLayout 进行布局
        frame.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10); // 增大组件之间的间距

        // 创建一个面板用于存放所有输入字段
        JPanel inputPanel = new JPanel(new GridBagLayout());
        gbc.gridx = 0;
        gbc.gridy = 0;

        // 设置全局字体,使所有组件的文字更大
        Font font = new Font("宋体", Font.PLAIN, 18);

        // 创建组件并添加到面板
        JLabel deptIdLabel = new JLabel("部门编号:");
        JTextField deptIdField = new JTextField(20);
        deptIdLabel.setFont(font);
        deptIdField.setFont(font);
        addComponent(inputPanel, deptIdLabel, deptIdField, gbc);

        JLabel deptNameLabel = new JLabel("部门名称:");
        JTextField deptNameField = new JTextField(20);
        deptNameLabel.setFont(font);
        deptNameField.setFont(font);
        addComponent(inputPanel, deptNameLabel, deptNameField, gbc);

        JLabel buildPeopleLabel = new JLabel("负责人:");
        JTextField buildPeopleField = new JTextField(20);
        buildPeopleLabel.setFont(font);
        buildPeopleField.setFont(font);
        addComponent(inputPanel, buildPeopleLabel, buildPeopleField, gbc);

        JLabel buildTimeLabel = new JLabel("成立日期:");
        JTextField buildTimeField = new JTextField(20);
        buildTimeLabel.setFont(font);
        buildTimeField.setFont(font);
        addComponent(inputPanel, buildTimeLabel, buildTimeField, gbc);

        // 将获取的对象的数据放入各个输入框内
        deptIdField.setText(dept.getDeptId());
        deptNameField.setEditable(false); // 部门名称不允许修改
        deptNameField.setText(dept.getDeptName());
        buildPeopleField.setText(dept.getBuildPeople());
        buildTimeField.setText(dept.getBuildTime());

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton saveButton = new JButton("修改");
        saveButton.setFont(font); // 设置按钮字体
        buttonPanel.add(saveButton);

        // 添加按钮点击事件监听器
        saveButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取输入的部门信息
                String deptId = deptIdField.getText().trim();
                String deptName = deptNameField.getText().trim();
                String buildPeople = buildPeopleField.getText().trim();
                String buildTime = buildTimeField.getText().trim();
                // 判断部门编号是否为纯数字
                if (!deptId.matches("\\d+")) {
                    JOptionPane.showMessageDialog(frame, "部门编号必须为纯数字!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //对日期输入的格式进行验证
                if (!buildTime.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "日期格式不正确,请输入yyyy-MM-dd格式的日期!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 验证输入是否为空
                if (deptId.isEmpty()||deptName.isEmpty() || buildPeople.isEmpty() || buildTime.isEmpty()) {
                    JOptionPane.showMessageDialog(frame, "请填写所有必填项!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                // 更新 Dept 对象
                Dept dept = new Dept(deptId, deptName, buildPeople, buildTime);
                //添加到哈希表中
                DeptUI.getDeptMap().put(dept.getDeptName(), dept);

                // 刷新部门表格
                DeptUI.refreshTable();

                // 将部门信息写入文件
                try {
                    DeptUI.writeDeptToFile(DeptUI.filePath);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(frame, "保存部门信息失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                //清空输入框
                deptIdField.setText("");
                deptNameField.setText("");
                buildPeopleField.setText("");
                buildTimeField.setText("");
                // 关闭页面
                frame.dispose();
            }
        });

        // 将输入面板和按钮面板添加到主窗口
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2; // 占两列
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        frame.add(inputPanel, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1; // 占一列
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weighty = 0.1;
        frame.add(buttonPanel, gbc);

        // 设置窗口可见
        frame.setVisible(true);
    }


    // 辅助方法:添加标签和输入框到面板
    private void addComponent(JPanel panel, JLabel label, JComponent textField, GridBagConstraints gbc) {
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(label, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        panel.add(textField, gbc);
    }

}

7.2.10EditEmpUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Employee;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

public class EditEmpUI {
    public EditEmpUI(Employee employee) {
        // 创建 JFrame
        JFrame frame = new JFrame("编辑员工");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 关闭时只关闭当前窗口,不退出整个程序
        frame.setSize(800, 600); // 增大窗口尺寸
        frame.setLocationRelativeTo(null); // 居中显示窗口

        // 使用 网格布局器进行布局
        frame.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10); // 增大组件之间的间距

        // 创建一个面板用于存放所有输入字段
        JPanel inputPanel = new JPanel(new GridBagLayout());
        gbc.gridx = 0;
        gbc.gridy = 0;

        // 设置全局字体,使所有组件的文字更大
        Font font = new Font("宋体", Font.PLAIN, 18);

        // 创建组件并添加到面板
        JLabel empIdLabel = new JLabel("员工ID:");
        JTextField empIdField = new JTextField(20);
        empIdLabel.setFont(font);
        empIdField.setFont(font);
        addComponent(inputPanel, empIdLabel, empIdField, gbc);

        JLabel nameLabel = new JLabel("姓名:");
        JTextField nameField = new JTextField(20);
        nameLabel.setFont(font);
        nameField.setFont(font);
        addComponent(inputPanel, nameLabel, nameField, gbc);

        JLabel sexLabel = new JLabel("性别:");
        JTextField sexField = new JTextField(20);
        sexLabel.setFont(font);
        sexField.setFont(font);
        addComponent(inputPanel, sexLabel, sexField, gbc);

        JLabel birthdayLabel = new JLabel("出生年月:");
        JTextField birthdayField = new JTextField(20);
        birthdayLabel.setFont(font);
        birthdayField.setFont(font);
        addComponent(inputPanel, birthdayLabel, birthdayField, gbc);

        JLabel workdayLabel = new JLabel("工作年月:");
        JTextField workdayField = new JTextField(20);
        workdayLabel.setFont(font);
        workdayField.setFont(font);
        addComponent(inputPanel, workdayLabel, workdayField, gbc);

        JLabel educationLabel = new JLabel("学历:");
        JTextField educationField = new JTextField(20);
        educationLabel.setFont(font);
        educationField.setFont(font);
        addComponent(inputPanel, educationLabel, educationField, gbc);

        // 部门标签
        JLabel positionLabel = new JLabel("部门:");
        positionLabel.setFont(font);
        //获取部门哈希表中所有的键
        String[] departments = DeptUI.getDeptMap().keys().toArray(new String[0]);
        // 创建下拉框,并添加预定义的部门选项
        JComboBox<String> positionComboBox = new JComboBox<>(departments);
        positionComboBox.setFont(font);
        // 将标签和下拉框添加到面板中
        addComponent(inputPanel, positionLabel, positionComboBox, gbc);

        JLabel addressLabel = new JLabel("住址:");
        JTextField addressField = new JTextField(20);
        addressLabel.setFont(font);
        addressField.setFont(font);
        addComponent(inputPanel, addressLabel, addressField, gbc);

        JLabel phoneLabel = new JLabel("电话:");
        JTextField phoneField = new JTextField(20);
        phoneLabel.setFont(font);
        phoneField.setFont(font);
        addComponent(inputPanel, phoneLabel, phoneField, gbc);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton addButton = new JButton("修改");
        addButton.setFont(font); // 设置按钮字体
        buttonPanel.add(addButton);

        //将获取的对象的数据放入各个输入框内
        empIdField.setText(employee.getEmpId());
        nameField.setText(employee.getName());
        sexField.setText(employee.getSex());
        birthdayField.setText(employee.getBirthday());
        workdayField.setText(employee.getWorkday());
        educationField.setText(employee.getEducation());
        positionComboBox.setSelectedItem(employee.getPosition());
        addressField.setText(employee.getAddress());
        phoneField.setText(employee.getPhone());

        //用户姓名不允许修改
        nameField.setEditable(false);

        // 添加按钮点击事件监听器
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取输入的员工信息
                String empId = empIdField.getText().trim();
                String name = nameField.getText().trim();
                String sex = sexField.getText().trim();
                String birthday = birthdayField.getText().trim();
                String workday = workdayField.getText().trim();
                String education = educationField.getText().trim();
                String position = positionComboBox.getSelectedItem().toString();
                String address = addressField.getText().trim();
                String phone = phoneField.getText().trim();
                //验证输入出生日期格式
                if (!birthday.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "出生年月格式不正确,请输入yyyy-MM-dd格式!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //验证输入工作日期格式
                if (!workday.matches("\\d{4}-\\d{2}-\\d{2}")) {
                    JOptionPane.showMessageDialog(frame, "工作年月格式不正确,请输入yyyy-MM-dd格式!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                // 验证输入是否为空
                if (empId.isEmpty() || name.isEmpty() || sex.isEmpty() || birthday.isEmpty() || workday.isEmpty() ||
                        education.isEmpty() || position.isEmpty() || address.isEmpty() || phone.isEmpty()) {
                    JOptionPane.showMessageDialog(frame, "请填写所有必填项!", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                // 创建 Employee 对象
                Employee employee = new Employee(empId, name, sex, birthday, workday, education, position, address, phone);

                // 将 Employee 对象添加到哈希表中,以员工的名字作为键
                EmpUI.getEmployeeMap().put(employee.getName(), employee);
                //刷新表格
                EmpUI.refreshTable();
                //将员工信息写入文件
                try {
                    EmpUI.writeEmployeesToFile(EmpUI.filePath);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }

                // 清空输入框
                empIdField.setText("");
                nameField.setText("");
                sexField.setText("");
                birthdayField.setText("");
                workdayField.setText("");
                educationField.setText("");
                positionComboBox.setSelectedItem("");
                addressField.setText("");
                phoneField.setText("");
                //关闭页面
                frame.dispose();
            }
        });

        // 将输入面板和按钮面板添加到主窗口
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2; // 占两列
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        frame.add(inputPanel, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1; // 占一列
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weighty = 0.1;
        frame.add(buttonPanel, gbc);

        // 设置窗口可见
        frame.setVisible(true);
    }

    // 辅助方法:添加标签和输入框到面板
    private void addComponent(JPanel panel, JLabel label, JComponent textField, GridBagConstraints gbc) {
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(label, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        panel.add(textField, gbc);
    }
}

7.2.11EmpUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.Employee;
import com.jxl_dyw.hashMap.MyHashMap;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.util.Arrays;

/**
 * 员工表面板
 */
public class EmpUI extends JPanel {
    // 员工表格
    private JTable employeeTable;
    private static DefaultTableModel tableModel;
    // 员工信息文件路径
    static String filePath = "src/main/resources/Emps.csv";
    //用于存放员工的哈希表
    private static MyHashMap<String , Employee> employeeMap = new MyHashMap<>();
    //get方法
    public static MyHashMap<String, Employee> getEmployeeMap() {
        return employeeMap;
    }
    public EmpUI() throws IOException {
        setLayout(new BorderLayout());
        //用文件输入读取Emps.csv文件中的员工信息,并添加到哈希表中
        readEmployeesFromFile(filePath);
        // 创建表格模型员工 ID、姓名、性别、出生年月、工作年月、学历、职务、住址、电话
        String[] columnNames = {"员工 ID", "姓名", "性别", "出生年月", "工作年月", "学历", "部门", "住址", "电话"};

        tableModel = new DefaultTableModel(columnNames, 0); // 初始化为空表格

        // 读取哈希表的数据,并将对象中的数据添加到表格中
        for (Employee employee : employeeMap.values()) {
            Object[] rowData = {
                    employee.getEmpId(),
                    employee.getName(),
                    employee.getSex(),
                    employee.getBirthday(),
                    employee.getWorkday(),
                    employee.getEducation(),
                    employee.getPosition(),
                    employee.getAddress(),
                    employee.getPhone()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }

        // 创建表格
        employeeTable = new JTable(tableModel);
        // 创建一个滚动面板,并将员工表格添加到其中
        // 确保当员工表格的内容超出屏幕显示范围时,可以通过滚动
        JScrollPane scrollPane = new JScrollPane(employeeTable);
        add(scrollPane, BorderLayout.CENTER);

        // 创建顶部栏
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

        // 查询按钮
        JButton checkButton = new JButton("查询员工");
        //增加搜索栏
        JTextField searchField = new JTextField(20);
        JButton addButton = new JButton("新增员工");
        //排序下拉列表框
        JComboBox<String> comboBox = new JComboBox<>();
        comboBox.addItem("默认");
        comboBox.addItem("姓名a->z升序");
        comboBox.addItem("姓名z->a降序");



        topPanel.add(checkButton);
        topPanel.add(searchField);
        topPanel.add(addButton);
        topPanel.add(comboBox);

        add(topPanel, BorderLayout.NORTH);

        // 调整表格的行高
        for (int row = 0; row < employeeTable.getRowCount(); row++) {
            employeeTable.setRowHeight(30); // 调整行高以适应按钮
            //设置表格的字体
            employeeTable.setFont(new Font("宋体", Font.PLAIN, 14));
        }
        //添加按钮的监听器
        addButton.addActionListener(e -> {
            new AddEmpUI();
        });

        //为下拉框的选项添加事件监听器
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Object selected = comboBox.getSelectedItem();
                if (selected.equals("姓名a->z升序")) {
                    //按姓名a->z升序
                    Object[] sortAsc = employeeMap.sortByNameAsc(employeeMap);
                    // 创建一个新的字符串数组,长度与sortAsc数组相同,并将sortAsc数组的内容复制到新数组中
                    String[] stringSortAsc = Arrays.copyOf(sortAsc, sortAsc.length, String[].class);
                    //刷新表格
                    refreshTablesort(stringSortAsc);

                } else if (selected.equals("姓名z->a降序")) {
                    //按姓名z->a降序
                    Object[] sortDesc = employeeMap.sortByNameDesc(employeeMap);
                    String[] stringSortDesc = Arrays.copyOf(sortDesc, sortDesc.length, String[].class);
                    //刷新表格
                    refreshTablesort(stringSortDesc);

                }else {
                    //默认刷新表格
                    refreshTable();
                }
            }
        });


        // 为查询按钮添加事件监听器
        checkButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String searchName = searchField.getText().trim();

                // 清空表格
                tableModel.setRowCount(0);

                if (searchName.isEmpty()) {
                    refreshTable();
                } else {
                    boolean found = false;
                    for (Employee employee : employeeMap.values()) {
                        if (employee.getName().contains(searchName) || employee.getName().contains(searchName)) {
                            Object[] rowData = {
                                    employee.getEmpId(),
                                    employee.getName(),
                                    employee.getSex(),
                                    employee.getBirthday(),
                                    employee.getWorkday(),
                                    employee.getEducation(),
                                    employee.getPosition(),
                                    employee.getAddress(),
                                    employee.getPhone()
                            };
                            tableModel.addRow(rowData);
                            found = true;
                        }
                    }
                    if (!found) {
                        JOptionPane.showMessageDialog(EmpUI.this, "未找到匹配的员工", "查询结果", JOptionPane.WARNING_MESSAGE);
                    }
                }
            }
        });

        // 添加鼠标右键菜单
        employeeTable.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    int row = employeeTable.rowAtPoint(e.getPoint());
                    if (row >= 0) {
                        showPopupMenu(e, row);
                    }
                }
            }
        });
    }

    // 刷新排序后的表格
    private void refreshTablesort(String []keys) {
        // 清空表格
        tableModel.setRowCount(0);

        // 遍历哈希表,将每个员工的信息添加到表格中
        for (String key: keys) {
            Object[] rowData = {
                    employeeMap.get(key).getEmpId(),
                    employeeMap.get(key).getName(),
                    employeeMap.get(key).getSex(),
                    employeeMap.get(key).getBirthday(),
                    employeeMap.get(key).getWorkday(),
                    employeeMap.get(key).getEducation(),
                    employeeMap.get(key).getPosition(),
                    employeeMap.get(key).getAddress(),
                    employeeMap.get(key).getPhone()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }
    }

    // 显示鼠标右键菜单
    private void showPopupMenu(MouseEvent e, int row) {
        JPopupMenu popupMenu = new JPopupMenu();

        JMenuItem editItem = new JMenuItem("编辑");
        editItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取选中的行数据
                String name = (String) tableModel.getValueAt(row, 1);
                Employee employee = employeeMap.get(name);

                // 弹出编辑窗口
                new EditEmpUI(employee);
            }
        });
        popupMenu.add(editItem);

        JMenuItem deleteItem = new JMenuItem("删除");
        deleteItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取选中的行数据
                String name = (String) tableModel.getValueAt(row, 1);
                Employee employee = employeeMap.get(name);

                // 弹出确认对话框
                int confirm = JOptionPane.showConfirmDialog(EmpUI.this, "确定要删除员工 " + employee.getName() + " 吗?", "确认删除", JOptionPane.YES_NO_OPTION);
                if (confirm == JOptionPane.YES_OPTION) {
                    // 删除哈希表中的员工
                    employeeMap.remove(name);
                    tableModel.removeRow(row);
                }
                //将新的数据写入文件中
                try {
                    writeEmployeesToFile(filePath);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        });
        popupMenu.add(deleteItem);

        popupMenu.show(e.getComponent(), e.getX(), e.getY());
    }

    //将哈希表中的数据写入到CSV文件中
    public static void writeEmployeesToFile(String filePath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {

            // 遍历哈希表,将每个员工的信息写入CSV文件
            for (Employee employee : employeeMap.values()) {
                writer.write(String.join(",",
                        employee.getEmpId(),
                        employee.getName(),
                        employee.getSex(),
                        employee.getBirthday(),
                        employee.getWorkday(),
                        employee.getEducation(),
                        employee.getPosition(),
                        employee.getAddress(),
                        employee.getPhone()
                ));
                writer.newLine();
            }
        }
    }


    // 刷新表格,重新加载哈希表中的数据
    public static void refreshTable() {
        loadEmployeeDataToTable();
    }


    // 从哈希表中加载员工数据到表格
    private static void loadEmployeeDataToTable() {
        // 清空表格
        tableModel.setRowCount(0);

        // 遍历哈希表,将每个员工的信息添加到表格中
        for (Employee employee : employeeMap.values()) {
            Object[] rowData = {
                    employee.getEmpId(),
                    employee.getName(),
                    employee.getSex(),
                    employee.getBirthday(),
                    employee.getWorkday(),
                    employee.getEducation(),
                    employee.getPosition(),
                    employee.getAddress(),
                    employee.getPhone()
            };
            tableModel.addRow(rowData); // 将每一行数据添加到表格模型中
        }
    }

    // 读取 CSV 文件并将数据添加到 employeeMap 中
    public void readEmployeesFromFile(String filePath) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                // 按逗号分隔每一行
                String[] fields = line.split(",");

                // 创建 Employee 对象
                Employee employee = new Employee(
                        fields[0],
                        fields[1],
                        fields[2],
                        fields[3],
                        fields[4],
                        fields[5],
                        fields[6],
                        fields[7],
                        fields[8]
                );

                // 将 Employee 对象添加到哈希表中,以员工的名字作为键
                employeeMap.put(employee.getName(), employee);
            }
        }
    }

}

7.2.12LoginUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.User;
import com.jxl_dyw.hashMap.MyHashMap;

import javax.swing.*;
import java.awt.*;
import java.io.*;

public class LoginUI extends JFrame {

    private JTextField usernameField;
    private JPasswordField passwordField;

    // 管理员信息文件路径
    static String filePath = "src/main/resources/User.csv";
    //用于存放管理员的哈希表
    private static MyHashMap<String , String> userMap = new MyHashMap<>();
    //get方法
    public static MyHashMap<String, String> getUserMap() {
        return userMap;
    }

    public LoginUI() {

        // 读取文件中的管理员信息
        try {
            readUsersFromFile(filePath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 设置窗口标题
        setTitle("员工信息管理系统");

        // 设置窗口大小和关闭操作
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建面板并设置布局
        JPanel formPanel = new JPanel();
        //网格布局管理器
        formPanel.setLayout(new GridBagLayout());
        //设置空边框
        formPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10);
        gbc.anchor = GridBagConstraints.WEST;

        // 添加用户名标签和文本框
        JLabel usernameLabel = new JLabel("账户名:");
        usernameLabel.setFont(new Font("宋体", Font.PLAIN, 20));
        gbc.gridx = 0;
        gbc.gridy = 0;
        formPanel.add(usernameLabel, gbc);

        usernameField = new JTextField(20);
        gbc.gridx = 1;
        formPanel.add(usernameField, gbc);

        // 添加密码标签和密码框
        JLabel passwordLabel = new JLabel("密码:");
        passwordLabel.setFont(new Font("宋体", Font.PLAIN, 20));
        gbc.gridx = 0;
        gbc.gridy = 1;
        formPanel.add(passwordLabel, gbc);

        passwordField = new JPasswordField(20);
        gbc.gridx = 1;
        formPanel.add(passwordField, gbc);

        // 添加按钮面板
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));

        // 添加登录按钮
        JButton loginButton = new JButton("登录");
        buttonPanel.add(loginButton);

        // 添加注册按钮
        JButton registerButton = new JButton("注册");
        buttonPanel.add(registerButton);

        // 设置按钮的大小
        loginButton.setPreferredSize(new Dimension(100, 30));
        registerButton.setPreferredSize(new Dimension(100, 30));

        // 将表单面板添加到窗口中央
        add(formPanel, BorderLayout.CENTER);
        // 将按钮面板添加到窗口底部
        add(buttonPanel, BorderLayout.SOUTH);

        // 显示窗口
        setLocationRelativeTo(null); // 窗口居中显示
        setVisible(true);

        //登录按钮的监听事件
        loginButton.addActionListener(e -> {
            // 登录逻辑
            String username = usernameField.getText();
            String password = new String(passwordField.getPassword());

            // 假设验证成功
            if (isValidLogin(username, password)) {
                // 跳转到MainUI
                MainUI mainUI = null;
                try {
                    mainUI = new MainUI();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
                mainUI.setVisible(true);
                dispose(); // 关闭当前登录界面
            } else {
                JOptionPane.showMessageDialog(this, "登录失败,请检查用户名和密码。");
            }
        });
        //注册按钮的监听事件
        registerButton.addActionListener(e -> {
            // 跳转到RegisterUI
            RegisterUI registerUI = new RegisterUI();
            registerUI.setVisible(true);
            dispose(); // 关闭当前登录界
        });
    }

    private boolean isValidLogin(String username, String password) {
        // 实现你的登录验证逻辑
        return userMap.get(username) != null && userMap.get(username).equals(password);
    }

    //读取用户表到哈希表
    public void readUsersFromFile(String filePath) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                // 按逗号分隔每一行
                String[] fields = line.split(",");

                // 创建 User 对象
                User user = new User(fields[0], fields[1]);

                // 将 User 对象添加到哈希表中,以用户名作为键
                userMap.put(user.getUsername(), user.getPassword());
            }
        }
    }

    //将哈希表中的数据写入到CSV文件中
    public static void writeUsersToFile(String filePath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {

            // 遍历哈希表,将每个用户的信息写入CSV文件
            for (String username : userMap.keys()) {
                writer.write(String.join(",",
                        username,
                        userMap.get(username)
                ));
                writer.newLine();
            }
        }
    }

}

7.2.13MainUI.java

package com.jxl_dyw.UI;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;

public class MainUI extends JFrame {
    //选项卡面板
    private JTabbedPane tabbedPane;
    private EmpUI empUI;
    private DeptUI deptUI;

    public MainUI() throws IOException {
        setTitle("企业人事管理系统");
        //点击窗口关闭按钮,关闭程序
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1200, 800);

        // 创建顶部栏
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        JLabel titleLabel = new JLabel("员工信息管理系统");
        topPanel.add(titleLabel);

        // 创建选项卡面板
        tabbedPane = new JTabbedPane();
        empUI = new EmpUI();
        deptUI = new DeptUI();
        tabbedPane.addTab("员工管理", empUI);
        tabbedPane.addTab("部门管理", deptUI);

        // 设置布局
        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.NORTH);
        add(tabbedPane, BorderLayout.CENTER);
        //使其居中
        setLocationRelativeTo(null);
        setVisible(true);
    }

}

7.2.14RegisterUI.java

package com.jxl_dyw.UI;

import com.jxl_dyw.entity.User;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;

public class RegisterUI extends JFrame {
    public RegisterUI() {
        // 设置窗口标题和关闭行为
        setTitle("注册");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 关闭时只关闭当前窗口,不退出整个程序
        setSize(800, 600); // 增大窗口尺寸
        setLocationRelativeTo(null); // 居中显示窗口

        // 添加窗口监听事件,点击关闭按钮时回退到登录页面
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                new LoginUI().setVisible(true);
            }
        });

        // 使用 GridBagLayout 进行布局
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10); // 增大组件之间的间距

        // 创建一个面板用于存放所有输入字段
        JPanel inputPanel = new JPanel(new GridBagLayout());
        gbc.gridx = 0;
        gbc.gridy = 0;

        // 设置全局字体,使所有组件的文字更大
        Font font = new Font("宋体", Font.PLAIN, 18);

        // 创建用户名和密码组件并添加到面板
        JLabel userLabel = new JLabel("用户名:");
        JTextField userField = new JTextField(20);
        userLabel.setFont(font);
        userField.setFont(font);
        addComponent(inputPanel, userLabel, userField, gbc);

        JLabel passwordLabel = new JLabel("密码:");
        JTextField passwordField = new JTextField(20);
        passwordLabel.setFont(font);
        passwordField.setFont(font);
        addComponent(inputPanel, passwordLabel, passwordField, gbc);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton registerButton = new JButton("注册");
        registerButton.setFont(font); // 设置按钮字体
        buttonPanel.add(registerButton);

        // 添加按钮点击事件监听器
        registerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取输入的用户信息
                String username = userField.getText().trim();
                String password = passwordField.getText().trim();

                // 验证输入是否为空
                if (username.isEmpty() || password.isEmpty()) {
                    JOptionPane.showMessageDialog(RegisterUI.this, "用户名和密码不能为空", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // 创建 User 对象
                User user = new User(username, password);

                // 将 User 对象添加到哈希表中,以用户名作为键
                LoginUI.getUserMap().put(user.getUsername(), user.getPassword());

                // 将用户信息写入文件
                try {
                    LoginUI.writeUsersToFile(LoginUI.filePath);
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }

                // 清空输入框
                userField.setText("");
                passwordField.setText("");

                // 弹出对话框
                JOptionPane.showMessageDialog(RegisterUI.this, "注册成功", "提示", JOptionPane.INFORMATION_MESSAGE);

                // 关闭注册页面并重新显示登录页面
                dispose();
                new LoginUI().setVisible(true);
            }
        });

        // 将输入面板和按钮面板添加到主窗口
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2; // 占两列
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        add(inputPanel, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1; // 占一列
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weighty = 0.1;
        add(buttonPanel, gbc);

        // 设置窗口可见
        setVisible(true);
    }

    private void addComponent(JPanel panel, JLabel label, JComponent textField, GridBagConstraints gbc) {
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(label, gbc);

        gbc.gridx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        panel.add(textField, gbc);
    }
}

7.2.15EmpApp.java

package com.jxl_dyw;

import com.jxl_dyw.UI.LoginUI;


public class EmpApp {
    public static void main(String[] args) {
        new LoginUI();
    }
}

7.2.16Dept.csv

102,市场部,李娜,2019-08-10
104,财务部,赵敏,2018-11-05
103,销售部,金小梁,2021-03-22
101,研发部,张伟,2020-05-15
105,人力资源部,刘洋,2022-07-12

7.2.17Emps.csv

1005,陈磊,男,1988-07-11,2014-03-01,硕士,财务部,杭州市西湖区XX路XX号,13512345678
E013,何晓波,男,1986-07-18,2011-09-10,本科,技术部,长沙市岳麓区XX大厦15层,12712345678
E008,周晓燕,女,1994-07-22,2019-03-15,本科,市场部,武汉市洪山区XX小区22号楼,13265432187
E015,宋晓阳,男,1989-03-12,2013-07-25,硕士,人力资源部,青岛市市南区XX花园12栋,12554321876
1010,郑丽,女,1991-10-20,2017-09-15,硕士,销售部,西安市雁塔区XX路XX号,13087654321
1002,李娜,女,1990-08-22,2012-05-15,硕士,财务部,上海市浦东新区XX路XX号,13987654321
1003,王强,男,1982-11-30,2008-09-01,博士,财务部,广州市天河区XX大道XX号,13612345678
E009,吴晓明,男,1984-11-25,2010-08-12,本科,人力资源部,重庆市渝中区XX花园15栋,13112345678
E010,郑晓玲,女,1995-02-10,2020-06-20,硕士,财务部,天津市南开区XX公寓25楼,13087654321
E007,杨晓东,男,1987-09-15,2012-12-05,硕士,技术部,南京市鼓楼区XX大厦18层,13354321876
E001,刘晓峰,男,1986-05-20,2011-07-15,本科,技术部,北京市海淀区XX大厦3层,13812345679
E017,冯晓龙,男,1985-11-28,2010-10-12,本科,研发部,沈阳市和平区XX大厦22层,12312345678
E012,黄晓莉,女,1990-10-30,2015-11-25,硕士,销售部,西安市雁塔区XX小区8号楼,12865432187
1006,刘芳,女,1992-12-18,2016-11-01,本科,市场营销部,成都市武侯区XX街XX号,13487654321
E019,许晓刚,男,1987-02-15,2012-11-10,本科,技术部,长春市朝阳区XX大厦10层,12154321876
E014,罗晓梅,女,1993-05-20,2018-04-15,本科,市场部,郑州市金水区XX小区20号楼,12687654321
E016,唐晓云,女,1994-09-05,2019-02-18,本科,财务部,大连市中山区XX公寓18楼,12465432187
E011,孙晓辉,男,1988-01-05,2014-05-15,本科,研发部,苏州市工业园区XX大厦10层,12954321876
E020,叶晓芬,女,1990-04-25,2015-05-20,硕士,市场部,济南市历下区XX小区8号楼,12065432187
1008,周静,女,1994-02-08,2019-04-01,本科,研发部,武汉市江汉区XX大街XX号,13287654321
E003,张伟民,男,1989-12-03,2013-09-10,本科,人力资源部,广州市白云区XX花园8栋,13654321877
E018,朱晓婷,女,1992-06-10,2017-08-20,硕士,销售部,哈尔滨市南岗区XX小区15号楼,12287654321
1009,吴迪,男,1989-05-12,2015-08-01,博士,算法研究部,重庆市渝中区XX路XX号,13112345678
E006,李晓霞,女,1992-03-19,2017-05-10,本科,销售部,杭州市西湖区XX小区10号楼,13487654321
E004,赵敏,女,1993-06-28,2018-02-18,本科,财务部,深圳市福田区XX公寓12楼,13765432188
E002,王丽华,女,1991-08-14,2016-04-25,硕士,市场部,上海市徐汇区XX小区15号楼,13987654322
1001,张伟,男,1985-03-15,2010-07-01,本科,技术研发部,北京市朝阳区XX街XX号,13812345678

7.2.18User.csv

11,11
顾清寒,520
aidh,1234
Djakarta,121233
李,123

7.3文件资源

文章顶部有项目压缩包可下载直接使用,也可以用git从gitee上拉取https://gitee.com/jin-xiao-liang

8.说明

这个小项目是我和一个同学在学校的实训上完成的,因为是数据结构课程的学期实训,所以像数据存储之类的没有采用数据库而是采用文件读取和哈希表来进行操作的,包括哈希表因为Java中有封装好的,直接用也有点偏离数据结构实训要求,所以哈希表部分索性就我们自己写一个哈希表。

项目采用swing组件的部分比较多,这个组件其实是属于比较过时的技术,大家不必深入研究,能看懂,会用ai来写就可以了,希望这篇文章能帮大家应付一下学校比较麻烦的作业之类的,觉得有帮助的可以点个关注哦!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐