项目标题里的“家庭大厨微信小程序+ssm”,看着很典型,其实就是一套“微信小程序做前端展示、SSM做后端服务”的完整实战项目。做过毕业设计或者课程设计的人应该都懂,这类项目最讲究“麻雀虽小五脏俱全”:小程序端要能看菜谱、搜菜、收藏、分享,后端要能管用户、管菜品、管分类,最后还得能顺利跑起来演示。
这类项目的价值在于,它把前端小程序和后端Java服务串在了一条链路里。你光会写小程序页面,不懂接口对接,项目是死的;你光会写SpringMVC,不会和小程序联调,项目也是空的。把两者打通,才算是真正做过一个全栈项目。这篇文章我按自己做类似项目的思路,把“家庭大厨”从架构设计到数据库、从接口实现到真机调试的完整过程拆开讲,顺便把一些坑也一并说清楚,适合正在做同类项目、或者打算拿这个方向练手的读者。
1. 项目拆解与技术选型
1.1 这个项目到底要做什么
先看名字。“家庭大厨”,核心场景就是家常菜谱。用户打开小程序,能浏览菜品列表,能按分类筛选,能搜索菜名,点进详情页能看到食材、步骤、做法小贴士,喜欢还能收藏。再往后延伸一点,可以是用户自己上传菜谱、分享自家的拿手菜。
整套东西分两头:微信小程序端负责界面和交互,SSM后端负责产出数据。小程序里看到的菜谱列表、详情、收藏状态,全部来自后端接口。这样设计的好处是,前端只管展示和收集操作,后端只管处理逻辑和返回数据,两边分开,将来小程序要改版或者后端要加功能,互不影响。
从学习角度看,这个项目覆盖的知识面很扎实:小程序WXML、WXSS、JavaScript、组件生命周期、wx.request网络请求,后端的Spring容器、SpringMVC路由、MyBatis持久化,再加上MySQL建表、Maven依赖管理。一套流程走下来,从数据库到浏览器页面之间那层“膜”就捅破了。
1.2 技术选型——为什么是微信小程序和SSM
前端选微信小程序,不需要过多解释。现在做移动端轻量应用,微信小程序是绕不开的选项。用户不用下载App,微信里直接搜就能打开,传播成本低。对个人开发者来说,小程序也是门槛最低的上线渠道,个人主体也能注册,适合练手和做作品集。
后端选SSM,即Spring、SpringMVC、MyBatis的组合。这个选择有两个层面的原因。
第一个原因是教学惯性。SSM是Java后端教学体系里承上启下的一套组合:Spring管对象,SpringMVC管请求分发,MyBatis管数据库操作。过了这一关,再上Spring Boot就会觉得顺理成章。很多院校的课程设计和毕业设计,指定技术栈就是SSM,所以这个项目天然适合这类场景。
第二个原因是技术上的匹配度。SSM虽然“老”,但对这种CRUD为主的小程序后端,反而是够用且清晰的选择。SpringMVC的@Controller加@RequestMapping就能把接口暴露出来,MyBatis的XML映射文件能把SQL写得明明白白,分页、条件查询都容易控制。相比Spring Boot,SSM需要你手动配置的东西更多,但正是这种“手动”,让你能更清楚框架底层发生了什么。
1.3 整体工作流程
打开小程序,用户看到首页,页面加载时调后端接口,后端收到请求后通过MyBatis查询MySQL,拿到数据后转成JSON返回,小程序渲染到页面上。用户搜索、收藏、提交菜谱,本质都是数据操作:小程序发起请求带上参数,后端处理后返回结果。
整个过程里,后端就像一个餐厅后厨,小程序就是菜单和传菜窗口。你点菜(发起请求),后厨(Controller)接单,让各班组(Service)去备菜,最后采购员(Mapper)去仓库(数据库)取货,再原路端回来。搞懂这条链路,整个项目就算吃到七成了。
2. 数据库设计与核心模块拆分
2.1 表结构设计思路
“家庭大厨”这类项目,数据库设计并不复杂,核心就是围绕“菜品”和“用户”两个实体展开。但在设计时要考虑到扩展性,不能只建一张菜谱表就完事。
基础的一套表结构大致如下:
用户表(user):
- id:主键
- openid:微信用户的唯一标识
- nickname:昵称
- avatar:头像
- create_time:注册时间
菜谱分类表(category):
- id:主键
- name:分类名,比如“家常菜”“凉菜”“汤羹”“主食”
- sort:排序字段,控制前端展示顺序
菜品表(dish):
- id:主键
- category_id:所属分类,关联分类表
- name:菜名
- cover:封面图URL
- intro:简介
- steps:做法步骤,可以用TEXT类型存富文本或JSON
- ingredients:食材清单,JSON数组或逗号分隔
- tips:小贴士
- create_time:发布时间
收藏表(favorite):
- id:主键
- user_id:用户ID
- dish_id:菜品ID
- create_time:收藏时间
- 唯一索引(user_id, dish_id),防止重复收藏
这套表的逻辑很清楚:菜品挂在分类下面,收藏挂在用户和菜品之间,通过外键关联起来。查询时,首页按分类把菜品分组展示,详情页根据菜品ID查到对应信息,收藏页通过收藏表join菜品表拿到当前用户的收藏列表。
2.2 字段设计里容易被忽视的细节
表结构看着简单,但真到自己建表时会遇到不少细节问题,几个关键点值得说说。
时间字段统一用datetime,不要用timestamp,两者在范围上差不多,但在做数据迁移和比较时,datetime更不容易出幺蛾子。create_time这类字段,建表时直接设默认值CURRENT_TIMESTAMP,后端插入时就不用再去手动填时间。
步骤字段steps,建议用TEXT类型,存JSON数组字符串。数据库层面不需要拆成“步骤表”,因为步骤一定属于某个菜品,是一对多的关系,但业务上几乎不会单独查询步骤,完全跟着菜品详情走。所以存成一个字段,反而省事。查询出来之后,后端用JSONArray解析,小程序端再用JSON.parse处理成数组,遍历渲染即可。
封面图字段cover,只存相对路径或URL,不要存图片的二进制数据。项目里通常会配一个图片上传接口,把图片传到服务器某个目录,数据库里只存/upload/xxx.jpg。这个约定要在前后端都保持一致,否则会出现图片路径对不上、显示不出来的问题。
性别、状态这类有固定取值的字段,用tinyint存,0和1就够了。别用varchar存“男”“女”,查询统计时不好写SQL,还容易脏数据。
2.3 索引与数据关系
外键在小项目里可以不加物理外键约束,但逻辑上的关系必须理清。菜品的category_id,查询时要做关联查询,那么在category_id上建索引,避免全表扫描。favorite表的user_id和dish_id都要建索引,尤其是分页查询收藏列表时,没有索引会明显变慢。
收藏表的唯一索引(user_id, dish_id)特别重要。用户连续点两次收藏,如果没有唯一索引,会插入两条重复记录,前端看到的就是收藏数不对。虽然可以在Service层用代码判断是否已收藏,但数据库层面的唯一索引是最后一道保险,双保险更稳。
用户表一定要存openid字段。微信小程序登录时,通过wx.login拿到code,后端再用code换openid。openid是用户在微信体系里的唯一身份,所有跟用户相关的操作(收藏、上传菜谱、浏览记录),都要靠openid来定位。
3. 微信小程序端开发详解
3.1 页面结构与tabBar搭建
小程序端的页面规划遵循“少而精”原则。家庭大厨这种项目,底部导航一般三到四个主页面就够:
- 首页:推荐菜品、分类入口、热门菜谱轮播
- 分类/发现页:按分类浏览全部菜谱
- 我的:用户信息、收藏列表、个人上传的菜谱
app.json里配置tabBar,至少要有两个tab项才能显示。图标需要准备PNG图片,放/images/tabbar目录下,选中的和未选中的各一套。颜色要跟整体风格统一,比如整体是暖色调美食风格,选中色用橙色系,未选中用灰色。
首页布局建议用swiper做顶部轮播图,放几个推荐的菜品封面图;下面用分类导航,横向排列几个分类图标,点击跳转到分类页并带上对应分类ID。菜品列表用上下滚动的卡片流,每个卡片显示封面、名称、简介和点击跳转详情的入口。卡片底部加一个收藏按钮,用户可以直接在列表页收藏,不用进详情。
详情页是信息量最大的页面。顶部大图,下面依次是菜名、分类标签、简介,然后是食材清单和步骤列表。食材清单用rich-text渲染,或者直接在WXML里用wx:for循环渲染数组。步骤部分用带数字编号的列表展示,每步一行,简洁清楚。
3.2 wx.request请求封装与接口对接
小程序里发起网络请求用wx.request,如果每个页面都写一遍完整调用,代码会非常冗余。实际开发中一定要做一层封装,把所有请求统一走同一个工具函数。
一个标准的请求封装大概长这样:
// utils/request.js const BASE_URL = 'http://localhost:8080/familychef'; // 后端接口地址 function request(options) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' }, success: (res) => { if (res.data.code === 200) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }); reject(res.data); } }, fail: (err) => { wx.showToast({ title: '网络异常,请检查后端服务', icon: 'none' }); reject(err); } }); }); } module.exports = { request };这里有几个专门处理过的点,都是踩过坑才加上的。
请求地址不能写死“http://localhost:8080”就完事。开发时在微信开发者工具里,localhost能用,但真机调试时手机访问的是后端电脑的地址,必须换成局域网IP,比如http://192.168.1.100:8080/familychef。这个地址要写成可配置的,方便切换。
后端返回的数据结构要统一。约定好{code: 200, msg: 'success', data: {...}}这种三段式结构,前端封装层统一判断code,只有code为200才走resolve,业务错误直接弹toast。这样一来,页面里调用接口就不需要重复写错误处理,代码干净很多。
登录态的token需要放header。家庭大厨这种项目如果做了用户登录,后端会返回一个token(或者直接用openid当标识),小程序端把它存到wx.setStorageSync里,每次请求带上。后端通过拦截器验证token合法性,防一手非法请求。
3.3 组件化与样式适配
小程序支持自定义组件,详情页的菜品卡片、分类页的分类图标、推荐列表里的评分组件,都可以抽成组件复用。卡片组件接收一个菜品对象作为property,渲染出封面、名称、收藏按钮,并触发点击事件让父页面响应。组件化之后,首页、分类页、收藏页都能复用同一套卡片,改样式只改一处。
样式的单位统一用rpx。750rpx等于屏幕宽度,不同机型都会自动适配。做开发时容易犯的错是混合使用px和rpx,导致某些机型上间距忽大忽小。字体大小、间距、图片尺寸,全部用rpx,省心。
顶部导航栏在app.json里可以配置navigationBarTitleText和navigationBarBackgroundColor,但不同机型上导航栏高度不一样。如果页面需要做自定义导航栏(比如详情页沉浸式大图效果),要考虑到状态栏高度——可以使用wx.getSystemInfoSync()获取statusBarHeight,然后手动计算顶部占位高度。家庭大厨这个项目用默认导航栏就够,不必过度设计。
3.4 登录流程的两种实现方式
家庭大厨的登录流程有两种常见做法。第一种是“静默登录+用户信息补充”,用户首次打开小程序时,前端调wx.login拿到code,传给后端换openid,后端查库发现没有这个openid就自动创建一条用户记录,返回给前端一个登录标识。第二种是“显式登录”,用户在“我的”页面点微信头像授权,拿到昵称、头像,再传给后端更新用户信息。
推荐用第一种。wx.login不需要用户主动确认,体验顺滑,用户打开小程序就已经是登录状态,收藏菜谱、上传菜谱这些操作都不需要先走一遍登录弹窗。昵称和头像可以在“我的”页面引导用户授权更新。
这里有个需要注意的地方:新版微信已经不允许通过wx.getUserProfile直接拿头像昵称了,头像需要通过button组件上的open-type="chooseAvatar"让用户手动选择,昵称通过input输入。做项目时要跟上这个规则,不然代码写出来不能通过审核。
4. SSM后端工程实现细节
4.1 工程结构与分层
SSM项目的后端工程结构,按分层思想来组织,一眼看过去就应该知道代码该放哪:
familychef-backend ├── pom.xml ├── src/main/java │ └── com.familychef │ ├── controller │ │ ├── DishController.java │ │ ├── CategoryController.java │ │ ├── FavoriteController.java │ │ └── UserController.java │ ├── service │ │ ├── DishService.java │ │ └── impl/DishServiceImpl.java │ ├── mapper │ │ ├── DishMapper.java │ │ └── CategoryMapper.java │ ├── entity │ │ ├── Dish.java │ │ ├── Category.java │ │ └── User.java │ └── utils │ └── Result.java ├── src/main/resources │ ├── jdbc.properties │ ├── mybatis-config.xml │ ├── spring-mvc.xml │ ├── spring-mybatis.xml │ └── mapper/DishMapper.xml └── src/main/webapp/WEB-INF/web.xmlController层不写业务逻辑,只接收参数、调Service、返回结果。Service层处理业务规则,比如“收藏前判断是否已存在”“菜品新增时校验分类是否存在”。Mapper层只做数据持久化。这样写的好处是,以后Controller里接口变了,或者数据库表变了,改动的范围是可控的。
4.2 Maven依赖配置
pom.xml里要引入的依赖,核心有这几块:Spring核心包、SpringMVC、MyBatis、MyBatis-Spring适配包、MySQL驱动、Druid连接池、Jackson(JSON处理)、Servlet API。有一个容易漏的是Jackson,SpringMVC默认返回JSON需要它来序列化,不配置会出现接口返回数据为空或者报406错误。
数据库连接池建议用Druid,配置监控和连接池参数都很方便。在jdbc.properties里写数据库连接信息:驱动类、URL、用户名、密码。注意URL里要加characterEncoding=utf-8,否则数据库里查出来的中文会乱码。
4.3 Spring与SpringMVC配置
SSM项目配置的核心是两个XML:spring-mybatis.xml和spring-mvc.xml。
spring-mybatis.xml里做几件事:开启注解扫描(扫Service和Mapper)、配置Druid数据源、配置SqlSessionFactory、配置MapperScannerConfigurer扫描Mapper接口生成代理对象、开启事务管理。
spring-mvc.xml里做几件事:开启注解驱动、配置Controller扫描、配置视图解析器(家庭大厨这种纯前后端分离项目,不需要JSP视图,配置个默认的就行)、配置静态资源放行。
关键配置大概是这样:
<!-- spring-mvc.xml 里的核心配置 --> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd HH:mm:ss"/> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>日期格式的转换必须单独配一下。默认Jackson序列化Date类型时输出的是毫秒数或者一串奇怪的格式,前端解析会怀疑人生。统一成yyyy-MM-dd HH:mm:ss,前端拿到直接展示即可。
4.4 Controller接口实现
后端接口设计,遵循REST风格但不用太较真,能用就行。家庭大厨项目核心接口无外乎以下几组:
菜品相关:
- GET
/api/dish/list:分页查询菜品列表,支持分类ID、关键字参数 - GET
/api/dish/detail?id=xxx:查询菜品详情 - POST
/api/dish/add:新增菜品 - PUT
/api/dish/update:更新菜品 - DELETE
/api/dish/delete?id=xxx:删除菜品
分类相关:
- GET
/api/category/list:查询所有分类
收藏相关:
- POST
/api/favorite/add:添加收藏 - POST
/api/favorite/cancel:取消收藏 - GET
/api/favorite/list?userId=xxx:某用户的收藏列表
用户相关:
- POST
/api/user/login:登录,参数为code,返回openid或token - GET
/api/user/info?openid=xxx:获取用户信息 - POST
/api/user/update:更新用户昵称头像
一个典型Controller方法的写法:
@Controller @RequestMapping("/api/dish") public class DishController { @Autowired private DishService dishService; @ResponseBody @RequestMapping(value = "/list", method = RequestMethod.GET) public Result list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, Integer categoryId, String keyword) { PageResult<Dish> data = dishService.getDishPage(page, size, categoryId, keyword); return Result.ok(data); } @ResponseBody @RequestMapping(value = "/detail", method = RequestMethod.GET) public Result detail(@RequestParam Integer id) { Dish detail = dishService.getDishDetail(id); return Result.ok(detail); } }@ResponseBody注解配合Jackson,能把返回值序列化成JSON。Result是统一返回对象,里面封装code、msg、data三个字段,构造函数里Result.ok(data)表示成功,Result.error("参数错误")表示失败。统一的返回格式对前端封装的请求函数特别友好,前后端联调时也少扯皮。
4.5 Service层与MyBatis映射的实战写法
Service层的关键在于判断业务逻辑。比如“新增菜品”这个操作,接收前端传来的表单数据,课程里最容易出现的问题是“一把梭”——Controller直接调Mapper插入,没有任何校验。正规做法是Service里先校验分类是否存在、菜名是否为空、封面图是否属于上传目录,再调用Mapper。
MyBatis的XML映射文件,是SQL真正发挥作用的地方。重点是动态SQL,也就是<where>和<if>标签。分类筛选和关键字搜索组合时,直接拼SQL字符串很容易出现“where后面跟了and”或者“条件掉了”。MyBatis的<where>标签会自动处理多余的and和or,这是它好用的一大原因。
一个常见的查询SQL写法:
<select id="selectDishPage" resultType="com.familychef.entity.Dish"> SELECT id, category_id AS categoryId, name, cover, intro, create_time AS createTime FROM dish <where> <if test="categoryId != null"> AND category_id = #{categoryId} </if> <if test="keyword != null and keyword != ''"> AND name LIKE CONCAT('%', #{keyword}, '%') </if> </where> ORDER BY create_time DESC LIMIT #{offset}, #{pageSize} </select>分页没有引入PageHelper插件,因为项目简单,手动写LIMIT offset, pageSize完全够用,还更容易理解。注意MySQL的LIMIT不支持像SQL Server那样用变量直接传参,要用#{}占位符,offset值在Service层算好传进来。
一对多关系在Mapper里处理。菜品详情的steps字段是JSON字符串,MyBatis查出来直接映射到String类型就行,后端不需要拆开,原样返回给前端,由前端解析。这样最省事儿,也最不容易出错。
5. 常见问题与排查实录
5.1 小程序请求后端失败的排查顺序
这个问题的报错方式五花八门:要么是“request:fail”,要么是控制台一片红,要么是数据一直是空的。遇到请求不通,先按下面的顺序排查:
第一,确认后端服务是启动状态。Tomcat没启动、或者IDEA里运行到一半崩了,小程序端怎么配都是白搭。
第二,确认端口号对不对。SpringMVC默认单Tomcat端口8080,如果你本地还有其他服务占用8080,或者改了端口,小程序端的BASE_URL必须跟着改。
第三,确认是不是网络地址问题。开发者工具里能用localhost不代表手机能用。真机调试时,手机和小程序后端电脑必须在同一个局域网,地址要换成后端的局域网IP。这里有个更隐蔽的坑:有些路由器开了AP隔离,同一个WiFi下设备互访不了,换热点再试。
第四,确认域名校验问题。2024年起微信对request合法域名要求更严格了,开发模式下可以在开发者工具右上角“详情-本地设置”里勾选“不校验合法域名”。但上线时必须在微信公众平台配置request合法域名,要么用HTTPS的正式域名,要么用已备案的云服务器IP。
第五,确认后端接口本身能通。用浏览器直接访问接口URL,比如http://localhost:8080/familychef/api/dish/list?page=1,看返回什么。浏览器能通、小程序不通,那是小程序端问题;浏览器也不通,那是后端问题,节省一半排查时间。
5.2 数据库中文乱码的处理
中文乱码问题在SSM项目里几乎是必踩坑。现象是前端展示的菜名变成问号或者一串乱码。原因一般是三个层面的字符集不统一。
第一层,数据库表的字符集。建表时用CREATE TABLE ... DEFAULT CHARSET=utf8mb4;,utf8mb4能存emoji,普通utf8存不了,小程序端的昵称里经常带emoji,统一用utf8mb4最稳。
第二层,数据源的连接字符集。jdbc.properties里的URL要带characterEncoding=utf-8,这个前面提过,不写必出问题。
第三层,请求的编码。SpringMVC的CharacterEncodingFilter要配置上,拦截所有请求设置UTF-8。配置的位置在web.xml里,一定放到过滤器链的第一个位置,不然POST请求中文参数会乱。
排查的时候先确认数据库里存的内容对不对。数据库里乱,是前两层问题;数据库里正常、接口返回乱,是第三层问题。这样定位很快。
5.3 图片上传后无法访问
图片上传是“家庭大厨”里比较实用的功能,但也容易出问题。最常见的坑是上传成功后数据库有了路径,前端却显示不出图片。
这类问题的根源在于Tomcat默认只处理Web应用内部路径,外部目录的资源要额外映射。如果图片上传到了D:/upload/目录,而Tomcat部署的项目在webapps/familychef,前端直接请求http://localhost:8080/upload/xxx.jpg是404的。
解决办法有两个。一是在spring-mvc.xml里配置资源映射:
<mvc:resources mapping="/upload/**" location="file:D:/upload/" />二是自己写一个Controller接口把图片流输出。开发环境随手用第一种,简单直接。注意location里的路径要以file:开头,且最后要有斜杠。
5.4 收藏功能“点两下报重复”
这个问题的特征很典型:用户第一次点收藏成功,第二次再点的时候报错或者没反应。原因就是收藏表没有做唯一索引,后端也没有做判断。
解决要双管齐下。数据库层面加唯一索引(user_id, dish_id),代码层面在Service里先查一遍是否已存在。如果已存在,接口直接返回“已收藏”状态,前端相应把按钮状态置为已收藏。前端也要配合,“已收藏”状态下按钮应该是实心状态,点击就取消收藏,而不是再次添加。
这里还容易忽略一个细节:收藏操作是否幂等。也就是说,同一个请求重复发两次,后端应该返回相同结果,不能第一次成功第二次报错。做到幂等,前端就算连点两次也不会出幺蛾子。
5.5 小程序端常见的布局适配问题
在做首页卡片列表时,常见问题是iPhone和安卓机型上元素间距不一致。原因基本都出在单位混用上。像高度、间距、圆角这类属性全部用rpx,字体可以偶尔用px,但要接受在不同机型上视觉差异。还有一个坑,图片组件默认不固定高度会剧烈跳动,列表刷新时体验很差。解决方法是给图片容器写死宽高比,比如封面图宽750rpx高420rpx,图片用mode="aspectFill"裁剪填充,页面加载时不会忽高忽低。
iPhone X以后的机型底部有home indicator,用wx.getWindowInfo判断底部安全区,在tabBar或页面底部操作栏上加对应padding。细节虽然小,但做项目演示时,这些细节决定了评委、面试官对你代码质量的判断。
6. 部署与扩展的实用建议
6.1 从本地调试到真机预览
开发完项目,第一步不是上线,而是真机预览。用微信开发者工具扫预览码,手机上打开小程序。这个过程能暴露很多开发者工具里发现不了的问题,尤其是网络请求和适配问题。
预览前要保证后端服务在运行,且手机能访问到后端接口。BASE_URL要改成手机可访问的局域网地址。如果后端电脑开了防火墙,要在防火墙入站规则里放行Tomcat的8080端口,否则手机还是连不上。
预览时打开手机端vConsole,可以实时看报错日志。微信开发者工具里也有“真机调试”功能,跟预览比多一个调试通道,能在电脑上看手机上的console输出和network情况,排查问题的效率高很多。
6.2 上线前要处理的小程序合规问题
如果项目计划上传审核,有几个合规点必须处理。第一个是用户隐私保护指引,小程序后台必须配置收集信息说明,尤其是涉及头像、昵称、位置时。第二个是request合法域名,必须换成备案过的HTTPS域名,开发阶段用的IP地址和localhost一律不能用于线上。第三个是个人信息保护,用户信息不能明文存在数据库,密码之类的字段至少要做哈希处理。
家庭大厨如果要做用户上传菜谱的功能,还需要做内容审核策略,不能让人随意上传不合规内容。这块在演示项目里可以简化,但文档里最好提一嘴,显得考虑周全。
6.3 后续可以扩展的方向
做完基础版本后,有几个扩展方向非常自然。第一个是首页推荐算法,可以根据收藏量排序,做“热菜榜”。第二个是搜索历史,用小程序缓存存储最近搜索词。第三个是用户主页,展示用户上传的菜谱和收藏列表。第四个是做菜谱的“一键生成购物清单”,把菜品里的食材汇总成列表,这是很实用的家庭场景功能。
还有一个可以关注的是订阅消息。用户收藏的菜谱有更新时,可以通过订阅消息推送提醒。注意微信的订阅消息是一次性订阅,每次推送前要引导用户点击授权,跟传统App的消息推送逻辑不太一样。
7. 我个人做这套项目的体感
做这类全栈项目,最花时间的地方其实不是写代码,而是联调。前端觉得后端接口返回格式不对,后端觉得前端传参不规范,两边一扯,半天就没了。我的经验是,动手之前先把接口文档定下来:每个接口的URL、请求方法、参数、返回结构,用表格列清楚。前后端各自照着文档开发,联调阶段基本一次过。
另一个体感很深的点是,项目演示时的流畅度很加分。数据量不大时接口响应都在毫秒级,但如果写SQL时不注意,关联查询查出几万行数据,页面就卡了。写SQL时先在数据库客户端把SQL跑一遍,看执行计划,再用到Mapper里。这套习惯,哪怕以后换到Spring Boot、MyBatis Plus,也一样用得上。
如果你正在做类似的课设或毕设项目,“家庭大厨”这个方向既不会太小显得单薄,也不会复杂到把控不住。把一个完整闭环跑通——从数据库到后端、从后端到小程序、从小程序回到用户操作,比堆砌花哨功能更有价值。做完之后,代码结构、接口设计、问题排查的思路,都会成为你下一份工程实践里最扎实的地基。