ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

JavaWeb金融借贷系统毕业设计:Servlet+JSP+MySQL实现等额本息还款

JavaWeb金融借贷系统毕业设计:Servlet+JSP+MySQL实现等额本息还款 简介一套基于JavaWeb实现的金融借贷系统P2P金融管理/小额贷款系统完整毕业设计资源面向计算机相关专业毕设学生及需要项目实战的Java学习者。资源包含可运行的项目源码、项目文档、数据库脚本及辅助软件工具系统采用Servlet、JDBC、FileUpload作为后台框架结合Bootstrap、jQuery、Ajax构建界面数据库使用MySQL覆盖融资产品查询与申请、每日新闻、后台贷款申请管理、产品类型管理、贷款周期管理、新闻管理、企业管理等模块功能完整、界面简洁适合用于毕设展示或项目练习。压缩包约14.67MB共15个文件主要包含源码压缩包p2p.zip、MySQL数据库脚本.sql、项目文档.pdf/.md、运行截图.png以及软件工具下载说明.txt从源码到部署说明一应俱全。目前已有2536人学习/下载资源经过严格调试确保可直接运行。附带文档和截图便于快速了解系统结构按目录整理清晰可节省配置与查阅时间。1. 金融借贷系统不是“借钱”那么简单这门毕设到底在做什么金融借贷系统是最经典的 JavaWeb 毕设题之一但很多人把它的难点想反了——以为页面多、表格漂亮就能拿高分真正卡住答辩的往往是那套“还钱”的数据逻辑。借一笔钱出去只需要一条 INSERT把钱按等额本息分 12 期收回来中间涉及审核状态流转、还款计划生成、逾期判定这些才是整套系统的核心。这篇笔记从技术选型、数据库设计、核心流程代码到避坑清单按我实际做这类项目的顺序讲清楚。适合正在做 JavaWeb 毕设、想用最短时间拿到一套能跑通全流程并讲明白源码的同学也适合想复习 Servlet JSP MySQL 全链路开发的从业者。2. 技术选型与项目骨架为什么 JavaWeb 仍是毕设最稳的答案2.1 技术栈分工Servlet 管流程、JSP 管页面、MySQL 管账目“JavaWeb”这个词在不同学校有不同界定。有的要求纯 Servlet JSP JDBC有的允许用 SSMSpring SpringMVC MyBatis少数直接默认 SpringBoot。我在做这类毕设时一般先问清楚题目出处标题写的是“基于 JavaWeb”没有带框架名那最稳妥的形态就是 Servlet 处理请求、JSP 渲染页面、MySQL 存账目数据JDBC 做持久化。这套组合的优点是每个环节都是答辩现场能说清原理的请求怎么进来、Servlet 怎么分发、数据库连接怎么管理。用 SpringBoot 虽然开发快但很多答辩老师会追问“那你讲讲 DispatcherServlet 和普通 Servlet 的区别”反而容易露馅。如果你有富余时间可以在核心用 Servlet 的前提下把连接池换成 Druid、把 DAO 层做个简单封装这些属于加分项不影响主架构。2.2 从零搭建项目骨架IDEA 建工程与包结构划分我习惯在 IDEA 里用普通 Java Enterprise 工程而不是 Maven 骨架原因是纯 Servlet 项目不需要拉一堆依赖手写 lib 目录放一个 mysql-connector-java 和一个 druid 就够。新建工程后选择 Web Application勾选 Create web.xml然后把包结构按职责切好这样后面写代码时不用回头重构src/main/java ├─ com.loan.servlet # Servlet 层接收请求、转发视图 ├─ com.loan.service # 业务层审核、还款计划生成等核心逻辑 ├─ com.loan.dao # DAO 层封装 JDBC 操作 ├─ com.loan.entity # 实体类对应数据库表 └─ com.loan.util # DBUtil、DateUtil、BigDecimalUtil 等工具 webapp ├─ admin/ # 管理端 JSP借款审核、放款管理 ├─ user/ # 用户端 JSP借款申请、还款列表 └─ WEB-INF/web.xml这个分层照着做就行Servlet 只做参数接收和页面跳转金额计算、状态判断必须放到 service 里别写在 Servlet 中。我用过一个血泪教训把等额本息算法直接写在审核 Servlet 里后来要支持两种还款方式时不得不重写整个方法。分层不是应付检查用的是给自己留后路。2.3 连接数据库JDBC 工具类与连接池参数调优JavaWeb 连 MySQL 的常规做法是写一个 DBUtil把驱动加载、连接获取、资源关闭统一收口。下面这个版本没有依赖框架直接复制到 util 包下改数据库名和密码就能用public class DBUtil { private static DruidDataSource dataSource; static { try { dataSource new DruidDataSource(); dataSource.setDriverClassName(com.mysql.cj.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/loan_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); dataSource.setMaxActive(20); dataSource.setMaxWait(60000); dataSource.setValidationQuery(SELECT 1); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void close(AutoCloseable... resources) { for (AutoCloseable r : resources) { if (r ! null) { try { r.close(); } catch (Exception ignored) {} } } } }连接池参数里initialSize设为 5 是启动时预热连接maxActive20 对应测试环境够用如果并发再大一些可以调到 50但要注意 MySQL 默认的max_connections是 151超了会报 Too many connections。maxWait单位是毫秒60000 表示 60 秒内拿不到连接就抛异常避免系统在数据库挂了时无限卡死。validationQuery会在取连接时做探活MySQL 用SELECT 1开销最小别写SELECT NOW()这种多余查询。注意 URL 里我用了serverTimezoneAsia/Shanghai这是新版驱动必须带的参数否则 8.0 驱动会直接报The server time zone value的运行时错误。characterEncodingutf8是为了让插入的中文不乱码这个我在第 5 章避坑清单里还会展开讲。3. 数据库设计是这套系统的“命根子”五张表把账算明白3.1 表结构拆解从用户到还款计划一条借款的生命周期金融借贷系统听名字像是贷款产品做的事落到数据库层面其实是一条借款申请从提交到结清的生命周期。我见过不少同学上来就设计十几张表权限表、日志表、配置表全堆上最后写代码时自己都连不清外键关系。毕设题目没必要这么做把下面 5 张核心表设计清楚业务逻辑就撑得住用户表存借款人和管理员用角色字段区分借款表存每一笔申请的金额、期限、利率、状态还款计划表在审核通过时按期数批量生成每期一条记录记录本金、利息、到期日和状态还款记录表用户每还一笔就写一条流水。外加一张简单的管理员操作表可选不做也不影响流程。关键是把“借款”和“还款计划”分开——它们是 1 对 N 的关系很多人混在一张表里导致后续做部分提前还款时完全没法处理。状态字段建议用字符串存代码而不是数字比如WAIT_AUDIT、AUDIT_PASS、REPAYING、FINISH这样写代码和调试时一眼能看懂SQL 排查也方便。数字枚举看起来省空间但对毕设项目来说可读性远比那一个字节重要。3.2 建表 SQL 落地金额字段为什么必须用 DECIMAL下面是核心表的建表脚本直接在 Navicat 或命令行里执行即可CREATE TABLE user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, salt VARCHAR(16) NOT NULL, role VARCHAR(10) DEFAULT USER, credit_limit DECIMAL(12,2) DEFAULT 10000.00, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE loan ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, amount DECIMAL(12,2) NOT NULL, annual_rate DECIMAL(5,2) NOT NULL, term_months INT NOT NULL, purpose VARCHAR(255) DEFAULT , status VARCHAR(20) DEFAULT WAIT_AUDIT, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP, audit_time DATETIME DEFAULT NULL, audit_user_id BIGINT DEFAULT NULL, reject_reason VARCHAR(255) DEFAULT NULL, KEY idx_user_id (user_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE repay_plan ( id BIGINT AUTO_INCREMENT PRIMARY KEY, loan_id BIGINT NOT NULL, period_num INT NOT NULL, due_date DATE NOT NULL, principal DECIMAL(12,2) NOT NULL, interest DECIMAL(12,2) NOT NULL, total DECIMAL(12,2) NOT NULL, status VARCHAR(20) DEFAULT UNPAID, pay_time DATETIME DEFAULT NULL, KEY idx_loan_id (loan_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE repay_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, loan_id BIGINT NOT NULL, plan_id BIGINT NOT NULL, pay_amount DECIMAL(12,2) NOT NULL, pay_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;所有金额字段都用DECIMAL(12,2)这是金融项目里必须养成的习惯。DECIMAL(12,2)表示整数部分最多 10 位、小数 2 位最大支持到 99 亿的金额对毕设和大多数业务场景都够。如果用 double 或者 float算等额本息时会出现 0.1 0.2 不等于 0.3 的精度问题这在第 5 章会专门讲。利率字段我用annual_rate存年利率比如年化 12% 存12.00计算月利率时再除以 12。不要直接存月利率因为还款计划生成、逾期利息计算都依赖年利率这个原始值存派生数据会让自己后面绕坑。索引上给 loan 表和 repay_plan 表都建了状态索引因为管理端查询“待审核列表”“未还款列表”是最高频的 SQL。3.3 状态字段设计让审核和还款可追溯借款表的status字段完整取值建议为WAIT_AUDIT待审核、AUDIT_PASS审核通过、AUDIT_REJECT审核拒绝、REPAYING还款中、FINISH已结清、OVERDUE已逾期。还款计划表的状态则简化成UNPAID未还、PAID已还、OVERDUE逾期。两个表的状态需要联动所有计划都还完借款表状态从REPAYING改成FINISH某一期计划超期未还借款表状态改为OVERDUE。这种设计能让业务逻辑非常直白管理端审核列表查status WAIT_AUDIT用户端还款列表查plan.status UNPAID不需要任何复杂的 join 条件。设计状态字段时唯一要注意的是别用1、2、3这样的数字代码因为当你写loan.getStatus() 3时三个月后自己都想不起来 3 代表什么。字符串状态虽然存储多几个字节换来的是代码可读性和排错效率值了。4. 核心流程代码实现借款、审核、还款计划生成4.1 注册与登录Session 管理和密码处理注册登录是每套系统的入口但借贷系统的密码处理不能省。明文存密码在答辩现场被老师打开数据库看一眼就崩了所以必须加盐哈希。下面的代码用在注册时生成密码和盐值public class PasswordUtil { public static String generateSalt() { return UUID.randomUUID().toString().replace(-, ).substring(0, 8); } public static String encrypt(String password, String salt) { String input salt password; for (int i 0; i 10; i) { input DigestUtils.md5Hex(input salt); } return input; } }逻辑说明先随机生成 8 位盐值然后把盐值和密码拼接做 10 轮 MD5。每轮迭代都把上一轮的输出再次拼盐这样即使两个用户密码相同生成的密文也不同。DigestUtils.md5Hex来自 commons-codec如果没有这个依赖可以用MessageDigest手动实现逻辑是一样的。登录时流程是按用户名查出 salt → 用输入的密码和库里的 salt 调用 encrypt → 比对结果。Session 里只存userId和role不要存密码页面展示用户信息时单独查库。4.2 借款申请提交金额、期限、利率的前置校验借款申请这一步看着只是插入一条 loan 记录实际要做的校验远比想象多。典型的校验链是用户是否存在、借款金额是否大于 0、是否超过该用户的授信额度、期限是否在允许范围内。校验失败时返回错误信息到申请页面成功后才插入草稿状态。下面是 Service 层的一段代码public Result applyLoan(Long userId, BigDecimal amount, Integer termMonths) { User user userDao.findById(userId); if (user null) return Result.error(用户不存在); // 校验金额正数 if (amount null || amount.compareTo(BigDecimal.ZERO) 0) { return Result.error(借款金额必须大于0); } // 校验授信额度 BigDecimal remainingLimit user.getCreditLimit() .subtract(loanDao.sumActiveAmountByUserId(userId)); if (amount.compareTo(remainingLimit) 0) { return Result.error(超出授信额度当前剩余可借 remainingLimit); } Loan loan new Loan(); loan.setUserId(userId); loan.setAmount(amount); loan.setAnnualRate(new BigDecimal(12.00)); // 由系统配置 loan.setTermMonths(termMonths); loan.setStatus(WAIT_AUDIT); loanDao.insert(loan); return Result.ok(申请成功请等待审核); }关键点有两个。第一金额比较用的是compareTo而不是因为 BigDecimal 的equals会比较精度new BigDecimal(10.0)和new BigDecimal(10.00)用equals不等而compareTo只看数值这是金融计算里必须记住的细节。第二sumActiveAmountByUserId统计的是该用户当前处于待审核和还款中状态的借款总额防止一个人提交多笔申请把额度套完如果忽略这点额度校验就形同虚设了。4.3 还款计划生成等额本息的算法与实现等额本息是毕设中最常被要求实现的还款方式答辩老师必问所以这段代码要能背也能写。公式是每期还款额 本金 × 月利率 × (1 月利率)^期数 / ((1 月利率)^期数 - 1)每期利息 剩余本金 × 月利率每期本金 每期还款额 - 当期利息。public ListRepayPlan generatePlan(Loan loan) { BigDecimal amount loan.getAmount(); int months loan.getTermMonths(); BigDecimal monthlyRate loan.getAnnualRate() .divide(new BigDecimal(1200), 8, RoundingMode.HALF_UP); // 计算每期还款额用 double 算幂再转 BigDecimal BigDecimal factor BigDecimal.valueOf( Math.pow(1 monthlyRate.doubleValue(), months)); BigDecimal monthPay amount.multiply(monthlyRate).multiply(factor) .divide(factor.subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP); BigDecimal remaining amount; ListRepayPlan list new ArrayList(); LocalDate dueDate LocalDate.now().plusMonths(1); for (int i 1; i months; i) { BigDecimal interest remaining.multiply(monthlyRate) .setScale(2, RoundingMode.HALF_UP); BigDecimal principal monthPay.subtract(interest); if (i months) { // 最后一期做平差避免累计误差 principal remaining; monthPay principal.add(interest); } RepayPlan plan new RepayPlan(); plan.setPeriodNum(i); plan.setDueDate(dueDate); plan.setPrincipal(principal); plan.setInterest(interest); plan.setTotal(monthPay); list.add(plan); remaining remaining.subtract(principal); dueDate dueDate.plusMonths(1); } return list; }这段代码里有两个必须讲清楚的细节。第一monthlyRate的除法用divide时指定了 8 位小数和HALF_UP舍入因为 BigDecimal 除法不指定精度会直接抛ArithmeticException这是初学者最常见的翻车点。第二最后一期做了“平差”处理由于每期利息按剩余本金重新计算最后一期的本金直接取剩余金额。如果不做这一步前面每期舍入误差累计起来最后一期会多出几分钱别人对账时会发现计划和实际还款差一分非常尴尬。日期计算用的是java.time.LocalDate它的plusMonths能正确处理跨年和大小月。比如还款日是每月 15 号1 月 15 日申请的借款第一期 2 月 15 日、第二期 3 月 15 日依次推下去不需要手工处理闰年。4.4 管理端审核事务保证数据一致性审核是整个系统里最容易出数据一致性问题的环节因为它要做两件事把 loan 状态从待审核改成已通过同时批量生成还款计划。这两步必须在一个事务里完成否则会出现贷款已经是“通过”状态但还款计划表是空的用户压根不知道怎么还钱。public void auditLoan(Long loanId, Long adminId, boolean pass) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); Loan loan loanDao.findById(conn, loanId); if (loan null) throw new RuntimeException(借款记录不存在); if (!WAIT_AUDIT.equals(loan.getStatus())) { throw new RuntimeException(该借款已处理请勿重复审核); } if (pass) { loanDao.updateStatus(conn, loanId, REPAYING, adminId); ListRepayPlan plans repayPlanService.generatePlan(loan); repayPlanDao.batchInsert(conn, plans); } else { loanDao.updateStatus(conn, loanId, AUDIT_REJECT, adminId); } conn.commit(); } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } throw new RuntimeException(审核失败 e.getMessage(), e); } finally { DBUtil.close(conn); } }注意这里 DAO 层的每个方法都传了Connection参数这是让多个 SQL 共享同一个事务的关键。很多初学者会写conn.setAutoCommit(false)之后又去调用 DAO但 DAO 内部自己getConnection()拿到了另一条连接导致事务控制完全失效。代码里还做了一次状态校验防止管理端在页面里双击“通过”按钮时被并发请求重复处理——虽然 Servlet 单线程处理每个请求但在真实项目里这是很常见的隐患。审核拒绝时不生成计划只改状态简单直接。5. 毕设级避坑清单运行、调试与演示中的五个血泪教训5.1 金额精度翻车double 算账差一分钱的正确解法现象还款计划每期金额单独看都对手动加一遍总额比借款本金多出 0.01 元或者用 double 算出19.999999这种奇葩数字。原因计算机里的 double 是二进制浮点数0.1 在二进制里是无限循环小数参与运算必然产生误差。金融计算不能用 double这是硬性规则。解决所有金额字段用BigDecimal数据库用DECIMAL(12,2)除法必须显式指定小数位和舍入模式。我一般统一用RoundingMode.HALF_UP也就是四舍五入符合还款场景的直觉。注意从 double 转 BigDecimal 时用BigDecimal.valueOf(19.99)而不是new BigDecimal(19.99)后者的构造方式会把 double 的二进制误差也带进来。5.2 事务没提交审核通过但还款计划没生成现象管理端看到借款状态已是“还款中”但用户端还款列表为空直接在数据库里查 repay_plan 表一条记录都没有。原因最常见的是 DAO 方法内部自己通过DBUtil.getConnection()获取了新的连接业务层的conn.setAutoCommit(false)作用在另外一条连接上commit 时链路上没有任何 SQL 参与事务。另一种情况是生成还款计划的方法抛了异常但 catch 块里没有 rollback异常之后连接被返回连接池状态已改的部分被连接池误提交。解决统一让 Service 层创建事务连接并作为参数传入 DAO 方法。每条连接在 finally 里关闭并归还连接池。异常分支一定要rollback()哪怕你觉得“SHA这个异常不会发生”也要写事务代码没有后悔药。5.3 日期计算踩坑跨月还款日与闰年现象借款申请日是 1 月 31 日第一期还款日成了 2 月 29 日或 3 月 3 日而不是 2 月 28 日用Calendar.add(Calendar.MONTH, 1)时还遇到过年份不跳、直接出现 13 月的情况。原因老版Calendar对月末日期的处理逻辑是“如果目标月份没有这一天则顺延到下个月的对应日”所以 1 月 31 日加一个月会变成 2 月 28 日或 3 月 3 日不同 JDK 版本行为还不一致。解决直接用java.time.LocalDateplusMonths(1)的规则虽然是“映射到目标月最后一天”但配合每月固定还款日建议申请日天然月份可以避免歧义。最省心做法是还款日统一取“下一个月的同一天”如果申请日在月末则明确显示为“当月最后一天”。毕设里一定要把日期工具类抽出来别散落在业务代码里。5.4 IDEA 运行 JavaWeb 项目配置Tomcat 版本不匹配导致项目起不来现象启动 Tomcat 时报UnsupportedClassVersionError或者项目部署后所有请求都 404控制台也没有明显报错有时是 JSP 页面打开乱码或报 500。原因IDEA 的 Web 项目跑不起来八成问题不在代码而在运行环境。常见三种情况Tomcat 版本和 JDK 版本不匹配比如 Tomcat 10 默认要求 JDK 11但学校机器装的是 JDK8项目的 Artifacts 没有配置 lib 依赖mysql 驱动和 druid jar 没被打进 WEB-INF/lib或者部署时选了 war 包模式而不是 war exploded导致改动 JSP 还要重新打包。解决毕设别追新版本Tomcat 8.5 JDK8 是最稳的组合。IDEA 里打开 Project Structure → Artifacts确认 Output Layout 里有WEB-INF/lib且包含项目的所有 jar 包Run Configuration 里 Deployment 选择war exploded这样改 JSP 刷新即生效。启动后先访问最简单的 index.jsp通了再试登录缩小排查范围。5.5 中文乱码编码问题在三个环节逐个排查现象JSP 页面中文显示正常但插入数据库后变成???或者表单提交的中文到 Servlet 里读出来是乱码。原因编码问题会在三个环节分别断掉——页面渲染、HTTP 传输、数据库存储。页面用的是 GBKTomcat 解析 POST 请求用的是 ISO-8859-1数据库表是 utf8任何一环不一致都会出乱码。解决第一个环节JSP 文件头部统一用% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %第二个环节在 web.xml 里配置编码过滤器让所有请求都经过 UTF-8 解码第三个环节建表统一utf8mb4连接 URL 加characterEncodingutf8。三个环节都统一了之后乱码基本绝迹。下面是最常用的过滤器配置filter filter-nameencodingFilter/filter-name filter-classcom.loan.util.EncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping过滤器类里只需要在doFilter中先设置request.setCharacterEncoding(encoding)再调用chain.doFilter(request, response)。注意 GET 请求的编码由 Tomcat 的URIEncoding控制可以在 server.xml 的 Connector 上加上URIEncodingUTF-8否则 URL 上的中文参数仍是乱码。6. 从能跑到能答辩给系统加分的三个进阶功能6.1 还款记录与逾期标记一个只支持“到期还款”的系统做出来很容易但答辩时没有亮点。我建议加一个逾期判定逻辑用定时任务或启动时扫描的方式把所有due_date CURDATE()且status UNPAID的还款计划标记为OVERDUE同步更新借款表状态。这个功能用一条 SQL 就能演示效果但能体现你对业务状态机的理解UPDATE repay_plan SET status OVERDUE WHERE status UNPAID AND due_date CURDATE();演示时可以先把系统时间改到还款日后一天或直接在测试库里把某条计划的 due_date 改成昨天然后执行这条 SQL再刷新页面给老师看状态变化。再加一个逾期费用字段还款时自动累加整个系统的完整度立刻不一样。6.2 数据可视化用 ECharts 把账目画出来管理端页面如果只有表格视觉上太干巴。常规做法是写一个统计 Servlet查询每月的放款总额和还款总额返回 JSON前端用 ECharts 画折线图。后端只需要一个最简单的查询SELECT DATE_FORMAT(apply_time, %Y-%m) AS month, SUM(amount) AS total FROM loan WHERE status IN (REPAYING, FINISH) GROUP BY DATE_FORMAT(apply_time, %Y-%m) ORDER BY month;前端在 admin/dashboard.jsp 里引入 ECharts 的 CDN初始化折线图把后端返回的 month 和 total 填进 xAxis 和 series。这个功能代码量不大但视觉冲击力很强答辩演示时放在最后展示老师会觉得你考虑了“管理视角”。6.3 答辩演示脚本三分钟讲清系统亮点我复盘过很多次毕设答辩发现真正加分的是讲解顺序。别从登录页逐页点起最好按下面这条链路走先讲数据库五张表的关联关系让老师知道你设计了状态机再注册一个新用户提交一笔 12000 元分 12 期、年化 12% 的借款切到管理端审核通过立刻打开还款计划列表指着数字验证第一期利息是 120 元最后演示还款、逾期标记和图表。每个环节都提前准备好测试数据千万别现场随便输金额一旦金额没设计好算出来的还款计划数字不整讲起来就乱了。这套流程走下来老师基本不会刁难细节。做这种带源码的毕设项目最忌讳的是拿到工程就跑跑通了就交。我做这类题时养成一个习惯拿到任何一套源码先自己删掉核心模块的几行代码逼着自己补回去顺便把每个方法的入参和返回理一遍。这个过程能让你从“能跑”到“能讲”答辩时被问到“这里为什么这样写”才能接得住。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进