
简介本资源是一份完整的图书管理系统毕业论文文档面向计算机类或信息管理专业本科毕业生用于毕业设计答辩与课程实践参考。论文围绕图书馆核心业务展开系统实现了用户权限管理、管理员增删改、密码维护、图书/读者/期刊/数据库的全生命周期操作以及数据查询统计等8大功能模块并从安全性、可扩展性、可靠性与易用性四方面阐述了系统设计要求涵盖需求分析、架构设计、数据库建模、界面设计及测试方案等关键环节。资源为单个Word文档.doc格式文件总数1个大小7.14MB内容结构规范包含封面、成绩评定表、任务书、摘要、正文、目录、附录及参考文献等标准毕业论文组成部分。目前已有102人学习下载适合需要参考毕业设计选题、系统功能设计逻辑、测试报告撰写规范及多层架构JavaMySQL实现思路的学生使用。1. 图书管理系统毕业论文不是写文档而是用代码把借还书流程跑通的实战记录“图书管理系统毕业论文.doc”——这个标题在高校计算机类毕设选题池里出现频率极高但背后常藏着一个现实矛盾学生交上去的是 Word 文档答辩时却要现场演示一个能增删查改、支持多用户登录、带借阅历史和逾期提醒的系统。很多同学卡在「写完需求分析就停更」或者「前端页面能点一连数据库就报错」最后靠截图口头描述蒙混过关。这不是论文能力问题而是缺乏一套可验证、可调试、可交付的最小闭环实现路径从数据库建模开始到后端接口暴露再到前端交互落地每一步都有明确输入输出、可复现命令、必调参数和典型报错日志。本文不讲 LaTeX 排版技巧也不列“系统采用 B/S 架构”这类空话只聚焦一件事如何用 Python Flask SQLite 在 3 天内搭出一个能真实借书、还书、查库存、导出报表的系统原型并把它完整写进毕业论文的“系统实现”章节。适合正在赶毕设 deadline、不想被导师问“你这系统到底跑没跑通”的大四同学也适合想快速验证课程设计逻辑的一线教学助教。2. 用 Flask SQLite 搭建图书管理后端从零建库到 REST 接口全链路2.1 数据库设计为什么用 SQLite 而不是 MySQL毕业设计阶段数据库选型不是比性能而是比部署成本和调试效率。MySQL 需装服务、配账号、开端口、处理权限而 SQLite 是单文件数据库Python 自带sqlite3模块无需额外安装服务所有操作都在.db文件里完成。对毕设而言它有三个不可替代优势零配置启动import sqlite3后直接connect(library.db)就能建库版本可追溯.db文件可直接 git 提交导师检查时双击就能用 DB Browser 打开看表结构迁移成本低后期真要换 MySQL只需改连接字符串和少量 SQL 语法如AUTOINCREMENT→AUTO_INCREMENT业务逻辑层完全不用动。提示别被“SQLite 不适合高并发”吓住——毕设系统最大并发就是你和导师同时打开网页压测根本不存在。真正该警惕的是别在 SQLite 里用外键约束做级联删除Flask-SQLAlchemy 默认开启但 SQLite 的PRAGMA foreign_keys ON在某些 Python 版本下默认关闭导致 delete cascade 失效借阅记录删不干净。2.2 建库脚本5 分钟生成带初始数据的 library.db以下脚本init_db.py会创建books、users、borrow_records三张表并插入 5 本测试图书和 2 个测试用户管理员 普通读者。关键点在于borrow_records表中return_date允许为NULL表示未归还books表中stock字段用于实时库存校验借书时减 1还书时加 1所有时间字段用TEXT存储 ISO8601 格式如2024-05-20 14:30:00避免 SQLite 时间函数兼容性问题。# init_db.py import sqlite3 from datetime import datetime def create_tables(): conn sqlite3.connect(library.db) cursor conn.cursor() # 创建图书表 cursor.execute( CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT, isbn TEXT UNIQUE NOT NULL, title TEXT NOT NULL, author TEXT, publisher TEXT, stock INTEGER DEFAULT 0, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ) # 创建用户表 cursor.execute( CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, role TEXT CHECK(role IN (admin, reader)) DEFAULT reader, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) ) # 创建借阅记录表 cursor.execute( CREATE TABLE IF NOT EXISTS borrow_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, book_id INTEGER NOT NULL, user_id INTEGER NOT NULL, borrow_date TEXT NOT NULL, return_date TEXT, FOREIGN KEY (book_id) REFERENCES books (id), FOREIGN KEY (user_id) REFERENCES users (id) ) ) # 插入测试数据仅首次运行 cursor.execute(SELECT COUNT(*) FROM books) if cursor.fetchone()[0] 0: books_data [ (978-7-02-012345-6, 深入理解计算机系统, Randal E. Bryant, 机械工业出版社, 3), (978-7-302-12345-6, 算法导论, Thomas H. Cormen, 清华大学出版社, 5), (978-7-5086-1234-5, 设计心理学, Donald A. Norman, 中信出版社, 2), (978-7-5133-1234-5, 三体, 刘慈欣, 重庆出版社, 8), (978-7-04-012345-6, 数据库系统概念, Abraham Silberschatz, 高等教育出版社, 4) ] cursor.executemany( INSERT INTO books (isbn, title, author, publisher, stock) VALUES (?, ?, ?, ?, ?), books_data ) cursor.execute(SELECT COUNT(*) FROM users) if cursor.fetchone()[0] 0: cursor.execute( INSERT INTO users (username, password, role) VALUES (?, ?, ?), (admin, pbkdf2:sha256:260000$..., admin) # 密码需后续用 werkzeug 生成 ) cursor.execute( INSERT INTO users (username, password, role) VALUES (?, ?, ?), (reader1, pbkdf2:sha256:260000$..., reader) ) conn.commit() conn.close() print(✅ 数据库初始化完成library.db 已创建含 5 本测试图书、2 个用户) if __name__ __main__: create_tables()逻辑说明与参数说明pbkdf2:sha256:260000$...是占位符实际密码需用werkzeug.security.generate_password_hash()生成见 2.3 节此处先留空避免硬编码明文密码CURRENT_TIMESTAMP在 SQLite 中自动填充当前时间无需 Python 端手动传参FOREIGN KEY约束必须配合PRAGMA foreign_keys ON才生效因此在 Flask 应用启动时需显式开启见 2.3 节app.config[SQLALCHEMY_ENGINE_OPTIONS]设置运行python init_db.py后生成library.db文件可用 DB Browser for SQLite 直接打开验证表结构和数据。2.3 Flask 后端骨架暴露 7 个核心 API覆盖全部业务场景毕业论文里“系统功能模块”章节常写成文字描述但评审老师更想看到每个功能对应哪个 URL、什么 HTTP 方法、返回什么 JSON。以下app.py实现了图书管理最刚需的 7 个接口全部基于原生 Flask不依赖 Flask-SQLAlchemy确保代码透明、无黑盒、易调试# app.py from flask import Flask, request, jsonify import sqlite3 from datetime import datetime import os app Flask(__name__) # 配置 SQLite 连接关键开启外键支持 def get_db_connection(): conn sqlite3.connect(library.db) conn.row_factory sqlite3.Row # 支持字典式取值row[title] conn.execute(PRAGMA foreign_keys ON) # 必须开启否则级联删除失效 return conn # —— 图书相关接口 —— app.route(/api/books, methods[GET]) def list_books(): conn get_db_connection() books conn.execute(SELECT * FROM books ORDER BY created_at DESC).fetchall() conn.close() return jsonify([dict(book) for book in books]) app.route(/api/books/int:book_id, methods[GET]) def get_book(book_id): conn get_db_connection() book conn.execute(SELECT * FROM books WHERE id ?, (book_id,)).fetchone() conn.close() return jsonify(dict(book)) if book else (Book not found, 404) app.route(/api/books, methods[POST]) def add_book(): data request.get_json() conn get_db_connection() try: conn.execute( INSERT INTO books (isbn, title, author, publisher, stock) VALUES (?, ?, ?, ?, ?), (data[isbn], data[title], data[author], data[publisher], data[stock]) ) conn.commit() return jsonify({message: Book added successfully}), 201 except sqlite3.IntegrityError: return jsonify({error: ISBN already exists}), 400 finally: conn.close() # —— 用户与借阅相关接口 —— app.route(/api/users/login, methods[POST]) def login(): data request.get_json() conn get_db_connection() user conn.execute( SELECT * FROM users WHERE username ?, (data[username],) ).fetchone() conn.close() if user and check_password_hash(user[password], data[password]): return jsonify({ user_id: user[id], username: user[username], role: user[role] }) return jsonify({error: Invalid credentials}), 401 app.route(/api/borrow, methods[POST]) def borrow_book(): data request.get_json() conn get_db_connection() try: # 检查库存 book conn.execute(SELECT stock FROM books WHERE id ?, (data[book_id],)).fetchone() if not book or book[stock] 0: return jsonify({error: Book out of stock}), 400 # 扣减库存并创建借阅记录 conn.execute(UPDATE books SET stock stock - 1 WHERE id ?, (data[book_id],)) conn.execute( INSERT INTO borrow_records (book_id, user_id, borrow_date) VALUES (?, ?, ?), (data[book_id], data[user_id], datetime.now().isoformat()) ) conn.commit() return jsonify({message: Borrow successful}) except Exception as e: conn.rollback() return jsonify({error: str(e)}), 500 finally: conn.close() app.route(/api/return, methods[POST]) def return_book(): data request.get_json() conn get_db_connection() try: # 更新借阅记录的 return_date conn.execute( UPDATE borrow_records SET return_date ? WHERE id ? AND return_date IS NULL, (datetime.now().isoformat(), data[record_id]) ) # 恢复库存 record conn.execute( SELECT book_id FROM borrow_records WHERE id ?, (data[record_id],) ).fetchone() if record: conn.execute(UPDATE books SET stock stock 1 WHERE id ?, (record[book_id],)) conn.commit() return jsonify({message: Return successful}) except Exception as e: conn.rollback() return jsonify({error: str(e)}), 500 finally: conn.close() app.route(/api/reports/overdue, methods[GET]) def overdue_report(): conn get_db_connection() # 查找借出超 30 天未还的记录 overdue conn.execute( SELECT br.id, b.title, u.username, br.borrow_date FROM borrow_records br JOIN books b ON br.book_id b.id JOIN users u ON br.user_id u.id WHERE br.return_date IS NULL AND julianday(now) - julianday(br.borrow_date) 30 ).fetchall() conn.close() return jsonify([dict(r) for r in overdue]) if __name__ __main__: app.run(debugTrue, host0.0.0.0, port5000)关键参数与逻辑说明conn.row_factory sqlite3.Row让查询结果支持row[title]取值避免row[2]这种易错索引julianday()是 SQLite 内置日期函数计算两个日期间的天数差比 Python 端解析字符串再计算更可靠check_password_hash()需提前导入from werkzeug.security import check_password_hash, generate_password_hash密码哈希生成见 2.4 节所有数据库操作都包裹在try/except/finally中确保conn.close()和conn.rollback()正确执行避免连接泄漏debugTrue仅用于开发论文答辩前务必改为debugFalse并用gunicorn启动见 4.2 节。3. 前端页面与交互用纯 HTML JS 实现借还书全流程不依赖框架3.1 静态页面结构一个 HTML 文件搞定全部界面毕业设计常陷入“学 Vue 却只写了个 Hello World”的陷阱。其实纯 HTML 原生 JavaScript 就能做出专业级交互且代码全部写在templates/index.html里无需构建工具、无需 npm、无需打包直接用浏览器打开就能跑。页面包含图书列表表格含搜索框借阅操作按钮点击弹出用户选择 借书确认还书操作入口显示“未归还”状态点击跳转还书页逾期报表查看按钮调用/api/reports/overdue。!-- templates/index.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 title图书管理系统/title style body { font-family: Helvetica Neue, Arial, sans-serif; margin: 0; padding: 20px; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { border: 1px solid #ddd; padding: 10px; text-align: left; } th { background-color: #f2f2f2; } .btn { background: #007bff; color: white; border: none; padding: 6px 12px; cursor: pointer; } .btn-danger { background: #dc3545; } .modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; } .overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 999; } /style /head body h1 图书管理系统/h1 input typetext idsearchInput placeholder按书名或作者搜索... oninputfilterBooks() button classbtn onclickloadBooks()刷新列表/button button classbtn onclickshowAddBookModal()添加图书/button table idbooksTable thead tr thISBN/thth书名/thth作者/thth出版社/thth库存/thth操作/th /tr /thead tbody idbooksBody/tbody /table !-- 添加图书弹窗 -- div classoverlay idaddModalOverlay/div div classmodal idaddBookModal h3添加新图书/h3 input typetext idisbn placeholderISBN requiredbrbr input typetext idtitle placeholder书名 requiredbrbr input typetext idauthor placeholder作者brbr input typetext idpublisher placeholder出版社brbr input typenumber idstock placeholder库存 value1 min0brbr button classbtn onclickaddBook()确认添加/button button classbtn btn-danger onclickcloseAddModal()取消/button /div !-- 借阅弹窗 -- div classoverlay idborrowModalOverlay/div div classmodal idborrowModal h3借阅图书/h3 p idborrowBookTitle/p label选择读者/label select idborrowUserId/selectbrbr button classbtn onclickconfirmBorrow()确认借阅/button button classbtn btn-danger onclickcloseBorrowModal()取消/button /div script let books []; const API_BASE http://localhost:5000/api; // 加载图书列表 function loadBooks() { fetch(${API_BASE}/books) .then(res res.json()) .then(data { books data; renderBooks(data); }); } function renderBooks(bookList) { const tbody document.getElementById(booksBody); tbody.innerHTML ; bookList.forEach(book { const row tbody.insertRow(); row.insertCell().textContent book.isbn; row.insertCell().textContent book.title; row.insertCell().textContent book.author; row.insertCell().textContent book.publisher; row.insertCell().textContent book.stock; const actions row.insertCell(); actions.innerHTML button classbtn onclickshowBorrowModal(${book.id}, ${book.title})借阅/button button classbtn btn-danger onclickshowReturnModal(${book.id})还书/button ; }); } // 搜索过滤 function filterBooks() { const keyword document.getElementById(searchInput).value.toLowerCase(); const filtered books.filter(book book.title.toLowerCase().includes(keyword) || book.author.toLowerCase().includes(keyword) ); renderBooks(filtered); } // 弹窗控制 function showAddBookModal() { document.getElementById(addBookModal).style.display block; document.getElementById(addModalOverlay).style.display block; } function closeAddModal() { document.getElementById(addBookModal).style.display none; document.getElementById(addModalOverlay).style.display none; } function showBorrowModal(bookId, title) { document.getElementById(borrowBookTitle).textContent 《${title}》; // 加载用户列表简化固定两个用户 const select document.getElementById(borrowUserId); select.innerHTML option value1admin/optionoption value2reader1/option; document.getElementById(borrowModal).style.display block; document.getElementById(borrowModalOverlay).style.display block; } function closeBorrowModal() { document.getElementById(borrowModal).style.display none; document.getElementById(borrowModalOverlay).style.display none; } // 添加图书 function addBook() { const data { isbn: document.getElementById(isbn).value, title: document.getElementById(title).value, author: document.getElementById(author).value, publisher: document.getElementById(publisher).value, stock: parseInt(document.getElementById(stock).value) || 0 }; fetch(${API_BASE}/books, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(data) }) .then(res res.json()) .then(data { alert(data.message || 添加成功); closeAddModal(); loadBooks(); }) .catch(err alert(添加失败 err)); } // 借阅确认 function confirmBorrow() { const bookId document.getElementById(borrowBookTitle).textContent.match(/《(.)》/)[1]; const userId document.getElementById(borrowUserId).value; // 实际应先通过 /api/users/login 获取 token此处简化 fetch(${API_BASE}/borrow, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ book_id: 1, user_id: userId }) // 简化 ID真实需动态获取 }) .then(res res.json()) .then(data { alert(data.message || 借阅成功); closeBorrowModal(); loadBooks(); }); } // 页面加载时初始化 window.onload loadBooks; /script /body /html为什么用原生 JS 而不是 Vue/React答辩现场零依赖U 盘拷贝整个templates/文件夹双击index.html就能打开界面不需要npm install、不需要yarn serve代码完全可控所有 AJAX 请求、DOM 操作、事件绑定都在一个文件里导师问“这个按钮怎么触发借书”你直接翻到confirmBorrow()函数指给他看毕业论文截图友好页面风格简洁、字体清晰、按钮位置统一截图放进论文“系统界面展示”章节毫无违和感调试门槛低浏览器按 F12Console 里直接fetch(/api/books)测试接口Network 标签看请求响应不用学 Vue Devtools。3.2 关键交互逻辑借书时的库存校验与事务回滚前端看似简单但真正的业务逻辑藏在后端接口里。以borrow_book()为例它的健壮性决定了系统是否“能用”库存原子性校验先SELECT stock再UPDATE books SET stock stock - 1中间不能被其他请求插入事务一致性保障借书涉及“扣库存”和“写借阅记录”两步任一步失败必须回滚否则出现“书没了但没记录”或“有记录但库存没扣”错误码语义明确400 Bad Request返回“Book out of stock”500 Internal Server Error返回具体异常信息开发期上线后应屏蔽敏感信息。注意SQLite 默认隔离级别是DEFERRED在单线程 Flask 开发服务器下足够安全。若未来扩展为多进程如gunicorn --workers 4需在get_db_connection()中加conn.isolation_level None并手动BEGIN/COMMIT但毕设阶段无需考虑。3.3 逾期报表生成用 SQLite 原生函数算出超期图书毕业论文常要求“提供统计分析功能”但很多同学写成“系统支持报表导出”。真正加分的做法是用一行 SQL 实现业务逻辑并在论文里贴出查询语句和结果截图。/api/reports/overdue接口的核心是SELECT br.id, b.title, u.username, br.borrow_date FROM borrow_records br JOIN books b ON br.book_id b.id JOIN users u ON br.user_id u.id WHERE br.return_date IS NULL AND julianday(now) - julianday(br.borrow_date) 30julianday()将日期转为儒略日数相减即得天数差比strftime(%s, now)更跨平台br.return_date IS NULL确保只查未归还记录结果直接 JSON 化前端用table渲染导出 CSV 只需加个按钮调用downloadCSV()函数代码略需时可补。这一行 SQL 就是论文“数据分析模块”章节的硬核内容——它不是“系统调用了报表组件”而是“系统通过 SQL 原生计算识别逾期行为”。4. 毕业论文写作指南把代码变成论文里的“系统实现”章节4.1 论文结构建议拒绝“技术堆砌”专注“问题-方案-验证”闭环很多同学的论文“系统实现”章节写成“本系统采用 Python 编写使用 Flask 框架……数据库选用 SQLite……前端使用 HTML/CSS/JS……”这叫技术罗列不是实现描述。评审老师想看到的是这个功能为什么这么设计遇到什么问题怎么解决的效果如何推荐按以下结构组织每小节 300–500 字小节标题写什么举例真实内容4.1.1 图书库存实时同步机制问题借书后库存未更新导致超借方案在borrow_book()中用UPDATE books SET stock stock - 1原子操作验证并发测试 10 次借同一本书库存准确减 10“经压力测试系统在 50 QPS 下库存误差率为 0%”4.1.2 逾期图书自动识别逻辑问题人工核查耗时方案用 SQLitejulianday()函数计算借阅天数验证导入 100 条测试记录30 天阈值识别准确率 100%“SQL 查询耗时稳定在 12ms 以内i5-8250U”4.1.3 前后端分离接口规范问题页面刷新丢失状态方案定义/api/booksGET/POST、/api/borrowPOST等 7 个 REST 接口验证Postman 全部接口返回 200错误码覆盖 400/401/500“接口文档已附录于论文第 42 页”提示所有“验证”必须有数据支撑。不要写“性能良好”要写“实测响应时间 ≤ 200ms”不要写“功能完整”要写“覆盖 12 个用例通过率 100%”用例表可放附录。4.2 系统部署与答辩演示3 条命令让导师现场验收答辩时最怕“本地能跑导师电脑报错”。解决方案是把部署过程压缩成 3 条可复制粘贴的命令并提前在导师电脑上预装 Python 3.8。# 1. 安装依赖仅需 Flask无其他包 pip install Flask Werkzeug # 2. 初始化数据库生成 library.db python init_db.py # 3. 启动服务生产模式禁用 debug gunicorn -w 1 -b 0.0.0.0:5000 app:appgunicorn比flask run更稳定-w 1指定单 worker避免 SQLite 并发冲突启动后访问http://导师电脑IP:5000即可打开系统无需任何前端构建答辩时准备 3 个演示用例搜索“算法”显示《算法导论》库存为 5点击借阅库存变为 4借阅记录新增一条访问/api/reports/overdue返回空数组证明无逾期手动修改borrow_records表的borrow_date为 40 天前再刷接口返回该记录。这就是“可验证的系统”——不是“我写了代码”而是“您现在就能看到结果”。4.3 代码与文档交付清单让导师 5 分钟看懂你的工作量毕业论文答辩材料包里除了.doc必须包含一个code/文件夹结构如下code/ ├── init_db.py # 数据库初始化脚本含测试数据 ├── app.py # Flask 后端7 个核心 API ├── templates/ │ └── index.html # 前端页面纯 HTML JS ├── library.db # 已初始化的数据库文件git 提交 └── requirements.txt # 仅两行Flask2.3.3, Werkzeug2.3.7library.db必须提交这是系统状态的“快照”导师双击就能用 DB Browser 查看数据requirements.txt版本号锁定避免pip install flask装到 v3.x 导致url_for()报错所有文件 UTF-8 编码Windows 记事本打开不乱码禁止提交.pyc、__pycache__、.vscode等无关文件——精简即专业。5. 避坑指南毕设中最容易翻车的 5 个细节血泪经验总结5.1 现象点击“借阅”按钮无反应浏览器 Console 报Failed to fetch原因前端请求地址写成http://localhost:5000/api/borrow但 Flask 启动时用了host127.0.0.1默认导致 Chrome 同源策略拦截localhost≠127.0.0.1。解决启动 Flask 时显式指定hostlocalhost或前端用相对路径/api/borrow推荐。5.2 现象添加图书时报UNIQUE constraint failed: books.isbn但数据库里明明没有该 ISBN原因SQLite 的INSERT OR IGNORE未启用且init_db.py中插入测试数据后未conn.commit()导致后续插入时主键冲突。解决检查init_db.py中cursor.executemany()后是否有conn.commit()或改用INSERT OR REPLACE INTO替代INSERT INTO。5.3 现象借阅后库存减 1但刷新页面库存又变回原值原因app.py中borrow_book()函数里conn.commit()被写在try块外异常时未执行或get_db_connection()未设置conn.row_factory导致fetchone()返回 tuple 而非 dictbook[stock]报错中断流程。解决将conn.commit()移至try块末尾并确保所有数据库操作后都conn.close()用print(type(book))调试返回类型。5.4 现象答辩现场导师电脑打不开index.html提示“跨域请求被阻止”原因直接双击 HTML 文件浏览器以file://协议打开AJAX 请求http://localhost:5000被视为跨域。解决答辩前用 Python 快速起一个静态服务器python -m http.server 8000然后访问http://localhost:8000/templates/index.html此时协议为http://同源。5.5 现象论文里截图的界面和实际运行不一致如按钮颜色、字体大小原因CSS 写在style标签里但未加!important被浏览器默认样式覆盖或截图时用了缩放125%导致像素模糊。解决截图前按Ctrl0重置缩放CSS 中关键样式加!important如.btn { background: #007bff !important; }所有字体用sans-serif避免宋体/微软雅黑渲染差异。6. 进阶技巧用 Git 版本管理讲好你的毕设故事让导师一眼看到成长6.1 用 Git 提交信息写“技术日记”替代论文里的空洞描述毕业论文“开发过程”章节常写成“第 1 周需求分析第 2 周系统设计……” 这是流水账。真正体现工程能力的是Git 提交记录本身就是开发日志。例如git log --oneline -n 10 a1b2c3d (HEAD - main) feat: add overdue report API with julianday calculation e4f5g6h fix: resolve stock race condition in borrow_book by adding transaction i7j8k9l refactor: move DB connection to get_db_connection() for reuse l0m1n2o docs: update API docstring for /api/borrow endpoint p3q4r5s test: add pytest for book search functionality把这些提交信息整理成表格放进论文附录比写“本人独立完成全部编码工作”有力得多。导师扫一眼就知道你解决了并发问题、优化了架构、写了测试、更新了文档——这才是工程师思维。6.2本文还有配套的精品资源点击获取