Java项目——苍穹外卖总结

附上本人代码连接:xiaoming325/sky-take-out (github.com)

项目概述

此项目是一个外卖点餐项目,分为商家端(管理员端)和用户端,商家端是一个网站,用户端是一个微信小程序,由于微信小程序没有上线,目前只能用微信开发者工具模拟手机进行操作测试。

后端环境

sky-common

constant:存放常量类,将一些常量(数字和字符串)封装为是实体类的属性,便于调用

context:存放BaseContext类,是基于ThreadLocal封装工具类,用于保存和获取当前登录用户id

enumeration:存放枚举类,将数据库的操作类型封装为枚举类的属性。将枚举类作为自定义注解类的属性,在AOP中对切入点方法进行注解时,可直接使用注解类的属性指定数据库操作类型,便于在AOP通知时用反射获取注解中指定的数据库操作类型,以便根据不同操作类型进行不同的通知

exception:存放各种自定义异常类,例如:登录失败异常,密码错误异常,套餐启用失败异常……

json:存放JacksonObjectMapper,是一个对象映射器,可以将Java和JSON互相序列化和反序列化,并可以指定格式

properties

存放配置属性类,阿里云、微信小程序、微信支付、JWT的相关配置属性类。

  • 配置属性类中存放相关变量属性,在配置文件中写好相关属性的值
  • 加注解,@Component,@ConfigurationProperties(将配置文件中相关属性的值赋给类中的成员),@Data

result:存放结果类,PageResult和Result,用于返回给前端。加相关lombok注解

utils:存放工具类,和配置属性类相对应。工具类中存放相关方法,工具类一般不加注解(视情况而定)

sky-pojo

存放DTO,VO和entity,需要视情况加相关lombok注解和@Builder(便于构造对象)

sky-server

后端服务,存放后端的三层架构、配置文件等。此模块中除了自定义注解类全局异常处理类,其余都需要加注解注册成为IOC容器中的bean。

其中controller,service,mapper不在这里做多解释,其余包依次为:

annotation:存放自定义注解类,上文已解释过

aspect:自定义切面类,用来编写切入点表达式和通知,实现AOP

@Aspect//设置当前类为切面类,告诉spring这个类是用来做AOP的

@Component//通知类(切面类)必须配置成Spring管理的bean

config:配置类,加上@Configuration注解。在这些配置类中通常编写方法,并将加入@Bean注解将方法返回对象注册为Bean

handler:存放全局异常处理器类,类上加@RestControllerAdvice注解,方法上加@ExceptionHandler注解,方法中捕获各种业务异常和sql异常并封装为Result进行返回(业务中的异常通过层层上抛最终到达这里被处理)

interceptor:存放管理员端和用户端的jwt令牌校验拦截器,类上加@Component。类中编写校验JWT的方法,除登录请求和用户端的查询营业状态请求外都需要校验JWT

task:利用Spring Task实现定时执行任务功能

WebSocket:存放WebSocketServer类,在类中编写代码实现客户端和服务端的连接,和互相发送消息。在其他地方依赖注入WebSocketServer类,可使用其内部的方法发送消息。

数据库表

employee员工表

user用户表

category分类表:分类的相关信息,根据type的值1和2分为两类(菜品类套餐类),每一个菜品类包含可多种菜品,每一个套餐类可包含多种套餐

shopping_cart购物车表:有user_id,dish_id,setmeal_id,dish_flavor分别关联用户表菜品表套餐表菜品口味表

address_book地址簿表:有user_id关联用户表

菜品类:

dish菜品表:菜品(除口味)的相关信息,包含逻辑外键category_id关联category分类表中的菜品类

dish_flavor菜品口味表:菜品口味的相关信息,包含逻辑外键dish_id关联dish菜品表

套餐类:

setmeal套餐表:套餐的相关信息,包含逻辑外键category_id关联category分类表中的套餐类

setmeal_dish套餐菜品关系表:套餐和菜品的关联关系,包含逻辑外键dish_id关联dish菜品表,逻辑外键category_id关联category分类表

订单类:

orders订单表:address_book_id关联地址簿表

order_detail订单细节表:order_id,dish_id,setmeal_id关联订单表菜品表套餐表

总结(部分):

category表:

category表中的菜品类对dish表中的菜品是一对多

category表中的套餐类对setmeal表中的套餐是一对多

dish表:

dish表中的菜品对dish_flavor口味表中的口味是一对多

setmeal_dish表:

一个套餐可能包含多个菜品,并且不同套餐的菜品可以重复,同一个套餐的菜品不能重复

所以setmeal_dish表中的dish_id、name、category_id都可以重复

业务需求分析

商家端(管理员端)

员工管理功能

接口

controller层

service层

mapper层

员工登录

参数:

EmployeeLoginDTO

返回值:

Result

参数:

EmployeeLoginDTO

返回值:

Employee

参数:

String username

返回值:

Employee

员工退出

参数:

void

返回值:

Result

新增员工

参数:

EmployeeDTO

返回值:

Result

参数:

EmployeeDTO

返回值:

void

参数:

Employee

返回值:

void

员工分页查询

参数:

EmployeePageQueryDTO

返回值:

Result

参数:

EmployeePageQueryDTO

返回值:

PageResult

参数:

EmployeePageQueryDTO

返回值:

Page

启用禁用员工账号

参数:

Integer status, Long id

返回值:

Result

参数:

Integer status, Long id

返回值:

void

参数:

Employee

返回值:

void

根据id查询员工信息

参数:

Long id

返回值:

Result

参数:

Long id

返回值:

Employee

参数:

Long id

返回值:

Employee

修改员工信息

参数:

EmployeeDTO

返回值:

Result

参数:

EmployeeDTO

返回值:

void

参数:

Employee

返回值:

void

总结
  1. Controller层接收的对象参数为DTO,一般不进行业务逻辑处理(除了登录功能要在Controller层中为登录成功的用户生成JWT令牌返回给前端),直接调用Service层方法将DTO传给Service层,并将返回结果封装给Result返回给前端
  2. Service层进行各种业务处理,一般是将DTO转换为entity实体类(并补全实体类缺少的属性,可使用AOP),直接调用Mapper层方法将entity实体类传给Mapper层
  3. Mapper层接收实体类参数,直接对数据库进行操作(复杂逻辑用动态sql编写)

1、Controller层的方法一般和Service层是一一对应的(一对一),但不同Service层中的请求可以调用同一个Mapper层方法(可以多对一),例如:修改员工信息和启用禁用员工账号是两个不同的请求,但调用的都是Mapper层中的update方法

2、Mapper层是整个业务的重点难点,要考虑如何操作数据库从而的到想要的数据。Mapper层也是最容易报错的地方,SQL编写容易出错,尤其注意动态SQL的语法

公共字段填充(AOP)

见以前博客和笔记

分类管理,菜品管理和套餐管理

三者类似,主要有新增,修改,删除,查询,分页查询,启用禁用等接口

店铺营业状态

只需要Controller层,设置营业状态时将其放入缓存,获取时直接从缓存中取出 

订单管理

订单状态:1待付款 2待接单 3已接单 4派送中 5已完成 6已取消

支付状态:0未支付 1已支付 2退款

订单搜索(分页查询):根据条件对订单进行分页查询

各个状态的订单数量统计:查询待接单、待派送、派送中的订单数量

订单详情:分别查询order订单表和order_detail订单细节表

接单:直接修改订单状态为已接单(前端已写好,只有已付款的订单才有接单按钮)

拒单:1、只有状态为待接单的订单才可以拒单 2、如果用户已支付则要退款 3、将订单状态改为已取消,并设置订单拒单原因和取消时间

取消订单:1、前端中已设置好,只有已完成的订单才可取消 2、如果用户已支付则要退款 3、将订单状态改为已取消,并设置订单取消原因和取消时间

派送订单:1、只有状态为已接单的订单才可以进行派送 2、将订单状态改为派送中

完成订单:1、只有状态为派送中的订单才可以改为已完成 2、更新订单状态为已完成并设置送达时间

数据统计

营业额统计、用户统计、订单统计、销量top10:这四者类似,根据开始日期和截止日期查询相关的数据

导出运营数据报表

工作台

今日数据查询:营业额、有效订单、订单完成率、平均客单价、新增用户

查询订单管理数据、查询菜品总览、查询套餐总览:类似以上,设置开始日期,截止日期和状态,用动态SQL进行查询

用户端

用户登录

微信用户登录,有相应的专门API

店铺营业状态

直接从缓存中读取店铺营业状态

分类管理

查询分类:根据类型查询分类

菜品管理

根据id查询菜品:先从缓存中查,查不到再去查数据库并放入缓存

套餐管理

条件查询套餐:利用缓存

查询套餐包含的菜品列表:查询dish菜品表和setmeal_dish套餐菜品表

订单管理

用户下单:1、地址簿不为空,收货地址没有超出配送范围、购物车不为空 2、向订单表和订单明细表插入数据,支付状态为待支付,订单状态为待付款 3、清空用户购物车

订单支付:1、调用微信支付接口 2、设置订单状态为待接单,更新支付时间 3、利用WebSocket向客户端浏览器发消息出发订单提醒

历史订单查询:查询订单表和订单明细表

查询订单详情:查询订单

用户取消订单:1、订单必须存在且状态为待付款或待接单,如果是待接单则要退款 2、更新订单状态为已取消、取消原因和取消时间

再来一单:1、查询订单明细表,将订单详情对象转换为购物车对象 2、将购物车对象集合批量添加到购物车表

订单催单:1、校验订单是否存在 2、利用WebSocket向客户端浏览器发消息出发催单提醒

购物车管理

添加购物车:1、先查看购物车是否有此商品,如果有只需将其数量加一,如果没有则直接添加 2、添加时判断是菜品还是套餐,添加方式不同

查看购物车:根据用户id查询购物车数据

清空购物车:根据用户id清空购物车数据

地址簿管理

查询当前用户的所有地址、根据id查询地址、根据id修改地址、根据id删除地址、查询默认地址

新增地址:新增地址都设置为不是默认地址

设置默认地址:1、将当前用户的所有地址修改为非默认地址 2、将当前地址改为默认地址

缓存

缓存套餐

用户端的查询方法使用缓存,先从缓存中查,查不到再从数据库中查,并放入缓存中

用户端的查询为根据分类id查询该分类下的菜品和菜品口味信息,将分类id作为键,多个菜品和菜品口味(DishVo)集合作为值加入缓存

管理员端的删改操作清理全部缓存,新增操作精确清理缓存(新增哪个),查询操作不涉及缓存

缓存菜品

同理缓存套餐

经验

  1. 进行修改操作时:动态sql中的不要用if标签非空判断拼接实体类中int类型的属性,因为int类型有默认值0,int类型肯定是非空并且会把表中本来的数据修改为默认值0。解决方法:修改前先进行查询将原来的数据作为实体类查询出来,在实体类的基础上改变属性后,将实体类作为参数传给mapper层进行修改操作,这样实体类中未修改的属性不会改变
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值