某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548
文章目录
- 1.需求分析
- 2.数据模型
- 3.代码开发
- 3.1 创建基本结构
- 3.2 代码实现
- 4.功能测试
1.需求分析
后台系统中可以管理分类信息,分类包括两种类型,分别是菜品分类和套餐分类。当我们在后台系统中添加菜品时需要选择一个菜品分类,当我们在后台系统中添加一个套餐时需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐。
如上,可以在后台系统的分类管理页面分别添加菜品分类和套餐分类:
2.数据模型
分类涉及到的数据库表为 category:
简单说明如下:
- name 字段设置了唯一约束,即分类名称不可重复;
- type 字段表示分类类型,1 为菜品分类,2 为套餐分类;
- sort 字段为该分类的排序优先级。
3.代码开发
3.1 创建基本结构
在正式开发之前,需要先将用到的类和接口的基本结构创建好。
实体类 entity/Category
(之前已经一次性导入了所有实体类了,直接使用即可),完整代码如下:
package cn.javgo.reggie_take_out.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 分类
*/
@Data
public class Category implements Serializable {
// 用于序列化的版本号
private static final long serialVersionUID = 1L;
// 主键
private Long id;
//类型 1 菜品分类 2 套餐分类
private Integer type;
//分类名称
private String name;
//顺序
private Integer sort;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
// private Integer isDeleted;
}
注意,先注释掉上述实体类中的 isDeleted 属性,后续涉及到时我们再进行分析。
准备 Mapper 接口 mapper/CategoryMapper
,声名如下:
package cn.javgo.reggie_take_out.mapper;
import cn.javgo.reggie_take_out.entity.Category;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
准备业务层接口 service/CategoryService
,及其实现类 service/CategoryServiceImpl
,声名如下:
package cn.javgo.reggie_take_out.service;
import cn.javgo.reggie_take_out.entity.Category;
import com.baomidou.mybatisplus.extension.service.IService;
public interface CategoryService extends IService<Category> {
}
package cn.javgo.reggie_take_out.service.impl;
import cn.javgo.reggie_take_out.entity.Category;
import cn.javgo.reggie_take_out.mapper.CategoryMapper;
import cn.javgo.reggie_take_out.service.CategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}
控制层 controller/CategoryController
,声名如下:
package cn.javgo.reggie_take_out.controller;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CategoryController {
}
3.2 代码实现
程序执行过程大致如下:
- 页面(backend/page/category/list.html)发送 ajax 请求,将新增分类窗口输入的数据以 json 形式提交到服务端;
- 服务端 Controller 接收页面提交的数据并调用 Service 将数据进行保存;
- Service 调用 Mapper 操作数据库,保存数据。
可以看到新增菜品分类和新增套餐分类请求的服务端地址(/category)和提交的 json 数据结构相同,所以服务端只需要提供一个方法统一处理即可:
如果是添加分类则会自动带上 type=1,如果是添加套餐则是 type=2:
CategoryController
中对应的处理方法如下:
package cn.javgo.reggie_take_out.controller;
import cn.javgo.reggie_take_out.common.R;
import cn.javgo.reggie_take_out.entity.Category;
import cn.javgo.reggie_take_out.service.CategoryService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 分类管理
*/
@RestController
@RequestMapping("/category")
public class CategoryController {
@Resource
private CategoryService categoryService;
/**
* 新增分类
* @param category 分类实体
* @return R
*/
@PostMapping
public R<String> save(@RequestBody Category category){
categoryService.save(category);
return R.success("新增分类成功");
}
}
4.功能测试
由于数据库表中已经有 “川菜”的分类了:
前面我们说过分类名字是设置了唯一约束的,所以我们再次添加“川菜”肯定会报异常,但是由于我们之前已经写了处理该异常的全局异常处理器,所以会进行对应的错误提示:
上面会显示“<唯一字段> 已存在”字样,是因为我们对 GlobalExceptionHandler#exceptionHandler
方法做了一些小小的改动,具体如下:
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
if(ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
return R.error(split[2] + "已存在");
}
return R.error("未知错误");
}
我们可以将 “川菜”这条记删除后再重新进行添加:
从新增的结记录中我们还可以看到之前写的公共字段也是正确地进行了填充: