每年到这个节点,总会有不少同学在选题上卡壳。做管理系统嫌太老套,做算法又担心自己撑不起来,左右为难。如果你也是这个状态,我强烈建议看看二手书交易系统这个方向,尤其是基于Spring Boot的那一套组合。这个题目看起来平平无奇,但恰恰是毕业设计和课程设计里性价比极高的选择,需求清晰、技术栈主流、工作量可控,关键是答辩的时候你有话可说。
这篇文章我会把自己做这个模拟项目X的全过程拆开揉碎了讲,从为什么选这个题,到数据库怎么设计,再到前后端联调里容易踩的坑,全部掏出来给你。我这套代码目前跑了差不多小半年,修修补补了好几轮,踩过的坑比你想象的多,写出来帮你省点时间。
1. 这个题目为什么值得做:需求认知与项目含金量
1.1 二手书交易系统的核心需求拆解
先别急着写代码,把需求搞透比什么都重要。二手书交易系统,说白了就是一个C2C的闲置图书流转平台,但你仔细拆一下会发现它其实涵盖了电商系统的大部分核心模块。
整个系统围绕着“书”这个商品展开,涉及买家、卖家、系统管理员三类角色。买家要能浏览图书、搜索筛选、加入购物车、下单购买;卖家要能上架图书、管理库存、处理订单;管理员要能做用户管理、图书审核、数据统计。这三条线交织在一起,其实就是一套完整的交易闭环。
我见过不少同学一上来就建了二十多张表,结果把自己绕晕了。其实核心就四张主表:用户表、图书表、订单表、购物车表,剩下的都是围绕它们展开的辅助表。你别小看这个系统,它既有商品管理(前后台都要维护)、又有交易流程(订单状态流转),还有权限控制(三角色分权),放在毕设这个层级的评判标准下,已经是一个非常丰满的题目了。
1.2 从技术面试的角度看这个项目的价值
有些同学担心这题太常见,到时候撞题。但我跟你说,企业招聘时看重的不是你的题目有多新颖,而是你在项目里体现出来的工程思维和解决问题的能力。
从技术栈的角度看,这个系统天然适合用Spring Boot来落地。它会用到Spring MVC处理请求路由,Spring Data JPA或MyBatis处理数据持久化,Spring Security或拦截器做权限控制,Redis做缓存和会话管理,再配合JWT做无状态认证。这一套流程走下来,最主流的企业级开发范式你就全部过了一遍。
更重要的是,交易系统天然带着“高并发”“数据一致性”“安全防护”这些关键词。哪怕你的实际场景根本没那么大并发,但只要你在文档或答辩时能说出“我用了Redis缓存热点图书信息,通过分布式锁避免超卖”,这个深度跟那种纯增删改查的管理系统之间,拉开的不只是一点差距。
1.3 课程设计与毕业设计的差异化定位
课程设计和毕业设计的要求其实差别不小,决定了很多细节上的取舍。
课程设计一般给的时间就一两周,重点是你把业务流程跑通,界面能用,核心功能都有,基本就能拿高分。这种场景下不用追求功能大而全,把卖家、买家、管理员三个角色的主线功能做好,前后端能通起来,就已经超过九成的人了。
毕业设计至少给一个学期,要求就上去了。这阶段你得有意识地构建一些亮点,比如引入Redis缓存,用消息队列或者定时任务来处理订单超时自动取消,设计一个合理的数据统计看板,这些都会成为答辩时的加分项。还有论文的硬要求,万字文档不是随便糊弄的,你的数据库设计ER图、UML用例图、系统架构图、时序图都得一整套路地画出来,光这个工作量就不小。
2. 技术选型的底层逻辑:为什么是Spring Boot这套组合
2.1 Spring Boot在当下生态中的权重
现在聊起Java后端,Spring Boot是绕不开的。那么多人选它做毕设,不是因为跟风,而是它确实把Java Web开发的效率拉到了一个很好的水平。
做传统SSM项目那种配置之苦,老开发都深有体会 —— 光是一个XML配置文件里各种namespace就能整得你怀疑人生。Spring Boot用自动配置把这堆事儿全干了,你只需要在pom.xml里引一个依赖,配置写在application.yml里,项目就能跑起来。这种“约定大于配置”的思路,对于毕业设计这种需要快速出活儿、同时还得讲清楚原理的场景,简直不能更合适。
另外,Spring Boot的生态整合能力也是一绝。它跟数据库交互的方案很多,跟前端做接口对接也很顺,甚至做部署的时候打一个可执行jar包就能跑,不需要装额外的服务器。这对想让老师现场看到Demo跑起来的同学来说,特别友好。
2.2 前端方案的选型:Vue3 + Element Plus组合的实战体验
现在的前端和后端,已经完全是两摊子了。后端老老实实出接口,前端专门写页面调接口,中间通过JSON做数据交换。
前端这块我对比过几个方案。传统的那套 —— 用模板引擎直接在页面里写Java代码,确实简单,但页面稍微复杂点就乱成一锅粥。另一种是前后端完全分离,用Vue作为前端框架,配合Element Plus这个组件库来做界面。
Vue3现在已经是市场主流了,上手曲线还算平缓。Element Plus是Element UI的升级版,专门给Vue3用的。全套组件都是现成的,表格、表单、弹窗、分页、上传,什么都有,你只需要拿过来按照文档配置一下就行。我做后台管理页面的时候,其实没有写太多的CSS样式,大部分界面元素都是Element Plus给的。而小程序端当时是直接放弃了,时间不够,而且利润不高,不如把所有精力都集中在Web端的体验上。
2.3 我踩过的那些SSM配置噩梦与Spring Boot带来的解药
说真的,我现在回头看以前做过的SSM项目,还能想起来被各种配置文件支配的恐惧。springmvc.xml、spring-mybatis.xml、web.xml,每个文件里面都得写一堆映射。
比如说,配MyBatis的mapper扫描器,配置路径写错一个字或者一个包名大小写不对,启动的时候就是各种层出不穷的报错。排查这种问题极其消耗耐心,而且对你的技术成长其实没啥帮助,纯粹是耐力训练。
Spring Boot的自动配置把这些全部藏在了背后。当然,它也不是魔法,底层原理还是要搞清楚的,但至少中间那些机械化的配置工作被省掉了。你会有更多的时间关注业务逻辑怎么写,表结构怎么设计,代码怎么组织,这些才是真正值钱的部分。
3. 数据库表结构设计:从用户到订单的完整链路
3.1 核心表结构设计与字段说明
数据库设计是整个系统真正的骨架,比代码还重要。因为代码可以重构,但表结构一旦定下来,后面再改就是牵一发而动全身。我这边整理一下自己项目的核心表设计,给你做个参考。
用户表(设计了用户ID、用户名、密码、昵称、头像、电话、余额等字段),这是所有模块的基础,每一张业务表基本都要跟它关联。我把用户表里的逻辑删除字段(is_deleted)也加上了,这算是做管理系统的基本素养 —— 数据不允许物理删除,只能打标记。
图书信息表涵盖图书ID、书名、作者、出版社、ISBN、原价、售价、成色、库存、封面图URL、图书描述、状态(在售/下架/已售出)等字段,归属卖家用户ID。ISBN这个字段实际使用中有奇效,你可以通过它去豆瓣或者图书相关的开放接口补充图书信息,比如封面图、内容简介,可以省下很多手工录入的时间。
订单表包括订单ID、订单编号、买家ID、卖家ID、图书ID、成交价格、数量、订单状态等字段。考虑到交易的复杂性,我还加了收货地址、联系电话和买家留言这几个字段,方便双方联系取货。订单状态我用了状态机的方式管理,从待支付到待发货、待收货、已完成再到已取消,每个状态之间的流转关系在代码里都做了严格校验,不允许跳状态。
购物车表含购物车ID、用户ID、图书ID、加入时间等字段,用唯一索引约束了用户和图书的组合,防止同一本书重复加入。
除了这四张核心表,我还做了管理员表、图书分类表、收藏表、轮播图表、通知公告表、评价表。评价表是后期加的,因为在测试过程中发现没有评价环节的话,整个交易链路其实是断的,买家买完就走,卖家也得不到反馈,没有平台的感觉。
3.2 设计过程中的关键考量与取舍
建表的时候有一个决策我觉得特别值得拿出来说:关于订单金额的存储类型。当时我查了很多资料,几乎所有的教程都会强调一个原则 —— 金额字段一定不要用float或者double,要用BigDecimal,或直接*100存整数。
为什么?因为浮点数在计算机中本身就是近似值,0.1 + 0.2可能等于0.30000000000000004,这在涉及真金白银的交易里是不可接受的。我当时初学的时候没在意这个,直到测试时发现书价算完总价对不上,差了零点零零几块钱,才明白这个坑有多阴。
另外,关于外键的使用,我后来也做了一次取舍。第一版设计时我用数据库层面的外键约束去保证引用完整性,后来发现查询性能会受影响,而且每次删除数据时约束检查都会占用额外开销。在开发阶段频繁改数据的时候,外键还经常导致删不掉数据,特别烦躁。后来应导师的建议,去掉了物理外键,改为在逻辑层面通过service层代码控制关联关系,数据完整性由应用层来保障,表之间的关联只保留逻辑关系。做了这个调整后,后面所有的批量操作都顺畅了很多。
4. 后端核心模块实现:从接口设计到权限控制
4.1 权限模型的选择与实现
权限控制我建议直接用拦截器加JWT的方式来做,别一上来就搞Spring Security,虽然它更强,但学习曲线有点陡。毕设时间有限,把核心业务做扎实比满汉全席搞一堆却都一知半解要好得多。
我的实现思路是这样的:用户登录成功后,后端根据用户信息生成JWT令牌返回给前端。前端把令牌存在本地,每次发请求时在HTTP Header里带上Authorization: Bearer token。后端写一个拦截器,对需要登录的接口做统一拦截,解析token,判断用户身份和角色,然后放行。
这种方式至少有两个好处。一是无状态,服务器端不需要存任何会话信息,对横向扩展友好;二是天然适合前后端分离架构,前端随便怎么换都没关系。而且你还能在拦截器里做很多统一处理,比如接口访问日志记录、token过期自动刷新之类的。
这里有个小细节,拦截器放行清单一定要配置好。登录、注册、图书列表、图书详情这些接口必须放行,因为用户没登录的情况下也得能浏览商品,不然谁来注册。而购物车、下单、修改图书这类操作就需要强校验了。
4.2 核心交易流程的代码实现解读
交易流程是整个系统的命脉,也是你答辩时最怕被追问的地方。我拿下单和超时处理这两个环节来详细讲讲。
下单接口的逻辑核心思想是“先锁库存、再生成订单”。具体的实现逻辑是:前端传用户ID和图书ID过来,后端先检查图书是否存在以及是否处于在售状态,然后检查库存,库存充足就尝试扣减库存数量并生成订单。同时需要判断图书的所有者是不是当前用户本人,因为不能买自己的书。
订单编号的生成也是一个很值得说道说道的地方。不要用简单的自增ID,因为订单编号往往需要具备唯一性和可追溯性。我用的方案是时间戳加随机数的组合:取当前时间的毫秒值再加一个3位的随机数,基本能保证唯一。如果你想更规范一点,可以加入日期前缀,做成类似20250115163025123这种格式,从订单号就能看出下单时间,出了问题也好排查。
关于订单超时未支付的自动取消逻辑,第一版时我用的方式是定时任务轮询数据库订单表,查出超过30分钟仍未支付的订单,然后修改状态为已取消,同时恢复库存。这种方式能跑通,但有一个明显的缺点:如果订单量大,频繁轮询数据库会带来较大的性能开销。而且轮询的最小时间间隔是一分钟,那么订单超时时间就有一分钟的误差,虽然业务上可接受,但总觉得不够优雅。
后来我优化成了延迟队列的方式。用户下单后,把订单信息同时推入一个延迟队列,给每条消息设置30分钟的延迟时间。等消费端收到这个消息时,先检查下订单的当前状态,如果还是待支付,就自动更新为已取消。如果这期间用户已经主动支付了,那这条消息就直接忽略掉。这个方案下的实时性和性能都比定时轮询好很多,而且在答辩时讲出来,含金量一下子就上去了。
4.3 Redis在系统中的实际应用场景
Redis在这套系统中的价值被严重低估的。很多同学做完项目,Redis就用了个缓存登录信息,其实这是一个非常值得深入挖掘的加分点。
我在系统中至少把Redis用在了三个场景:一个是缓存首页轮播图和公告信息,因为这类数据更新频率低、访问频率高,很适合放在缓存里;另一个是缓存热门图书榜单,通过Redis的ZSet有序集合给图书按销量和浏览量做排行,前端首页导航栏就能直接展示“热销榜单”和“新书速递”;还有分布式锁的简单应用场景,实现在多实例部署时防止并发请求导致超卖问题。
我先说下成本对比,帮你说服导师为什么要用Redis。如果在MySQL里做热门图书排行,你需要在图书表加一个查询字段,比如销量、浏览量,然后每次用户访问图书详情或者下单成功后,都要去更新这张大表,更新还会带来行锁竞争。而用Redis的ZSet,每个书的浏览量和销量作为score值,更新就是一次O(log n)级别的操作,排行榜查询直接取倒序前N个就行,响应速度基本上是毫秒级,同时还能定期把Redis的数据同步回MySQL落盘。
我在前台的商品列表页做了一个硬核加速方案:通过Spring AOP在一个查询方法的注解上面标注了缓存标记,第一次请求时把图书列表数据写入Redis缓存,后续的请求只要缓存没过期就直接从Redis拿,减少数据库的压力。当然,这里要考虑缓存和数据库的数据一致性问题,我使用了双删策略 —— 删除Redis中的数据、更新数据库、再次删除Redis中的缓存,基本能保证在并发场景也不会读到脏数据。
5. 前端页面的落地实现:从设计到联调
5.1 前端架构与关键路由设计
前端我用的是Vue3加Vite构建工具,配合Vue Router做路由管理。整体页面分成了两套体系:面向买家和卖家的门户端,以及面向管理员的后台管理端。
门户端的关键页面有:首页(也就是图书展示主页面)、图书详情页、购物车页面、订单确认页、个人中心、卖家图书管理页和发布图书页。买家通过首页了解平台推荐的热门书,点进详情页看书的成色描述和卖家信息,满意就顺手加到购物车。
后台管理端的关键页面包括:商品审核页、用户管理页、订单管理页、数据统计看板。后台管理端用的是Element Plus的栅格布局加侧边栏导航,这种经典的后台布局我大概用了不到两天就全做完了,如果你的工作量比较紧,抄这个路径可以省下不少时间。
这里重点讲一个关键点:路由守卫。这是很多同学容易忽略的地方。需求是这样的,如果用户未登录就访问购物车、订单中心这些需要登录态的页面,不能直接把用户扔到一个空白页,而是要自动跳转到登录页,登录成功后再跳转回原来的页面。这个能力我用的是Vue Router的全局前置守卫,在路由跳转前判断当前用户的登录状态,以及是否有访问目标页面的权限。如果既未登录又访问受保护页面,就重定向到登录页面,同时用redirect参数存下来源地址,登录成功后带着路由参数回跳。这个交互细节做好了,整个系统的体验感提升非常明显。
5.2 发布图书与图片上传的完整流程
图书发布是整个系统里前端逻辑最重的一个页面,因为信息项特别多,图书名称、作者、ISBN、分类、原价、售价、成色描述、图书封面、图书实拍细节图,一共有十来个字段要提交。
图片上传这一块要单独拎出来说。图书封面肯定不能像其他用户信息那样手动输入URL,这既不美观也不符合用户习惯。我当时用了Element Plus的Upload组件,做了一个OSS本地存储的方案:前端选择图片后向后端发一个multipart请求,后端接收文件后,校验文件类型和大小(图片类型限制在jpg、png格式,大小限制在2MB以内),然后给它重新生成一个唯一的文件名(防止中文名乱码和重名覆盖),存储到服务器指定目录下,同时返回这个图片的访问URL给前端,前端拿到URL后再跟其他表单字段一起提交。
我遇到的坑是图片上传和表单提交的时序问题 —— 用户可能先选了图片但没提交表单,这时候服务器上就产生了一个孤儿文件,时间久了会积累很多垃圾数据。解决方式是给上传接口加一个临时文件标记,当用户最终提交了完整的表单后再把临时文件转正为正式文件。如果用户最终取消了发布操作,则通过一个清理机制定期清理孤儿文件。虽然这个逻辑应用层不算复杂,但体现了你对数据一致性和系统资源消耗的思考。
5.3 前后端联调时的常见障碍
前后端分离开发时,联调阶段是最痛苦的。很多同学后端说接口测过了,前端也说自己页面没问题,但一拼起来就各种报错。
最常见的坑是跨域问题。浏览器的同源策略下,前端跑在8080端口,后端跑在8081端口,只要端口不一致,前端发Ajax请求就被浏览器拦截了。解决方案有几种:第一个是后端配置CORS(跨域资源共享),在响应头里加上Access-Control-Allow-Origin等字段,允许指定来源的跨域请求;第二个是用Nginx做反向代理,把前端的/api前缀的请求代理到后端服务地址,这种方案更接近生产环境。
我最初是直接在Spring Boot的WebMvcConfigurer里配置了CORS,开发时可以畅通无阻。但后来部署到服务器上做演示时发现,直接暴露后端端口不太好管理,又抽时间加了Nginx反向代理配置,这样网站对外只有一个80端口,统一走Nginx转发,前后端分离部署也更安全了。
另一个联调阶段容易踩的坑是接口返回的数据结构和前端期望的对不上。比如后端返回的时间格式是2024-01-15T10:30:00这种带T的ISO格式,前端Element组件库处理起来就需要额外转换。后来我在后端配置了全局的日期格式序列化器,统一转换成了yyyy-MM-dd HH:mm:ss这个格式,前端就省去了好多额外的工作。还有空值的处理,如果后端返回的字段有空值,前端展示时要注意做兜底处理,不能直接显示“null”或者“undefined”在页面上。
6. 安全加固与性能优化:答辩时的加分武器
6.1 接口安全防护的实践
做交易系统,安全这块不强化一下是说不过去的。哪怕你做的只是个演示项目,老师如果问你别人恶意下单怎么办、被人把接口盗刷了怎么办,你不能说不出个一二三。
登录接口的防暴力破解是第一站。我在登录接口加了简单的防刷机制:同一个IP在1分钟内的失败登录次数超过5次,就会被封锁10分钟。用Redis的计数器实现,key是IP加日期加小时的组合,value是失败次数,同时设置了过期时间。这个代码量很少,但讲出来很出效果。
SQL注入防护方面,因为我用的是MyBatis-Plus配合#{}占位符来写SQL,它底层就是预编译机制,天然防注入。这里有一个重要提醒:不要图省事用${}直接拼接字符串,我在代码审查时发现一些团队喜欢用这种方式来做动态排序,这就是给黑客送弹药,千万别学。
XSS跨站脚本攻击的防护也不能忽视。用户在前台提交图书描述时,如果恶意用户提交一段包含<script>标签的内容,这些脚本在其他用户浏览时就会被执行。我在后端加了一个全局过滤器,对请求参数中的<、>、"、'等特殊字符做HTML转义处理,把它变成无害的实体字符。虽然这个策略会牺牲一点点富文本展示的灵活度(有些用户想在描述里写点HTML格式的内容会受影响),但安全大于体验,何况毕设场景完全够用了。
6.2 密码加密与数据脱敏的硬性要求
密码加密这件事,如果你的数据库里存的是明文密码,答辩时基本是送人头。这不是基础问题,而是安全素养问题。
正确的做法是使用不可逆的哈希算法加盐存储。Spring Security框架自带一个BCryptPasswordEncoder,它是基于Blowfish算法的加密实现,每次对同一个密码加密得到的密文都不同,因为在计算过程中加入了随机盐值。用户登录时,再把用户输入的密码跟数据库里的密文进行比对校验。这个方案在校验时不需要解密数据库里的密文,只需要用同样的算法重新计算一次比对即可,所以要安全得多。
除了密码,用户手机号、收货地址这种敏感信息也要注意脱敏处理。比如前端展示时只显示138****1234,后端接口返回的数据在需要脱敏的字段上统一用工具类处理,避免把完整的隐私数据暴露在日志中和不必要的接口返回中。虽然系统是课程设计,但从一开始就培养这个意识,对你以后工作很有帮助。
6.3 数据库性能优化的进阶实战
数据量一大,各种慢查询就找上门了。我用课程设计的模拟数据量测过,也就几万多条数据,加不加索引的差距就已经很明显了。
图书表的查询条件集中在书名、作者、ISBN和分类这几个字段上,这些字段我都建了索引。但这里有个细节需要注意,单列索引在组合查询时的效果有限,比如前台经常用的“按分类加关键词搜索”,我给(category_id, status)建了一个联合索引,因为大多数搜索场景都限定在在售这个状态下,把状态跟分类放在一起做联合索引,能减少回表次数。
还有一个很容易被忽略的性能问题:N+1查询。比如查一个订单列表,查询出订单之后,你需要逐个查询订单关联的图书信息,一个订单查一次数据库。如果一页显示10条订单,就是1次查询加10次查询,共11次数据库交互。这种写法在数据量越小的时候越不容易暴露,但数据量上来了之后系统就会越来越慢。解决办法是使用连表查询一次性把订单和图书信息都查出来,或者用MyBatis-Plus的高级功能做嵌套结果映射。这种优化思路在很多真实项目里也是常考常问的,提前打个底子不吃亏。
7. 课程设计实战中的避坑指南
7.1 我从第一版到最终版迭代中踩过的坑
第一版我急着写代码,几乎是想到哪写到哪的节奏。登录逻辑写完了就写图书中心,测试的时候顺手发现一个bug就改一下,改完继续往下加功能。这么搞了两周,代码倒是写了不少,但维护起来要命 —— 很多功能模块之间耦合得很厉害,改一个地方没准把另一处功能弄崩了,而且数据库设计也没仔细想,字段类型和长度不合适的隐患不少。
后来我彻底推倒重构了。先花了两天把数据库表结构重新梳理了一遍,把用户和订单整理出清晰的一对多关系。然后代码按controller、service、mapper三层结构重新组织,接口统一以/api前缀开头,返回值统一封装成Result对象,包含状态码、消息和数据三个部分。这么一整理,写代码的速度反而比第一版快了一倍,因为思路理顺了,不用每次现想。
一个有代表性的坑是LocalDateTime字段的JSON序列化问题。Spring Boot默认的Jackson序列化LocalDateTime时,输出是一串数组格式,比如[2024, 1, 15, 16, 30, 25],前端根本没法直接用。后来我在配置里加了一个Jackson2ObjectMapperBuilderCustomizer,设置好日期格式和时区,才算彻底解决。这种细节问题,不踩一次坑根本注意不到。
7.2 文档编写的技巧与答辩经验分享
很多同学文档写得痛苦,其实是因为代码写完才开始对着代码回忆流程。我的经验是先写文档骨架再补代码细节 —— 开题时就把系统设计的整体框架定好,写清楚系统的各个模块和功能,之后实现时把关键代码段、数据库设计、测试结果往里面填就行。
文档和答辩的核心思路是一致的:不断自问“为什么”。为什么用Spring Boot而不是普通Java Web?答案是快速开发能力和生态体系。为什么会选择Redis缓存?答案是把高频访问的图书信息和热门榜单放到内存中来降低数据库压力,提升响应速度。为什么订单状态要单独建一个枚举类而不是直接在代码里写魔法值?答案是代码可读性和设计规范。
答辩的时候一定要准备的几个问题:超卖问题怎么解决?密码是怎么加密的?购物车是怎么设计实现?用户登录后的token什么时候失效?每个功能模块背后的实现逻辑,最好是三句话能说清楚 —— 做了什么、怎么做的、为什么这样做。
7.3 推荐的学习路径与项目扩展方向
如果你的基础还不太扎实,建议按这个顺序学:先过一遍Maven构建工具和Git版本控制,再学Spring Boot的基础注解和依赖注入,然后是MyBatis-Plus的增删改查和分页查询,接着是Vue3的组件化开发和路由管理,最后是前端的调用接口联调。这个路径走下来,一般两三周就能跑通基础流程,剩下的时间都可以拿来打磨细节和做优化了。
系统后续可以扩展的方向其实很多。比如接入在线支付功能,支付宝或者微信支付的沙箱环境都可以模拟;比如增加图书推荐算法,通过协同过滤或者基于用户行为的简单推荐,给不同用户推荐可能感兴趣的图书,这就蹭上了机器学习的热点;再比如做一个移动端的小程序版,跟Web端共享同一套后端接口,工作量也不大,但在成果展示上呈现出一个完整的跨平台产品,效果会好很多。
8. 写在最后的实操心得
这套系统我前前后后写了小半年,最大的体会是:毕设项目不求多炫酷,但求把每个环节做扎实。数据库设计想清楚,核心交易链路捋顺,加上安全与性能的思考,就已经是相当完整且有说服力的作品了。技术永远在更新,可解决实际问题的思路和排查问题的能力,是任何时候都能用上的硬通货。
最后再分享一个小技巧:一定不要装着项目只做一次,三不五时跑起来用一用。你亲手写完的代码,一个月之后回来看,可能会认不出来 —— 别问我怎么知道的。平时养成定期运行测试、随手补充注释的习惯,到写文档和准备答辩的时候,会感谢当时勤快的自己。