背景痛点:学生项目常见问题
做毕设最怕“跑通就行”。很多同学把天气 API 的 URL、密钥、城市代码直接写死在 Controller,结果老师一换城市演示就 404;异常不处理,对方接口一限流,前端直接白屏;每次刷新页面都去打一次第三方,分分钟把免费额度打光。
这些问题总结起来就三句话:硬编码、无异常、重复请求。AI 辅助工具(GitHub Copilot / 通义灵码)能帮你快速生成功能代码,但如果不先想清楚“哪里该抽象、哪里该兜底”,AI 只是把坏习惯写得更快而已。
技术选型对比:别让“能跑”变成“只能跑”
HTTP 客户端:RestTemplate vs WebClient
- RestTemplate 进入维护模式,同步阻塞,高并发下线程数飙升。
- WebClient 响应式、非阻塞,配合 Spring WebFlux 一条线程扛 1k QPS 很轻松。
毕设并发不高,但答辩现场老师喜欢狂点刷新,WebClient 更稳。
本地缓存:Redis vs Caffeine
- Redis 跨进程、可集群,但多一次网络 I/O,本地笔记本还要再装服务。
- Caffeine 基于 LRU+TinyLFU,命中率 99%,引入一个 jar 即可,重启即清空,正合毕设“单机演示”场景。
最终组合:WebClient + Caffeine,既轻量又能扛并发。
核心实现:AI 帮你写骨架,你来做决策
下面示范“城市天气查询”模块,目标:高内聚、低耦合、可测试。
领域模型先行
让 AI 生成实体,Prompt:
“用 Java 17 record 定义一个 WeatherResponse,包含城市、温度、湿度、更新时间字段,添加 Swagger 注解”
得到:@Schema(description = "天气响应体") public record WeatherResponse( @Schema(description = "城市") String city, @Schema(description = "温度") Double temp, @Schema(description = "湿度") Integer humidity, @Schema(description = "更新时间") LocalDateTime updateTime ) {}声明式 HTTP 客户端
用 OpenFeign 代替手写 WebClient,Prompt:
“Spring Cloud OpenFeign 接口,调用 GET https://api.openweathermap.org/data/2.5/weather,返回 WeatherResponse,路径参数 q、appid,开启 gzip”
AI 直接给出:@FeignClient(name = "weatherClient", url = "${weather.api.base-url}") public interface WeatherClient { @GetMapping(value = "/data/2.5/weather", consumes = "application/json") WeatherResponse getWeather(@RequestParam("q") String city, @RequestParam("appid") String appId); }本地缓存层
引入 Caffeine,Prompt:
“Spring Boot 使用 Caffeine 缓存,过期时间 10 分钟,最大条目 1000,记录命中率”
生成配置类:@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager mgr = new CaffeineCacheManager(); mgr.setCaffeine(Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .recordStats()); return mgr; } }服务层兜底
在 Service 加@Cacheable("weather"),并捕获降级:@Service @RequiredArgsConstructor public class WeatherService { private final WeatherClient client; @Value("${weather.api.app-id}") private String appId; @Cacheable(value = "weather", key = "#city", unless = "#result==null") public WeatherResponse getCachedWeather(String city) { try { return client.getWeather(city, appId); } catch (FeignException e) { throw new BizException("第三方服务繁忙,请稍后再试"); } } }注意:AI 会忘记兜底,你要手动加
try/catch并转译成业务异常,保持 Clean Code 的“错误处理集中化”原则。
性能与安全:老师不一定会问,一问就要答得上
缓存过期策略
天气数据变化慢,10 分钟 TTL 足够;若担心雪崩,加随机 0~30 秒 jitter,防止集中失效。API 密钥管理
坚决不写进代码。- 本地开发:Spring Profile +
application-local文件里占位符${WEATHER_APP_ID},IDE 启动参数注入。 - 线上演示:GitHub Codespaces 的 Secret 或阿里云 SAE 环境变量,仓库代码里不出现真实值,答辩时直接展示环境变量页。
- 本地开发:Spring Profile +
防刷机制
用 Bucket4j + Spring Boot Starter 做接口限流,Prompt:
“基于 IP 的令牌桶,每秒 5 次,突发 10 次”
30 秒即可生成过滤器,老师现场狂点也不会把免费额度打光。
生产环境避坑指南:毕设也要“能上线”
冷启动延迟
Caffeine 在首次加载时构建缓存,可把热门城市(北京、上海、广州)提前预热,CommandLineRunner 里异步刷一次。第三方不可用
加断路器 Resilience4j,失败率 50% 即打开,5 秒后半开。AI 能生成模板,但阈值要根据免费额度调低。幂等性
虽然查询天然幂等,但统计调用次数的埋点表要防重复写入。给每次请求生成 UUID,数据库唯一索引兜底。日志与监控
引入 Micrometer + Prometheus,暴露/actuator/metrics命中率、QPS,答辩时给老师看 Grafana 大屏,加分项拉满。
把 AI 当成“不会累的结对伙伴”
整个开发过程里,AI 负责三板斧:样板代码、单元测试、注释润色。
但“决策”必须留在你手里:缓存时间、降级策略、异常转译,这些才是老师想听到的“你为什么这么做”。
把 Prompt 当成需求文档写得越细,AI 返回越贴合;写完立刻让 AI 生成 JUnit + Mockito 用例,Prompt:
“给 WeatherService 写单元测试,Mock WeatherClient,断言缓存命中时不会调用 Feign”
30 秒就能拿到可运行用例,再让 GitHub Actions 跑一遍,绿色小勾比任何口头解释都香。
结尾思考:下一步让 AI 帮你“提问题”
代码写完只是 50%,测试覆盖率、性能基准、安全扫描都得补。
试试把下面这段话丢给 AI:
“扮演面试官,针对我的天气预报系统,从性能、安全、可扩展角度提出五个尖锐问题,并给出改进代码”
你会发现 AI 比你更会“找茬”。
把生成的改进意见再喂回去,让 AI 继续重构——循环几轮,代码质量会呈指数级上涨。
毕设不是终点,学会“用 AI 提问”才是长期竞争力。祝你答辩一次过,把更多时间留给真正的创造。