外卖"/>
瑞吉外卖
文章目录
- 一、后台登录功能post
- 1. 实现登录
- 2. 退出功能
- 3. 完善登录功能(过滤器)
- 4. 技术总结
- 二、新增员工信息post
- 1. 新增员工
- 2. 处理已存在账号的异常(异常处理器)
- 3. 技术总结
- 三、分页查询
- 1. mybatis-plus配置类
- 2. controller类
- 3. 技术总结
- 四、修改员工状态信息
- 1. 在controller中创建update方法
- 2. 编写消息转换器Messager Converter
- 五、编辑员工信息
- 六、公共字段自动填充
- 1. 基本操作
- 2.使用threadlocal完善功能
- 七、新增菜品分类
- 八、分页查询菜品
- 九、删除分类
- 1. 基本删除功能
- 2. 完善删除功能
- 十、文件上传与下载
- 1. 定义
- 2. 文件上传
- 3. 文件下载
- 十一、新增菜品
- 1. 整体需求
- 2. 准备工作
- 3. 启动项目,进入菜品管理,点击菜品分类下拉框,成功获得数据
- 4. 接收页面提交的数据
- 5. 保存数据到菜品表和菜品口味表
- 十二、菜品信息分页查询
- 十三、修改菜品
- 十四、新增套餐
- 1.根据菜品分类查找数据回显
- 2. 保存信息到数据库
- 十五、 套餐信息分页查询
- 十六、删除套餐
- 1. 需求分析
- 2. 分析
- 十七、移动端登录
- 十八、新增地址簿
- 十九、菜品展示
- 菜品部分
- 套餐部分
- 二十、添加购物车
- 1. 需求
- 2. 代码
- 二十一、查看购物车和清空购物车
- 二十二、用户下单
- 二十三、优化部分:前后端分离
- 1. YApi
- 2. Swagger
- 3. 项目部署 ****
- 4.反向代理
- 优化部分:Mysql主从复制、读写分离(对移动端)
- 0. 原因分析
- 1. 主从复制
- 2. 读写分离
一、后台登录功能post
1. 实现登录
- 将页面提交的密码进行MD5加密处理
- 根据页面提交的用户名username查询数据库
- 如果没有查询到则返回登录失败结果
- 密码比对,如果不一致则返回登录结果
- 查看员工状态,如果已为禁用状态,则返回员工已禁用结果
- 登录成功,将员工id存入session并返回登录成功结果
2. 退出功能
3. 完善登录功能(过滤器)
检验是否已经登录,若没有登录,则跳转到登录页面
4. 技术总结
密码加密md5技术
利用mybatis-plus进行数据库查询
HttpServletRequest的session操作
过滤器Filter
二、新增员工信息post
1. 新增员工
2. 处理已存在账号的异常(异常处理器)
3. 技术总结
session操作
mybatis-plus对数据库增加数据,save方法
异常处理:@ControllerAdvice和@ExceptionHandler
三、分页查询
1. mybatis-plus配置类
2. controller类
3. 技术总结
mybatis-plus实现分页查询
四、修改员工状态信息
1. 在controller中创建update方法
2. 编写消息转换器Messager Converter
- 点击编辑按钮时,页面跳转到add.html,并在url中携带参数[员工id]
- 在add.html页面获取url中的参数[员工id]
- 发送ajax请求,请求服务端,同时提交员工id参数
- 服务端接收请求,根据员工id查询员工信息,将员工信息以json形式响应给页面
- 页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显
- 点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端
- 服务端接收员工信息,并进行处理,完成后给页面响应
- 页面接收到服务端响应信息后进行相应处理
第五步出现问题 - 问题描述
js对long型数据进行处理时丢失精度,导致提交的id和数据库中的id不一致。
我们可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串
五、编辑员工信息
- 核心问题
----之所以可以修改是因为前面已经写了update方法 点击保存的时候 默认用了update方法
获取url中的参数id - 整体流程
- 点击编辑按钮时,页面跳转到add.html,并在url中携带参数[员工id]
- 在add.html页面获取url中的参数[员工id]
- 发送ajax请求,请求服务端,同时提交员工id参数
- 服务端接收请求,根据员工id查询员工信息,将员工信息以json形式响应给页面
- 页面接收服务端响应的json数据,通过VUE的数据绑定进行员工信息回显
- 点击保存按钮,发送ajax请求,将页面中的员工信息以json方式提交给服务端
- 服务端接收员工信息,并进行处理,完成后给页面响应
- 页面接收到服务端响应信息后进行相应处理
前端做的就是把参数id拿出来交给服务端
服务端就是id查询数据库,然后把信息以json的方式交给服务端
六、公共字段自动填充
1. 基本操作
employee实体类加上@TableField
注释掉原来代码对公共字段的设置
编写MyMetaObjectHandler类
2.使用threadlocal完善功能
- 原理
在学习ThreadLocal之前,我们需要先确认一个事情,就是客户端发送的每次http请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程:
1.LoginCheckFilter的doFilter方法
2.EmployeeController的update方法
3.MyMetaObjectHandler的updateFill方法 - ThreadLocal常用方法:
public void set(T value) 设置当前线程的线程局部变量的值
public T get() 返回当前线程所对应的线程局部变量的值 - 流程
我们可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获得当前线程所对应的线程局部变量的值(用户id)。
七、新增菜品分类
- 流程
实体类Category(直接从课程资料中导入即可)
Mapper接口CategoryMapper
业务层接口CategoryService
业务层实现类CategoryServicelmpl
控制层CategoryController
八、分页查询菜品
- 流程
页面发送ajax请求,将分页查询参数(page、pageSize)提交到服务端
服务端Controller接收页面提交的数据并调用Service查询数据
Service调用Mapper操作数据库,查询分页数据
Controler将查询到的分页数据响应给页面
页面接收到分页数据并通过ElementUI的Table组件展示到页面上
九、删除分类
- 需求分析
在分类管理列表页面,可以对某个分类进行删除操作
需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除
1. 基本删除功能
2. 完善删除功能
(1)实体类Dish和Setmeal(从课程资料中复制即可)
(2)Mapper接口DishMapper和setmealMapper
(3)Service接口DishService和SetmealService
(4)Service实现类DishServicelmpl和SetmealServicelmpl
- 在categoryService中自定义remove方法
逻辑:依次判断是否和菜品、套餐是否关联,采用mybatis-plus构造条件查询器 - 若关联,自定义异常抛出
继承runningtime异常,
在全局异常处理中,对异常处理
十、文件上传与下载
1. 定义
- 文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程
- 文件下载,也称为download,是指将文件从服务器传输到本地计算机的过程
- 通过浏览器进行文件下载,通常有两种表现形式:
以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录
直接在浏览器中打开,本质上就是服务端将文件以流的形式写回浏览器的过程。 - MultipartFile
MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。
MultipartFile后面的参数名必须为file,因为需要和前端页面的name保持一致,否则不会生效
2. 文件上传
postmapping
transferTo把原来的文件转存
3. 文件下载
- FileInputStream流
被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作如读取图片视频等
- ServletOutputStream outputStream = response.getOutputStream();
通过HttpServletResponse的getOutputStream()创建一个输出流,那么servlet容器就会把response对象交给服务器,服务器将response对象中的内容拆解响应给客户端。 - response.setContentType
这个方法设置发送到客户端的响应的内容类型
InputStream.read(byte[])参数详解 - fileInputStream.read(bytes)) != -1
byte数组作为一个缓冲区,每次存入和缓冲区一样大小(byte.length)的数据。当然实际存入的数据是一个个十进制的整数。整个流程是这样子的,文件 -> 输入字节流(二进制整数) -> 十进制整数(通过read(byte[])实现)
输入字节流in按照byte数组缓冲区每4个字节循环一次进行read操作,直到读到-1这个整数(-1是一个标识,就是文件数据的末尾)。 - outputStream.write(bytes,0,len);
java.io.OutputStream.write(byte[] b, int off, int len) 方法从指定的字节数组开始到当前输出流关闭写入len字节。一般的合约write(b, off, len),一些在数组b中的字节写入,以便输出流;元素b[off]是写入的第一个字节和b[off+len-1]是写的这个操作的最后一个字节。
十一、新增菜品
1. 整体需求
后台系统中可以管理菜品信息,通过新增功能来添加一个新的菜品
在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片
在移动端会按照菜品分类来展示对应的菜品信息。
2. 准备工作
实体类DishFlavor(直接从课程资料中导入即可,Dish实体前面课程中已经导入过了)
Mapper接口DishFlavorMapper
业务层接口DishFlavorService
业务层实现类DishFlavorServicelmpl
控制层DishController
3. 启动项目,进入菜品管理,点击菜品分类下拉框,成功获得数据
mybatis-plus查询
4. 接收页面提交的数据
因为Dish实体类不满足接收flavor参数,即需要导入DishDto,用于封装页面提交的数据
5. 保存数据到菜品表和菜品口味表
在保存数据到菜品表和菜品口味表的过程中,我们需要对保存到菜品口味表的数据做相应的处理
取出dishDto的dishId,通过stream流对每一组flavor的dishId赋值
保存菜品口味到菜品数据表
需要重写dishservice的save方法
十二、菜品信息分页查询
与前面的不同在于
在前端页面发现菜品分类对应的prop属性名为categoryName
但我们在响应的数据当中并没有发现categoryName字段
在之前我们创建了DishDto类,发现类中的属性名正好和前端的属性名对应
因此需要把Dish的属性拷贝到DishDto里面 重新写
注意record对象封装的是每一个dish对象 需要改写为dishdto
前端需要的字段 后端的实体类必须满足
多表操作需要加事务管理
十三、修改菜品
- 页面发送ajax请求,请求服务端获取分类数据,用于菜品分类下拉框中数据展示(已完成)
- 页面发送ajax请求,请求服务端,根据id查询当前菜品信息,用于菜品信息回显
- 页面发送请求,请求服务端进行图片下载,用于页图片回显(已完成)
- 点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以json形式提交到服务端
1和3已经完成
十四、新增套餐
- 页面(backend/page/combo/add.html)发送ajax请求,请求服务端获取套餐分类数据并展示到下拉框中(已完成)
- 页面发送ajax请求,请求服务端,获取菜品分类数据并展示到添加菜品窗口中
- 页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中
- 页面发送请求进行图片上传,请求服务端将图片保存到服务器(已完成)
- 页面发送请求进行图片下载,将上传的图片进行回显(已完成)
- 点击保存按钮,发送ajax请求,将套餐相关数据以json形式提交到服务端
1.根据菜品分类查找数据回显
2. 保存信息到数据库
十五、 套餐信息分页查询
- 页面(backend/page/combo/list.html)发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端,获取分页数据
- 页面发送请求,请求服务端进行图片下载,用于页面图片展示
十六、删除套餐
1. 需求分析
在套餐管理列表页面点击删除按钮,可以删除对应的套餐信息
也可以通过复选框选择多个套餐,点击批量删除按钮一次删除多个套餐
注意,对于状态为售卖中的套餐不能删除,需要先停售,然后才能删除。
2. 分析
观察删除单个套餐和批量删除套餐的请求信息可以发现,两种请求的地址和请求方式都是相同的
不同的则是传递的id个数,所以在服务端可以提供一个方法来统一处理。
删除SetMeal表
删除SetMealDish表
起售停售功能没有写
十七、移动端登录
在登录页面(front/page/login.html)输入手机号,点击【获取验证码】按钮,页面发送ajax请求,在服务端调用短信服务API给指定手机号发送验证码短信**(不使用短信服务,手动查看验证码,并输入)**
在登录页面输入验证码,点击【登录】按钮,发送ajax请求,在服务端处理登录请求
- 导入User类相关
- 过滤器放行
- 过滤器检测是否登录
- 获取验证码
- 登录
十八、新增地址簿
常规新增
新增默认地址:先把所有设置0 再改指定位1
十九、菜品展示
根据分类展示菜品和套餐 如果有口味点击规格能修改
菜品部分
-
页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
改前端代码 前端写死了 需要同时 购物车和菜品分类成功 才能渲染 为了方便可以先注释掉购物车部分
后端的再categorycontroller里面已经写了list方法 -
页面发送ajax请求,获取第一个分类下的菜品或者套餐
后端的再dishcontroller里面已经写了list方法,但是没有实现规格 可选口味功能 需要改写
套餐部分
setmeal 写一个 list方法
二十、添加购物车
1. 需求
- 移动端用户可以将菜品或者套餐添加到购物车
- 对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车
- 对于套餐来说,可以直接点击将当前套餐加入购物车
- 在购物车中可以修改菜品和套餐的数量,也可以清空购物车。
2. 代码
设置用户id
判断是菜品还是套餐
判断菜品或套餐是否已存在
二十一、查看购物车和清空购物车
把前端代码改好
注意登录用户要保持一致
根据用户id查表
考虑问题 有没有 点减号 删除信息 减少数量
二十二、用户下单
在购物车中点击去结算按钮,页面跳转到订单确认页面
在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址
在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据
在订单确认页面点击去支付按钮,发送ajax请求,请求服务端完成下单操作…未完成
//获取当前用户id
//查询当前用户的购物车数据
//查询用户数据
//查询地址数据
//向订单表插入数据,一条数据
//向订单明细表插入数据,多条数据
//清空购物车数据
二十三、优化部分:前后端分离
1. YApi
前面的定制接口部分,定义了接口规范,给前后端人员看,同时可以实现模拟作用
2. Swagger
配置好相关的东西 可以导出你项目中所有的接口信息
3. 项目部署 ****
192.168.138.100(服务器A)
Nginx:部署前端项目、配置反向代理
MySql:主从复制结构中的主库
192.168.138.101(服务器B)
jdk:运行java项目
git:版本控制工具
maven:项目构建工具
jar:Spring Boot 项目打成jar包基于内置Tomcat运行
MySql:主从复制结构中的从库
172.17.2.94(服务器C)
Redis:缓存中间件
4.反向代理
上面第一张图 为访问的地址,对应的是代理服务器
通过反向代理配置,对url进行重写后,跳转到另外一个服务器
优化部分:Mysql主从复制、读写分离(对移动端)
0. 原因分析
1. 主从复制
- 介绍
主从复制是读写分离的基础
- 配置过程
提前准备两台服务器 - 主库
- 从库
这里的bin 和 los两个参数必须严格对照前面master的
2. 读写分离
java怎么知道主库执行写操作,从库执行读操作
配置文件修改
更多推荐
瑞吉外卖
发布评论