news 2026/10/7 17:36:34

基于Java与Spring Boot的课表日程提醒管理系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Java与Spring Boot的课表日程提醒管理系统设计与实现

刚接手这个课题的时候,说实话我以为是又一个普通的增删改查管理系统。但真正开始落地"基于Java的课表日程提醒管理系统设计与实现"时才发现,课表不是简单一个CRUD就能打发的,课程的时间维度、单双周逻辑、调课联动、提醒任务调度,每一块拆开都是值得好好打磨的工程点。这篇文章我就把完整的项目思路、表结构设计、冲突检测算法和定时提醒实现完整拆开讲,适合正在做Java课程设计、准备面试时被问项目经验,或者单纯想用真实项目练手Spring Boot和定时任务的读者。

课表日程提醒管理系统,核心就解决两件事:第一,把复杂、易变动的课表变成结构化数据,自动检查冲突;第二,在课程开始前指定时间点,稳定可靠地提醒用户。很多人觉得手机日历够用了,但实际使用过一个学期就会发现,单双周、调课、跨周课程这些场景在通用日历里维护起来非常痛苦。这就是这个系统存在的价值。

1. 为什么需要自建课表日程提醒管理系统:先从手动维护课表的崩溃说起

1.1 手动备忘录处理课程排期的真实痛点

大学课表有几个经典难点,是普通备忘录和通用日历工具很难解决的。第一是单双周,一周上这门课、下一周不上,在通用日历里你得建两条重复事件,还得手动跳过反方向的那一周,维护成本非常高。第二是临时调课,老师出差、教室冲突、法定节假日调整,课程时间一变,一系列后续提醒全部作废,手动改起来极其痛苦。第三是跨周课程,比如"第3周至第16周,每周一上午",这种周次范围的概念在通用日历里没有原生支持。

我自己之前用手机自带日历维护过一学期的课表,一个调课通知就能让我同时改四个入口,改完还要担心漏掉哪一个导致记错教室。等到真正做过这个Java项目,我才深刻感受到:课表数据不是简单的时间事件集合,它有自己的领域模型,应该用周次掩码、星期维度和节次维度去建模,把这些痛点彻底结构化掉。

1.2 系统到底应该管哪些事:范围界定

做系统最怕一开始就想做"大而全",所以我先明确边界。这个课表日程提醒管理系统解决四个核心问题:

  • 课程管理:维护课程名称、授课教师、上课地点、起止周次、星期几、开始节次和持续节次。
  • 冲突检测:新增或修改课程时,自动检测同一时间维度下是否与已有课程冲突,冲突维度要覆盖学生、教师、教室三类资源。
  • 日程提醒:针对每门课程设置提前N分钟提醒,系统在到达触发时间点后通过站内消息、邮件或第三方推送渠道通知用户。
  • 确认闭环:用户收到提醒后标记"已确认",避免同一个提醒反复打扰。

像成绩管理、选课审批、教师考勤这些功能,在这个项目里我全部砍掉。因为一旦扩大范围,核心的规则引擎和调度链路反而会被冲淡。项目做得好不好,不是功能多不多,而是核心链路稳不稳。

1.3 适用场景与功能清单

这套系统最典型的使用者是两类人。一类是高校在读学生,需要一个能hold住单双周和调课的私人课表工具;另一类是教务或班级管理者,需要统一发布课表并确保重点课程不被遗漏。对Java学习者来说,这个项目包含的对象关系映射、事务控制、日期时间处理、定时任务、锁机制、结构化检索,恰好覆盖了企业级开发的主要高频技能点。

我最终落地的功能清单如下:用户登录与课表隔离、课程增删改查、批量导入课程表、时间冲突自动校验、单双周及跨周处理、提前提醒配置、定时扫描提醒、重复提醒防抖、提醒记录查询、调课联动修改提醒任务。这个清单对应了后端的整个代码骨架,下一节就讲技术选型为什么这么组合。

2. 技术选型与整体架构设计:Java生态下的务实组合

2.1 为什么是Spring Boot加MyBatis加MySQL

后端我选的就是最主流的组合:Spring Boot 2.7作为基础框架,MyBatis作为持久层,MySQL 8.0作为数据库。这样选不是因为它最时髦,而是因为它最稳、最好招人、也最好排查问题。

Spring Boot在这个项目里解决的是"配置地狱"问题,内嵌Tomcat后直接java -jar就能启动,对课程设计、毕业设计场景特别友好。MyBatis我坚持用XML写SQL而不是用注解,原因很简单:课表冲突检测里会涉及到多条联表查询和动态条件拼接,XML里写 比在Java代码里拼字符串要清晰太多,而且后续万一要换成MyBatis-Plus,底层的映射思想也是一脉相承的。

为什么不引入Redis,也不引入消息队列?我明确告诉你,这个项目的访问量级根本不需要。提醒任务本质上是一个定时轮询然后推消息的动作,数据库完全可以支撑。过度引入中间件只会让刚入门的读者被环境搭建劝退。真正的性能优化留给缓存层处理,后面我会专门讲。总之,技术选型的核心原则是:用最少的组件解决最多的问题,每个组件都要能说清它的不可替代性。

2.2 定时任务框架的三选一:Spring Task、Quartz还是XXL-Job

提醒系统的灵魂在定时任务,所以框架选择我单独拎出来对比。网上经常有人一上来就推XXL-Job,但我个人建议小项目优先从Spring自带的@Scheduled或Quartz起步,原因看下面这张对比表:

方案学习成本分布式能力任务持久化适用场景
Spring @Scheduled极低无无单机轮询扫描,适合课表提醒量级
Quartz中等需自行实现支持JobStore持久化按课程生成精确触发任务
XXL-Job较高完整支持支持多服务节点、需要调度控制台

实际开发里我采用了混合策略:课程提醒的扫描任务用Spring @Scheduled每30秒跑一次,因为这类任务只需要查"到点未提醒"的数据,天然适合轮询;而每个用户自定义的精确时间提醒,如果未来量大、需要暂停恢复、错峰执行,再演进到Quartz也不迟。起初就用@Scheduled完全够用,而且调试时直接打断点非常方便。后面第5节我会给两种方案的完整代码,你先看场景再选型。

2.3 模块划分与一次完整请求的流动路径

这个项目的后端模块我分成四层:Controller层负责参数接收和响应封装,Service层承担业务规则比如冲突检测,Mapper层做数据访问,还有独立的reminder包专门放定时任务和推送逻辑。为了不把代码写成一坨,我额外抽了三个工具类:WeekMaskUtil做周次位运算、TimeSlotUtil做节次时间槽计算、DateUtil做日期边界处理。

一条完整的新增课程请求,流动路径是这样的:前端提交课程参数到CourseController,校验基础字段后交给CourseService,Service里先转换时间段对象,调用TimeSlotUtil检测与已有课程是否相交,相交则抛出业务异常,否则事务性地插入课程表,并根据remindBeforeMinutes生成一条待触发的提醒记录,写入提醒任务表。整个流程保证要么课程和提醒一起成功,要么一起回滚。这个事务边界也是项目的一个关键设计点,很多新手在这里会漏掉提醒记录的一致性。

3. 数据库设计:用周历模型撑起课表的时间维度

3.1 六张表的设计逻辑

课表系统如果只建一张course表,后期会非常痛苦。我把数据拆成六张表:用户表sys_user、课程表course、提醒配置表remind_config、提醒记录表remind_record、教室表classroom、调课记录表course_adjustment。有人会问教室表是不是冗余,其实不做不知道,一旦要做"按教室检测冲突",教室就必须有独立表并被课程引用。

课程表的设计是这个项目最核心的建模。我用了周次起止+星期+节次起止三个维度描述一门课的上课时间,再用一个week_mask字段解决单双周和跳周问题,这个字段值得展开讲,见3.2节。提醒方面,课程与提醒配置是一对多关系,因为同一门课可能同时需要"提前30分钟""提前一天"两个提醒,这也符合真实场景。

3.2 周次掩码:用位运算表达任意周次规则

单双周问题很多人用week_type=1|2硬编码解决,但遇到"第3到第10周上课,其中第5周停课"就完全不够用。我采用的方案是:在课程表里存一个week_maskBIGINT字段,把1到64周映射到二进制位,第i周上课则第i位为1,否则为0。

一门"第1周到第16周每周一上课"的课程,week_mask就等于0b1111111111111111,也就是十进制的65535。如果是"单周上课",mask就是所有奇数位为1。判断某周是否上课,代码就是:

public static boolean isWeekActive(long weekMask, int weekOfTerm) { if (weekOfTerm < 1 || weekOfTerm > 64) { return false; } return (weekMask & (1L << (weekOfTerm - 1))) != 0; }

位运算一次判断完成,没有任何循环。调课、停课只需要动态修改mask的某一位,比一堆区间判断干净得多。这个方案也是我在这个项目里最满意的一个设计点,面试被问到"怎么处理单双周"时,这个回答能说明你确实思考过领域模型的本质。

3.3 核心建表SQL参考

下面是我实际使用的核心建表语句,删减了部分非关键字段方便阅读:

CREATE TABLE `course` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `user_id` BIGINT NOT NULL COMMENT '所属用户', `course_name` VARCHAR(128) NOT NULL COMMENT '课程名称', `teacher_name` VARCHAR(64) DEFAULT '' COMMENT '授课教师', `classroom_id` BIGINT DEFAULT NULL COMMENT '教室ID', `day_of_week` TINYINT NOT NULL COMMENT '1-7 表示周一至周日', `start_section` TINYINT NOT NULL COMMENT '开始节次', `end_section` TINYINT NOT NULL COMMENT '结束节次', `week_start` INT NOT NULL COMMENT '开始周次', `week_end` INT NOT NULL COMMENT '结束周次', `week_mask` BIGINT NOT NULL COMMENT '周次位掩码', `remind_before_minutes` INT NOT NULL DEFAULT 30 COMMENT '提前提醒分钟数', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 0停用', `create_time` DATETIME NOT NULL, `update_time` DATETIME NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程表';
CREATE TABLE `remind_record` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `course_id` BIGINT NOT NULL, `user_id` BIGINT NOT NULL, `remind_time` DATETIME NOT NULL COMMENT '计划提醒时间', `actual_notify_time` DATETIME DEFAULT NULL COMMENT '实际推送时间', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待触发 1已推送 2已确认 3已取消', `retry_count` INT NOT NULL DEFAULT 0, UNIQUE KEY `uk_course_remind` (`course_id`, `remind_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提醒记录表';

注意uk_course_remind这个唯一索引,它是我防重复提醒的第一道屏障。同一门课在同一提醒时间只能有一条记录,数据库层面堵死了并发重复插入的可能。这个细节建议直接抄进你自己的项目里。

3.4 容易被忽视的边界情况:跨学期、跨天和节假日

数据库设计时一定要想清楚时间边界,否则代码写一半会卡住。第一是跨学期,某些课程从第17周考完试、第18周开始实训,我引入了term_id字段做学期隔离,所有课表检索都带上term_id,避免跨学期的周次串号。第二是跨天提醒,比如周一早上8点的课,用户设置提前12小时提醒,触发时间就是周日的20点,扫描任务必须能处理"提醒时间落在昨天但课程在明天"这种跨天逻辑,所以提醒记录表里直接存remind_time绝对时间,而不是存"提前N分钟"这种相对值。第三是节假日,我的建议是维护一张holiday表,扫描提醒时如果当天是节假日则自动顺延或取消提醒,状态置为3。这个功能虽然不复杂,但很体现产品思维的完整度。

4. 课程冲突检测与周次解析:核心算法的工程化实现

4.1 时间槽相交检测的几何建模

冲突检测的本质是判断两个时间段是否在"同一时间维度"上重合。对于同一用户、同一学期、同一天的两门课,如果第3节到第4节的课程和第4节到第5节的课程产生了节次重叠,就是冲突。

我检测时先用节次换算出绝对时间。假设一个标准课时段是:第1节08:00-08:50,第2节09:00-09:50,每节课后休息10分钟。那第3节的开始时间就是10:00,结束是10:50。换算后课程A的时间槽是[10:00,10:50],课程B是[10:50,11:40],两个区间左闭右开,边界不重叠,所以不冲突。判断两个左闭右开区间[t1,t2)和[t3,t4)是否相交的核心条件是t1 < t4 && t3 < t2,这比一堆if嵌套清晰得多。

但在同一天同一用户下检测节次重叠,其实连时间换算都不用,直接用start_section和end_section判断:A.startSection <= B.endSection && B.startSection <= A.endSection。规则就是:只要A的开始节次不晚于B的结束节次,且B的开始节次不晚于A的结束节次,就一定重叠。我同时把用户、教师、教室三个维度分别做检测,一个课程实例可能因为占用同一间教室而冲突,也可能因为占用同一位老师而冲突,三类资源冲突需要分别提示用户具体原因。

4.2 周次掩码与单双周的实际解析

周次掩码除了判断"某周是否上课",还要解决"两门课是否在同一周共同上课"的问题。比如课程A是单周上课,课程B也是单周上课,虽然它们都在周三第3-4节,但week_mask的按位与结果非0,所以确实冲突。

这一步我把4.1的节次重叠条件再叠加周次相交判断,完整冲突条件如下:

day_of_week 相同 AND start_section/end_section 有重叠 AND (week_mask & other_week_mask) != 0

三条同时满足才叫冲突。注意这里不能直接week_mask == other_week_mask,因为两门课的授课周次范围可能一个是1到16周、另一个是9到20周,它们只有一部分重叠,必须用按位与。这个位运算方案可以同时处理"单双周""跨周""临时停课"三类情况,代码量却只有几行。

4.3 新增课程与调课时的冲突校验流程

新增课程的流程我前面提过,这里补一个调课场景。调课是最容易产生脏数据的操作,因为原始课程已经被公告通知过了。我设计了一个course_adjustment表记录调课记录,每次调课实际执行三步:先把原课程state置为停用并把提醒记录置为取消;再新增一条新时间的新课程记录;最后把原课程和调课记录关联起来。这么做的好处是历史数据完整保留,用户可以对比查看"原时间"和"新时间",不会因为直接update把轨迹抹掉。

校验冲突时,要特别注意必须排除掉自己。修改课程时如果先把课程数据查询出来再把自己的id加入待校验集合就会误报冲突,我踩过这个坑。正确做法是把当前课程id从待校验列表中移除,或者直接用"新时间槽与已有全量课程冲突检测,如果冲突的课程id等于当前id则跳过",二选一即可。

4.4 批量导入课表时的性能与正确性

很多人会把课表从教务系统复制出来,以Excel形式导入。批量导入时最坏情况是几千门课做两两冲突检测,复杂度是O(n²),如果每一对都走数据库查询,性能直接崩掉。我的优化思路是:先把已有课程按user_id+day_of_week聚合到Map里,key是"用户ID-星期几",value是这一天的课程列表,然后新课程进来只需要跟同一天的课程比较,查询范围瞬间缩小。在这个基础上再做一次week_mask的预过滤,如果两门课的mask按位与为0,连节次重叠判断都可以跳过。

5. 定时提醒的全链路实现:轮询扫描、精确调度与幂等推送

5.1 基于Spring @Scheduled的到期扫描任务

这是项目的核心运行逻辑。我用@Scheduled(fixedRate = 30000)每30秒扫描一次提醒记录表,查到所有status=0且remind_time <= now的记录,然后逐个推送。为什么用30秒而不是1秒?因为课表提醒是分钟级精确度的场景,提前30分钟提醒,误差30秒完全不影响体验,但数据库扫描压力却小了30倍。

扫描任务的伪代码逻辑如下:

@Scheduled(fixedRate = 30000) @Transactional public void scanExpiredRemind() { List<RemindRecord> records = remindRecordMapper.selectPendingExpired(new Date()); for (RemindRecord record : records) { // 先尝试原子化抢锁更新状态 int updated = remindRecordMapper.compareAndSetStatus( record.getId(), 0, 1, new Date()); if (updated == 0) { continue; // 其他节点已经处理 } pushService.push(record); } }

这里最关键的是compareAndSetStatus,它执行的是UPDATE remind_record SET status = 1, actual_notify_time = ? WHERE id = ? AND status = 0。这条SQL只有恰好把status从0改成1的请求才会返回影响行数1,其他并发请求返回0直接跳过。这就是数据库层面的乐观锁,比在Java代码里加synchronized要可靠得多。

5.2 触发方式对比:扫描式还是任务式

如果课程数量特别大,比如几千个用户每人十几门课,全表扫描的代价会逐渐上升。这时可以给remind_record表的remind_time和status建联合索引,扫描效率依然能撑住。但如果想更进一步,就按2.2表的对比演进到Quartz,在创建提醒记录时同时生成一个一次性Trigger,到点直接触发任务执行。

我用Quartz做过一版原型,大致流程是:创建提醒记录后,用JobDataMap携带courseId和recordId,调度一个SimpleTrigger在remind_time时刻执行推送,推送完成后删除自己的触发器。这个方案的好处是完全不需要轮询,任务准时精确;缺点是每次课表变动都要同步更新Quartz里的trigger,如果用户改了上课时间而Quartz任务没跟着改,就会出现"任务到点了,但课程已经取消了"的尴尬局面。

所以要我说,课表场景的提醒更适配轮询扫描,因为课程变动频率并不低,扫描式方案天然容忍数据变化,每次扫描都读最新状态。Quartz精确调度适合的是"固定不变的一次性会议提醒"。选型没有绝对优劣,看数据变动频度。

5.3 并发分布式部署下的防重提醒

当项目部署到多个节点时,定时任务会在每台机器上各跑一遍,如果不做处理,用户会被相同提醒轰炸。我在5.1里已经通过compareAndSetStatus解决了数据库层的并发覆盖问题,但还有一个细节:如果多台机器同时扫描,可能同一条记录被不同节点先后读到,前面节点推送成功但事务未提交,后面节点读不到,所以不会重复,这条路径没问题;但如果事务提交前另一边已经读到旧数据就会出问题。

更稳妥的额外方案是用Redis分布式锁,但为了少引入组件,我只用数据库唯一索引加CAS更新。这个方案在上线后验证下来没有任何重复推送的实际案例。面试中如果有人问你"怎么防止定时任务重复执行",你回答出数据库状态机CAS+唯一索引,就已经比只会说synchronized的人高一个段位了。

5.4 推送渠道的抽象设计

提醒最终要通过某种渠道触达用户,我把推送逻辑抽象成接口:

public interface RemindPusher { void push(RemindContext context); }

默认实现是站内消息,往notify_message表插一条记录,用户登录后在右下角看到红点。第二版我加了邮件推送,用JavaMailSender发送HTML格式的提醒邮件。如果要接入微信公众号或钉钉机器人,只需要新增一个实现类,完全不用改动扫描任务代码。这就是面向接口设计在真实项目里的价值。实际测试时我强烈建议先用站内消息跑通全链路,再去接邮件或第三方推送,否则排查问题时很容易分不清到底是定时任务没触发,还是第三方接口没调通。

6. 踩过的坑与性能优化:从开发调试到稳定运行的真实复盘

6.1 服务器时区错乱导致提前一小时提醒

这个坑我在开发环境完全没遇到,一部署到服务器就出现了:所有提醒都提前了8小时触发。查了半天发现是服务器的/etc/timezone没有设置成Asia/Shanghai,而MySQL连接串里也没有加serverTimezone=Asia/Shanghai参数。Java程序在启动时读取本地时区,数据库连接又因为JDBC规范统一转成UTC存储datetime,两边时区一错位,时间判断就全乱。

解决方案分三步:第一,服务器执行timedatectl set-timezone Asia/Shanghai;第二,JDBC连接串显式加上serverTimezone=Asia/Shanghai&useLegacyDatetimeCode=false;第三,所有Java代码里创建日期一律用LocalDateTime.now(),禁止用new Date()再手动减8小时这种骚操作。做完这三步,提醒时间才和本地完全一致。

6.2 批量导入课表的批量插入优化

批量导入Excel课表时,我最初用的是MyBatis的<foreach>循环insert,3000条数据跑了接近一分钟,原因是一条条insert的数据库往返太慢。后来改成MyBatis的批量执行器,sqlSession.getMapper(CourseMapper.class)配合ExecutorType.BATCH,把3000条压缩到几百毫秒。还有一个隐藏优化点:导入前先清空该用户当月已生成的未触发提醒记录,再重新生成,避免旧课程被停用后提醒记录变成僵尸数据。

6.3 统一异常处理与空指针排查

这个项目的异常处理我建议用@RestControllerAdvice统一拦截,把业务异常Spring自带的BizException和参数校验异常分开处理,前端就能拿到统一的响应结构。数据库时间字段容易查到null,如果用getRemindTime()直接参与计算就会NPE,我把所有时间字段的Mapper查询都加了COALESCE处理,同时Java侧强制用包装类型接收并在入口处做空校验,双保险。

6.4 缓存课表热数据与提醒预生成

运行一段时间后,我观察到列表查询接口频繁读course表,而且很多查询是为了检测冲突。优化方式是把每用户每天的课表列表缓存在本地内存里,加一个volatile标志位防并发,课程变更时直接失效缓存。因为课表数据最大量级也就几千条,用本地缓存比引入Redis更省事。提醒预生成方面,我每天凌晨跑一个任务,为未来24小时内到期的课程提前生成提醒记录,这样扫描任务只需要查record表而不用频繁关联course表,整个链路持续稳定运行。

最后再分享一点个人体会:这个项目最大的收获不是CRUD本身,而是理解了领域建模的重要性。课表不是简单的"事件+时间",它包含周次、节次、资源维度,需要真正吃透业务才能设计出week_mask这种恰到好处的方案。如果你也想拿这个项目练手,建议从最简单的单用户课表做起,先把冲突检测和提醒扫描跑通,再逐步加上批量导入和调课联动,每一步都踩实了再往前走。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 17:36:31

DeepSeek Harness 桌面端实战:AI Agent 工程化与内网部署指南

DeepSeek Harness 官方桌面端终于有了&#xff01; 这消息在技术社区里其实比很多人想象的要大。过去大半年&#xff0c;大家讨论 AI Agent 基本停留在"用 API 调模型"或者"跑个交互脚本"的层面&#xff0c;真正把 Agent 当成一套工程系统来管理的工具少之…

作者头像 李华
网站建设 2026/10/7 17:34:47

开源扫地机器人全栈拆解:从SLAM建图到路径规划二次开发实战

1. 一台扫地机拆出来的全栈知识地图第一次把一台开源扫地机器人完整拆开、跑通建图、再自己改了一版路径规划算法之后&#xff0c;我最大的感受是&#xff1a;这东西根本不是什么"高级玩具"&#xff0c;它是一套被压缩进塑料壳里的机器人工程课程。你花几百块买一台开…

作者头像 李华
网站建设 2026/10/7 17:34:29

Label Studio Source Storage 配置指南:对象存储同步与排障实战

1. Source storage 到底是干嘛的&#xff1a;先搞懂同步模型&#xff0c;再动手点界面 做标注项目做到数据量上来之后&#xff0c;最烦的就是怎么把一堆文件喂给 Label Studio。小项目可以用页面批量上传&#xff0c;几十张图还能忍&#xff1b;到了几千、几万个文件&#xff0…

作者头像 李华
网站建设 2026/10/7 17:34:21

SpringBoot+Vue3+MyBatis+MySQL课表管理系统完整实现与部署指南

前阵子一个学弟找我帮忙收拾一套课表管理系统&#xff0c;他的需求说得很直白&#xff1a;老师要求后端必须用SpringBoot&#xff0c;前端用Vue&#xff0c;数据库用MySQL&#xff0c;还要能按周次切换课表、按班级/教师/教室三种维度查询。我看了一眼他下载的所谓“完整源码”…

作者头像 李华
网站建设 2026/10/7 17:33:33

同城上门喂遛宠物系统:SpringBoot+Vue+MySQL全栈源码解析

干同行交流多了就会发现&#xff0c;一套能“到手就能跑”的项目源码有多稀缺。大部分仓库不是缺配置就是数据库脚本没给全&#xff0c;更有甚者前端接口连不上后端&#xff0c;最终只能靠猜和补。这次聊的同城上门喂遛宠物系统&#xff0c;至少在交付形态上把 SpringBoot 后端…

作者头像 李华
网站建设 2026/10/7 17:33:07

洛谷刷题全攻略:从红题到黑题的进阶路线与踩坑总结

洛谷刷题这件事&#xff0c;我认真持续了大半年。前前后后AC了两百多道题&#xff0c;TLE和WA的次数已经数不清&#xff0c;中间也经历过“打开题解就能看懂、关上题解就写不出来”的绝望期。这篇《洛谷刷题有感》&#xff0c;我想写的不是某个具体题目的题解&#xff0c;而是把…

作者头像 李华