写在前面
在学习苍穹外卖过程中,弹幕常有 “为什么我打不开?为什么我没有输出?”的疑问,针对这些我也在学习过程中同样遇到的问题,万分感激在弹幕中找到了答案,并作出这系列汇总。本文内容是基于弹幕对苍穹外卖项目的实施与补充,仅供学习与分享之用,如有侵权请联系删除~
2024-07-30
目录
EmployeeController:startOrStop()
EmployeeService & EmployeeServiceImpl :startOrStop()实现逻辑
EmployeeMapper&EmployeeMapper.xml:声明 update 方法
EmployeeMapper.xml编写
① 查询接口:EmployeeController:getById()
① 查询接口:EmployeeService & EmployeeServiceImpl 实现 getById逻辑
EmployeeServiceImpl 实现 getById逻辑
① 查询接口:EmployeeMapper接口中声明 getById
②更新接口:EmployeeController 中创建 update方法
②更新接口:EmployeeService&EmployeeServiceImpl 实现逻辑
EmployeeServiceImpl 实现update 方法
CategoryController的save方法
CategoryDTO类
CategoryService & CategoryServiceImpl的save方法
CategoryService的save方法代码
CategoryServiceImpl的save实现逻辑
CategoryMapper.java & CategoryMapper.xml
CategoryMapper.java的insert方法
CategoryController的page方法
CategoryService & CategoryServiceImpl:pageQuery实现逻辑:
CategoryService的pageQuery方法代码
CategoryServiceImpl的pageQuery方法代码
CategoryMapper.java & CategoryMapper.xml定义pageQuery方法
CategoryMapper.java声明pageQuery方法
CategoryMapper.xml定义pageQuery
CategoryController的deleteById方法
CategoryService & CategoryServiceImpl:deleteById实现逻辑:
CategoryService的deleteById方法代码
CategoryServiceImpl的deleteById方法代码
DishMapper.java的countByCategoryId方法
SetmealMapper.java的countByCategoryId方法
抛异常时,输出提示
CategoryMapper.java & CategoryMapper.xml定义deleteById方法
CategoryMapper.java声明deleteById方法
CategoryController的update方法
CategoryService & CategoryServiceImpl的update方法
CategoryService的update方法代码
CategoryServiceImpl的update实现逻辑
CategoryMapper.java & CategoryMapper.xml的update方法
CategoryMapper.java实现update
CategoryMapper.xml的update方法
CategoryController的startOrStop方法
CategoryService & CategoryServiceImpl的startOrStop方法
CategoryService的startOrStop方法代码
CategoryServiceImpl的startOrStop实现逻辑
CategoryController的list方法
CategoryService & CategoryServiceImpl的list方法
CategoryService的list方法代码
CategoryServiceImpl的list实现逻辑
CategoryMapper.java & CategoryMapper.xml的list方法
CategoryMapper.java实现list
CategoryMapper.xml的list方法
修改分类④
启用、禁用员工账号功能
需求分析和设计
分析 => 查看产品原型
思考:启用、禁用员工账号,通过修改什么数据实现?
设计 ==> 接口文档
思考:
用何种请求方式? ==> post请求 ==> 路径传参(status/n)、查询传参(?id=n)给后端处理;
如何传参? ==> 示例路径:http://localhost/api/employee/status/1?id=6
为什么要传id?==> 需要知道哪个员工修改状态
实现逻辑
EmployeeController:startOrStop()
- 返回值:封装为Result ==> result是否添加泛型数据 取决于data是否需要返回
- 如本功能必须返回code,不需返回data ==> 不需要添加泛型数据
- 需要返回data:一般在查询时用 ==> 添加泛型示例 Result<Employee>
@PostMapping注解:根据接口文档,将缺少的路径部分补充上
接收路径参数:使用@PathVariable注解声明
路径参数的名称和参数名称一致,可直接使用;
名称不一致需要补充声明,如👇
EmployeeService & EmployeeServiceImpl :startOrStop()实现逻辑
- 利用传来的status和id创建对应的实体对象;
- 将该实体作为参数,调用mapper执行update方法修改;
当要修改数据库某一条数据时,修改方法最好传实体为参数(而不是某个值),可以提高代码的复用性。
EmployeeServiceImpl启用、禁用员工方法
使用builder()方法构建员工实体(需要在Employee类添加注释才可使用)
EmployeeMapper&EmployeeMapper.xml:声明 update 方法
动态SQL语句在mapper文件中声明,在xml文件中编写
EmployeeMapper.java声明
EmployeeMapper.xml编写
- 动态SQL语句执行更新:根据传来的Employee实体对象不同(哪些属性为空),执行的SQL语句随之不同。
- parameterType="Employee" ==> 不写完整的包名可以对应到相应的实体类吗
- mybatis配置已经在yml文件里完成
测试:图方便用前后端联调了
使用swagger测试别忘记配置token(详见day2篇)
编辑员工功能
需求分析与设计
分析 => 查看产品原型
思考:原型展示涉及了几个接口?
- 修改时数据回显 ==> 查询员工数据接口
- 保存按钮 ==> 修改员工数据接口
设计 => 接口文档
- 查询 ==> GET请求、路径参数传参(查询的员工id)、返回员工数据(data)
- 修改 ==> PUT请求、请求体json传参、返回code
POST | PUT | |
---|---|---|
服务器资源 | 创建新资源、非幂等性(重复请求结果可能不同) | 更新现有资源、幂等性(重复请求结果不变) |
URL | 通常指向一个集合的资源(例POST /users),在该集合中创建一个新的子资源。 | 通常指向具体的资源(例/users/1),服务器根据请求体中的数据更新该资源。 |
响应 | 服务器通常返回201 Created状态码,并在响应头中包含新创建资源的URL (例 HTTP/1.1 201 Created | 服务器通常返回200 OK状态码或204 No Content状态码,表示资源已成功更新。 (例 HTTP/1.1 200 OK) |
实现逻辑
① 查询接口:EmployeeController:getById()
- 需要返回data,明确泛型为Employee实体
- 接收路径参数id
- 将id作为参数,调用(稍后定义的)EmployeeService的getById方法
- 将方法返回的实体作为参数data返回给前端
① 查询接口:EmployeeService & EmployeeServiceImpl 实现 getById逻辑
- 根据参数id,调用mapper的getById(id)方法查询;
- 获取返回的Employee实体对象,保证安全性,修改****隐藏密码;
- 然后返回Employee实体对象给前端;
EmployeeServiceImpl 实现 getById逻辑
① 查询接口:EmployeeMapper接口中声明 getById
编写静态SQL语句
②更新接口:EmployeeController 中创建 update方法
- @PostMapping注解:定义接口路径
- 接收参数:接收json格式的DTO,要用@RequestBody注解
- 调用service的update方法(稍后定义),将DTO作为参数传入
- 返回值:封装为Result
(修改员工接口和day2新增员工接口十分相似,只需修改@PutMapping注解、方法名即可)
②更新接口:EmployeeService&EmployeeServiceImpl 实现逻辑
EmployeeServiceImpl 实现update 方法
- 创建一个新的Employee实体对象
- 将EmployeeDTO的属性复制到该实体对象中
- 补充缺少的属性值
- 将该实体作为参数,调用mapper的update方法(前文启、禁用员工功能时已完成定义)
BaseContext.java类 详见day2篇
测试:
使用swagger测试接口(太麻烦了、、省略) ==> 前后端联调测试
数据回显👇
保存更新员工数据👇
分类模块功能(课程内只需要导入,在此分析代码加深理解)
个人感觉功能③较为重要
(tips:跟视频导入代码,因为是拷贝的类,防止未编译,建议在Maven手动编译一下)
需求分析与设计
分析 => 查看产品原型
思考:原型展示的数据应该有何种限制?何种规则?
业务规则:
- 分类名称必须是唯一的
- 分类按照类型可以分为菜品分类和套餐分类
- 新添加的分类状态默认为“禁用”
设计 => 接口文档
思考:该模块涉及多少接口?
接口设计:增、删、改、查(图片太多不放了。。)
- 新增分类 ==> POST请求、请求体json传参、返回code
- 分类分页查询 ==> GET请求、查询参数传参、返回data
- 根据id删除分类 ==> DELETE请求、查询参数传参、返回code
- 修改分类 ==> PUT请求、请求体json传参、返回code
- 启用禁用分类 ==> POST请求、路径(status/n)、查询参数(?id=n)传参、返回code
- 根据类型查询分类 ==> GET请求、查询参数传参、返回data
数据库如何设计分类表?
Name:唯一
Type:1菜品分类,2套餐分类
Sort :用于分类数据的排序 – 固定分类查询列表的顺序
Status:启用禁用
实现逻辑:
创建新CategoryController类
路径:src/main/java/com/sky/controller/admin/CategoryController.java
- 添加@RestController注解在MVC中声明Controller类
- 添加@RequestMapping("/admin/category")请求路径
- API注解,在swagger测试中显示模块名称
- 使用@Slf4j注解,可用于管理输出日志
- @Autowired注入service调用功能
新增分类 ①
CategoryController的save方法
- 根据接口文档的路径和请求方法 ==> 定义注解
- 定义返回值 ==> <String>可以省略
- 使用DTO接收前端传来的参数
CategoryDTO类
为什么使用DTO类在day2篇已有说明,不做赘述。
CategoryService & CategoryServiceImpl的save方法
路径:
- src/main/java/com/sky/service/CategoryService.java(如果自己新建,注意新建为接口)
- src/main/java/com/sky/service/impl/CategoryServiceImpl.java(Java类)
CategoryService的save方法代码
CategoryServiceImpl的save实现逻辑
创建新 分类对象
将传来的DTO的属性复制给该分类对象
新添加的分类为禁用 ==> 防止在没有添加菜品时将空分类展示在用户端
将缺少的属性手动补齐
调用mapper的insert(稍后在mapper定义)方法,传入该实体对象
(有关联数据的新增、修改、删除时都需要多考虑一下 !!!)
CategoryMapper.java & CategoryMapper.xml
路径:
- src/main/java/com/sky/mapper/CategoryMapper.java(如果自己新建,注意新建为接口)
- src/main/resources/mapper/CategoryMapper.xml
CategoryMapper.java的insert方法
使用注解编写静态SQL
分页查询②
CategoryController的page方法
- @GetMapping注解:定义接口路径,补上类缺失的 " /page "
- 接收参数:接收查询参数传参的DTO,不用@RequestBody注解
- 调用service的pageQuery方法(稍后定义),将DTO作为参数传入
- 返回值:封装的Result<PageResult>
CategoryService & CategoryServiceImpl:pageQuery实现逻辑:
CategoryService的pageQuery方法代码
CategoryServiceImpl的pageQuery方法代码
- 使用PageHelper插件,传入 页码、每页展示数 => 在每次查询SQL中拼接 limit...)
- 调用mapper,根据DTO查询数据库,返回Page<实例>
- 如果DTO的name属性为空:查询整表;
- 如果DTO的name属性非空:根据name模糊查询;
- 将page封装为自定义的PageResult对象返回
(自定义的PageResult对象在day2已说明)
CategoryMapper.java & CategoryMapper.xml定义pageQuery方法
CategoryMapper.java声明pageQuery方法
CategoryMapper.xml定义pageQuery
根据id删除分类③
CategoryController的deleteById方法
- @DeleteMapping注解:根据接口文档,不用补路径
- 接收参数:接收查询参数传参的id
- 调用service的deleteById方法(稍后定义),将id作为参数传入
- 返回值:code
CategoryService & CategoryServiceImpl:deleteById实现逻辑:
CategoryService的deleteById方法代码
CategoryServiceImpl的deleteById方法代码
删除分类时,不能有关联该分类的菜品、套餐 ==> 否则删除了菜品、套餐没分类了。。
- 查询该id分类是否关联了菜品 ==> 调用dishMapper
- 在dishMapper定义countByCategoryId方法,根据id查询计数有多少符合条件的dish,返回一个Integer
- if判断,>0则该id分类关联了菜品,抛异常 ==> 提示不能删除
- 查询该id分类是否关联了套餐 ==> 调用SetmealMapper
- 在SetmealMapper定义countByCategoryId方法,根据id查询计数有多少符合条件的setmeal,返回一个Integer
- if判断,>0则该id分类关联了套餐,抛异常 ==> 提示不能删除
都没抛异常,即没关联菜品和套餐,调用categoryMapper的deleteById方法(稍后定义),传入该id删除
DishMapper.java的countByCategoryId方法
SetmealMapper.java的countByCategoryId方法
抛异常时,输出提示
- CATEGORY_BE_RELATED_BY_DISH:当前分类关联了菜品,不能删除
- CATEGORY_BE_RELATED_BY_SETMEAL:当前分类关联了套餐,不能删除
CategoryMapper.java & CategoryMapper.xml定义deleteById方法
CategoryMapper.java声明deleteById方法
修改分类④
CategoryController的update方法
- 根据接口文档的路径和PUT请求方法 ==> 定义注解
- 定义返回值 ==> <String>可以省略
- 使用DTO接收前端传来的参数
CategoryService & CategoryServiceImpl的update方法
CategoryService的update方法代码
CategoryServiceImpl的update实现逻辑
- 创建新Category分类对象
- 将传来的DTO的属性复制给该分类对象
- 将缺少的属性手动补齐
- 调用mapper的update(稍后在mapper定义)方法,传入该实体对象
CategoryMapper.java & CategoryMapper.xml的update方法
CategoryMapper.java实现update
CategoryMapper.xml的update方法
启用禁用分类 ⑤
CategoryController的startOrStop方法
- 根据接口文档的路径和POST请求方法 ==> 补全路径
- 定义返回值 ==> <String>可以省略
- 接收路径参数:使用@PathVariable注解声明,接收路径参数status和查询参数id
CategoryService & CategoryServiceImpl的startOrStop方法
CategoryService的startOrStop方法代码
CategoryServiceImpl的startOrStop实现逻辑
- 根据status和id参数创建Category分类对象
- 调用mapper的update(修改分类功能时在mapper定义)方法,传入该实体对象
根据类型查询分类⑥
分类类型有(菜品1、套餐2)
CategoryController的list方法
- 根据接口文档的路径和GET请求方法 ==> 补全路径
- 定义返回值 ==> 分类实体对象列表作为data 封装为result
- 接收路径参数:查询参数type(菜品1、套餐2)
- 调用CategoryService的list方法,返回分类实体对象列表list
CategoryService & CategoryServiceImpl的list方法
CategoryService的list方法代码
CategoryServiceImpl的list实现逻辑
- 调用mapper,根据type的值 查询返回 实体list
CategoryMapper.java & CategoryMapper.xml的list方法
CategoryMapper.java实现list
CategoryMapper.xml的list方法
所以符合查询条件的n条数据,封装为n个实体的列表list返回
测试
使用前后端联调测试(swagger填数据实在有点麻烦。。)
分页查询功能②
新增分类功能①
根据id删除分类③
启用、禁用分类⑤
根据类型查询分类⑥
修改分类④