写到这里,系列里已经出现过一长串名字:Sa-Token、MyBatis-Plus、Jsoup、ddddocr、MinIO……每次提到都只是一两句话带过。这一篇把它们集中起来,挨个说清楚四件事:**它是什么、GitHub 在哪、它在这个项目里干了什么、为什么适合这里。** 先说明一下写法。「为什么」这一栏,我不想写成「因为它很强大」这种废话,所以每一项我只写**在这个具体项目里** 它赢在哪,有时候也会写它不太舒服的地方。开源项目没有完美的,你用之前最好知道它的脾气。 项目的整体技术栈,在第 0 篇有一张表。下面按「后端 → 小程序 → 管理后台」的顺序来。 ## 后端 ### Spring Boot **是什么** :Spring 家族里「开箱即用」的那一层。自动配置、内嵌服务器、一堆 starter,让你不用从一堆 XML 或配置类开始搭项目。 **GitHub** :https://github.com/spring-projects/spring-boot **在项目里干什么** :整个后端的骨架,版本 3.2.5,JDK 17。有意思的是,它在这里跑的不是传统的 Servlet/Tomcat,而是 **WebFlux + Netty** (第 2 篇讲过为什么,以及两种模式并存带来的一堆坑)。 **为什么是它** :Java 后端的默认选项,没什么悬念。要连数据库、Redis、对象存储,要跑定时任务、发邮件,Spring Boot 的生态里每一样都有现成的 starter,时间可以花在「怎么用对」上,而不是「选什么」上。 ### Reactor 与 Reactor Netty **是什么** :Spring WebFlux 底下的响应式编程库(`Mono`、`Flux` 就是它的类型),以及基于 Netty 的 HTTP 服务端 / 客户端实现。 **GitHub** : \- https://github.com/reactor/reactor-core \- https://github.com/reactor/reactor-netty **在项目里干什么** :一是整个 WebFlux 的底层;二是 `WebClient`——调微博开放平台全部走它。三条经验之谈:连接超时和响应超时一定要设(项目里统一是连接 5 秒 / 响应 15 秒);阻塞的东西一律扔进 `boundedElastic`;ThreadLocal 在这里不可靠(Sa-Token 那个事故就是这么来的)。 **为什么是它** :迁到 WebFlux 之后它就是默认选项,说不上选择。不过要诚实地说一句:响应式的学习曲线是真的陡,调试起来也比同步代码费劲。**如果你的项目并发不大,同步的 Spring MVC 完全够用,而且更省心。** 这个项目里微博、教务、微信、OCR 这些外部调用特别多,大量时间在等 IO,响应式才有明显价值。 ### Sa-Token **是什么** :一个国产的轻量级 Java 权限认证框架,登录认证、权限认证、会话管理、踢人下线、单点登录这些都有,API 很短:`StpUtil.login(id)`、`StpUtil.getLoginId()`、`@SaCheckLogin`。 **GitHub** :https://github.com/dromara/sa-token (官网文档 https://sa-token.cc ) **在项目里干什么** : \- 小程序用户的登录态:登录身份就是微信 openid,`StpUtil.login(openid)`; \- 会话持久化到 Redis,重启不掉线; \- 管理后台**另起一个独立的登录体系** (`StpLogic("admin")`),和用户端互不干扰; \- 用 `@SaCheckLogin` 注解保护接口。 **为什么是它** :这个选型我之前专门写过一篇,[从 Shiro 到 Sa-Token](),里面讲了它比 Spring Security 好上手在哪。放到这个项目里,还有两个具体的理由:一是它有 **reactor 版的 starter** ,WebFlux 能直接用;二是「双体系」(用户端、管理端)开箱就支持。 踩过的坑也要说:**在 WebFlux 下它基于 ThreadLocal 的上下文会在切线程时丢掉** ,要自己处理(第 3 篇整篇都在讲这个)。这不是 Sa-Token 的问题,是响应式本身的问题,但你用的时候得知道。 ### MyBatis-Plus **是什么** :MyBatis 的增强工具。单表增删改查不用写 SQL,实体加个注解就能用。 **GitHub** :https://github.com/baomidou/mybatis-plus **在项目里干什么** :项目里的**阻塞数据通道** ——用户、敏感词、课表这些存量的表,大量还是走它。 **为什么是它** :最实际的原因是**存量代码** 。项目最早是 Servlet + MyBatis 的,WebFlux 是后来逐步迁的,没必要一次性全推倒重来。MyBatis-Plus 对简单 CRUD 的省力程度很高,只有复杂查询才需要自己写 SQL。 ### Spring Data R2DBC 与 MariaDB R2DBC 驱动 **是什么** :R2DBC 是「响应式的数据库访问规范」,可以理解成响应式世界的 JDBC。Spring Data R2DBC 在它上面做了 Repository 抽象,再配一个具体数据库的驱动。 **GitHub** : \- https://github.com/spring-projects/spring-data-relational (Spring Data R2DBC 在这个仓库里) \- https://github.com/mariadb-corporation/mariadb-connector-r2dbc **在项目里干什么** :**响应式的读路径** 。列表、课表、反馈这些读多的地方走它,仓储类大概有二十多个。 **为什么是它** :WebFlux 里如果数据库访问还是阻塞的,响应式的好处就被浪费了一半。所以读路径迁成了 R2DBC。 但它不是银弹,用的时候踩到的几个:对带非空 `@Id` 的实体,`save()` 会走 `UPDATE`,行不存在就报错,所以「有则更新无则插入」要**自己手写 upsert** ;这个驱动对 `null` 参数编码会报错,绑定前要把 null 清洗掉;代码注释里还记着一条——**Repository 的删除方法在这个工程里实测静默不生效** ,所以需要删除的地方,改用了显式 SQL。所以比较稳妥的分工是:**读路径用 R2DBC,复杂的写路径老老实实留给 MyBatis。** ### MariaDB **是什么** :MySQL 的开源分支,兼容性很好。 **GitHub** :https://github.com/MariaDB/server **在项目里干什么** :主库,所有业务数据都在里面,统一 `utf8mb4`(不然 emoji 存不进去)。 **为什么是它** :兼容 MySQL 的 SQL 和使用习惯,Java 这边用官方的 MariaDB 驱动就行,没有额外的学习成本。 ### Redis **是什么** :内存里的数据结构服务器,字符串、List、Hash、Set 都有,读写极快。 **GitHub** :https://github.com/redis/redis **在项目里干什么** ,这是整个项目里用法最多的一个组件: \- Sa-Token 的会话存储; \- **教务登录队列** (用 `List` 做 FIFO 队列)和**防重复提交的活跃锁** (`SETNX` 加过期时间); \- 评论缓存(空结果也缓存,但 TTL 更短); \- 管理端登录失败计数(账号 5 次 / IP 20 次,15 分钟窗口); \- 教务代理池。 **为什么是它** :一台 Redis 同时解决会话、队列、锁、缓存、计数五件事,运维上就一个组件。要提醒的只有一点:**一定要设超时** 。Redis 一抖,没有超时的请求会全部挂住(第 2 篇有这个教训)。 ### MinIO **是什么** :兼容 S3 协议的开源对象存储,一条 Docker 命令就能跑起来。 **GitHub** :https://github.com/minio/minio **在项目里干什么** :存所有的图片——投稿配图、教务验证码图、课表分享封面、反馈附件。 **为什么是它** :不用租云厂商的对象存储,自己一台机器就行;接口兼容 S3,将来想换成云上的,改配置就能换,不用动代码。图片的内网连接地址和对外访问地址要分开配(第 7 篇)。 ### OkHttp 与 Retrofit **是什么** :OkHttp 是 Java / Android 上最常见的 HTTP 客户端;Retrofit 在它上面做了「把接口写成 Java 接口」的声明式封装。 **GitHub** : \- https://github.com/lysine-dev/okhttp (原 square/okhttp,GitHub 会自动跳转) \- https://github.com/lysine-dev/retrofit (原 square/retrofit) **在项目里干什么** :**教务系统登录** 和微信接口。微博那条链路已经全部迁到了 WebClient(README 里叫「OkHttp 清零」),但教务这块还留着它。 **为什么还留着** :教务登录有两个需求 WebClient 不太顺手:一是要靠 **CookieJar** 管理 `JSESSIONID` 会话(第 12 篇讲过,会话要从 CookieJar 里取,不能靠响应头);二是要**按请求选择代理** 。这两个用 OkHttp 的 `CookieJar` 和 `ProxySelector` 很自然。**不是所有东西都值得迁。** ### Jsoup **是什么** :Java 的 HTML 解析库,支持类似 jQuery 的 CSS 选择器,容错很好,脏 HTML 也能解析。 **GitHub** :https://github.com/jhy/jsoup **在项目里干什么** :解析教务系统的课表页面。用 `div[class^=kbcontent]` 这种选择器取出每门课;登录页里有没有 `showMsg` 元素,也是靠它来判断登录成不成功。 **为什么是它** :解析外部 HTML 这件事,Jsoup 几乎是 Java 里的默认答案。它宽容——教务页面不是标准整齐的 HTML,用严格的 XML 解析器根本没法用。 ### Hutool **是什么** :一个国产的 Java 工具类大全,把字符串、日期、加密、JSON、集合这些零碎的活包成了顺手的静态方法。 **GitHub** :https://github.com/chinabugotech/hutool (原 dromara/hutool,GitHub 会自动跳转) **在项目里干什么** :项目里随处可见的小事:`BCrypt` 校验管理员密码、`SecureUtil.aes` 加密教务密码、`JSONUtil` 解析微博的返回、`RandomUtil` 取随机延迟。 **为什么是它** :省事。但也有一个提醒:Hutool 很全,容易让你什么都往它身上靠。像 AES 这种,**密钥长度这类细节它不替你检查** (第 12 篇那个 17 字节密钥的故事)。工具库省的是敲代码的时间,不替你做安全决策。 ### imgscalr **是什么** :一个很简单的 Java 图片缩放库,等比缩放、抗锯齿,几行代码搞定。 **GitHub** :https://github.com/rkalla/imgscalr **在项目里干什么** :投稿图片超过 1920×1080 时等比缩放,再压成 JPG。 **为什么是它** :只做这一件事,简单。它是一个相当老的库,属于「老但够用」——如果要做复杂的图像处理,该换别的。 ### ddddocr **是什么** :一个开源的通用验证码识别库,Python 写的,用深度学习模型,开箱即用,不需要自己训练。 **GitHub** :https://github.com/sml2h3/ddddocr **在项目里干什么** :识别教务系统登录时的验证码。我把它用 Docker 部署成一个独立的 HTTP 服务,后端通过 `POST /classification` 把图片(Base64)发过去,拿回识别文本。 **为什么是它** :不用自己训练模型,这是最大的省事。以独立服务的方式部署,Java 后端和 Python 模型完全解耦,后端只需要会发一个 HTTP 请求。准确率不是 100%(所以才有多轮重试),这是前面几篇一直在强调的一点。 ### springdoc-openapi **是什么** :给 Spring 项目自动生成 OpenAPI 文档和 Swagger UI。 **GitHub** :https://github.com/springdoc/springdoc-openapi **在项目里干什么** :生成接口文档,在 Swagger 页面右上角填入登录返回的 token,就可以直接调试需要登录的接口。 **为什么是它** :WebFlux 下用的是它的 `webflux-ui` 版本。接口一百多个,没有文档靠记忆是不现实的。 ### Lombok **是什么** :用注解(`@Data`、`@Slf4j` 之类)在编译期生成 getter/setter/日志对象这些样板代码。 **GitHub** :https://github.com/projectlombok/lombok **在项目里干什么** :实体类的 `@Data`,各个类里的 `@Slf4j`。 **为什么是它** :省掉大量机械代码。唯一的代价是:它依赖编译期注解处理,换 IDE 或构建工具时,偶尔要确认一下插件有没有装好。 ### Gradle **是什么** :构建工具,用 Groovy 或 Kotlin 写构建脚本。 **GitHub** :https://github.com/gradle/gradle **在项目里干什么** :项目用的是 Kotlin DSL(`build.gradle.kts`),依赖管理和打包都在里面,并且把阿里云镜像放在了仓库列表最前面(直连 Maven 中央仓在国内不稳)。 ## 小程序 ### Taro **是什么** :一个「一套代码,多端运行」的框架。你用 React 或 Vue 写,它帮你编译成微信小程序、支付宝小程序、H5 等等。 **GitHub** :https://github.com/NervJS/taro **在项目里干什么** :用 Vue 3 写微信小程序,版本 3.6.25。 **为什么是它** :原生写法(WXML / WXSS)写大项目比较吃力,TypeScript 和工程化也要自己折腾。Taro 让你能用 Vue 3 的 ` 发表评论 取消回复 使用cookie技术保留您的个人信息以便您下次快速评论,继续评论表示您已同意该条款 评论 * 私密评论 名称 * 🎲 邮箱 * 地址 发表评论 提交中...