
简介这是一套基于JavaWeb实现的金融借贷系统毕业设计资源面向计算机相关专业的毕设学生及需要项目实战练习的Java人群涵盖P2P金融管理、小额贷款等核心业务场景。资源包内含15个文件包括项目源码zip压缩包、数据库脚本sql、项目文档pdf/md以及多张运行截图png和软件工具说明txt整体大小约14.67MB目录结构清晰便于直接导入开发工具进行部署与二次开发。目前已有2535人学习下载。系统采用Servlet、JDBC、BootStrap、jQuery、Ajax及MySQL等技术实现前台支持融资产品查询、产品详情、申请贷款及每日新闻浏览后台具备贷款申请审核、融资产品管理、产品类型管理、贷款周期管理、新闻管理、企业管理等完整功能并附带详细项目文档与调试通过的源码可帮助读者快速理解JavaWeb项目从设计到实现的全流程提升实际开发与毕业设计答辩能力。1. 从一张数据表开始的金融借贷系统每年毕业季都有大量 JavaWeb 方向的毕设选题金融借贷系统是其中出现频率极高的一类但多数同学把它做成了「用户的增删改查」——能注册、能登录、能提交借款申请后台审核一下就交差了。真正的借贷系统难点不在页面多不多而在三件事利率怎么算、逾期怎么罚、额度怎么控。这三件事落在数据库里就是几张表的关系设计和一组存储过程/事务边界的问题。本文以「基于 JavaWeb 实现的金融借贷系统」为线索把这套系统从技术选型、数据库设计、核心业务实现到安全防护和部署调试的完整路径讲清楚。你可以直接把它当作毕设的落地方案也可以拿来当作理解企业级借贷业务的入门样本。文中所有代码和 SQL 都可以独立复现不依赖任何虚构的框架版本——你本地装好 JDK 8、Tomcat 8.5、MySQL 5.7就能把整个项目跑起来。2. 技术选型与三层架构JavaWeb 借贷系统的骨架怎么搭2.1 为什么是 JSP Servlet MyBatis而不是 Spring Boot金融借贷系统作为毕设最常见的组合是 JSP Servlet MyBatis MySQL偶尔有人用 SSHStruts2 Spring Hibernate但 Struts2 已经明显过时。Spring Boot 虽然开发效率更高但很多学校毕设的答辩要求里明确写了「基于 JavaWeb」或者导师规定必须体现 JSP/Servlet 的核心知识所以这套经典组合依然是主流。从学习的角度讲Servlet 能让你看清 HTTP 请求从doGet/doPost到业务层再到数据库的完整链路而 MyBatis 比 Hibernate 更容易手写 SQL借贷业务里大量复杂的联表查询、金额计算用原生 SQL 表达比 Hibernate 的 HQL 直观得多。系统的分层结构如下src/main/java ├── com.example.loan.entity // 实体类User, LoanOrder, RepaymentPlan ├── com.example.loan.dao // MyBatis Mapper 接口 ├── com.example.loan.service // 业务接口 实现 ├── com.example.loan.controller // Servlet 控制器 ├── com.example.loan.util // DB连接池、日期计算、金额格式化工具 └── com.example.loan.filter // 编码过滤器、登录过滤器控制层用 Servlet接收前端 JSP 页面提交的参数调用 Service 层方法返回结果后转发或重定向到视图。这个分层的好处是答辩时你可以清晰地讲出每一层的职责也方便单独为业务逻辑写单元测试。2.2 数据库设计的核心用户、借款订单、还款计划三张主表一个借贷系统无论业务多简单至少需要五张核心表user用户、loan_order借款订单、repayment_plan还款计划、bank_card银行卡、operation_log操作日志。下面的建表 SQL 是精简版省略了索引和外键的部分注释实际使用时可在此基础上扩展。CREATE TABLE user ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(255) NOT NULL COMMENT SHA-256加盐后的密码, real_name VARCHAR(30) DEFAULT NULL COMMENT 真实姓名, id_card VARCHAR(18) DEFAULT NULL COMMENT 身份证号, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, credit_limit DECIMAL(12,2) DEFAULT 0 COMMENT 可用授信额度, user_type TINYINT DEFAULT 1 COMMENT 1-普通用户 2-管理员, status TINYINT DEFAULT 1 COMMENT 1-正常 0-冻结, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; CREATE TABLE loan_order ( id BIGINT NOT NULL AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 订单号业务编号, user_id BIGINT NOT NULL COMMENT 借款人ID, amount DECIMAL(12,2) NOT NULL COMMENT 借款金额, term TINYINT NOT NULL COMMENT 期数3/6/9/12, interest_rate DECIMAL(5,4) NOT NULL COMMENT 月利率, repayment_method TINYINT DEFAULT 1 COMMENT 1-等额本息 2-先息后本, status TINYINT DEFAULT 0 COMMENT 0-待审核 1-已放款 2-还款中 3-已结清 4-已拒绝 5-逾期, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP, approve_time DATETIME DEFAULT NULL, approve_user_id BIGINT DEFAULT NULL, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT借款订单表;2.2.1 还款计划表的特殊设计repayment_plan是整套系统的核心它在放款那一刻就生成整份还款计划每一期包括应还本金、应还利息、应还总额、到期日和实际还款日期。CREATE TABLE repayment_plan ( id BIGINT NOT NULL AUTO_INCREMENT, loan_id BIGINT NOT NULL COMMENT 借款订单ID, term_no TINYINT NOT NULL COMMENT 第几期, principal DECIMAL(12,2) NOT NULL COMMENT 本期应还本金, interest DECIMAL(12,2) NOT NULL COMMENT 本期应还利息, total_amount DECIMAL(12,2) NOT NULL COMMENT 本期应还总额, due_date DATE NOT NULL COMMENT 到期日, actual_pay_date DATE DEFAULT NULL COMMENT 实际还款日期, status TINYINT DEFAULT 0 COMMENT 0-待还 1-已还 2-逾期, PRIMARY KEY (id), KEY idx_loan_id (loan_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT还款计划表;DECIMAL(12,2)是金额字段的唯一正确选择任何时候都不要用double或float存钱二进制浮点数在利率计算中会产生精度丢失。表结构设计完成后下一步是把它们映射成 MyBatis 的 Mapper 接口和 XML 文件这一步直接决定后面业务代码好不好写。2.3 MyBatis 配置与 Mapper写清楚 SQL 映射关系MyBatis 的核心配置在mybatis-config.xml中包含数据源、事务管理和 Mapper 注册。Servlet 项目里通常用 Druid 连接池管理数据库连接配置如下configuration environments defaultdevelopment environment iddevelopment transactionManager typeJDBC/ dataSource typecom.alibaba.druid.pool.DruidDataSource property namedriverClassName valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/loan_db?useSSLfalseamp;serverTimezoneAsia/Shanghai/ property nameusername valueroot/ property namepassword value123456/ property nameinitialSize value5/ property namemaxActive value20/ /dataSource /environment /environments mappers mapper resourcemappers/LoanOrderMapper.xml/ mapper resourcemappers/RepaymentPlanMapper.xml/ mapper resourcemappers/UserMapper.xml/ /mappers /configurationtransactionManager typeJDBC表示事务由每个操作自己控制DruidDataSource负责连接复用。Mapper 接口与 XML 通过 namespace 绑定例如LoanOrderMapper.xml里新增借款订单的语句如下insert idinsertOrder parameterTypecom.example.loan.entity.LoanOrder useGeneratedKeystrue keyPropertyid INSERT INTO loan_order (order_no, user_id, amount, term, interest_rate, repayment_method, status, apply_time) VALUES (#{orderNo}, #{userId}, #{amount}, #{term}, #{interestRate}, #{repaymentMethod}, 0, NOW()) /insertuseGeneratedKeystrue让 MySQL 自动生成的自增主键回填到实体对象的id属性上这样后面生成还款计划时不需要再查一遍订单 ID。#{}占位符是 PreparedStatement 的参数占位能有效防止 SQL 注入——在借贷系统中用户输入的任何金额、期数参数都必须走#{}不能拼接进 SQL。3. 借贷核心业务实现从申请到放款再到还款状态机3.1 放款时的利息计算等额本息和先息后本的 SQL 与精度处理放款操作是借贷系统最关键的步骤它要做三件事更新订单状态、扣除用户授信额度、生成完整的还款计划表。这三件事必须在一个数据库事务里完成否则用户钱放款了但额度没扣或者订单状态是放款成功但还款计划没生成都会造成严重的数据不一致。利息算法取决于还款方式。等额本息的月供公式是月供 本金 × 月利率 × (1 月利率)^期数 / ((1 月利率)^期数 - 1)每一步计算都要用BigDecimal不能用double。Java 侧的计算代码如下public static BigDecimal calculateMonthlyPayment(BigDecimal principal, BigDecimal monthlyRate, int term) { // 每月还款额 P * r * (1r)^n / ((1r)^n - 1) BigDecimal onePlusRate BigDecimal.ONE.add(monthlyRate); BigDecimal power onePlusRate.pow(term); // (1r)^n BigDecimal numerator principal.multiply(monthlyRate).multiply(power); BigDecimal denominator power.subtract(BigDecimal.ONE); return numerator.divide(denominator, 2, RoundingMode.HALF_UP); }RoundingMode.HALF_UP表示四舍五入divide的第二个参数 2 表示保留两位小数。算完月供后每期的本金和利息要逐期分摊每期利息 剩余本金 × 月利率每期本金 月供 - 当期利息。最后一期要把剩余本金全部清掉避免尾差。生成还款计划的 Service 方法核心逻辑如下public void approveLoan(Long orderId, Long approverId) { LoanOrder order loanOrderMapper.selectById(orderId); if (order null || order.getStatus() ! 0) { throw new BusinessException(订单不存在或已被处理); } // 校验用户额度 User user userMapper.selectById(order.getUserId()); if (user.getCreditLimit().compareTo(order.getAmount()) 0) { throw new BusinessException(用户授信额度不足); } try { // 开启事务Spring或手动管理 // 1. 更新订单状态为已放款 loanOrderMapper.updateStatus(orderId, 1, new Date(), approverId); // 2. 扣减用户额度 userMapper.deductCreditLimit(user.getId(), order.getAmount()); // 3. 生成还款计划 ListRepaymentPlan plans generateRepaymentPlans(order); repaymentPlanMapper.batchInsert(plans); // 提交事务 } catch (Exception e) { // 回滚事务 throw new BusinessException(放款失败 e.getMessage()); } }3.1.1 状态机设计每个状态流转要有迹可循订单状态从0-待审核到1-已放款再到2-还款中最后到3-已结清中间可以跳到4-已拒绝逾期时进入5-逾期。状态转移必须通过代码强制约束不能允许从4-已拒绝直接变成3-已结清否则审核逻辑会变成摆设。每个状态变更同时在operation_log表里记录操作人、操作时间和备注方便答辩时展示系统的可追溯性。3.2 还款模块的两种口子主动还款与批量逾期扫描还款功能通常有两类入口用户点击「立即还款」主动还当期以及系统定时任务每天扫描已过到期日但状态仍为待还的订单将其标记为逾期。主动还款时需要校验还款金额与repayment_plan里的total_amount完全一致允许小于等于部分还款但会产生备注。代码实现要点是加乐观锁UPDATE repayment_plan SET status 1, actual_pay_date #{payDate} WHERE id #{planId} AND status 0SQL 中附带status 0条件保证当两个人同时发起还款时只有一个人能成功更新另一个更新影响行数为 0代码据此抛出「重复还款」异常。这是最朴素的乐观锁也是答辩中最容易讲清楚的一个亮点。3.3 逾期罚息用 SQL 定时任务批量更新订单状态逾期计算是金融借贷系统的加分项。每日凌晨 02:00执行一次定时任务扫描所有处于还款期内的订单对due_date CURDATE() AND status 0的还款计划执行如下 SQLUPDATE repayment_plan SET status 2 WHERE loan_id #{loanId} AND status 0 AND due_date CURDATE();同一笔订单下所有未还计划批量标为逾期后再把订单整体状态同步成5-逾期。逾期罚息通常定义为剩余本金的万分之五每天这部分金额计入下一期应还总额BigDecimal penalty owedPrincipal.multiply(new BigDecimal(0.0005)) .multiply(BigDecimal.valueOf(overdueDays)); newTotalAmount plan.getTotalAmount().add(penalty); repaymentPlanMapper.updateTotalAmount(plan.getId(), newTotalAmount);罚息计算只影响未还期数不改变已还期数的实际还款金额这是金融业务的底线规则。做完业务流程下一步要考虑的是这套 JavaWeb 借贷系统在权限和数据安全上容易被忽视的几个点。4. 登录认证、MD5 加盐与 SQL 注入防御的落地写法4.1 登录过滤器的白名单设计JavaWeb 的登录拦截用Filter实现不用 Spring Security因为毕设阶段不需要那么重的框架。LoginFilter拦截除登录页、注册页、静态资源以外的所有路径检查 Session 中是否有user对象public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); if (uri.endsWith(/login.jsp) || uri.endsWith(/register.jsp) || uri.endsWith(/user/login) || uri.endsWith(/user/register) || uri.contains(/static/)) { chain.doFilter(request, response); return; } Object user req.getSession().getAttribute(loginUser); if (user null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); }白名单之外的所有请求强制要求登录避免用户直接通过 URL 跳进后台页面。第二步是区分普通用户和管理员的权限管理员接口用AdminFilter校验loginUser.userType 2用户仅能操作自己的订单所有查询 SQL 都必须附带user_id #{currentUserId}条件防止水平越权。4.2 密码存储不要用明文也不要用简单 MD5用户表里的password字段如果直接存 MD5 值Rainbow Table 一查就能还原弱口令。正确做法是加盐哈希即SHA-256(salt password)其中 salt 是 16 位随机字符串每个用户独立。注册时的写入方式String salt UUID.randomUUID().toString().replace(-, ).substring(0, 16); String hashed DigestUtils.sha256Hex(salt rawPassword); user.setSalt(salt); user.setPassword(hashed);登录时按用户名查出salt和password用相同算法算一遍再比较。使用 Apache Commons Codec 的DigestUtils是常见做法实际项目中也可以用 JDK 自带的MessageDigest只是代码量略大。注意SHA-256 加盐只是毕设够用的方案生产级系统应使用 BCrypt 或 PBKDF2答辩时能说出这一层区别本身就是加分项。4.3 SQL 注入防线的最后一个兜底MyBatis 的#{}已经能挡住 99% 的注入攻击但如果你在 ORDER BY 或 LIKE 查询里用了${}注入窗口依然存在。比如用户输入的排序字段直接拼进${sortField}就可能变成ORDER BY id; DROP TABLE user;--。借贷系统里凡是涉及用户输入的参数一律用#{}排序字段做白名单校验String[] allowedSort {amount, create_time, status}; String sortField Arrays.asList(allowedSort).contains(req.getParameter(sort)) ? req.getParameter(sort) : create_time;LIKE查询也要注意百分号转义用户搜索订单号时输入%会匹配全部记录既影响性能也泄露数据用StringEscapeUtils.escapeSql做预处理比较稳妥。到这里系统已经具备基本安全能力最后看项目源码跑起来的完整路径。5. 拿到源码后从导入到调试的完整踩坑清单5.1 项目目录结构与导入步骤规范的毕设源码一般会有这样的目录结构loan-system/ ├── sql/loan_db.sql // 数据库初始化脚本 ├── src/main/java // Java 源码 ├── src/main/resources // mybatis-config.xml, mapper XML ├── src/main/webapp/WEB-INF/ // web.xml, jsp 页面 ├── pom.xml // Maven 依赖如果用 Maven └── README.md // 部署说明导入时用 IntelliJ IDEA 打开pom.xml让 Maven 自动下载依赖如果没有 pom.xml就用 Eclipse 的 Dynamic Web Project 方式导入手动把lib目录下的 jar 包加入 Build Path。然后修改mybatis-config.xml里的数据库账号密码再在 MySQL 中执行mysql -u root -p sql/loan_db.sql最后在 Tomcat 的 Deployment 里添加该项目 context path 为/loan启动 Tomcat 访问http://localhost:8080/loan。如果页面 404先看 CATALINA 日志绝大多数是 jar 包冲突或 Maven 依赖下载不完整导致 Servlet 类加载失败。5.2 复现时需要验证的 6 个功能点功能点操作步骤预期结果失败排查方向注册/登录注册新账号→登录登录成功进入首页密码字段长度是否够SHA-256 结果 64 字符提交借款申请输入金额、期数、还款方式生成待审核订单loan_order表插入是否成功额度是否充足管理员审核放款用 admin 登录→审核通过订单状态变已放款还款计划生成事务是否回滚repayment_plan是否有数据主动还款选择一期还款计划点还款状态变已还金额正确乐观锁是否生效金额精度是否一致逾期扫描把某期 due_date 改成昨天→跑定时任务状态变逾期罚息计入定时任务是否注册SQL 日期条件是否匹配额度扣减/恢复放款后可看额度变化放款扣额还清后恢复额度变更是否在事务内5.3 毕设答辩的隐藏加分点从「跑通」到「讲清楚」版本兼容性是最常见的坑JDK 8 对应 Tomcat 8.5/9.0JDK 11 对应 Tomcat 9JDK 17 直接用 Tomcat 10 会有 javax 到 jakarta 的包名变更Servlet 代码需要全量替换依赖。如果源码是javax.servlet包就老实配 JDK 8 和 Tomcat 8.5不要追求新版。另一个容易被问到的细节是金额格式化页面展示时用DecimalFormat(#,##0.00)保证千分位导出 Excel 或生成 PDF 对账单时注意BigDecimal的setScale(2, RoundingMode.HALF_UP)避免页面显示 1000.0 而数据库里是 1000.00 这类不一致。答辩演示时把「数据库事务回滚」「乐观锁防重复还款」「额度扣减与恢复」这三个点演示一遍能够覆盖大多数评委关于业务完整性的追问。本文还有配套的精品资源点击获取