苍穹外卖 Day03:菜品 CRUD、店铺状态与微信登录
菜品模块完整 CRUD
接口一览(/admin/dish)
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /admin/dish | 新增菜品(含口味,前一日已完成) |
| GET | /admin/dish/page | 分页查询(可选条件:name/categoryId/status) |
| DELETE | /admin/dish?ids=1,2,3 | 批量删除(删除前校验) |
| GET | /admin/dish/{id} | 根据 id 查询(含口味,回显用) |
| PUT | /admin/dish | 修改菜品(先删口味再重插) |
分页查询
PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());DishMapper.xml 里 left outer join category c on d.category_id = c.id 联表取 categoryName,配合 <where> 动态条件与 order by d.create_time desc 排序。
批量删除
删除前做两道校验,全部通过才执行删除:
// 校验是否起售中for (Long id : ids) { Dish dish = dishMapper.getById(id); if (dish.getStatus() == StatusConstant.ENABLE) { throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE); }}// 校验是否被套餐关联List<Long> setmealIds = setmealDishMapper.getSetmealDishIds(ids);if (setmealIds != null && setmealIds.size() > 0) { throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);}// 批量删主表 + 批量删口味表dishMapper.deleteByIds(ids);dishFlavorMapper.deleteByDishIds(ids);套餐关联校验对应的 SQL 在 SetmealDishMapper.xml:select setmeal_dish.id from setmeal_dish where setmeal_dish.dish_id in (...)。
修改菜品
主表 update(动态 <set>)+ 删旧口味 + 批量插新口味:
dishMapper.update(dish); // 动态 set,AutoFill 补 updateTime/updateUserdishFlavorMapper.deleteByDishId(dishDTO.getId()); // 删旧口味// 再 insertBatch 新口味(foreach 回填 dishId)DishMapper.xml 的 deleteByIds/update 用到 <foreach> / <set> / <if> 动态标签;公共字段由 @AutoFill(value = OperationType.INSERT/UPDATE) 标记、切面自动填充。
Redis 店铺营业状态
营业状态是高频访问、且要被管理端与用户端跨端共享的数据,适合放 Redis。存 Integer 值:1 = 营业中,0 = 打烊中;key 为常量 SHOP_STATUS,读取走 (Integer) redisTemplate.opsForValue().get(KEY)。
RedisTemplate 配置的一个坑
@Configuration@Slf4jpublic class RedisConfiguration { public RedisTemplate redisTemplate(RedisConnectionFactory factory) { // 设置了 key 的 String 序列化器 template.setKeySerializer(new StringRedisSerializer()); return template; }}问题是 redisTemplate 方法上少了 @Bean:该方法不会被 Spring 调用注册,自定义序列化配置完全不生效。此时 @Autowired RedisTemplate 注入的实际是 Spring Boot 自动配置(RedisAutoConfiguration)提供的默认 RedisTemplate(JDK 序列化)。功能能跑,但 key/value 在 Redis 里是二进制乱码。修复就是在方法上加 @Bean。
admin/user 双 ShopController
管理端与用户端各有一个 ShopController,类名相同会引发 bean 名冲突,用显式命名规避:@RestController("adminShopController") / @RestController("userShopController")。
- 管理端:
PUT /admin/shop/{status}设置状态;GET /admin/shop/status查询 - 用户端:
GET /user/shop/status只读查询
微信登录
登录流程(UserController.login → UserServiceImpl.wxLogin):
- 小程序调
wx.login()拿临时code - 后端请求微信
https://api.weixin.qq.com/sns/jscode2session(参数:appid/secret/js_code/grant_type=authorization_code),换回openid(附 session_key) - 按 openid 查 user 表:不存在则自动注册(UserMapper.xml 的 insert 配
useGeneratedKeys="true" keyProperty="id"回填主键);存在则直接登录 - 签发用户端 JWT(
JwtProperties.userSecretKey/userTtl,claims 放userId) - 返回
UserLoginVO{id, openid, token},后续请求在请求头携带 token
关键点:
- openid 为 null 时抛
LoginFailedException(LOGIN_FAILED),走业务异常统一处理 - claims 键用
JwtClaimsConstant.USER_ID = "userId",与管理端的 EMP_ID 区分 - UserMapper 上有注解 SQL
@Select("select * from user where openid = #{openId}"),insert 走 XML
两个待修隐患:
- UserServiceImpl 误 import 了
org.aspectj.bridge.Message,属无用脏 import,应删除 - 用户端 JWT 校验拦截器尚未实现——WebMvcConfiguration 目前只注册了
/admin/**的 JwtTokenAdminInterceptor,/user/**的校验需要补上
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





















