[toc]
XOrder前言
该项目分为小程序前后端和后台管理系统前后端,无论小程序端还是管理系统均为 SpringBoot + Vue / Wx 前后端分离项目,项目的定位是一个 Java 入门项目,在开始做此项目之前,我没有任何的前端基础,也没有使用过任何的 Java 开发框架,学习与这个项目是同步开始的,这个项目从头到尾都是一个人完成的,也没有看网课提前学习(导致了很多架构不合理,无奈重构),也算是边学边实践了。
这个项目并未涉及到分布式相关,我的下一个学习计划就是学习分布式相关,或许到时候回来重构项目,希望你我一起努力。
更新日志环境微信开发者工具
下载开发者工具直接导入项目即可。
Java开发环境
IDEA2021.2
JDK11
MySql 8.0
Vue开发环境
不知道,对前端不熟,自己乱搞的,前往介绍 | vue-element-admin (panjiachen.github.io)自行了解。
成果展示
后台管理系统:XOrder后台管理系统
小程序端由于未申请企业账号不允许上线,可自行下载代码体验,部分照片:
下载安装
如果需要下载的话,提一些需要注意的点吧:
小程序端小程序前端扫码点餐
在小程序首页点击扫码点餐,前往草料二维码生成器 (cli.im)生成,文本内容为 storeId=XXX&table=XXXX,例如:
文件树
├─component # 自定义的组件 ├─dist # 引用的组件库 ├─images # 存放静态图片 └─pages # 主页面 ├─address # 收货地址页面 ├─cancel-reason # 退货原因页面 ├─collection # 收藏菜品页面 ├─dish-detail # 订单详情 ├─dish-order # 点餐主页面 ├─index # 首页 ├─integral # 会员积分(待实现) ├─member # 会员(待实现) ├─message # 我的消息 ├─order # 订单页面 ├─order-detail # 订单详情 ├─order-meal # 点餐页面 ├─order-ok # 订单已确认 ├─order-sure # 确认订单 └─user # 我的 ├─app.json # 配置 tarbar,引入 dist 组件库 ├─app.js # 配置全局遍历 ├─app.wxss # 配置全局样式
技术选型鸣谢
VanApp 轻量、可靠的小程序 UI 组件库
小程序后端
这算是我的第一个 SpringBoot 项目了,很青涩,甚至参数还得从 httpServletRequest 取
文件树
├─logs ├─src │ ├─main │ │ ├─java │ │ │ └─com │ │ │ └─happysnaker │ │ │ ├─api # 引入百度地图 API 进行经纬度解析 │ │ │ ├─config # 配置文件 │ │ │ ├─controller # │ │ │ │ └─base # │ │ │ ├─exception # 自定义异常 │ │ │ ├─filter # 自定义过滤器 │ │ │ ├─mapper # dao 层 │ │ │ ├─Observer # 观察者 │ │ │ │ └─impl │ │ │ ├─pojo # POJO │ │ │ ├─service # 业务层 │ │ │ │ └─impl │ │ │ └─utils # 实用类 │ │ └─resources │ │ ├─com │ │ │ └─happysnaker │ │ │ └─mapper │ │ ├─static │ │ └─templates │ └─test │ └─java │ └─com │ └─happysnaker
技术选型技术说明官网
SpringBoot
容器+MVC框架
MyBatis
ORM框架
RabbitMQ
消息队列
Redis
分布式缓存
Lombok
简化对象封装工具
Swagger-UI
文档生成工具
项目总结
在此,我学到了如何去生成(手动) token,jwt 形式的 token 是由 头部、载荷和签名构成的,头部是一些标识信息,如 jwt 形式、签名算法等;载荷是要承载的数据,如用户ID、过期时间、发行人等等;头部和载荷采用 base64 进行 ascii 编码,它们仍然是明文的,因此不应承载敏感数据;签名就是利用私匙对头部和载荷进行加密,这就是计网里面的 MAC(报文完整性)加密,通过对头部和载荷加密我们确定这个 token 有没有被篡改,因为私匙只有我们知道,token 生成在 utils 包下的 token 实用类生成,此外我还定义了 TokenBuilder 类,以建造者模式去生成 token。
抽象过滤器如下所示,子类继承抽象类并实现抽象方法即可,具体的 doFilter 方法由抽象类完成,子类做自己要做的即可,这利用了模板方法的设计模式。
public abstract class AbstractFilterChain implements Filter { AbstractFilterChain myFilterChain; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { if (isRequired((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse)) { if (!doFilter((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse)) { return; } } if (myFilterChain != null) { myFilterChain.doFilter(servletRequest, servletResponse, filterChain); return; } filterChain.doFilter(servletRequest, servletResponse); } public abstract boolean isRequired(HttpServletRequest request, HttpServletResponse response); public abstract boolean doFilter(HttpServletRequest request, HttpServletResponse response); }
我尝试利用 jdk 动态代理生成Service代理,但这样做会一直报错(xxx proxy$104 无法转化 xx)
PS: 这里如果面试官问还可以怎么优化分布式锁,除了锁住商品ID细化之外,我们还可以将库存表分区,对不同区使用不同的锁,这样又可以将锁细化。
现在它已经足够优秀了,我的重构之路就到此结束了,但我们还有一个问题没有解决:**Redis中没有 key 怎么办?**这个问题没有那么简单,主要是两个问题:
考虑 A,B 同时察觉到没有缓存,都尝试更新,假设我们已经对更新操作上锁,那么可能会出现 A 更新了缓存为数据库中的 XX,然后立马扣减了缓存,此时 redis 为 XX1,这个时候 B 才姗姗来迟,B又将缓存更新数据库中的 XX,造成不可重复读。即使只有一个更改者 A 想要更新缓存,但是此时可能 MQ 中有消费者 B 正准备扣减缓存,A先入,更新为 XX,此时 redis 为 XX,而 B 马上对数据库更改了,数据库变成了 XX1,数据不一致。
其实 1 和 2 本质上是一个问题,解决1可以加一个乐观锁,在更新方法中重新判断 key 是否存在,令整个方法成为原子方法(或利用分布式锁)。
解决方法 2 则要保证更新缓存时,没有消费者,所以我们需要在 1 的原子方法内去等待消费队列为空。
未完成的任务
优惠券、会员没有实现,设计数据库都考虑到了。
emmm,写着写着才发现,购物车这玩意,应该让后端去处理数据,我全在前端做了,一大坨,包括判断折扣,处理精度问题,整麻了....如果在前端做,那么后端必须对发过来的订单进行重复的验证,麻了,写不动了,好吧我觉得前后端都要做...
没有完成真正的支付功能,个人小程序不让接入支付,涉及到金额相关的实现的没有那么严谨,甚至可能被攻击...
如果我还能记得起来这个项目的话,我会进行又一次重构。
管理系统端管理系统前端
项目基于mall-admin-web是一个电商后台管理系统的前端项目,基于Vue+Element实现二次开发,对于整体的架构与部署,可以参考:介绍 | vue-element-admin (panjiachen.github.io),我基本上只修改了 src 里和 api 文件下的内容。
遇到所有部署问题,基本上都可以在介绍 | vue-element-admin (panjiachen.github.io)找到解决方法。
文件树
├─src ├──views ├─authority-ms # 权限控制 │ ├─admin │ └─role ├─dish-ms # 菜品模块 │ ├─combo │ │ └─components │ └─dish │ └─components ├─home # 首页 ├─layout # 整体路由布局 │ ├─components │ │ └─Sidebar │ └─mixin ├─login # 登录 ├─marketing-ms # 营销 │ ├─coupon │ │ └─components │ ├─discount │ ├─new │ └─recommend ├─order-ms # 订单模块 │ └─order └─store-ms # 店铺模块 └─store └─component
技术选型技术说明官网
Vue
前端框架
Vue-router
路由框架
Vuex
全局状态管理框架
Element
前端UI框架
Axios
暂无评论内容