简介:一个基于Java设计的个人信息维护系统完整项目包,适合Java初学者和在校学生作为Web开发课程设计或毕业设计参考。资源围绕用户登录、个人信息展示、信息修改、登录历史查询等核心模块展开,完整覆盖Java面向对象编程、JDBC数据库操作、MVC分层设计、SQL增删改查等关键技能。压缩包共78个文件,主要包含Java源码、Maven及IDEA配置文件(42个xml)、前端样式脚本(css/js共10个)、数据库初始化脚本(2个sql)、课程设计报告docx、说明文档md等,整体大小仅1.24MB,目录结构规范,便于按模块查阅和复用。项目已具备完整的环境配置与数据库表结构,导入开发工具后即可运行调试,适合直接改造扩展。已有100人学习下载,对正在完成类似管理信息系统实训任务的开发者具有较强的参考价值。
1. 基于 java 设计的个人信息维护系统:把课设代码真正跑起来才算会用
很多人下载量很大的 java 管理系统源码,真正动手跑一遍才发现,最花时间的不是业务逻辑,而是环境、编码和类路径。这套基于 java 设计的个人信息维护系统.zip 属于经典课设形态:登录窗口、个人信息维护、增删改查、数据导入导出,覆盖 JDBC 连接、面向对象分层、异常处理这些 Java 面试常考细节。它适合两类人,一是被课设或毕设卡住的在校生,想找一份能改能跑的代码照着调;二是准备 Java 面试、想看“从接收输入到写回 MySQL”完整链路的人。下面按我拆项目的习惯,从解压目录开始,一路说到连续踩坑后的验证方法。
我拿到这种压缩包时,第一件事不是打开 README,而是先确认它是 Java SE 桌面程序还是 JavaWeb 工程。这套资料的主流形态是 Swing + JDBC + MySQL,少数变体会把ui层换成 Servlet。无论哪种,dao和service两层代码基本是通用的,把这两层读懂了,换界面只是时间问题。
2. 先拆解项目骨架:包目录、数据库脚本和启动链路
2.1 拿到 zip 不要急着解压双击
很多人在 Windows 里直接双击 zip,要么看到一层套一层的目录,要么解压出来文件名全是乱码。我的习惯是先把 zip 复制到无中文、无空格的路径,比如D:\projects\personal-info-system,然后用 7-Zip 解压。系统自带解压器碰到某些老打包工具生成的 zip 时,会把 UTF-8 文件名按 GBK 解,于是整个src目录都变成问号。这个坑我用一句话总结:解压消费的是压缩包内部字节,解压工具的字符集直接影响文件名的还原,所以解压工具比下载网址更值得挑剔。
解压后先看一层目录,不要急着双击.java文件。常见课设源码的顶层长这样:
personal-info-system/ ├── src/ │ ├── com/example/entity/ │ ├── com/example/dao/ │ ├── com/example/service/ │ ├── com/example/ui/ │ └── com/example/util/ ├── lib/ │ ├── mysql-connector-java-8.0.33.jar │ └── poi-3.17.jar ├── db/ │ ├── personal_info.sql │ └── readme.txt ├── .classpath └── .project这个结构说明它是一条 Java SE 桌面程序:entity放数据对象,dao放数据库访问,service放业务判断,ui放 Swing 界面,util放连接管理等公共工具。很多 JavaWeb 变体其实共用同一套dao和service,只是把ui下的JFrame换成了Servlet。这里要注意:先看lib是不是空的。如果lib目录里没有 jar,说明打包的人把依赖裁掉了,你需要自己补 MySQL 驱动和 POI 依赖,这一步会卡掉一半人。
我用jar命令快速验证压缩包完整性,比解压更快:
jar tf personal-info-system.zip | head -n 20如果jar都打不开,说明它可能不是标准 zip,或者伪加密 flag 被改过,这时候换 7-Zip 强制试读。命令里的head -n 20只取前 20 行,避免控制台被文件清单刷屏。
2.2 数据表设计:为什么要把 user 和 person 分开
“个人信息维护系统”听起来只需要一张表,但正常运行最少要有两张:t_user管登录,t_person管业务数据。把它们分开的道理在于,登录态下只查一次用户表,之后所有个人信息的操作都通过user_id隔离,不同账号看不到彼此的数据。这不只是课设习惯,企业管理系统里也是同一套思路。
对应db/personal_info.sql,核心脚本是这样:
CREATE DATABASE IF NOT EXISTS personal_info DEFAULT CHARACTER SET utf8mb4; USE personal_info; CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; CREATE TABLE t_person ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, name VARCHAR(32) NOT NULL, gender CHAR(1) DEFAULT '男', phone VARCHAR(20), email VARCHAR(64), address VARCHAR(128), remark VARCHAR(255), update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_person_user FOREIGN KEY (user_id) REFERENCES t_user(id) ON DELETE CASCADE ) ENGINE=InnoDB;username建了唯一索引,防止注册重复账号;password用VARCHAR(64),后期若要改成 MD5 或 SHA-256 哈希,64 个字符刚好放得下。t_person.user_id外键设ON DELETE CASCADE,删除用户时自动清理它的个人信息,避免表里残留没人认领的孤儿数据。字符集用utf8mb4而不是utf8,是为了处理姓名里的生僻字和 emoji,很多老课设在这上面翻车。ON UPDATE CURRENT_TIMESTAMP让update_time在记录更新时自动改时间,比在 Java 代码里手动new Timestamp()更可靠,你少写一行,数据库帮你兜底。
2.3 启动链路:main 方法、登录窗口到主界面
源码里通常有一个入口类,名字可能是App或者Main。点开它,你会看到一条干净的三步启动链:
public class App { public static void main(String[] args) { // 先检查数据库连接,再显示登录窗口 DbHelper.init(); // 弹出登录窗口 LoginFrame login = new LoginFrame(); login.setVisible(true); // 登录成功后,LoginFrame 内部会创建 MainFrame 并关闭自己 } }DbHelper.init()一般负责加载驱动,并向数据库发一条空查询验证连通性。如果数据库没启动,它在弹登录窗口之前就会弹出JOptionPane报错,这是刻意设计的:环境问题越早暴露,越容易排查。登录窗口只负责收集用户名和密码,真正的比对逻辑放在dao层,窗口里的JButton监听器只调用LoginService.login(username, password),拿返回值决定是否进入MainFrame。
我看到不少学员改课设时,喜欢把 SQL 直接写进LoginFrame的ActionListener,结果数据库密码一改,界面代码也跟着改,最后窗口类和数据库逻辑拧成一股绳。这个项目把ui和dao分开是好的排版习惯,你不要在改造时亲手破坏它。
3. 环境搭建与导入:JDK、MySQL 8.0、IDE 的版本配合
3.1 JDK 和 MySQL 版本是第一个坑
这个项目的默认环境是 JDK 8。如果你机器上装的是 JDK 17,很多老代码里的Accessibility相关反射调用会抛InaccessibleObjectException,但它通常不影响主流程。比较麻烦的是 MySQL 8.0,在 Windows 上通过 zip 包手动安装时,需要先执行mysqld --initialize-insecure初始化 data 目录,再手动启动服务,整整多出三四个步骤。许多下载过 MySQL 8.0 zip 包的人,卡在“装完但连不上”的阶段。
先给出版本配合表,后面所有操作都按这张表来检查:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8(8u201+) | 课设代码基于 JDK8 语法,切到 11/17 可能遇到模块化限制 |
| MySQL Server | 5.7 或 8.0 | 8.0 需要配置认证插件和时区 |
| mysql-connector-java | 5.1.49 配 5.7;8.0.33 配 8.0 | 用 5.x 驱动连 8.0 会遇到认证插件报错 |
| Apache POI | 3.17 或 4.1.2 | 3.17 支持 xls,4.x 才稳定支持 xlsx |
| IDE | Eclipse 2020+ / IntelliJ IDEA | 老 Eclipse 对 JDK8 之后的支持很别扭 |
这张表的意思是:如果你按常见做法用 MySQL 8.0,就要把DbConfig里的驱动改成com.mysql.cj.jdbc.Driver,连接串加时区参数。如果你还在用 5.7,老驱动也能跑,但看不到新驱动带来的性能优化。代码里写com.mysql.jdbc.Driver是能兼容 8.0 驱动的,只是会有几行劝退警告,课设评审看到会问,索性直接改掉。
3.2 从 zip 到能运行的导入步骤
我还是按自己最顺手的顺序走,每一步都有它存在的理由:
- 把 zip 解压到无中文路径,例如
D:\projects\personal-info-system。 - 用 IDE 打开项目:Eclipse 里选
Open Projects from File System;IDEA 里选New -> Project from Existing Sources,然后选中解压后的目录。 - 如果没有被自动识别,手动建一个普通 Java 工程,把
src目录拷进去。 - 把
lib下的 jar 文件添加到类路径,IDEA 里是右键Add as Library。 - 在
DbConfig.java里改成本机数据库账号密码。 - 执行
db/personal_info.sql,确认两张表生成成功。 - 运行
App或Main。
第 3 步看起来多余,但很实用:很多下载包里的.project和.classpath是别人机器上的绝对路径,直接导入会导致lib引到别人的磁盘路径,编译一路报红。手动建工程再拷src,等于把他人机器的痕迹全部剥掉,反而稳定。第 6 步不要偷懒用 IDE 的数据库面板点一下就跑,最好在命令行里执行:
mysql -u root -p < db/personal_info.sql这段命令有个容易被忽略的细节:如果你直接打开 SQL 文件在某个客户端里执行,而客户端默认连接的不是personal_info库,那么表会建到错误的位置。命令行执行时,SQL 内部有USE personal_info;,库名和表名一并处理,不容易错。
3.3 改配置连接数据库
项目通常会把数据库连接信息集中到一个类里,名字可能是DbConfig或DBUtil。它长这样:
public class DbConfig { public static final String DRIVER = "com.mysql.cj.jdbc.Driver"; public static final String URL = "jdbc:mysql://localhost:3306/personal_info" + "?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; public static final String USER = "root"; public static final String PASSWORD = "123456"; }serverTimezone=Asia/Shanghai是 MySQL 8.0 必备参数,否则 JDBC 驱动拿不到服务器时区时会抛异常。characterEncoding=utf8要和数据库的utf8mb4配合,保证从 Java 写入的中文能原样落库。useSSL=false只是关闭加密连接,本地开发没必要开,开着反而容易因为证书问题连不上。PASSWORD那一格要改成你自己的 root 密码,如果手动安装 MySQL 8.0 zip 包时用了--initialize-insecure,初始密码是空的,也要在这里写空字符串。
从这一步能看出这套信息维护系统的数据流:所有界面操作最终都会经过DbConfig里的连接参数,参数错一个,界面再漂亮也白搭。
4. 核心功能拆解:登录校验、增删改查、Excel 导入导出
4.1 登录模块不要用拼接 SQL
网上能搜到的老课设里,经常见到这样的写法:
String sql = "SELECT id FROM t_user WHERE username='" + username + "' AND password='" + password + "'";这种写法在单机课设里能跑,但它是一道送命题。面试官只要问“你知道 SQL 注入吗”,这个实现的答案就是“我写的登录直接被绕过”。常见做法是全程用PreparedStatement,把输入当参数传给 SQL,而不是拼进字符串:
public boolean login(String username, String password) { String sql = "SELECT id FROM t_user WHERE username=? AND password=?"; try (Connection conn = DbHelper.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery(); return rs.next(); } catch (SQLException e) { log.error("登录查询失败", e); return false; } }逻辑上先用?占位,再用setString把值填进去,这样用户名里的单引号、反斜杠会被驱动转义,不再是 SQL 语法的一部分。try-with-resources会自动关闭Connection、PreparedStatement、ResultSet,接口排在ps.setString(1, username)的顺序要和 SQL 里?的顺序一一对应,多一个少一个都会抛参数索引异常。
补充一句:登录逻辑只返回boolean,不要返回整张用户表。界面需要的是“是否登录成功”,不是用户的密码哈希。返回true之后,再根据业务需要去查id和username,这是分层设计里最小化数据暴露的习惯。
4.2 个人信息的增删改查:DAO 层该写什么
这套系统的核心是维护个人信息,也就是对t_person表做 CRUD。DAO 层的方法名基本能对上八股文里常背的insert/update/delete/select。这里以更新操作为例:
public int updatePerson(Person p) { String sql = "UPDATE t_person SET name=?, phone=?, email=?, address=?, remark=? WHERE id=?"; try (Connection conn = DbHelper.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, p.getName()); ps.setString(2, p.getPhone()); ps.setString(3, p.getEmail()); ps.setString(4, p.getAddress()); ps.setString(5, p.getRemark()); ps.setInt(6, p.getId()); return ps.executeUpdate(); } catch (SQLException e) { throw new RuntimeException("更新个人信息失败", e); } }executeUpdate()返回的是受影响行数,0 表示没有匹配到id,1 表示更新成功。这个方法直接抛RuntimeException而不是吞掉异常,是为了让上层的service或ui决定怎么提示用户——比如弹窗还是写日志。这里的Person p是一个 POJO,字段和t_person表一一对应,表结构改动时,要同步改实体类和 SQL。
在每个 long text 中,关键的观察点是Connection的开销。此类课设每次操作新建连接,严格来说不符合生产环境。在课程设计中常见做法的确如此,因为没有连接池依赖。修改为dbcp连接池的参数与依赖是这个项目的后续工作。
4.3 用 POI 导出和导入 Excel
个人信息维护系统通常有一项“导出报表”的功能,技术选型十有八九是 Apache POI。导出到.xls的代码如下:
public void exportToExcel(List<Person> list, String filePath) { try (Workbook wb = new HSSFWorkbook()) { Sheet sheet = wb.createSheet("个人信息"); Row header = sheet.createRow(0); String[] titles = {"姓名", "性别", "电话", "邮箱", "地址"}; for (int i = 0; i < titles.length; i++) { header.createCell(i).setCellValue(titles[i]); } for (int i = 0; i < list.size(); i++) { Row row = sheet.createRow(i + 1); Person p = list.get(i); row.createCell(0).setCellValue(p.getName()); row.createCell(1).setCellValue(p.getGender()); row.createCell(2).setCellValue(p.getPhone()); row.createCell(3).setCellValue(p.getEmail()); row.createCell(4).setCellValue(p.getAddress()); } try (FileOutputStream fos = new FileOutputStream(filePath)) { wb.write(fos); } } catch (IOException e) { throw new RuntimeException("导出失败", e); } }HSSFWorkbook对应的是旧版.xls格式,最大行数 65536。个人信息维护系统几百条数据完全够用,但要处理大名单,就该换成XSSFWorkbook,它支持到 1048576 行,文件格式是.xlsx。表头从第 0 行开始,数据从第 1 行开始,这是 POI 的常见约定;循环里i + 1就是给表头让位。
导入方向动作相反,用WorkbookFactory.create(InputStream)打开文件,遍历每一行,把单元格值读进Person对象。这里容易踩的一个点是空行判断,Excel 里被格式过但没内容的行会返回非 null 的空Row,要判断cell == null或cell.toString().trim().isEmpty()再跳过去,不然 DAO 层会插入一堆空记录。
5. 常见问题与避坑:五个反复出现的翻车场景
5.1 ZIP 文件解压出错或提示伪加密
现象:双击 zip 后系统提示文件损坏或需要密码,但下载页面明确说无密码;强制解压后目录树少文件,.java文件打开是乱码。
原因:部分压缩包工具会写入非标准 flag,被解压软件误判成加密项,也就是常说的 zip 伪加密;另一些则是打包时用了自解压格式但扩展名写成 zip。普通课程设计资源很少恶意改 flag,但老打包工具确实会留下兼容性问题。
解决:不要依赖 Windows 自带解压器。用 7-Zip 打开压缩包,它遇到伪加密通常能自动修复并读取文件列表。更稳妥的方式是在命令行里用jar tf先列出条目,能列出完整目录就证明压缩包本身没问题,后续只是解压工具选择问题。
5.2 控制台和数据库中文乱码
现象:登录成功后,主界面表格里的姓名显示成问号;MySQL 客户端里查t_person,中文也是???。
原因:三层字符集不一致,Java 编译编码、控制台编码、MySQL 连接串编码,任何一层用错都会让中文在传输过程中变成不可识别字符。最常见的情况是 IDE 默认用 GBK,项目文件是 UTF-8,一编译就乱。
解决:把 IDE 的文件编码、控制台编码都设成 UTF-8,IDEA 里在Help -> Edit Custom VM Options加-Dfile.encoding=UTF-8;数据库连接串加characterEncoding=utf8;MySQL 表结构确认是utf8mb4。三层统一后再删库重建、重新执行 SQL,中文就能落库。这里强调重建的顺序,连接字符集写在 URL 里,表字符集写在 DDL 里,改完一层不重建,旧数据还是坏的。
5.3 ClassNotFoundException:驱动有但类路径找不到
现象:运行App时抛java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。
原因:jar 文件在磁盘上存在,但没被 IDE 加载到模块或类路径。用 Eclipse 导入.project工程时,.classpath里记录的可能是别人机器上的绝对路径,你的电脑上根本没有那个目录,IDE 找不到就静默忽略了。
解决:先确定lib目录的 jar 已添加为 Library。IDEA 里右键lib目录,选Add as Library;Eclipse 里Project Properties -> Java Build Path -> Add JARs。如果项目不用 IDE,命令行运行时加上类路径参数:
java -cp ".;lib/*" com.example.Applib/*是通配符,表示把lib下所有 jar 都加入类路径。这条命令在 Windows 下注意分号和星号的写法,Linux/macOS 要把分号换成冒号。
5.4 MySQL 8.0 与老驱动不兼容
现象:连接时报Unable to load authentication plugin 'caching_sha2_password',或提示Public Key Retrieval is not allowed。
原因:MySQL 8.0 默认认证插件是caching_sha2_password,而 mysql-connector-java 5.x 不认识这个插件,老驱动只能在mysql_native_password下工作。
解决:把驱动换成 8.0.x 版本,连接串里的Driver改为com.mysql.cj.jdbc.Driver,并在 URL 上追加allowPublicKeyRetrieval=true&useSSL=false。如果电脑上 MySQL 8.0 是用 zip 包手动装的,确认初始化时用的mysqld --initialize-insecure,root 密码为空,再把DbConfig.PASSWORD改成空字符串,否则后续所有查询都会因认证失败被拒。这个场景在“MySQL8.0 zip windows10 安装教程”里尤其常见,服务装好了,驱动对不上,项目启动直接黑屏报错。
5.5 启动后登录失败:表和初始化数据没建
现象:窗口能弹出来,输入默认账号admin / admin却提示密码错误;后台 SQL 日志显示Table 'personal_info.t_user' doesn't exist。
原因:只跑了 Java 程序,没有执行db/personal_info.sql。有的版本把初始化数据写进了脚本,比如插入admin账号,但你只建表没插数,所以登录查不到行。
解决:先登录 MySQL,执行source D:/projects/personal-info-system/db/personal_info.sql,执行完后用下面这段 SQL 确认:
SELECT id, username FROM t_user; SELECT COUNT(*) FROM t_person;如果t_user有数据但账号还是登不进,检查DbConfig的密码是否真的改对了,以及druid或连接工具是不是缓存的旧连接。我见过最隐蔽的情况是 MySQL 服务同时跑了两个实例,IDE 连的是 3307 端口,你初始化数据却在 3306,代码和数据库根本不是一个东西。遇到这种先查端口,再查库名,最后查表名。
6. 进阶改造:密码加盐、一键启动脚本和可复现的验证流程
6.1 让登录密码从明文中解脱出来
课设里如果t_user.password存的是明文,面试时被问到会很被动。改造方案分两步:注册时生成随机盐,保存成salt$hash;登录时用同一盐重新计算后比对。常见做法是用MessageDigest做 SHA-256:
public static String sha256(String input) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } }String.format("%02x", b)把每个字节转成两位十六进制,拼出来就是 64 位定长字符串。改造时别直接把原密码更新成哈希,因为老用户库里的密码是明文,哈希算法对不上,他们全部会登录失败。要写一个一次性迁移脚本,把明文密码先统一改成带盐哈希,再让登录逻辑切到新校验。
6.2 一键启动脚本
开发阶段用 IDE 跑很方便,但换机器演示时,一个run.bat更省事:
@echo off set PROJECT_DIR=D:\projects\personal-info-system cd /d %PROJECT_DIR% java -cp ".;lib/*" com.example.App pausecd /d %PROJECT_DIR%保证工作目录正确,否则DbHelper里如果用了相对路径读配置文件,会找不到资源。pause是为了让窗口在程序异常退出时不要闪没,方便看报错。把这个脚本放在项目根目录,比每次打开 IDE 等加载快得多,也适合答辩现场。
6.3 每次跑通后我固定走的验证三步
第一个动作,手工注册一个新账号,录入一条姓名含生僻字的信息,然后到 MySQL 客户端查t_person,确认中文没有变成问号。第二个动作,点击导出 Excel,再把导出文件里的数据重新导入,检查是否有重复记录。第三个动作,删除刚注册的账号,用上面那条 SQL 看t_person中关联数据是否被级联删除。
这三步覆盖了编码、IO、外键三个最容易出问题的位置。有一次我把课设密码改成加盐哈希后,忘了处理库里已有的老账号,整整一个上午连登录都失败。从那以后,每次执行 SQL 脚本和改认证逻辑,我都会先备份t_user数据,并在验证清单里强制走一遍老数据迁移流程,再把程序交付出去。希望这个习惯也能帮到你。
本文还有配套的精品资源,点击获取