2026/10/14 5:19:15

ThinkPHP5小说阅读网站设计与实现:从数据库到部署的完整毕设指南

ThinkPHP5小说阅读网站设计与实现:从数据库到部署的完整毕设指南 每年毕设开题季Web方向的小说阅读网站几乎都会出现在选题列表里。用ThinkPHP5做一个完整的小说站听起来门槛不高但真要把前台阅读体验、后台管理、书架同步、搜索这些模块串起来跑通还能在答辩时把每一步设计理由讲清楚很多人是在最后两周才开始补课的。这篇就基于thinkphp5基于web的小说阅读网站的设计与实现这个题目聊聊我做完这个项目后的完整思路从选型逻辑、数据库设计、核心模块实现到真实踩过的坑和部署答辩经验一次说透。这个题目的受众很明确——正在准备计算机毕业设计的同学尤其是选了Web开发方向、用PHP框架做项目的。哪怕你还没开始写代码只要把下面几条主线捋清楚再动手做项目至少能少走一半弯路。1. 为什么小说阅读网站是毕设常青树选ThinkPHP5是稳棋还是险棋1.1 选题热度背后的真实原因小说阅读网站这类题目在毕业设计里长期热门原因有三个方面。第一需求边界清晰。用户端无非就是注册登录、分类浏览、搜索小说、查看章节、加入书架、记录阅读进度管理端就是书籍管理、章节管理、分类管理、用户管理、数据统计。这种边界明确的业务非常适合用来展示需求分析→数据库设计→编码实现→测试部署的完整工程流程答辩时有话可讲。第二技术栈覆盖全面。一个小说站天然涉及前端页面展示、后端接口逻辑、数据库设计、会话管理、全文搜索、缓存策略、权限控制等多种技术点。用ThinkPHP5实现时框架的MVC分层、ORM、模板引擎、验证器、缓存机制基本都被用到正好覆盖了课程里学的主要内容。答辩时无论老师问MVC还是问数据库都能找到对应的落地点。第三业务可扩展性强。可以把小说阅读进一步扩展到评论系统、打赏功能、阅读排行榜、推荐算法等方向这些扩展点让毕设的创新性有了着落不至于做完一个纯增删改查项目后被质疑工作量不足。1.2 为什么考虑用ThinkPHP5而不是其他框架我帮人看过不少同类毕设有人用ThinkPHP6有人用Laravel也有人坚持原生PHP。如果题目明确写了ThinkPHP5那没什么好纠结的按题目去做。但如果你还有自主选择空间我的建议是优先考虑ThinkPHP5。原因很实际。学校机房、老一点的服务器环境、导师给的参考代码大多围绕TP5编写。TP5的资料存量极大遇到问题随便一搜就是解决方案不像TP6那样很多教程还没跟上。对毕设项目来说稳定、熟悉、资料多比框架新重要得多。TP5本身的设计也比较适合教学展示。它保留了比较明显的MVC分目录结构application/index/controller、application/admin/controller一眼就能看出哪个是前台哪个是后台数据库操作既能走Db类原生查询也能走模型关联模板语法接近原生PHP改起来不费劲。这些特点让答辩时讲技术细节更容易因为框架没有帮你隐藏太多东西。1.3 这个题目最容易翻车的三个地方选了这个题不代表就能顺利做完。从我接触的情况看最常见的翻车点有三个。第一个是数据库设计想得太简单。小说站可不是两张表就能搞定的至少要有用户表、书籍表、章节表、分类表、书架表、管理员表外加可能的评论表、推荐位配置表。字段设计不合理的话后面写功能时处处别扭。比如书架表如果没有处理好书ID章节ID的联动更新就很容易出现阅读进度丢失之类的问题。第二个是阅读页性能没考虑。小说章节内容动辄几千字如果把整本书的所有章节一次性查出来渲染或者每访问一章都全表扫描一次慢是必然的。这个问题后面会专门展开。第三个是后台管理重量不够。有些同学把精力全砸在前台页面上后台就放两个列表页草草了事。答辩时老师最爱问的就是管理员怎么维护书籍内容你怎么统计访问量答不上来基本就暴露了工作量不足。2. 功能清单先排雷前台、后台和隐藏加分项2.1 前台用户端不要只盯着能看书前台是整个项目的门面但很多人的理解仅限于展示书籍列表和章节内容。实际拆解下来前台至少应该包含以下模块用户模块注册、登录、退出、密码修改。注册时建议加入邮箱验证或至少验证码手机号可以不做避免学生身份的信息安全问题。登录态建议用TP5自带的Session记录不需要引入JWT降低复杂度。书籍展示模块首页推荐位、分类列表、书籍详情页。详情页要有书籍封面、作者、简介、最新章节信息、点击量和推荐按钮。这里的推荐位不要写死建议在后台用推荐状态字段控制。阅读模块章节列表、正文阅读页、上一章/下一章切换、记忆上次阅读位置。正文页要做基本的排版处理比如段落缩进、文字大小调节加分项、背景色切换加分项。书架模块加入书架、移出书架、按最近阅读时间排序。书架在登录状态下存库未登录时给提示即可没必要做本地缓存否则数据同步逻辑会很麻烦。搜索模块按书名、作者名模糊搜索搜索结果的排序和分页。这一块也是后文会提到的性能重灾区。2.2 后台管理端工作量撑起来的关键有的同学觉得后台只是附赠随便弄两下就行这就错了。小说站的管理端恰恰是工作量最容易体现的地方。后台建议独立跑一个admin模块功能包括管理员登录与权限区分至少区分超级管理员和普通编辑普通编辑只能维护书籍内容不能管理用户更不能动系统设置。书籍管理书籍的增删改查、上下架、推荐位开关、封面上传。封面上传要考虑图片格式和白名单校验不要随便拿一个move()就完事。章节管理在书籍详情下按章节号维护章节内容支持手动添加、批量导入、编辑删除。批量导入建议支持TXT文本按行拆分这样答辩演示时导入一本真书的效果会非常震撼。分类管理分类的增删改和排序分类删除前要检查是否有书籍关联。用户管理用户列表、禁用/启用账号、重置密码。数据统计书籍点击量排行、用户注册量走势、书架收藏排行用简单图表展示即可。这里如果做得好答辩时非常加分。2.3 非功能性需求才是拉开差距的地方除了前后的功能清单我在帮人审方案时一定会强调三类非功能性需求。第一是安全性。TP5的ORM自带参数绑定但有些人图省事直接拼SQL这就是漏洞。密码不能用明文存储至少用TP5自带的md5加盐或password_hash。文件上传要限制类型防文件包含攻击。第二是健壮性。同一本书重复加入书架怎么办后台删除书籍时关联的书架数据怎么处理搜索关键词为空时是提示还是返回全部这些问题如果都能在编码前想清楚后面的调试时间能省一大半。第三是可维护性。代码注释、目录规范、配置文件分离这些本来就该做。答辩时老师翻代码看到注释规范第一印象会好很多。3. 数据库设计小说站的核心竞争力其实在表结构3.1 核心表结构与字段设计的思路数据库表可以按用户相关、内容相关、行为相关三类来规划。内容相关是核心行为相关最容易出错。我最终采用的表结构大致如下去掉了部分冗余字段只讲主干-- 用户表 CREATE TABLE novel_user ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, email VARCHAR(100) DEFAULT , create_time INT(11) NOT NULL, status TINYINT(1) DEFAULT 1 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 分类表 CREATE TABLE novel_category ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, sort_order INT DEFAULT 0 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 书籍表 CREATE TABLE novel_book ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, category_id INT UNSIGNED NOT NULL, title VARCHAR(200) NOT NULL, author VARCHAR(50) NOT NULL, intro TEXT, cover VARCHAR(255) DEFAULT , status TINYINT(1) DEFAULT 1 COMMENT 1上架 0下架, is_hot TINYINT(1) DEFAULT 0 COMMENT 首页推荐, click_count INT UNSIGNED DEFAULT 0, chapter_count INT UNSIGNED DEFAULT 0, last_chapter_title VARCHAR(200) DEFAULT , create_time INT(11) NOT NULL, KEY category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 章节表 CREATE TABLE novel_chapter ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, book_id INT UNSIGNED NOT NULL, chapter_no INT UNSIGNED NOT NULL COMMENT 章节序号, title VARCHAR(200) NOT NULL, content MEDIUMTEXT NOT NULL, word_count INT UNSIGNED DEFAULT 0, create_time INT(11) NOT NULL, UNIQUE KEY uk_book_no (book_id, chapter_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 书架表 CREATE TABLE novel_shelf ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL, book_id INT UNSIGNED NOT NULL, chapter_id INT UNSIGNED NOT NULL COMMENT 最近阅读章节, update_time INT(11) NOT NULL, UNIQUE KEY uk_user_book (user_id, book_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;特别注意novel_chapter的唯一索引uk_book_no它的作用是防止同一本书下章节号重复。小说章节一旦通过导入或爬虫维护很容易出现重复章节没有唯一索引的话后台插入第二条同号章节时就会静默覆盖或报错排查起来非常痛苦。3.2 设计时最容易疏忽的两个关联细节第一个细节是书籍表和章节表之间的冗余字段。我在novel_book里放了chapter_count和last_chapter_title创建章节时同步更新这两个字段。冗余字段会增加维护逻辑但换来的好处是首页和书籍列表页不用每次count和查最新章节性能提升明显。代价是每次增删章节时要记得同步更新忘记更新就会显示错误。这里可以在章节模型的事件钩子里统一处理避免散落在多个控制器里。第二个细节是书架表的唯一索引和更新策略。书架表用的是UNIQUE KEY uk_user_book (user_id, book_id)保证一个用户对同一本书只保留一条记录。当用户读到新章节时不是新增一条记录而是更新chapter_id和update_time。这个插入时若存在则更新的操作用TP5的Db::execute配合ON DUPLICATE KEY UPDATE一步完成比先查后改要靠谱得多还避免了并发下的数据不一致。3.3 编码前的ER图和数据字典在动手写代码之前务必用工具把ER图画出来再写一份数据字典。数据字典的格式可以参考这样的表格答辩时可以放到论文附录里表名主要字段字段类型说明novel_useridINT主键novel_userusernameVARCHAR(50)用户名唯一novel_booktitleVARCHAR(200)书名novel_bookstatusTINYINT(1)1上架 0下架novel_chaptercontentMEDIUMTEXT章节正文novel_shelfchapter_idINT最近阅读章节ID数据字典不仅方便编码时查字段名也是论文和答辩PPT里必不可少的内容。提前花一小时整理好后面省下的是反复翻表结构的时间。4. 四大核心模块的实现套路书架、阅读、搜索、用户体系4.1 书架模块自动更新进度的逻辑书架看起来简单但自动更新进度这个交互要做好是有讲究的。用户不需要手动点击更新进度而是在打开正文页时自动把当前章节写进书架。我当时的实现是在阅读页控制器里统一处理public function read() { $bookId (int)input(param.book_id); $chapterId (int)input(param.id); $chapter Db::name(chapter)-where(id, $chapterId)-where(book_id, $bookId)-find(); if (!$chapter) { $this-error(章节不存在); } // 更新阅读进度 $userId session(user_id); if ($userId) { $data [ user_id $userId, book_id $bookId, chapter_id $chapterId, update_time time(), ]; Db::execute(INSERT INTO novel_shelf (user_id, book_id, chapter_id, update_time) VALUES (:user_id, :book_id, :chapter_id, :update_time) ON DUPLICATE KEY UPDATE chapter_id VALUES(chapter_id), update_time VALUES(update_time), $data); } // 继续渲染阅读页 ... }这样每次进阅读页时书架进度自动就是最新的。SQL语句里用了命名占位符而不是字符串拼接这点在TP5里尤其重要能防SQL注入。书籍详情页的加入书架按钮也不要做成单独的表单请求直接用AJAX调用一个接口返回JSON状态前端提示已加入书架或已在书架中。接口内部同样处理插入和更新的情况。4.2 阅读页章节切换与性能阅读页是用户停留时间最长的页面这部分优化做得好展示效果立竿见影。章节列表建议在书籍详情页异步加载而不是直接渲染几十章甚至几百章。可以用TP5的paginate()做分页每次加载50章滚动到底部再请求下一页。这里用AJAX加HTML拼接的方式后端返回渲染好的片段前端直接插入DOM比返回JSON再拼DOM简单得多。正文渲染有一个关键细节小说的章节内容通常来自TXT导入或收集的数据里面会有大量换行、半角空格和各种分隔符。入库前一定要做数据清洗。我常用的做法是入库时统一把\r\n转换成br再过滤掉HTML标签防止XSS。展示时用CSS统一控制段落间距而不是直接把原始的text/plain输出到页面上。上一章/下一章切换可以走同一个阅读控制器用chapter_no加减1来判断// 上一章 Db::name(chapter) -where(book_id, $bookId) -where(chapter_no, , $currentNo) -order(chapter_no desc) -find(); // 下一章 Db::name(chapter) -where(book_id, $bookId) -where(chapter_no, , $currentNo) -order(chapter_no asc) -find();注意这里要用章节号而不是主键id来判断相邻章节因为手动导入时主键顺序未必和章节顺序一致。4.3 搜索模块模糊查询之外的性能优化搜索是小说站的标配功能也是很多毕设做得最粗糙的地方。最简单的实现是$keyword input(keyword); $list Db::name(book) -where(title|author, like, %.$keyword.%) -paginate(10);这个写法在数据量小的时候没问题一旦书籍表超过几千条且没有索引LIKE %关键词%就会做全表扫描搜索响应会明显变慢。优化可以从三个层面入手。第一个层面是加索引。title和author字段各自建普通索引虽然LIKE %keyword%不一定走索引但MySQL 5.7以上对字符串长度较短的字段在一定条件下也能用上索引至少可以缓解。第二个层面是加缓存。用TP5的Cache类把搜索结果缓存起来缓存键用关键词的MD5值过期时间设5分钟。第三个层面是限制搜索范围。前端加一个下拉选项让用户选择按书名或按作者搜索避免两个字段同时模糊匹配带来的性能开销。还有一个小建议搜索页不要返回空页面给用户。搜不到结果时给出推荐阅读栏目拉几条热门书籍填充这样既友好又能提升页面利用率。4.4 用户体系注册、登录和密码处理用户体系是小说站的基础功能TP5做起来很快但有几个细节不能马虎。注册时要用TP5的Validate类做表单验证用户名、邮箱格式、密码长度都有对应规则。不要用前端JS验证就算完服务端验证必须做。密码存储我用的是password_hash()生成校验时用password_verify()这和TP5自带的md5封装不同但更安全答辩时如果老师问到密码存储策略这是一个很不错的加分回答。登录后的用户状态用session(user_id)记录模板中用session(username)判断是否显示用户名还是登录/注册按钮。注销时调用session(null)清空所有会话数据防止用户信息残留。5. 性能优化和缓存策略让老框架跑出体面速度5.1 缓存策略应该从哪个层面做小说站的性能瓶颈不在框架本身而在数据库查询和页面渲染。TP5自带的缓存机制支持文件缓存和Redis缓存没有Redis环境时可以直接用文件缓存代码写起来一样答辩时说明文件缓存独立部署也是一种合理方案。我的推荐是两级缓存。第一级缓存书籍基础信息和章节列表键名类似book_info_{id}、book_chapter_list_{id}过期时间600秒。第二级缓存正文内容键名chapter_content_{id}过期时间可以设置更长一些因为章节内容入库后基本不会频繁修改。这样连续点击阅读多个章节时大部分查询都走缓存数据库压力一下子下来了。代码示例use think\Cache; // 获取章节内容优先走缓存 function getChapterContent($chapterId) { $cacheKey chapter_content_ . $chapterId; $content Cache::get($cacheKey); if (!$content) { $content Db::name(chapter)-where(id, $chapterId)-value(content); Cache::set($cacheKey, $content, 3600); } return $content; }注意value(content)返回的是字段值而不是整行记录比find()后取字段要省一点内存。5.2 SQL层面的优化和慢查询排查性能问题光靠缓存不能全解决SQL本身也要写对。比如书籍列表按点击量排序时如果不对click_count字段建索引数据量大之后排序会非常慢。后台统计用户注册走势时不要用GROUP BY去扫全年数据可以按天生成一条统计记录后台直接读统计表。调试SQL性能时TP5提供了Db::getLastSql()方法可以在排查时打印最后执行的SQL语句。结合数据库管理工具的慢查询日志基本能精准定位是哪条查询拖慢了响应。我在实测中发现很多页面加载很慢的问题不是单条SQL太慢而是循环里调用了查询。典型的场景是书籍列表页循环每本书查最新章节N本书就是N条SQL。后来改成在列表页直接用join关联章节表按MAX(chapter_no)分组查询一次SQL就把所有书籍的最新章节信息带出来。不要把所有逻辑都放在控制器里TP5的模型层有事件机制和访问器把复杂查询封装成模型方法控制器只负责调度这样代码结构清晰得多排查性能问题也更方便。5.3 前端层面的加载优化除了后端前端也有几个简单有效的优化点。封面图是小说站最占体积的资源之一。封面图压缩到200KB以内必要时用懒加载loadinglazy属性在详情页列表场景下很有用。首页推荐位不要放太多书8到10本足够否则页面长度直接拉跨用户还没看到分类导航就失去耐心了。正文页的上一章/下一章按钮建议提前预加载。当前章节渲染完成后用AJAX静默请求下一章节的内容存入浏览器缓存或一个隐藏DOM节点。用户点下一章时几乎无缝切换阅读体验提升明显。这个功能记得提前测试防止预加载和实际点击时章节号不一致造成的错乱。6. 实测中遇到的三个坑白屏、错乱和超时的完整排查6.1 首页白屏伪静态配置和运行目录权限第一次在服务器上部署TP5项目最常见的问题是一打开首页就404或者白屏。当时我排查了一整天最后定位到两个原因。第一个是Nginx的伪静态规则没有按TP5文档配置。TP5的URL访问依赖pathinfo模式如果服务器没有把请求重写到index.php路由就无法解析。正确的Nginx配置是在server块中加入location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } }第二个是runtime目录没有写权限。TP5运行时会向runtime目录写入缓存文件和日志如果没有写权限页面会直接抛出系统错误甚至白屏。部署时执行一次chmod -R 777 runtime顺便提一句本地开发时用TP5自带的php think run命令启动开发服务器伪静态问题会少很多但部署到Nginx时还是要回归检查一遍。6.2 书架章节进度错乱的根因排查有段时间书架功能出现一个很隐蔽的bug用户读到了第80章但书架列表显示的进度还是第45章而且刷新后进度还会跳变。一开始我以为是写入时机不对后来加了日志才定位到真正的原因。问题出在书架写入的SQL上。当时我先用select查一遍书架里有没有这本书的记录有就update没有就insert。但用户连续点击上一章下一章时两次请求几乎同时到达两个请求都查到不存在记录于是都走insert分支其中一个插入失败被异常吞掉整体进度就没更新。改成INSERT ... ON DUPLICATE KEY UPDATE后这个问题就彻底消失了。所以这里也想提醒一句涉及存在即更新、不存在即插入的场景不要让数据库的查询和写入分两步走直接用原子化操作。6.3 搜索超时模糊查询字段的索引问题搜索页在书本数量达到几千条之后开始变慢有些关键词甚至需要两三秒才能出结果。我查看数据库慢查询日志发现慢的不是搜索结果本身而是搜索结果的统计总数那条SQL。TP5的paginate()默认会先执行一次count查询而count加LIKE模糊查询的组合非常消耗性能。解决方式有两个如果翻页不需要精确总数就改用Paginator的简化模式或者在前端直接限制最大翻页数比如最多50页超出就提示用户缩小关键词范围。另一个方式是给title、author字段各加一个普通索引虽然对%keyword%帮助有限但至少能让MySQL在排序时快一点。要提醒的是不要为了搜索性能轻易引入全文索引或Elasticsearch。对毕设项目来说数据量根本没有到那个量级加了复杂组件会引入大量额外运维成本答辩时还可能被追问你是怎么保证索引和数据库一致性的反而给自己挖坑。6.4 数据导入中文乱码和章节错乱书籍数据导入环节也踩过不少坑。从网上拿来的TXT文件编码很可能是GBK或GB2312直接入库就会变成乱码。必须在导入前统一转成UTF-8$content mb_convert_encoding($content, UTF-8, GBK);如果混合了多种编码建议先做编码检测再统一转换。导入章节时还要注意目录识别的逻辑有些TXT文件开头有第一章 XXXXX的目录行正文里又有同样的标题行不做过滤就会产生大量空章节或重复章节。我当时的方法是先按行读取用正则匹配第([0-9零一二三四五六七八九十百千])章识别章节标题命中标题行就新开一个章节正文行累积到当前章节里。标题行和正文行都有的情况下优先保证章节号递增且唯一重复标题直接跳过。7. 部署到服务器和答辩准备的最后冲刺7.1 服务器部署的环境细节部署环境我建议采用最常见搭配Nginx PHP 7.x MySQL 5.7。操作系统选Linux发行版。具体安装流程网上很多不再赘述但有几个容易踩的细节值得强调。一是PHP版本的选择。TP5.0在PHP 7.0到7.4下表现稳定不建议用PHP 8部分老扩展可能不兼容报错排查起来麻烦。二是OPcache建议开启PHP进程对TP5这种多文件的框架加速效果明显。三是application/config.php里的app_debug部署后要设为falseapp_trace也要关掉否则页面底部会显示调试信息安全性也不好。数据库连接时application/database.php里的hostname不要用localhost优先用127.0.0.1避免PHP在某些环境下解析localhost为IPv6导致连不上。字符集设置成utf8mb4因为章节内容里很可能有各种特殊字符和emojiutf8会丢数据。7.2 演示数据怎么准备才像样答辩演示时最尴尬的事情莫过于页面上只有零星几本测试书章节内容还是aaaabbbb这种假数据。建议提前准备一套像样的演示数据。至少找5到8本不同分类的书籍每本书配好封面图、简介、统一风格的章节内容。可以手动整理几本短篇每本录入10到20章确保章节列表、阅读切换、书架进度这些功能都有内容可展示。更讲究一点的话模拟一些真实的用户行为数据注册几个演示账号让其中一个账号的书籍点击量、书架收藏量看起来自然一些后台统计页面才有内容可看。封面图不要用太大的图建议提前用工具压缩并统一尺寸。上传到本地服务器时记得把图片放到public/static/upload目录下不要放在runtime里否则清理缓存时图片会被误删。7.3 答辩提问的高频问题清单答辩问答环节老师基本会围绕以下几个方向提问提前准备答案很重要。第一个方向是框架原理。ThinkPHP5的请求生命周期是怎样的$_GET和TP5的Input类有什么异同路由是怎么实现伪静态的这类问题只要画一遍流程图基本都能答上来。第二个方向是数据库设计。为什么书架表要设唯一索引书籍表和章节表之间是什么关系冗余字段怎么保证一致性这些问题在本文第3章都有对应解释。第三个方向是安全。怎么做SQL注入防护密码加密是怎么做的文件上传有哪些限制如果你在实现里用了预处理、密码哈希、白名单校验如实回答即可。第四个方向是性能。缓存用的是什么机制大数据量下搜索怎么优化有没有考虑过并发访问这类问题不求答得多深关键在于展示出你做过的优化决策。建议答辩前把项目的核心流程图和数据库ER图打印出来或者放进PPT。演示时不要一上来就登录后台按用户视角走一遍首页、分类列表、书籍详情、阅读、书架、搜索再做一遍后台的书籍和章节管理最后展示统计页。流程顺畅比花里胡哨的界面更能赢得老师好感。这些做完这个题目差不多就稳了。最后分享一个我做毕设时的体会这类项目真正的分水岭不在能不能跑起来而在能不能讲清楚为什么这么设计。代码写完只是第一步把每个模块的设计理由、每次排查问题的思路都整理清楚答辩时你才有底气。如果时间有余把书架自动更新、搜索缓存优化这两个点再深挖一下做成设计亮点写进论文里效果会更好。