源码在 https://gitee.com/pluto8/take-out
1、软件开发流程
2、角色分工:
3、软件环境
1、项目介绍
本项目是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括系统管理后台和移动端应用两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的菜品、套餐、订单等进行管理维护、移动端应用主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单等
2、产品原型(产品经理提供)
产品原型,就是一款产品成型之前的一个简单的框架,就是将页面的排版布局展现出来,使产品的初步构思有一个可视化的展示。通过原型展示,可以更加直观的了解项目的需求和提供的功能。产品原型主要用于展示项目的功能,并不是最终的页面效果
3、技术选型
4、功能架构
5、角色
1、数据库环境搭建
导入sql文件
2、maven项目搭建
创建maven项目,导入pom.xml和application.yml
直接将前端后端页面复制在resource下,会出现tomcat找不到静态资源页面的情况(报404)
可以通过配置文件来解决。创建一个WebMvcConfig
package com.xqh.reggie.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
*设置静态资源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
}
登录功能
1、需求分析
1)页面原型展示
2)登录页面展示
页面请求—>controller—>service—>Mapper—>DB
3)封装结果类。通用返回结果,服务端响应的数据最终都会封装成此对象
4)controller中创建登录方法
逻辑:页面提交的密码进行md5加密—>根据页面提交的用户名查询数据库,查询不到则返回登录失败,查询到---->密码比对,错误则登录失败,正确---->查看员工状态,已禁用则返回已禁用状态,正常—>登录成功,将员工id存入Session并返回登陆成功结果。
退出登录
1、处理逻辑:清理Session中的用户id,返回结果
员工管理
1、完善登录功能
存在一个问题:用户如果不登录,直接访问系统首页面,照样可以正常访问,这是不合理的。
我们希望看到的是,只有登录成功后才可以访问系统中的页面,如果没有登录则跳转到登录页面
如何实现?使用过滤器或者拦截器
2、新增员工
使用异常处理器进行全局异常捕获
总结:
3、员工信息分页查询
业务逻辑:
4、禁用、启用员工账号
只有admin账户可以使用这个功能。其他用户不显示这个功能(这主要是前端实现,if判断)
出现问题:js对long型数据进行处理时丢失精度,导致提交的id和数据库的id不一致,如何解决?
我们可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串
具体实现步骤:
5、编辑员工信息
分类管理
1、公共字段自动填充
在员工管理功能开发时,新增员工时要设置创建时间、更新时间、创建人、更新人,这些属于公共字段,很多表中都有这些字段,那么能不能对于这些公共字段在某个地方统一处理,来简化开发呢?对于此,MyBatisPlus提供了公共字段自动填充 功能
实现步骤:
如何在MyMetaObjectHandler类中获取当前登录用户的id呢?
首先,因为在MyMetaObjectHandler类中是不能获得HttpSession对象的,所以我们不能通过session来获取到登录用户的id。可以使用ThreadLocal来解决此问题,它是jdk中提供的一个类。
需要先确认一个事情,就是客户端每次发送的http请求,对应的在服务端都会分配一个新的线程来处理 。当发送编辑请求时,同时经过下面三个方法,这三个方法对应的线程id是相同的。
:LoginCheckFilter的doFilter方法
:EmployeeController中的update方法
:MyMetaObjectHandler的updateFill方法
一次请求对应的线程id是相同的!
ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不会影响其他线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
2、新增分类
需求分析:后台系统中可以管理分类信息,分类包括两种类型,分别是菜品分类和套餐分类。可以在后台系统的分类管理页面分别添加菜品分类和套餐分类。新增菜品分类、新增套餐分类。之后的菜品管理和套餐管理,是要关联上这里有的菜品和套餐。
3、分类信息分页查询
构建分页构造器,构造条件构造器,执行分页查询
4、删除分类
在分类管理列表页面,可以对某个分类进行删除操作,需要注意的是,当分类关联了菜品或者套餐时,此分类不允许删除。即菜品和套餐有没有关联上级菜品分类和上级套餐分类,如果有关联,则这个上级菜品分类或上级套餐分类是不允许删除的,没有关联下级的分类才可以被删除。
5、修改分类
菜品管理
1、文件上传和下载
服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件: commons-fileupload,commons-io
本质都是对流的操作。Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件。
是指从服务器传输到本地计算机的过程。通过浏览器进行文件下载,通常有两种表现形式:以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录;直接在浏览器中打开(比如直接显示某个菜品的图片)
通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程
2、新增菜品
需求分析:
后台管理中可以管理菜品信息,通过新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片,在移动端会按照菜品分类来展示对应的菜品信息。
一步是做add业务,一步是要根据type查询分类列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szr7aW2F-1686311832446)(D:\桌面\校园外卖\3.jpg)]
3、更新菜品
同样是对两张表进行操作。
套餐管理
1、新增套餐
2、分页查询
3、删除套餐
删除单个套餐和批量删除套餐,这两种请求的地址和请求方式都是相同的。不同的则是传递的id的个数,所以在服务端可以提供一个方法来统一处理
1、阿里云短息服务–介绍
阿里云短信服务是广大企业客户快速触达手机用户所优选使用的通信能力,调用API或用群发助手,即可发送验证码、通知类和营销类短信。
应用场景:
2、设置短信签名
短信签名是短信发送者的署名,表示发送方的身份
3、设置模板管理
用户登录名称 [email protected]
AccessKey ID LTAI5t7DTMFcMRWLJp4BJArf
AccessKey Secret 6XPca4cbldESNPws1JyuCWL3CNRP1D
4、需求分析
为了方便用户登录,移动端通常都会提供通过手机验证码登录的功能。手机验证码登录的优点:
十一、菜单列表
十二、购物车
十三、用户下单
十四、后台中订单管理
十五、前后台交互
后台控制订单的状态,例如从已下单到已派送再到已完成,而前台用户端,会显示订单已派送,已完成,当显示已完成,用户端可以直接点击再来一单,可以将订单再次添加到购物车中
测试
1、添加员工—添加一个测试账号,测试后面的所有功能 test61 123456
2、移动端—注册一个新号码 15083555837 查看数据库是否正常
3、员工管理
4、分类管理
5、菜品管理
6、套餐管理
7、订单管理
8、用户端–查看菜品
9、加入购物车
10.下单
11、查看订单,查询订单状态
12、订单已完成,可以再来一单
通过redis+SpringCache缓存
缓存短信验证码
缓存菜品数据
缓存菜品是通过菜品分类和状态来动态创建一个key
通过Spring cache缓存
在SpringBoot项目中使用Spring Cache的操作步骤(使用Redis缓存技术)
缓存套餐数据
数据库优化
1、读写分离
面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈,对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
2、MySQL主从复制
MySQL主从复制是一个异步的复制过程,底层是基于MySQL数据库自带的二进制日志功能。就是一台或多台MySQL数据库(slave,从库)从另一台MySQL数据库(master,主库)进行日志的复制然后再解析日志并应用到自身,最终实现从库的数据和主库的数据保持一致。MySql主从复制是MySQL数据库自带功能,无需借助第三方工具。
master将改变记录到二进制日志
slave将master的binary log拷贝到它的中继日志(relay log)
slave重做中继日志中的事件,将改变应用到自己数据库中
整合Nginx
Nginx是高性能的HTTP和反向代理的web服务器,处理高并发能力十分强大,能经受高负载的考验;其特点是,占有内存少,并发能力强,事实上nginx的并发能力比同类型的网页服务器表现较好。
常用命令
默认会有这两个进程
打开nginx,会在logs中生成nginx.pid,里面放的就是运行的nginx的ip
1、静态资源处理
listen 是访问nginx的端口号
index就是打开nginx显示的主页
2、反向代理
理解:正向代理是在客户端设置代理,那么我客户端仍然需要知道我要访问哪个目标服务器,只是说变成了由代理服务器帮我去请求这个目的地址;而反向代理,我只需要访问代理服务器,代理服务器会将目标服务器的东西返回给我,我不需要知道目标服务器的地址
server{
listen 82;
server_name localhost;
location /{
proxy_pass http://192.168.100.101:8080; #反向代理配置,将请求转发到指定服务
}
}
这个设置的意思:将本ip地址端口号82的请求转发到 192.168.180.100:80端口上去。所以现在访问本ip地址端口号82也可以访问 192.168.180.100:80这个ip的服务
3、负载均衡
负载均衡器:将用户请求根据对应的负载均衡算法分发到应用集群中的一台服务器进行处理
默认轮询分发请求
也可以设置其他策略:
权重方式 :通过再server后设置 weight=** ,来设置地址的权重。对应非要分发的访问次数多少
依据ip分配方式:ip_hash
依据最少连接方式:哪个服务器连接少多分发
前后端分离开发
开发工具:
技术框架:
YApi
介绍:
YApi是高效、易用、功能强大的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松、发布、维护API,YApi还为用户提供了优秀的交互体验,开发人员只需利用平台接口的接口数据写入工具以及简单的点击操作就可以实现接口的管理。
YApi让接口开发更简单高效,让接口的管理更具可读性、可维护性,让团队协作更合理。
也可以用api
整合Swagger
Swagger
使用swagger你只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。
由于原生swagger,定义接口是写json文件,比较繁琐。Knife4j是为java mvc框架集成Swagger生成API文档的增强解决方案。
整合JWT
随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。
① 在传统的用户登录认证中,因为http是无状态的,所以都是采用session方式。用户登录成功,服务端会保证一个session,当然会给客户端一个sessionId,客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId。
cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。而JWT不是这样的,只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可。
② JWT方式校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录,验证token更为简单。
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。JWT最重要的作用就是对 token信息的防伪作用。
部署
管理员通过internet访问nginx,然后nginx将请求转发到tomcat。
把前端打包,复制到nginx下的html文件下。修改nginx.conf,配置反向代理。将请求nginx这个服务器的转发到后端服务器