本项目(苍穹外卖)是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括 系统管理后台 和 小程序端应用 两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护,对餐厅的各类数据进行统计,同时也可进行来单语音播报功能。小程序端主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单、支付、催单等。
接下来,通过功能架构图来展示管理端和用户端的具体业务功能模块。
关于本项目的技术选型, 我们将会从 用户层、网关层、应用层、数据层 这几个方面进行介绍,主要用于展示项目中使用到的技术框架和中间件等。
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). 前端工程基于 nginx
2). 启动nginx,访问测试
双击 nginx.exe 即可启动 nginx 服务,访问端口号为 80
http://localhost:80
后端工程基于 maven 进行项目构建,并且进行分模块开发。
后端的初始工程中已经实现了登录功能,直接进行前后端联调测试即可
实现思路:
1. 接受并封装前端参数
2. 调用Service方法查询数据库
1. Service内部调用Mapper查询数据库 得到与输入用户名对应的员工数据,封装成对象
1. Mapper 使用@Select("select * from employee where username = #{username}")
2. 将数据库中的员工密码 与 输入密码对比
3. 若对比成功, 将员工对象返回给controller
3. 再将员工对象封装并返回给前端
一 **问题:**员工表中的密码是明文存储,安全性太低。
解决思路:1. 数据库中的密码使用的是md5加密后的密码,
因此在进行密码对比的过程中, 也要对前端输入的密码进行一次md5加密
// TODO 后期需要进行md5加密,然后再进行比对 password = DigestUtils.md5DigestAsHex(password.getBytes());
二. 返回给前端的封装过程涉及到了jwt令牌构建token
其中密钥,存在时间等都在xml文件中指定
/**
* 登录
*
* @param employeeLoginDTO
* @return
*/
@PostMapping("/login")
public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
log.info("员工登录:{}", employeeLoginDTO);
//调用service方法查询数据库
Employee employee = employeeService.login(employeeLoginDTO);
//登录成功后,生成jwt令牌
Map claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token)
.build();
return Result.success(employeeLoginVO);
}
/**
* 员工登录
*
* @param employeeLoginDTO
* @return
*/
public Employee login(EmployeeLoginDTO employeeLoginDTO) {
String username = employeeLoginDTO.getUsername();
String password = employeeLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Employee employee = employeeMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (employee == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
if (!password.equals(employee.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (employee.getStatus() == StatusConstant.DISABLE) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return employee;
}
package com.sky.mapper;
import com.sky.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface EmployeeMapper {
/**
* 根据用户名查询员工
* @param username
* @return
*/
@Select("select * from employee where username = #{username}")
Employee getByUsername(String username);
}
三. 对登录功能测试完毕后,接下来,我们思考一个问题:前端发送的请求,是如何请求到后端服务的?
前端请求地址:http://localhost/api/employee/login
后端接口地址:http://localhost:8080/admin/employee/login
8080是后端Tomcat服务器的端口号
前端请求地址 后端接口地址
1). nginx反向代理
nginx 反向代理,就是将前端发送的动态请求由 nginx 转发到后端服务器
nginx 反向代理的好处: