尧图精选

Java通讯录课设解析:JDBC连接MySQL与PreparedStatement防注入

🕒 发布时间:2026/9/15 22:33:54 📁 来源:尧图网络
简介面向高校学子的Java通讯录管理系统课程设计项目内含完整源代码、MySQL数据库相关文件与课程设计实验报告适用于正在学习Java编程、MySQL数据库及软件工程流程的学生。压缩包共51个文件以30个class编译文件、6个java源文件、6个xml配置为主同时提供3个csv联系人示例数据、1个数据库驱动jar包、1份docx实验报告以及IDEA工程配置文件压缩后仅3.64MB目录结构清晰便于按模块查找。当前已有573人学习下载。项目涵盖登录注册、菜单导航、通讯录联系人增删改查等典型功能借助源文件与数据库脚本可快速搭建MySQL环境CSV样本数据可直接导入测试实验报告则系统梳理项目背景、设计思路、实现方法、常见问题与排错过程为课程设计文档撰写提供直接参考。读者可据此完整走通Java桌面应用与MySQL联动开发流程理解数据库表设计、JDBC操作、文件读写等关键知识点积累可复用的项目实战经验。1. 课设包AddressBook.zip里藏着什么拿到AddressBook.zip这个通讯录课设包我第一件事不是翻开实验报告而是直接删掉.idea目录把src下的Java文件按顺序读了一遍。包里没有花哨的框架就是Swing界面加MySQL连接器Menu、Login、Register、MySql、AddressBook、Test六个类构建了一条完整的注册、登录、维护联系人链路。这种「Java文件CSV样例mysql-connector-java-8.0.25.jar」的组合恰好覆盖了课程设计的三大硬指标GUI交互、数据库访问、文件数据处理。无论你是想找一份可运行的Java通讯录管理系统源码还是想把课程设计报告里的数据库设计落到实处这个包都值得拆开看看。2. MySQL连接层与数据库表设计在课设题目里只要能跑通就算完成但如果你把MySql.java写成一个到处new连接的散装类答辩时老师的第一个问题就会落在“连接资源要不要关”上。这个项目里MySql.java承担的就是统一的连接入口它不掺业务逻辑只负责把驱动加载、URL拼装、Connection获取这三件事收敛到一个地方。2.1 连接参数mysql-connector-java 8.0.25的坑先看MySql.java核心代码public class MySql { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/addressbook ?useUnicodetruecharacterEncodingutf8 useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }这段代码里有三个容易被忽略的点。第一8.0.25的驱动类名带cj如果照抄旧博客写com.mysql.jdbc.Driver在升级后的驱动里会抛类找不到。第二连接串必须带serverTimezone否则MySQL驱动无法解析服务器时区直接报The server time zone value错误课设一般填Asia/Shanghai就够。第三useSSLfalse并不是为了安全而是避免本地开发时反复出现SSL握手警告真正的生产连接要反过来开启。这里的USER和PASSWORD我默认写成了root和123456你拿到源码后需要改成自己本机MySQL的账号。在Test.java里验证连接是否通常见做法是写一段静态代码块public class Test { public static void main(String[] args) throws SQLException { try (Connection conn MySql.getConnection()) { System.out.println(connected: conn.isClosed()); } } }这样运行main方法能立即暴露是否缺驱动、端口不对、密码错误三类问题。try-with-resources会自动关闭连接这点在课设代码里显得很重要因为运输demo时我不会让老师盯着控制台看资源回收。注意如果你本机MySQL占用的是3307或其他端口记得同步修改URL里的端口号如果密码有特殊字符DriverManager不会帮你转义最好直接改MySQL密码为简单密码。2.2 建库建表通讯录怎么建模数据库设计是课程设计报告的核心不能打开MySQL乱敲一通就完事。跟AddressBook配套的库建议拆成两张表user管登录账号contact管联系人。如果只建一张联系人表你会发现注册功能没有落点所有用户看到的是同一份通讯录这在演示多用户场景时很容易被问住。下面是配套建表脚本CREATE DATABASE addressbook DEFAULT CHARACTER SET utf8mb4; USE addressbook; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE contact ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, name VARCHAR(50) NOT NULL, phone VARCHAR(20), email VARCHAR(100), address VARCHAR(255), remark VARCHAR(255), FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ) ENGINEInnoDB; ALTER TABLE contact ADD INDEX idx_user_name (user_id, name);关键字段说明如下字段类型用途注意点user.idINT主键自增不用业务数据当主键user.usernameVARCHAR登录名加UNIQUE约束防重复注册user.passwordVARCHAR密码摘要长度给255给哈希算法留空间contact.user_idINT外键级联删除用户注销时清掉联系人contact.phoneVARCHAR手机号别用BIGINT电话开头0会丢这里把phone设计成字符串而不是数字是很多初学者踩过的坑。手机号如果存成BIGINT138前导的0不会显示而且长度超过int上限还会报错。另一个容易漏的是idx_user_name联合索引虽然课设数据量小但加上这个索引后在联系人列表页按下拉搜索的SQL会快很多这个冗余设计可以直接写进实验报告的性能分析部分。2.3 先看看CSV样例再动业务代码压缩包里带了address.csv、xiaomenglong.csv、abc.csv三个数据文件它们的作用有两个一是充当测试数据源二是给数据库填充提供模板。拿到文件后先用命令确认编码file address.csv head -5 address.csv如果输出显示Non-ISO extended-ASCII说明文件是GBK直接用JDBC读取会乱码需要转成UTF-8再导入。我一般会写一个小工具先做编码规整而不是等内容读到一半才去排查。这个处理细节放在下一章CSV导入部分一起说你现在只需要知道数据库表结构定了CSV的列顺序应当与contact表的name, phone, email, address, remark对应即使样本数据里有空列也要保证读取时按索引取值不越界。另外.idea和out目录是IntelliJ IDEA的工程配置与编译产物拿到源码包后应该先删除再导入IDE否则可能出现模块名错乱导致AddressBook.iml路径对不上。如果你换电脑运行只保留src、lib和CSV文件其他都可以重建这也是很多课设包下载后运行不了的隐性原因。3. 登录注册的防注入与密码校验实现通讯录系统不是只有联系人管理登录注册才是门面。Login.java和Register.java这两个类在界面上是独立的JFrame但它们在业务上都直连MySQL。这里最常见的错误是把用户名直接拼到SQL里比如SELECT * FROM user WHERE username username 一次带引号的输入就能让整个查询语法错乱更复杂的输入可以直接绕过密码校验。课设代码里改掉这一点报告的“安全性设计”才有东西可写。3.1 注册时把密码和确认密码分开校验注册界面通常有用户名、密码、确认密码三个JTextField。服务端方法可以写成public boolean register(String username, String password, String confirm) { if (username null || username.trim().isEmpty()) { return false; } if (password null || password.length() 6) { return false; } if (!password.equals(confirm)) { return false; } String sql INSERT INTO user(username, password) VALUES(?, ?); try (Connection conn MySql.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username.trim()); ps.setString(2, hashPassword(username.trim(), password)); int rows ps.executeUpdate(); return rows 1; } catch (SQLException e) { e.printStackTrace(); return false; } }这里把“两次密码一致”的校验放在Service层而不是只放在按钮事件里是为了避免在测试时绕过界面直接调用方法时非空校验失效。setString按类型填充参数驱动会把值当纯字符串处理单引号、反斜杠都不再参与SQL语法解析这就是预编译解决注入的核心原理。rows 1用于判断是否真的写进去一行用户名重名时数据库会抛异常这里先直接捕获返回false。3.2 Statement拼接和PreparedStatement的差别一张对比表能帮你看清为什么要放弃字符串拼接写法代码示意问题Statementstmt.executeQuery(select * from user where username name )参数值可能改变SQL结构PreparedStatementps.setString(1, name)参数和SQL模板分离驱动做转义实际测试时输入admin OR 11能直接绕过一个简单的拼接SQL。而PreparedStatement在服务端会把?占位符编译成参数即使传入攻击字符串查询也只会去找username等于这段字面量的记录。对课设而言这个知识点足够在论文里写两页。3.3 密码不能明文落库用SHA-256加盐课程设计报告里如果写“密码使用MD5加密”答辩时老师很可能追问MD5为什么不安全。我的建议是至少用SHA-256而且加盐。简单实现private static String hashPassword(String username, String rawPassword) { try { String salted username : rawPassword; MessageDigest md MessageDigest.getInstance(SHA-256); byte[] digest md.digest(salted.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); } }这里用用户名做盐虽然强度远不如真随机盐但至少避免了同密码同摘要的彩虹表问题。如果你想把项目再做扎实一点可以把盐字段单独存一列每次注册生成随机盐登录校验时拿出来重新计算。登录方法顺着同样的思路写SELECT id, password FROM user WHERE username?查出摘要后用同样的哈希函数比对如果一致则返回userId。3.4 登录成功后的会话状态传递Swing应用没有真正意义上的ServletSession但你可以把当前登录用户ID存在一个静态上下文里或者把userId传给主窗体。我的做法是在Login.java里成功后执行AddressBook window new AddressBook(uid); window.setVisible(true); dispose();dispose()关闭登录窗口而非System.exit(0)否则整个JVM退出了。AddressBook内部所有查询条件都带user_id ?确保A用户看不到B用户的联系人。这个设计虽然简单却是通讯录系统多用户数据隔离的第一道防线。3.5 密码框和字符数组的小细节还有一个不常被注意的细节登录密码框应该用JPasswordField而不是JTextField并且取密码时用getPassword()返回char[]而不是getText()返回String。String是不可变对象会在堆上待一段时间而char[]用完可以手动填0。在课程设计报告里这属于安全细节虽然Swing课设不会真被内存dump但答辩时提一句能让老师觉得你有工程意识。4. 通讯录增删改查与CSV导入导出联系人的核心操作无非四个查、增、改、删。在AddressBook.java里界面是一个JTable加一个DefaultTableModel表格数据来自数据库查询结果。课设版本通常不会引入DAO框架所以我把SQL全部收敛到统一方法里避免在按钮事件里散落字符串拼接。4.1 模糊查询参数拼接的边界搜索框一般按姓名或电话查SQL可以写为public ListContact queryContacts(int userId, String keyword) { ListContact list new ArrayList(); String sql SELECT * FROM contact WHERE user_id? AND (name LIKE ? OR phone LIKE ?); try (Connection conn MySql.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, userId); String pattern % keyword.trim() %; ps.setString(2, pattern); ps.setString(3, pattern); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Contact c new Contact(); c.setId(rs.getInt(id)); c.setName(rs.getString(name)); c.setPhone(rs.getString(phone)); list.add(c); } } } catch (SQLException e) { e.printStackTrace(); } return list; }LIKE关键字配合%是把查询条件从精确匹配改成子串匹配的关键。注意keyword.trim()要先执行否则输入空格会退化成查全表课设数据少看不出差别但在演示时容易被人为敲出一个很长的响应。如果搜索框支持回车触发查询记得在JTextField上注册ActionListener这样录入完直接按回车就能刷新表格比每次点查询按钮更顺手。4.2 批量导入CSV时的批处理与事务压缩包里的三个CSV文件如果直接导入一条条executeUpdate()也能跑但文件里有100条以上记录时频繁提交事务会让速度肉眼可见地下降。我一般会这样做String insertSql INSERT INTO contact(user_id, name, phone) VALUES(?, ?, ?); try (Connection conn MySql.getConnection(); PreparedStatement ps conn.prepareStatement(insertSql)) { conn.setAutoCommit(false); int count 0; for (String[] row : csvRows) { ps.setInt(1, currentUserId); ps.setString(2, row[0]); ps.setString(3, row[1]); ps.addBatch(); if (count % 500 0) { ps.executeBatch(); } } ps.executeBatch(); conn.commit(); } catch (SQLException e) { conn.rollback(); e.printStackTrace(); }这段代码里有三个设计值得写进注释addBatch把多条SQL攒在一起执行减少网络往返每500条调用一次executeBatch防止批量太大把驱动内存撑高先把AutoCommit关掉一旦中间出现重复主键可以整体回滚而不是留下一半数据。currentUserId来自登录后的会话保证导入的联系人归属到当前用户而非全局。4.3 CSV的编码和转义细节CSV看起来简单但实际导入时有两个高频报错点。第一是编码Windows版的Excel默认GBK而IDEA和MySQL默认UTF-8直接打开address.csv可能正常用InputStreamReader读出来就乱码。第二是字段里的逗号比如地址“北京市,朝阳区”如果直接按,分割列会错位进而导致插入SQL抛异常。课设样本里没有这种数据但你自己测试时最好处理一下。文件来源实际编码读取问题Windows Excel 另存为GBK/GB2312IDEA直接读出现乱码代码手写生成UTF-8Excel双击打开乱码一个可用的读取函数是判断文件头是否带BOM再按BOM选择编码String line; try (BufferedReader reader new BufferedReader(new InputStreamReader( new FileInputStream(csvFile), UTF-8))) { while ((line reader.readLine()) ! null) { if (line.startsWith(\uFEFF)) { line line.substring(1); } String[] cols line.split(,, -1); // cols.length 不足时补空串 } }split(,, -1)里的-1参数会把末尾的空字符串也保留避免“最后一列为空导致数组越界”。如果对CSV健壮性要求更高可以引入opencsv解析引号字段但在课设场景下会多一个jar依赖看你是想加分还是想省事。导出时也建议在文件开头写\uFEFF这样Excel双击打开UTF-8文件不会出现中文乱码这个技巧我是在实验报告截图时才发现有奇效。提示如果你在Windows控制台跑Java程序输出的中文乱码但文件内容正常多半是控制台代码页问题不是CSV代码的问题别在导入函数上浪费时间。5. 用压力测试把AddressBook的课设报告写厚课程设计报告写到“系统测试”章节时最怕只有“运行-点按钮-截图”三步。AddressBook.zip本身带数据文件正好可以用来做一次可复现的压力测试让你在答辩时能拿出数字而不是形容词。5.1 先造1000条联系人的CSV在项目根目录用shell快速生成一个大数据文件for i in $(seq 1 1000); do echo 测试用户$i,13$((RANDOM%10))0000$iexample.com,测试地址$i big.csv done然后写一个简单的方法把big.csv导入到数据库。注意导入前先清空当前用户的联系人否则第二次跑会堆积重复数据。导入1000条后在搜索框输入“测试用户9”观察从按下回车到表格刷新的时间这个耗时就能写进报告的响应时间测试表格。5.2 检查连接是否泄漏课设里的MySql.getConnection()如果只开不关跑几个小时后MySQL会报Too many connections。用JVisualVM挂到项目进程上观察线程数是否随着每次查询持续上涨。正确做法是每个查询方法都用try-with-resources关闭Connection同时把MySQL的max_connections改成默认151放大泄漏效果。如果发现连接数一直在涨优先检查代码里是否有conn没有关闭的查询分支尤其是异常路径上的catch块。5.3 把数据当作报告素材实验报告的性能部分不需要花哨一张表格用三组数据就够查询100条、500条、1000条的耗时以及对应内存占用。加上导入前后的对比截图老师看到的就不是“系统运行正常”而是“有量化指标的系统验证”。最后记得在Test.java里加上一个自动插入测试数据的main方法保证演示时不会手忙脚乱敲SQL。压测前先删掉本机MySQL的慢查询日志否则读到的耗时会被写日志干扰。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →