瑞吉外卖项目复盘(五)
本章内容
- 新增套餐(SetmealDishDto,需要操作两张表,需要添加@Transactional)
- 套餐分页查询(页面展示需要套餐分类的名称字段,因此SetmealDishDTO中需要有一个categoryName字段)
- 删除套餐(需要删除套餐的基本信息和套餐对应的菜品信息,因此也需要添加@Transactional标签)
- 短信发送
- 手机验证码登录(登录成功会将用户的手机号存入session中,登录的验证码也可以放到session中方便比对)
1、新增套餐
将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal_dish表插入套餐和菜品的关联数据。因此在新增套餐时,涉及到两个表:setmeal和setmeal_dish表。
在setmeal_dish表中我们存储了菜品的name和price的冗余信息,这样我们就不用再根据dish_id去dish表中查询菜品的name和price了。
SetmealDto
这个数据传输对象DTO,主要用于封装页面在新增套餐时传递过来的json格式的数据,其中包含套餐的基本信息,还包含套餐关联的菜品集合。
新增套餐的逻辑:
- 新建套餐需要选择套餐的分类,需要获取套餐分类列表。(已实现)
- 为套餐选择菜品时需要获取菜品的分类列表。(已实现)
- 需要获取每个菜品分类下的菜品信息,用于选择菜品。
- 图片上传(已实现)
- 图片下载(已实现)
- 把套餐的相关信息上传给服务器,服务器需要保存套餐信息
其他的都已实现,我们只需要实现3和6:
根据类别id查询菜品列表
根据这个需求,我们只需要根据页面传递的菜品分类的id,查询菜品列表即可。可以直接在DishController里新增一个方法,声明一个Long类型的categoryId,这样做是没问题的。但是考虑到该方法的拓展性,我们在这里定义方法时,通过Dish这个实体类接收参数。
保存套餐
前端提交的数据,可以使用SetmealDishDto传递,不仅包含套餐的基本信息,还包含套餐的菜品列表。需要在业务层SetmealService定义saveWithDish方法,并在ImplServiceImpl中实现该方法。具体实现逻辑:
- 保存套餐基本信息
- 保存套餐关联的菜品集合,并为集合中的每一个元素赋值套餐ID。
- 批量保存套餐关联的菜品集合
需要注意的是:这里对两张表进行操作,需要设置事务
套餐分页查询
在进行套餐数据分页查询时,除了传递分页参数外,还可以传递一个可选的条件(套餐名称)。查询返回的字段中,除了套餐的基本信息,还有一个套餐的分类名称(因此SetmealDishDto中需要有一个categoryName字段)。
分页查询功能的实现逻辑:
- 构建分页条件对象
- 构建查询条件对象,如果传递了套餐名称,根据套餐名称模糊查询,并对结果按修改时间降序配列
- 执行分页查询
- 组装数据并返回
删除套餐
可以删除单个套餐,也可以通过选中复选框批量删除套餐。(对于售卖中的套餐不能删除,需要先停售,然后才能删除)
删除单个和批量删除套餐可以合并成一个函数,根据传递过来的要删除的套餐id列表去删除套餐表中的套餐基本信息和SetmealDish表中,套餐对应的菜品信息。该方法的实现逻辑为:
- 查询该批次套餐中是否存在售卖中的套餐,如果存在,不允许删除
- 删除套餐数据
- 删除套餐关联的菜品信息
短信发送
可以使用阿里云短信服务,
需要引入阿里云的SDK,根据其提供的模板,将对应的手机号,签名修改成我们自己的签名就可以使用了。
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>2.1.0</version>
</dependency>
验证码登录
为了方便用户登录,移动端通常会提供通过手机验证码登录的功能。手机验证码登录有如下优点:
- 方便快捷,无需注册,直接登录(手机号作为区分用户的标识)
- 使用短信验证码作为登录凭证,无需记忆密码
- 安全
如果验证登录成功,服务端会把用户的手机号存储在sessionStorage中,前端页面会跳转到移动端的首页页面。。
这里我们需要将手机验证码登录用到的两个请求(获取验证码和登录)在过滤器处理时直接放行。对于移动端的页面,也是用户登录之后才可以访问的,如果用户已登录,我们获取到登录信息,存入ThreadLocal中(在后续的业务处理中,如果需要获取登录用户的Id,可以直接从ThreadLocal中获取)
服务端生成的验证码也可以存入session中,便于登陆时进行比对。
登录方法的具体逻辑为:
- 获取前端传递的手机号和验证码
- 从Session中获取手机号对应的正确的验证码
- 进行验证码的比对,如果比对失败,直接返回错误信息
- 如果比对成功,需要根据手机号查询当前用户,如果用户不存在,则自动注册一个用户
- 将登录用户的ID存储到Session中