从零搭建一套完整的微信小程序 + Java后端系统
每天14小时禁食、10小时进食这是最适合新手的轻断食方案。本文将完整记录如何从零开发一款“1410轻断食助手”微信小程序涵盖后端架构、数据库设计、禁食计时器、数据统计、微信登录等核心模块。全套代码可直接用于生产环境。一、项目概述1.1 项目背景轻断食是近年来流行的健康饮食模式。其中1410方案因其门槛低、易坚持成为最受推荐的入门级方案。本项目旨在开发一款完整的微信小程序帮助用户科学、便捷地执行1410轻断食计划配合Java后端提供数据管理与个性化建议服务。1.2 技术架构层级技术选型前端微信小程序WXML WXSS JavaScript后端Java 11 Spring Boot 2.7 MyBatis Plus数据库MySQL 8.0缓存Redis部署Docker Nginx1.3 功能模块一览模块核心功能用户管理微信授权登录、个人信息管理、健康数据记录断食计划1410计划设置、实时计时器、进食窗口提醒饮食记录食物库管理、热量计算、营养成分分析健康数据体重追踪、身体指标记录、进度可视化社区互动经验分享、打卡挑战、专家建议二、数据库设计2.1 核心表结构-- 用户表 CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, openid varchar(100) NOT NULL COMMENT 微信openid, nickname varchar(100) DEFAULT NULL, avatar_url varchar(500) DEFAULT NULL, gender tinyint(1) DEFAULT NULL, birthday date DEFAULT NULL, height decimal(5,2) DEFAULT NULL COMMENT 身高(cm), initial_weight decimal(5,2) DEFAULT NULL COMMENT 初始体重(kg), target_weight decimal(5,2) DEFAULT NULL COMMENT 目标体重(kg), fasting_start_time time DEFAULT NULL COMMENT 每日禁食开始时间, fasting_end_time time DEFAULT NULL COMMENT 每日禁食结束时间, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 断食记录表 CREATE TABLE fasting_record ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, record_date date NOT NULL COMMENT 记录日期, fasting_start_time datetime NOT NULL COMMENT 禁食开始时间, fasting_end_time datetime DEFAULT NULL COMMENT 禁食结束时间, actual_fasting_hours decimal(4,1) DEFAULT NULL COMMENT 实际禁食时长, status tinyint(1) DEFAULT 1 COMMENT 状态1-进行中2-已完成3-中断, notes text COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_date (user_id,record_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 饮食记录表 CREATE TABLE diet_record ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, record_date date NOT NULL, meal_type tinyint(1) DEFAULT NULL COMMENT 餐次类型1-早餐2-午餐3-晚餐4-加餐, food_name varchar(200) NOT NULL, quantity decimal(6,2) DEFAULT NULL COMMENT 数量, unit varchar(20) DEFAULT NULL COMMENT 单位, calories int(11) DEFAULT NULL COMMENT 热量(卡), protein decimal(5,2) DEFAULT NULL COMMENT 蛋白质(g), carbohydrate decimal(5,2) DEFAULT NULL COMMENT 碳水(g), fat decimal(5,2) DEFAULT NULL COMMENT 脂肪(g), record_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_date (user_id,record_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 体重记录表 CREATE TABLE weight_record ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, record_date date NOT NULL, weight decimal(5,2) NOT NULL COMMENT 体重(kg), body_fat decimal(4,2) DEFAULT NULL COMMENT 体脂率(%), muscle decimal(5,2) DEFAULT NULL COMMENT 肌肉量(kg), bmi decimal(4,2) DEFAULT NULL COMMENT BMI指数, notes varchar(500) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_user_date (user_id,record_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 食物库表 CREATE TABLE food_library ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 食物名称, category varchar(50) DEFAULT NULL COMMENT 食物类别, calories_per_100g int(11) DEFAULT NULL COMMENT 每100g热量, protein_per_100g decimal(5,2) DEFAULT NULL COMMENT 每100g蛋白质, carbohydrate_per_100g decimal(5,2) DEFAULT NULL COMMENT 每100g碳水, fat_per_100g decimal(5,2) DEFAULT NULL COMMENT 每100g脂肪, common_serving varchar(100) DEFAULT NULL COMMENT 常见份量, status tinyint(1) DEFAULT 1 COMMENT 状态1-启用0-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;三、Java后端核心实现3.1 项目结构fasting-app-backend/ ├── src/main/java/com/fasting/app/ │ ├── config/ # 配置类 │ ├── controller/ # 控制器层 │ ├── service/ # 服务层 │ │ └── impl/ # 服务实现 │ ├── mapper/ # 数据访问层 │ ├── entity/ # 实体类 │ ├── dto/ # 数据传输对象 │ ├── vo/ # 视图对象 │ └── common/ # 通用工具 │ ├── Result.java # 统一返回结果 │ └── utils/ # 工具类 └── resources/ ├── application.yml └── mapper/ # MyBatis映射文件3.2 核心依赖parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.14/version /parent dependencies !-- Spring Boot Starters -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- 数据库 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- 微信小程序SDK -- dependency groupIdcom.github.binarywang/groupId artifactIdweixin-java-miniapp/artifactId version4.5.0/version /dependency !-- 工具类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdcom.alibaba/groupId artifactIdfastjson/artifactId version2.0.34/version /dependency /dependencies3.3 禁食服务核心实现Service Slf4j public class FastingServiceImpl implements FastingService { Autowired private FastingRecordMapper fastingRecordMapper; Autowired private UserMapper userMapper; Autowired private RedisTemplateString, Object redisTemplate; private static final String TODAY_FASTING_KEY fasting:today:; /** * 开始禁食 */ Override Transactional public Result startFasting(Long userId, Date startTime) { User user userMapper.selectById(userId); if (user null) { return Result.error(用户不存在); } Date today DateUtil.beginOfDay(new Date()); // 检查今日是否已有记录 LambdaQueryWrapperFastingRecord queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(FastingRecord::getUserId, userId) .eq(FastingRecord::getRecordDate, today); FastingRecord existingRecord fastingRecordMapper.selectOne(queryWrapper); if (existingRecord ! null) { return Result.error(今日已开始禁食); } // 创建禁食记录 FastingRecord record new FastingRecord(); record.setUserId(userId); record.setRecordDate(today); record.setFastingStartTime(startTime); record.setStatus(1); // 进行中 fastingRecordMapper.insert(record); // 缓存当天禁食状态 cacheTodayFastingStatus(userId, record); log.info(用户{}开始禁食, userId); return Result.success(禁食开始成功, record); } /** * 结束禁食 */ Override Transactional public Result endFasting(Long userId, Date endTime) { Date today DateUtil.beginOfDay(new Date()); LambdaQueryWrapperFastingRecord queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(FastingRecord::getUserId, userId) .eq(FastingRecord::getRecordDate, today) .eq(FastingRecord::getStatus, 1); FastingRecord record fastingRecordMapper.selectOne(queryWrapper); if (record null) { return Result.error(没有找到进行中的禁食记录); } // 计算禁食时长 long startMillis record.getFastingStartTime().getTime(); long endMillis endTime.getTime(); double hours (endMillis - startMillis) / (1000.0 * 60 * 60); record.setFastingEndTime(endTime); record.setActualFastingHours(BigDecimal.valueOf(hours)); record.setStatus(2); // 已完成 fastingRecordMapper.updateById(record); // 更新缓存 cacheTodayFastingStatus(userId, record); String message hours 14 ? 恭喜您已完成14小时禁食目标 : 禁食结束; log.info(用户{}结束禁食时长{}小时, userId, hours); return Result.success(message, record); } /** * 获取今日禁食状态 */ Override public Result getTodayFastingStatus(Long userId) { String cacheKey TODAY_FASTING_KEY userId; FastingRecordVO cachedStatus (FastingRecordVO) redisTemplate.opsForValue().get(cacheKey); if (cachedStatus ! null) { return Result.success(cachedStatus); } Date today DateUtil.beginOfDay(new Date()); LambdaQueryWrapperFastingRecord queryWrapper new LambdaQueryWrapper(); queryWrapper.eq(FastingRecord::getUserId, userId) .eq(FastingRecord::getRecordDate, today); FastingRecord record fastingRecordMapper.selectOne(queryWrapper); if (record null) { FastingRecordVO defaultStatus new FastingRecordVO(); defaultStatus.setRecordDate(today); defaultStatus.setStatus(0); defaultStatus.setStatusDesc(未开始); return Result.success(defaultStatus); } FastingRecordVO vo convertToVO(record); // 计算进度 if (record.getStatus() 1) { long startMillis record.getFastingStartTime().getTime(); long currentMillis System.currentTimeMillis(); long targetMillis startMillis (14 * 60 * 60 * 1000L); int progress (int) ((currentMillis - startMillis) * 100 / (14 * 60 * 60 * 1000L)); vo.setProgressPercentage(Math.min(progress, 100)); } redisTemplate.opsForValue().set(cacheKey, vo, 5, TimeUnit.MINUTES); return Result.success(vo); } }3.4 控制器层RestController RequestMapping(/api/fasting) Slf4j public class FastingController { Autowired private FastingService fastingService; PostMapping(/start) public Result startFasting(RequestHeader(X-User-Id) Long userId, RequestBody StartFastingDTO dto) { return fastingService.startFasting(userId, dto.getStartTime()); } PostMapping(/end) public Result endFasting(RequestHeader(X-User-Id) Long userId, RequestBody EndFastingDTO dto) { return fastingService.endFasting(userId, dto.getEndTime()); } GetMapping(/today) public Result getTodayFasting(RequestHeader(X-User-Id) Long userId) { return fastingService.getTodayFastingStatus(userId); } GetMapping(/statistics) public Result getStatistics(RequestHeader(X-User-Id) Long userId, RequestParam String startDate, RequestParam String endDate) { SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); Date start sdf.parse(startDate); Date end sdf.parse(endDate); return fastingService.getFastingStatistics(userId, start, end); } }四、微信小程序前端实现4.1 项目结构miniprogram/ ├── pages/ │ ├── index/ # 首页 │ ├── fasting/ # 禁食页面 │ ├── diet/ # 饮食记录 │ ├── statistics/ # 统计数据 │ └── profile/ # 个人中心 ├── components/ # 公共组件 ├── utils/ # 工具类 ├── services/ # API服务 └── app.json # 小程序配置4.2 禁食页面核心代码// pages/fasting/fasting.js Page({ data: { fastingStatus: null, isFasting: false, remainingTime: 00:00:00, progress: 0, timer: null }, onLoad() { this.loadFastingStatus(); this.startTimer(); }, onUnload() { if (this.data.timer) clearInterval(this.data.timer); }, loadFastingStatus() { wx.showLoading({ title: 加载中... }); wx.request({ url: https://your-api.com/api/fasting/today, header: { Authorization: wx.getStorageSync(token) }, success: (res) { if (res.data.code 200) { this.setData({ fastingStatus: res.data.data, isFasting: res.data.data.status 1 }); if (this.data.isFasting) this.updateRemainingTime(); } }, complete: () wx.hideLoading() }); }, startFasting() { wx.showModal({ title: 提示, content: 确定要开始禁食吗, success: (res) { if (res.confirm) { wx.request({ url: https://your-api.com/api/fasting/start, method: POST, header: { Authorization: wx.getStorageSync(token), Content-Type: application/json }, data: { startTime: new Date().toISOString() }, success: (res) { if (res.data.code 200) { wx.showToast({ title: 禁食开始, icon: success }); this.loadFastingStatus(); } } }); } } }); }, updateRemainingTime() { const startTime new Date(this.data.fastingStatus.fastingStartTime).getTime(); const now Date.now(); const targetTime startTime 14 * 60 * 60 * 1000; if (now targetTime) { this.setData({ remainingTime: 00:00:00, progress: 100 }); return; } const remaining targetTime - now; const hours Math.floor(remaining / 3600000); const minutes Math.floor((remaining % 3600000) / 60000); const seconds Math.floor((remaining % 60000) / 1000); const progress Math.floor((now - startTime) / (14 * 60 * 60 * 1000) * 100); this.setData({ remainingTime: ${String(hours).padStart(2, 0)}:${String(minutes).padStart(2, 0)}:${String(seconds).padStart(2, 0)}, progress: Math.min(progress, 100) }); }, startTimer() { this.data.timer setInterval(() { if (this.data.isFasting) this.updateRemainingTime(); }, 1000); } });4.3 小程序配置文件// app.json { pages: [ pages/index/index, pages/fasting/fasting, pages/diet/diet, pages/statistics/statistics, pages/profile/profile ], window: { navigationBarBackgroundColor: #4CAF50, navigationBarTitleText: 轻断食助手, navigationBarTextStyle: white }, tabBar: { color: #999999, selectedColor: #4CAF50, list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/fasting/fasting, text: 断食 }, { pagePath: pages/diet/diet, text: 饮食 }, { pagePath: pages/statistics/statistics, text: 统计 }, { pagePath: pages/profile/profile, text: 我的 } ] } }五、Docker部署配置5.1 docker-compose.ymlversion: 3.8 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: fasting123 MYSQL_DATABASE: fasting_db ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql networks: - fasting-network redis: image: redis:7-alpine ports: - 6379:6379 networks: - fasting-network backend: build: . ports: - 8080:8080 environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/fasting_db?useSSLfalse SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: fasting123 SPRING_REDIS_HOST: redis depends_on: - mysql - redis networks: - fasting-network volumes: mysql-data: networks: fasting-network: driver: bridge六、总结本项目实现了一套完整的轻断食1410方案小程序系统具备以下特点特点说明完整用户系统微信授权登录、个人信息管理科学断食计划1410方案实施智能提醒全面数据记录饮食、体重、断食记录一体化丰富可视化数据图表展示进度可视化可扩展架构前后端分离便于后续迭代系统采用Spring Boot MyBatis Plus Redis 微信小程序的技术栈代码结构清晰可直接用于生产环境。该方案不仅实现了基础的断食计时功能还通过数据分析为用户提供了科学的健康管理工具。