一、项目介绍&Github
线上点单小程序和后台管理系统 后端,Github项目地址:springboot-order-out

1. 管理端
| 模块 | 描述 |
|---|---|
| 登录/退出 | 内部员工必须登录后,才可以访问系统管理后台 |
| 员工管理 | 管理员可以在系统后台对员工信息进行管理,包含查询、新增、编辑、禁用等功能 |
| 分类管理 | 主要对当前餐厅经营的 菜品分类 或 套餐分类 进行管理维护, 包含查询、新增、修改、删除等功能 |
| 菜品管理 | 主要维护各个分类下的菜品信息,包含查询、新增、修改、删除、启售、停售等功能 |
| 套餐管理 | 主要维护当前餐厅中的套餐信息,包含查询、新增、修改、删除、启售、停售等功能 |
| 订单管理 | 主要维护用户在移动端下的订单信息,包含查询、取消、派送、完成,以及订单报表下载等功能 |
| 数据统计 | 主要完成对餐厅的各类数据统计,如营业额、用户数量、订单等 |
2. 用户端
| 模块 | 描述 |
|---|---|
| 登录/退出 | 用户需要通过微信授权后登录使用小程序进行点餐 |
| 点餐-菜单 | 在点餐界面需要展示出菜品分类/套餐分类, 并根据当前选择的分类加载其中的菜品信息, 供用户查询选择 |
| 点餐-购物车 | 用户选中的菜品就会加入用户的购物车, 主要包含 查询购物车、加入购物车、删除购物车、清空购物车等功能 |
| 订单支付 | 用户选完菜品/套餐后, 可以对购物车菜品进行结算支付, 这时就需要进行订单的支付 |
| 个人信息 | 在个人中心页面中会展示当前用户的基本信息, 用户可以管理收货地址, 也可以查询历史订单数据 |
二、技术选型

1). 用户层
本项目中在构建系统管理后台的前端页面,我们会用到H5、Vue.js、ElementUI、apache echarts(展示图表)等技术。而在构建移动端应用时,我们会使用到微信小程序。
2). 网关层
Nginx是一个服务器,主要用来作为Http服务器,部署静态资源,访问性能高。在Nginx中还有两个比较重要的作用: 反向代理和负载均衡, 在进行项目部署时,要实现Tomcat的负载均衡,就可以通过Nginx来实现。
3). 应用层
SpringBoot: 快速构建Spring项目, 采用 “约定优于配置” 的思想, 简化Spring项目的配置开发。
SpringMVC:SpringMVC是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合,可以无缝集成。
Spring Task: 由Spring提供的定时任务框架。
httpclient: 主要实现了对http请求的发送。
Spring Cache: 由Spring提供的数据缓存框架
JWT: 用于对应用程序上的用户进行身份验证的标记。
阿里云OSS: 对象存储服务,在项目中主要存储文件,如图片等。
Swagger: 可以自动的帮助开发人员生成接口文档,并对接口进行测试。
POI: 封装了对Excel表格的常用操作。
WebSocket: 一种通信网络协议,使客户端和服务器之间的数据交换更加简单,用于项目的来单、催单功能实现。
4). 数据层
MySQL: 关系型数据库, 本项目的核心业务数据都会采用MySQL进行存储。
Redis: 基于key-value格式存储的内存数据库, 访问速度快, 经常使用它做缓存。
Mybatis: 本项目持久层将会使用Mybatis开发。
pagehelper: 分页插件。
spring data redis: 简化java代码操作Redis的API。
5). 工具
git: 版本控制工具, 在团队协作中, 使用该工具对项目中的代码进行管理。
maven: 项目构建工具。
junit:单元测试工具,开发人员功能实现完毕后,需要通过junit对功能进行单元测试。
postman: 接口测工具,模拟用户发起的各类HTTP请求,获取对应的响应结果。
三、开发环境搭建
后端模块:
| 序号 | 名称 | 说明 |
|---|---|---|
| 1 | sky-take-out | maven父工程,统一管理依赖版本,聚合其他子模块 |
| 2 | sky-common | 子模块,存放公共类,例如:工具类、常量类、异常类等 |
| 3 | sky-pojo | 子模块,存放实体类、VO、DTO等 |
| 4 | sky-server | 子模块,后端服务,存放配置文件、Controller、Service、Mapper等 |
- sky-common: 模块中存放的是一些公共类,可以供其他模块使用
| 名称 | 说明 |
|---|---|
| constant | 存放相关常量类 |
| context | 存放上下文类 |
| enumeration | 项目的枚举类存储 |
| exception | 存放自定义异常类 |
| json | 处理json转换的类 |
| properties | 存放SpringBoot相关的配置属性类 |
| result | 返回结果类的封装 |
| utils | 常用工具类 |
- sky-pojo: 模块中存放的是一些 entity、DTO、VO
| 名称 | 说明 |
|---|---|
| Entity | 实体,通常和数据库中的表对应 |
| DTO | 数据传输对象,通常用于程序中各层之间传递数据 |
| VO | 视图对象,为前端展示数据提供的对象 |
| POJO | 普通Java对象,只有属性和对应的getter和setter |
- sky-server: 模块中存放的是 配置文件、配置类、拦截器、controller、service、mapper、启动类等
| 名称 | 说明 |
|---|---|
| config | 存放配置类 |
| controller | 存放controller类 |
| interceptor | 存放拦截器类 |
| mapper | 存放mapper接口 |
| service | 存放service类 |
| SkyApplication | 启动类 |
- 数据库:
| 序号 | 表名 | 中文名 |
|---|---|---|
| 1 | employee | 员工表 |
| 2 | category | 分类表 |
| 3 | dish | 菜品表 |
| 4 | dish_flavor | 菜品口味表 |
| 5 | setmeal | 套餐表 |
| 6 | setmeal_dish | 套餐菜品关系表 |
| 7 | user | 用户表 |
| 8 | address_book | 地址表 |
| 9 | shopping_cart | 购物车表 |
| 10 | orders | 订单表 |
| 11 | order_detail | 订单明细表 |
四、员工管理
4.1 新增员工
原型:

接口设计:

① sql
sql 不要写错,插入字段和values属性一一对应,否则无法插入数据。
/**
* 插入员工数据
* @param employee
* @return
*/
@Insert("insert into employee(name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status)" +
" VALUES" +
"(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status}) ")
void insert(Employee employee);
yml文件中设置驼峰命名所以插入字段中不需要起别名

② 对象拷贝 DTO 与 Entity
DTO是根据请求参数建立的实体类,在与原实体有较大差别时候,另外建立一个实体,用来接收请求参数
使用DTO接收前端请求数据,之后 再用Entity实体类封装,使用对象拷贝,剩下的数据手动SET设置。

③ 异常捕获与处理
当录入的用户名已存在,抛出了异常,但是没有处理


全局异常处理 GlobalExceptionHandler
添加对报错异常的处理方法:
查看是否包含特定异常信息,再截取报错消息,返回给前端显示。
/**
* 重复数据 Duplicate entry 异常
*
* @param ex SQLIntegrityConstraintViolationException
* @return
*/
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex) {
log.error("异常信息:{}", ex.getMessage());
//Duplicate entry 'dougwake' for key 'employee.idx_username'
String message = ex.getMessage();
if (message.contains("Duplicate entry")) {
String[] split = message.split(" ");
String username = split[2];
String msg = username + MessageConstant.ALREADY_EXISTS;
return Result.error(msg);
}
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
捕获异常,并且处理:

④ 动态获取当前登录者Id
新增员工时,创建人id和修改人id设置为固定值
如何动态获取当前登录员工的Id?
- 新增员工时,需要确定操作者的ID:(当前登录Id)
- jwt,生成使用流程:
- 用户登录,生成token,把用户信息(Id)也存放进去,然后响应给前端

- 除登录请求外,其他请求都要进入拦截器。
- 所以,在拦截器解析token中拿到这次登录的用户Id存储,由service层获取Id,赋值给属性:

- 如何存储,以及怎样传递给service层的save方法使用?
- 通过
ThreadLocal进行传递。 - 项目使用工具类BaseContext

- 通过
BaseContext.setCurrentId(empId); //存入id
Long currentId = BaseContext.getCurrentId();//获取Id

⑤ ThreadLocal
介绍:
- ThreadLocal 并不是一个Thread,而是Thread的局部变量。
- ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
- 举例:点击一次新增用户的功能,即发送一次请求,这就是一个线程。
- 再点击一次,就是再次发送一次请求,又是一个线程。
- 每次发送请求中每个线程都是独立的,都有独立的存储空间。
常用方法:
- public void set(T value) 设置当前线程的线程局部变量的值
- public T get() 返回当前线程所对应的线程局部变量的值
- public void remove() 移除当前线程的线程局部变量
注意:客户端发送的每次请求,后端的Tomcat服务器都会分配一个单独的线程来处理请求
测试:
//测试执行一次请求中,当前线程ID
System.out.println(Thread.currentThread().getId());
两次请求的线程Id是不同的:
4.2 员工分页查询
原型:

接口:

① 请求参数实体 与 响应数据实体
EmployeePageQueryDTO 实体用来接收请求参数:

PageResult 实体用于返回数据:

② controller层
- get请求方式 不需要 @RequestBody
- 返回的对象类型为:
Result<PageResult>

③ service层 使用pageHelper分页
- pageHelper 底层是拦截器
- 拼接limit
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
Page<Employee></





最低0.47元/天 解锁文章
8224

被折叠的 条评论
为什么被折叠?



