ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring Boot实战:打造七夕专属纪念日小系统(倒计时+心愿单+时光信)

Spring Boot实战:打造七夕专属纪念日小系统(倒计时+心愿单+时光信) 快到七夕朋友圈又开始刷起“同款礼物”“同款晚餐”。有人说七夕嘛和谁过都一样送花、吃饭、看电影今年跟去年没什么区别。其实我特别不认同这句话——七夕的形式可以复制但“和谁过”带来的专属感完全没法标准化。同样是倒计时同样是告白文案如果它是你亲手搭建、只属于两个人、能记录你们纪念日和愿望的小系统那体验就完全不一样了。这篇文章我就把这样一套“专属纪念日小系统”完整拆开后端用 Spring Boot 提供接口前端用 HTML/CSS/JS 做成一个氛围感页面数据用 H2 内存数据库免安装运行。读完你能掌握 Spring Boot 项目搭建、Spring Data JPA 增删改查、RESTful API 设计和前后端联调也能在七夕前真正动手做一个有心意的作品。1. 七夕怎么会和谁过都一样呢先聊聊标题这句话背后的意思。节日更像是一个提醒告诉我们应该停下来为重要的人花点心思。而“和谁过”之所以不一样是因为每个人共同经历的记忆不同第一次见面的日期、第一次旅行的城市、彼此许下的心愿、想写却一直没说的话。这些东西用通用礼品表达不出来但用一套专属系统可以承载。这个项目的定位就不是做一个“大而全”的社交产品而是做一个“小而暖”的私人站点首页显示七夕倒计时让对方知道你在等着这个日子展示你们的纪念日时间线像一本回忆相册提供一个心愿单两个人一起写下想完成的事提供一封“时光信”把平时不好意思说的话写下来再加一个随机情话按钮让对方每天打开都能看到一句不一样的话。从技术角度看它又是一个完整的 Web 开发练习后端接口、数据库建模、前端渲染、配置管理、异常排查、部署上线全部覆盖。对 Java 后端入门、正在准备个人项目的开发者也很有价值。2. 需求分析与功能设计任何项目动手之前先把需求拆清楚。网上很多代码能跑但改起来很痛苦就是因为没有设计直接写。2.1 核心使用场景这个系统的使用场景非常简单男生/女生在网页上维护两个人共同的数据对方打开网页就能看到倒计时、纪念日和留言两人可以随时往心愿单里添加内容时光信像一个小留言板攒下两个人想说的话。所以它不需要注册登录、不需要复杂的权限核心就是数据维护 页面展示。如果以后想公开部署再加登录也不迟。2.2 功能模块划分模块功能说明涉及接口七夕倒计时读取配置的七夕日期计算距离天数GET /api/next-qixi纪念日时间线展示纪念日列表按日期升序排列GET /api/anniversaries心愿单新增心愿、查询心愿、删除已完成心愿GET/POST/DELETE /api/wishes时光信新增留言、查询留言按时间倒序GET/POST /api/letters今日情话点击按钮随机返回一句情话GET /api/random-love2.3 技术选型技术栈选型遵循一个原则简单、免安装、容易跑通。后端框架Spring Boot内置 Tomcat启动就能访问持久层Spring Data JPA避免手写大量 SQL数据库H2 内存数据库不需要安装 MySQL方便演示前端原生 HTML/CSS/JS不引入 Vue、React也不需要 Node.js 构建请求方式浏览器原生 fetch不需要额外前端依赖。这套组合的最大优势是只要电脑有 JDK 和 Maven直接把项目拉下来就能跑。2.4 页面结构规划页面按一个长页面往下排适合移动端浏览页面顶部七夕倒计时 第 1 屏纪念日时间线 第 2 屏许个心愿心愿单 第 3 屏时光信 第 4 屏今日情话整体做成卡片式风格配夏季夜晚的渐变背景再把爱心和文字颜色调整一下七夕氛围就有了。3. 环境准备与项目初始化3.1 开发环境我本地的环境可以作为参考JDK8 或 11 都可以示例代码基于 Java 8 语法Maven3.6 及以上IDEIDEA 或 EclipseSpring Boot2.7.x稳定且网上资料最多。如果你用的是 Spring Boot 3.x需要注意示例里的javax.persistence.*在 Boot 3 中已经改成了jakarta.persistence.*。为了减少入门障碍本文以 Spring Boot 2.7.x 为基线这点会在后面“常见问题”里再强调。3.2 创建项目推荐两种方式到 Spring Initializr 生成一个基础工程依赖选Spring Web和Spring Data JPA直接在 IDEA 里新建 Spring Boot 项目按下面内容补全文件。项目名我定义为qixi-gift包名com.example.qixi。最终目录结构如下qixi-gift/ ├── pom.xml └── src/main/ ├── java/com/example/qixi/ │ ├── QixiApplication.java │ ├── config/DataInitializer.java │ ├── controller/ApiController.java │ ├── entity/Anniversary.java │ ├── entity/Wish.java │ ├── entity/LoveLetter.java │ ├── repository/AnniversaryRepository.java │ ├── repository/WishRepository.java │ ├── repository/LoveLetterRepository.java │ ├── service/QixiService.java │ └── util/QixiDateUtil.java └── resources/ ├── application.yml └── static/index.html3.3 引入依赖先看pom.xml核心依赖就三个?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent groupIdcom.example/groupId artifactIdqixi-gift/artifactId version1.0.0/version nameqixi-gift/name description七夕专属纪念日小系统/description properties java.version8/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project这里解释一下几个依赖的作用spring-boot-starter-web提供 Web 容器和 Spring MVC负责处理 HTTP 请求spring-boot-starter-data-jpa简化数据库访问通过实体类自动建表、操作数据h2嵌入式内存数据库项目启动时数据库自动创建关闭后数据消失非常适合本地演示。3.4 配置文件在src/main/resources/application.yml中写入server: port: 8080 spring: application: name: qixi-gift datasource: url: jdbc:h2:mem:qixi;DB_CLOSE_DELAY-1 driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: update show-sql: true h2: console: enabled: true path: /h2-console qixi: # 示例配置请替换为实际年份七夕对应的公历日期格式yyyy-MM-dd date: 2025-08-31配置要点jdbc:h2:mem:qixi表示使用 H2 内存库数据库名是qixiDB_CLOSE_DELAY-1保证项目运行期间数据库不会因为连接断开而清空ddl-auto: update让 JPA 在启动时根据实体类自动建表或更新表结构show-sql: true方便你在控制台看到实际执行的 SQL开启 H2 控制台后可以通过http://localhost:8080/h2-console查看表数据。七夕日期这里单独放到配置里不写死在代码中是因为七夕是农历节日每年对应的公历日期不同。实际使用前把qixi.date改成当年的七夕公历日期即可。3.5 启动类package com.example.qixi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class QixiApplication { public static void main(String[] args) { SpringApplication.run(QixiApplication.class, args); } }SpringBootApplication是 Spring Boot 的核心注解它组合了Configuration、EnableAutoConfiguration和ComponentScan启动时自动扫描当前包及子包下的组件。4. 数据模型与接口设计4.1 数据模型设计这个系统只涉及三张表设计得很轻量表名字段用途anniversaryid、title、date、description记录纪念日事件wishid、content、done、created_at记录心愿内容与完成状态love_letterid、content、writer、created_at记录时光信留言4.2 实体类编写先写Anniversary实体package com.example.qixi.entity; import javax.persistence.*; import java.time.LocalDate; Entity Table(name anniversary) public class Anniversary { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false, length 50) private String title; Column(nullable false) private LocalDate date; Column(length 500) private String description; public Anniversary() { } public Anniversary(String title, LocalDate date, String description) { this.title title; this.date date; this.description description; } public Long getId() { return id; } public void setId(Long id) { this.id id; } public String getTitle() { return title; } public void setTitle(String title) { this.title title; } public LocalDate getDate() { return date; } public void setDate(LocalDate date) { this.date date; } public String getDescription() { return description; } public void setDescription(String description) { this.description description; } }这里用LocalDate而不是Date因为纪念日只需要年月日不需要时分秒更直观。再写Wish实体package com.example.qixi.entity; import javax.persistence.*; import java.time.LocalDateTime; Entity Table(name wish) public class Wish { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false, length 200) private String content; Column(nullable false) private Boolean done false; Column(nullable false) private LocalDateTime createdAt; public Wish() { } public Long getId() { return id; } public void setId(Long id) { this.id id; } public String getContent() { return content; } public void setContent(String content) { this.content content; } public Boolean getDone() { return done; } public void setDone(Boolean done) { this.done done; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt createdAt; } }接着是LoveLetter实体package com.example.qixi.entity; import javax.persistence.*; import java.time.LocalDateTime; Entity Table(name love_letter) public class LoveLetter { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false, length 1000) private String content; Column(length 50) private String writer; Column(nullable false) private LocalDateTime createdAt; public LoveLetter() { } public Long getId() { return id; } public void setId(Long id) { this.id id; } public String getContent() { return content; } public void setContent(String content) { this.content content; } public String getWriter() { return writer; } public void setWriter(String writer) { this.writer writer; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt createdAt; } }4.3 数据访问层三个 Repository 接口非常简单继承JpaRepository后会自动拥有save、findAll、deleteById等基础方法。package com.example.qixi.repository; import com.example.qixi.entity.Anniversary; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface AnniversaryRepository extends JpaRepositoryAnniversary, Long { ListAnniversary findAllByOrderByDateAsc(); }package com.example.qixi.repository; import com.example.qixi.entity.Wish; import org.springframework.data.jpa.repository.JpaRepository; public interface WishRepository extends JpaRepositoryWish, Long { }package com.example.qixi.repository; import com.example.qixi.entity.LoveLetter; import org.springframework.data.jpa.repository.JpaRepository; public interface LoveLetterRepository extends JpaRepositoryLoveLetter, Long { }findAllByOrderByDateAsc()是 Spring Data JPA 的方法名解析意思是按date字段升序排列正好适合时间线的展示顺序。4.4 接口设计总览后端接口统一返回 JSON前端使用fetch请求。方法路径功能说明GET/api/next-qixi获取七夕日期和剩余天数GET/api/anniversaries查询纪念日列表GET/api/wishes查询心愿列表POST/api/wishes新增心愿DELETE/api/wishes/{id}删除心愿GET/api/letters查询时光信列表POST/api/letters新增时光信GET/api/random-love获取随机情话5. 核心代码实现5.1 服务层服务层把接口要用的逻辑集中起来Controller 只负责接收请求和返回结果。package com.example.qixi.service; import com.example.qixi.entity.Anniversary; import com.example.qixi.entity.LoveLetter; import com.example.qixi.entity.Wish; import com.example.qixi.repository.AnniversaryRepository; import com.example.qixi.repository.LoveLetterRepository; import com.example.qixi.repository.WishRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; Service public class QixiService { private static final String[] LOVE_MESSAGES { 想在每一个普通的日子里都给你一点不普通的心意。, 世界很大但我只想和你看同一片晚霞。, 遇见你之后所有的节日都变得有意义了。, 最好的告白不是‘我爱你’而是‘未来我都想和你在一起’。, 愿我们在彼此看不到的岁月里各自努力然后顶峰相见。 }; Value(${qixi.date}) private String qixiDateStr; private final AnniversaryRepository anniversaryRepository; private final WishRepository wishRepository; private final LoveLetterRepository loveLetterRepository; public QixiService(AnniversaryRepository anniversaryRepository, WishRepository wishRepository, LoveLetterRepository loveLetterRepository) { this.anniversaryRepository anniversaryRepository; this.wishRepository wishRepository; this.loveLetterRepository loveLetterRepository; } public MapString, Object getNextQixiInfo() { LocalDate today LocalDate.now(); LocalDate qixiDate LocalDate.parse(qixiDateStr); long days ChronoUnit.DAYS.between(today, qixiDate); MapString, Object result new HashMap(); result.put(date, qixiDate.toString()); result.put(days, days); return result; } public ListAnniversary listAnniversaries() { return anniversaryRepository.findAllByOrderByDateAsc(); } public ListWish listWishes() { return wishRepository.findAll(Sort.by(Sort.Direction.ASC, createdAt)); } public Wish addWish(Wish wish) { if (wish.getCreatedAt() null) { wish.setCreatedAt(LocalDateTime.now()); } if (wish.getDone() null) { wish.setDone(false); } return wishRepository.save(wish); } public void deleteWish(Long id) { wishRepository.deleteById(id); } public ListLoveLetter listLetters() { return loveLetterRepository.findAll(Sort.by(Sort.Direction.DESC, createdAt)); } public LoveLetter addLetter(LoveLetter letter) { if (letter.getCreatedAt() null) { letter.setCreatedAt(LocalDateTime.now()); } return loveLetterRepository.save(letter); } public MapString, String randomLove() { Random random new Random(); int index random.nextInt(LOVE_MESSAGES.length); MapString, String result new HashMap(); result.put(content, LOVE_MESSAGES[index]); return result; } }这段代码需要注意两个点第一Value(${qixi.date})会把配置文件里的qixi.date注入到qixiDateStr中这是 Spring Boot 外部化配置的常用手法以后改日期不用改代码。第二addWish和addLetter里做了一次兜底赋值如果前端没有传createdAt或done后端会自动补上避免存进 null 值。5.2 控制器层控制器只做参数接收和结果返回逻辑都在 Service 里。package com.example.qixi.controller; import com.example.qixi.entity.Anniversary; import com.example.qixi.entity.LoveLetter; import com.example.qixi.entity.Wish; import com.example.qixi.service.QixiService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; RestController RequestMapping(/api) public class ApiController { private final QixiService qixiService; public ApiController(QixiService qixiService) { this.qixiService qixiService; } GetMapping(/next-qixi) public MapString, Object nextQixi() { return qixiService.getNextQixiInfo(); } GetMapping(/anniversaries) public ListAnniversary anniversaries() { return qixiService.listAnniversaries(); } GetMapping(/wishes) public ListWish wishes() { return qixiService.listWishes(); } PostMapping(/wishes) public Wish addWish(RequestBody Wish wish) { return qixiService.addWish(wish); } DeleteMapping(/wishes/{id}) public ResponseEntityVoid deleteWish(PathVariable Long id) { qixiService.deleteWish(id); return ResponseEntity.noContent().build(); } GetMapping(/letters) public ListLoveLetter letters() { return qixiService.listLetters(); } PostMapping(/letters) public LoveLetter addLetter(RequestBody LoveLetter letter) { return qixiService.addLetter(letter); } GetMapping(/random-love) public MapString, String randomLove() { return qixiService.randomLove(); } }RestController表示这个类的所有方法默认返回 JSON不需要再写ResponseBody。RequestBody会把前端传来的 JSON 自动反序列化成对应的 Java 对象。PathVariable用来接收 URL 中的路径参数。5.3 初始化示例数据空页面的效果不够直观所以项目启动时如果数据库里没有数据就自动写入几条示例纪念日。package com.example.qixi.config; import com.example.qixi.entity.Anniversary; import com.example.qixi.entity.LoveLetter; import com.example.qixi.entity.Wish; import com.example.qixi.repository.AnniversaryRepository; import com.example.qixi.repository.LoveLetterRepository; import com.example.qixi.repository.WishRepository; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Arrays; Component public class DataInitializer implements CommandLineRunner { private final AnniversaryRepository anniversaryRepository; private final WishRepository wishRepository; private final LoveLetterRepository loveLetterRepository; public DataInitializer(AnniversaryRepository anniversaryRepository, WishRepository wishRepository, LoveLetterRepository loveLetterRepository) { this.anniversaryRepository anniversaryRepository; this.wishRepository wishRepository; this.loveLetterRepository loveLetterRepository; } Override public void run(String... args) { if (anniversaryRepository.count() 0) { anniversaryRepository.saveAll(Arrays.asList( new Anniversary(第一次见面, LocalDate.of(2022, 5, 20), 那天你穿了一件白色的裙子。), new Anniversary(在一起的日子, LocalDate.of(2022, 6, 1), 从那天开始很多节日都不一样了。), new Anniversary(第一次旅行, LocalDate.of(2023, 10, 1), 在陌生的城市却一点也不觉得孤单。) )); } if (wishRepository.count() 0) { Wish wish new Wish(); wish.setContent(一起去海边看一次日出); wish.setDone(false); wish.setCreatedAt(LocalDateTime.now()); wishRepository.save(wish); } if (loveLetterRepository.count() 0) { LoveLetter letter new LoveLetter(); letter.setContent(这篇文章写到一半我突然想如果真的有时间机器我大概还是会选在同一天遇见你。); letter.setWriter(你的专属后端工程师); letter.setCreatedAt(LocalDateTime.now()); loveLetterRepository.save(letter); } } }CommandLineRunner会在 Spring Boot 启动完成后执行一次适合做这种初始化数据的工作。count() 0的判断保证不会重复插入。6. 前端页面把“不一样”呈现出来后端接口写好了页面是用户直接看到的部分也是“和谁过不一样”的最终落点。在src/main/resources/static/index.html中写一个完整的单页面CSS 和 JS 都内嵌在文件里复制即用。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我们的七夕/title style * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: PingFang SC, Microsoft YaHei, sans-serif; background: linear-gradient(135deg, #1a0533 0%, #2d1b69 50%, #4a2c8a 100%); min-height: 100vh; color: #fff; padding: 20px; } .container { max-width: 640px; margin: 0 auto; } header { text-align: center; padding: 50px 20px 30px; } header h1 { font-size: 28px; font-weight: 300; letter-spacing: 2px; } header .days { font-size: 60px; font-weight: 700; color: #ffd166; margin: 10px 0; } header .date { font-size: 14px; opacity: 0.7; } .card { background: rgba(255, 255, 255, 0.08); backdrop-filter: blur(6px); border-radius: 16px; padding: 24px; margin-bottom: 20px; border: 1px solid rgba(255, 255, 255, 0.1); } .card h2 { font-size: 20px; margin-bottom: 16px; border-left: 4px solid #ffd166; padding-left: 12px; } .timeline-item { padding: 10px 0; border-bottom: 1px dashed rgba(255, 255, 255, 0.15); } .timeline-item:last-child { border-bottom: none; } .timeline-item strong { display: block; font-size: 16px; } .timeline-item span { display: inline-block; margin-top: 4px; font-size: 13px; color: #ffd166; } .timeline-item p { margin-top: 6px; font-size: 14px; opacity: 0.8; line-height: 1.6; } .input-row { display: flex; gap: 10px; margin-bottom: 16px; } input[typetext], textarea { flex: 1; padding: 10px 14px; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.1); color: #fff; font-size: 14px; outline: none; } textarea { width: 100%; min-height: 90px; resize: vertical; margin-bottom: 12px; } button { padding: 10px 18px; border: none; border-radius: 8px; background: #ffd166; color: #1a0533; font-size: 14px; font-weight: 600; cursor: pointer; transition: transform 0.2s, opacity 0.2s; } button:hover { transform: translateY(-2px); opacity: 0.9; } ul { list-style: none; } ul li { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px dashed rgba(255, 255, 255, 0.1); font-size: 15px; } .delete-btn { background: transparent; color: #ff6b6b; padding: 4px 10px; font-size: 13px; border: 1px solid rgba(255, 107, 107, 0.5); } .letter-item { padding: 12px 0; border-bottom: 1px dashed rgba(255, 255, 255, 0.1); } .letter-item:last-child { border-bottom: none; } .letter-item .writer { font-size: 13px; color: #ffd166; margin-top: 6px; } .letter-item .time { font-size: 12px; opacity: 0.6; margin-top: 2px; } .love-box { text-align: center; padding: 20px; } .love-box p { font-size: 18px; line-height: 1.8; margin-top: 16px; min-height: 60px; color: #ffe8a3; } .heart { color: #ff6b6b; } media (max-width: 480px) { header h1 { font-size: 22px; } header .days { font-size: 44px; } .input-row { flex-direction: column; } button { width: 100%; } } /style /head body div classcontainer header h1距离七夕还有 span classheart♥/span/h1 div classdays span iddays--/span 天 /div div classdate idqixiDate/div /header section classcard h2我们的纪念日/h2 div idanniversaryList p加载中.../p /div /section section classcard h2许个心愿/h2 div classinput-row input typetext idwishInput placeholder写下想一起完成的事 button idaddWishBtn添加/button /div ul idwishList/ul /section section classcard h2时光信/h2 textarea idletterInput placeholder写一封给 TA 的信落款写你的名字/textarea button idaddLetterBtn寄出这封信/button div idletterList/div /section section classcard love-box h2今日情话/h2 button idloveBtn换一句情话/button p idloveMessage/p /section /div script function escapeHtml(text) { const div document.createElement(div); div.appendChild(document.createTextNode(text null ? : String(text))); return div.innerHTML; } async function loadNextQixi() { const res await fetch(/api/next-qixi); const data await res.json(); document.getElementById(days).textContent data.days; document.getElementById(qixiDate).textContent 七夕日期 data.date; } async function loadAnniversaries() { const res await fetch(/api/anniversaries); const data await res.json(); const wrap document.getElementById(anniversaryList); if (!data.length) { wrap.innerHTML p还没有记录快添加一个纪念日吧。/p; return; } wrap.innerHTML data.map(item div classtimeline-item strong escapeHtml(item.title) /strong span escapeHtml(item.date) /span (item.description ? p escapeHtml(item.description) /p : ) /div ).join(); } async function loadWishes() { const res await fetch(/api/wishes); const data await res.json(); const wrap document.getElementById(wishList); if (!data.length) { wrap.innerHTML li还没有心愿添加一个吧。/li; return; } wrap.innerHTML data.map(item li span escapeHtml(item.content) /span button classdelete-btn>mvn spring-boot:run如果 Maven 依赖下载正常控制台会出现 Spring Boot 启动日志最后一行显示类似Tomcat started on port(s): 8080 (http) Started QixiApplication in 3.6 seconds然后浏览器访问http://localhost:80807.2 验证功能按下面的清单逐项验证操作预期结果打开首页页面显示七夕倒计时天数和日期查看纪念日区域显示三条示例纪念日按日期升序输入心愿并点击添加心愿出现在列表中点击心愿的“完成/删除”对应心愿从列表消失输入时光信并点击寄出信出现在时光信列表顶部点击“换一句情话”情话内容随机变化访问/h2-console可以登录 H2 控制台并查看三张表7.3 直接验证接口如果不想打开浏览器也可以直接
返回列表