苍穹外卖

https://www.bilibili.com/video/BV1TP411v7v6/?spm_id_from=333.788.video.desc.click&vd_source=1a39594354c31d775ddc587407a55282

〇 经验总结

0 自动装配

  • 主启动类上的注解@SpringbootApplication是一个复合注解,其中比较重要的
    • @SpringbootConfiguration:springboot的相关配置
    • @EnableAutoConfiguration
    • @ComponentScan:扫描一些包并注入
  • 重点@EnableAutoConfiguration,也是一个复合注解
    • @import(AutoConfigurationImportSelect.class)
  • AutoConfigurationImportSelect中一个重要的方法:importSelect()作用是选取一些类,注入到IOC容器中

  • 配置文件的信息如何加载到bean中:spring.factories文件存储了一些键信息,然后加载的时候配置文件的值就被加载到这个文件中了

  • 两种

    • @Autowired:根据类型自动注入
    • @Resource:根据bean的名称自动注入

1 Mybatis

  • 分页查询

    • PageHelper:原理是存储分页信息在ThreadLocal中,在执行sql前拦截器会读取到分页信息动态插入到sql中再执行

      image-20240224180047211

  • 批量插入

    image-20240224182755036

    mapper:

    image-20240224182807077

  • 参数传递xxxMapper.java中方法的形参名可以不与.xml一致,MyBatis 会按照参数的位置进行匹配而不是参数的名字,若有多个参数,则应该按顺序使用

    • 也可以使用@ParamList<TeachplanDto> selectTreeNodes(@Param("courseId") Long courseId, @Param("name") String name);指定mapper中的名字

2 微信登录

  • 过程

    • 前端传入授权码发送至服务端

    • 服务端携带授权码code + appid + secret 采用HttpClient发送请求到https://api.weixin.qq.com/sns/jscode2session

    • 得到微信服务端返回的openid + session_key,其中openid也就是微信用户的唯一标识

    • 根据openid查询数据库中是否存在此用户(openid不是主键),若不存在则自动创建,存在则返回该用户信息

    • 为该用户生成jwt令牌(密钥+过期时间+信息)

      • 密钥用于加密解密jwt信息
      • 信息claims是一个map,在本项目中只存储了userId这一个信息
    • 返回VO对象

      <img src=(https://myl-mdimg.oss-cn-beijing.aliyuncs.com/TyporaImg/苍穹外卖.assets/image-20240224190705160.png“ alt=”image-20240224190705160” style=”zoom: 67%;” />

3 redis和SpringCache

4 微信支付

  • 用户点击支付,向接口发送请求,传入订单号及付款方式(微信)
  • 服务端获取到当前用户的id,采用JSAPI下单,传入appid、mchid(商户号)、description、out_trade_no、notify_url(回调地址)等信息,发送post请求(httpclient)https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
  • 解析返回结果:prepay_id(关键,这个要给前端): 预支付交易会话标识,根据prepay_id及appid、时间等信息生成二次签名(预支付交易单)
  • 支付结果异步通知:读取数据、解密数据、业务处理:修改订单状态、给微信响应

5 百度地图

6 来单提醒/用户催单

  • 客户端通过/ws/{sid}与服务端建立websocket长连接,会话对象Session存储在map中,当需要发送消息的时候调用session.getBasicRemote().sendText(message);方法即可

  • 在客户支付成功之后调用

Ⅰ 整体介绍

一 软件开发整体介绍

1.1 流程

  • 需求分析:需求规格说明书、产品原型
  • 设计:UI设计、数据库设计、接口设计
  • 编码:项目代码、单元测试
  • 测试:测试用例、测试报告
  • 上线运维:软件环境安装、配置

1.2 角色分工

image-20231112215647568

1.3 软件环境

  • 开发环境:开发阶段环境,一般外部用户无法访问
  • 测试环境:测试人员使用,一般外部用户无法访问
  • 生产环境:线上环境,正式提供对外服务的环境

二 苍穹外卖项目介绍

2.1 项目介绍

  • 定位:专门为餐饮企业(餐厅、饭店)定制的一款软件产品

  • 功能架构

    image-20231112215927930

2.2 产品原型

  • 产品原型:用于展示项目的业务功能,一般由产品经理进行设计

2.3 技术选型

  • 技术选型:展示项目中使用到的技术框架和中间件等

    image-20231112220002355

三 开发环境搭建

  • 整体结构
    • 前端
      • 管理端:Web
      • 用户端:小程序
    • 后端
      • 后端服务:Java

3.1 前端环境搭建

  • 前端工程基于nginx运行
  • 双击项目目录下的nginx.exe即可启动服务,端口号为80

3.2 后端环境搭建

  • 后端工程基于maven进行项目构建,并且进行分模块开发

  • sky-take-out:maven父工程,统一管理依赖版本,聚合其他子模块

    • sky-common:子模块,存放公共类,例如:工具类、常量类、异常类等
    • sky-pojo:子模块,存放实体类、VO、DTO等
      • entity:实体,通常与数据库的表对应
      • DTO:数据传输对象,通常于程序中各层之间传递数据
      • VO:视图对象,为前端展示数据提供的对象
      • POJO:普通Java对象,只有属性和对应的getter和setter
    • sky-server:子模块,后端服务,存放配置文件、Controller、Service、Mapper等
  • 使用Git进行版本控制

  • 数据库环境搭建

    image-20231112220832816

  • 前后端联调

3.3 完善登录功能

  • 问题:员工表中的密码是明文存储,安全性低
  • 思路:将密码加密后存储,提高安全性,使用MD5加密方式对明文密码加密

四 接入接口文档

4.1 前后端分离开发流程

image-20231112221529341

  • 在YApi中管理接口

五 Swagger

  • 类似于postman 但是postman一个一个测试比较麻烦

5.1 介绍

  • 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。

    官网:https://swagger.io/

  • Knife4j 是为Java MVC框架集成Swagger生成Api文档的增强解决方案。

5.2 使用方式

  • 导入坐标
  • 配置类中加入配置
  • 设置静态资源映射,否则接口文档页面无法访问

5.3 常用注解

image-20231112221816822

Ⅱ 员工管理、分类管理

一 新增员工

1.1 需求分析和设计

  • 产品原型

    • 账号唯一
    • 手机号合法的
    • 身份证合法
    • 密码默认123456
  • 接口设计

    • 请求参数

      • Path:/admin/employee
      • Method:POST

      image-20231113202940688

    • 返回数据

      image-20231113202956877

    • 约定

      • 管理端的请求,/admin作为前缀
      • 用户端的请求,/user作为前缀
  • 数据库设计(employee表)

    image-20231113203143786

1.2 代码开发

  • 根据新增员工接口设计对应的DTO

    • 注意:当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Data
      public class EmployeeDTO implements Serializable {
      private Long id;
      private String username;
      private String name;
      private String phone;
      private String sex;
      private String idNumber;
      }

1.3 功能测试

  • 通过接口文档测试(多用这种)

  • 通过前后端联调测试

  • 由于开发阶段前端和后端是并行开发的,后端完成某个功能后,此时前端对应的功能可能还没有开发完成,

    导致无法进行前后端联调测试。所以在开发阶段,后端测试主要以接口文档测试为主。

  • 注意配置token,在接口文档中定义一个全局变量,key为token(有时效的)

1.3 代码完善

  • 录入的用户名已存在,抛出异常后没有处理

    • 全局异常处理器处理

      image-20231113205617529

  • 新增员工时,创建人id和修改人id设置为了固定值

    • 通过某种方式动态获取当前登录员工的id

      image-20231113210316469

      • 员工登录成功后会生成JWT令牌并响应给前端
      • 后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录员工id
      • 解析出登录员工id后,如何传递给Service的save方法?
  • ThreadLocal

    • 并不是一个Thread,而是Thread的局部变量。
    • ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
      • image-20231113210620803
    • 客户端发送的每次请求,后端的Tomcat服务器都会分配一个单独的线程来处理请求
    • 在拦截器中解析出当前登录的员工的id,并放入的线程局部变量中,随后在保存的时候读取这个id

二 员工分页查询

2.1 需求分析和设计

  • 业务规则

    • 根据页码展示员工信息
    • 每页10条数据
    • 分页查询时可以根据需要,输入员工姓名进行查询
  • 接口设计

    • 请求参数

      • Path:/admin/employee/page
      • Method:GET
      • image-20231113211539458
    • 返回数据

      image-20231113211520807

2.2 代码开发

  • 根据接口设计对应的DTO

    image-20231113211659677

  • 后面所有的分页查询,统一都封装成PageResult对象:

    image-20231113211718332

  • 员工信息分页查询后返回的对象类型为:Result<PageResult>

    image-20231113211815663

2.3 功能测试

2.4 代码完善

  • 方式一:在属性上加入注解,对日期进行格式化

    image-20231113215900420

  • 方式二:在 WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理

三 启用禁用员工账号

3.1 需求分析与设计

  • 业务规则

    • 可以对状态为“启用” 的员工账号进行“禁用”操作
    • 可以对状态为“禁用”的员工账号进行“启用”操作
    • 状态为“禁用”的员工账号不能登录系统
  • 接口设计

    image-20231113220915625

3.2 代码开发

3.3 功能测试

四 编辑员工

4.1 需求分析与设计

  • 业务规则

    • 根据id查询员工信息
    • 编辑员工信息
  • 接口设计

    • 根据id查询员工信息

      image-20231113222420681

    • 编辑员工信息

      image-20231113222441435

4.2 代码开发

4.3 功能测试

五 导入分类模块功能代码

  • 与员工管理类似

5.1 需求分析与设计

  • 业务规则

    • 分类名称必须是唯一
    • 分类按照类型可以分为菜品分类套餐分类
    • 新添加的分类状态默认为“禁用”
  • 接口设计

    • 新增分类
    • 分类分页查询
    • 根据id删除分类
    • 修改分类
    • 启用禁用分类
    • 根据类型查询分类
  • 数据库设计(category表)

    image-20231113223801771

5.2 代码开发

5.3 功能测试

Ⅲ 菜品管理

一 公共字段自动填充

1.1 问题分析

  • 业务表中的公共字段重复,导致代码冗余、不便于后期维护

    image-20231116224758489

1.2 实现思路

image-20231116224942816

  • 自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法
  • 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值
  • 在 Mapper 的方法上加入 AutoFill 注解
  • 技术点:枚举、注解、AOP、反射

1.3 代码开发

  • 自定义注解AutoFill
  • 自定义切面 AutoFillAspect
  • 完善自定义切面 AutoFillAspect 的 autoFill 方法
  • 在Mapper接口的方法上加入 AutoFill 注解
  • 将业务层为公共字段赋值的代码注释掉

1.4 功能测试

二 新增菜品

2.1 需求分析和设计

  • 业务规则

    • 菜品名称必须是唯一的
    • 菜品必须属于某个分类下,不能单独存在
    • 新增菜品时可以根据情况选择菜品的口味
    • 每个菜品必须对应一张图片
  • 接口设计

    • 根据类型查询分类(已完成)

      image-20231116232910259

    • 文件上传

      image-20231116233003532

    • 新增菜品

      image-20231116233013731

  • 数据库设计(dish菜品表和dish_flavor口味表)

    image-20231116233046342

2.2 代码开发

2.3 功能测试

三 菜品分页查询

3.1 需求分析和设计

  • 业务规则

    • 根据页码展示菜品信息
    • 每页展示10条数据
    • 分页查询时可以根据需要输入菜品名称、菜品分类、菜品状态进行查询
  • 接口设计

    image-20231117153112174

3.2 代码开发

3.3 功能测试

四 删除菜品

4.1 需求分析和设计

  • 业务规则

    • 可以一次删除一个菜品,也可以批量删除菜品
    • 起售中的菜品不能删除
    • 被套餐关联的菜品不能删除
    • 删除菜品后,关联的口味数据也需要删除掉
  • 接口设计

    image-20231117211019552

  • 数据库设计

    image-20231117211032524

4.2 代码开发

4.3 功能测试

五 修改菜品

5.1 需求分析和设计

  • 接口设计

    • 根据id查询菜品

      image-20231117215618556

    • 根据类型查询分类(已实现)

    • 文件上传(已实现)

    • 修改菜品

      image-20231117215636319

5.2 代码开发

5.3 功能测试

Ⅳ 店铺状态

一 Redis

1.1 简介

1.2 Redis服务启动与停止

  • 服务端

    • 服务启动命令cmd:redis-server.exe redis.windows.conf
    • Redis服务默认端口号为 6379 ,通过快捷键Ctrl + C 即可停止Redis服务
  • 客户端

    • 客户端连接命令cmd:redis-cli.exe

    • 通过redis-cli.exe命令默认连接的是本地的redis服务,并且使用默认6379端口。也可以通过指定如下参数连接:

      • -h ip地址

      • -p 端口号

      • -a 密码(如果需要)

        image-20231120095709243

  • 设置Redis服务密码

    • 修改redis.windows.conf

    • requirepass 123456

      image-20231120095546630

  • 客户端图形工具

    • Another-Redis-Desktop-

二 Redis数据类型

2.1 5种常用数据类型

  • 字符串 String
    • 普通字符串,Redis中最简单的数据类型
  • 哈希 hash
    • 也叫散列,类似于Java中的HashMap结构
  • 列表 list
    • 按照插入顺序排序,可以有重复元素,类似于Java中的LinkedList
  • 集合 set
    • 无序集合,没有重复元素,类似于Java中的HashSet
  • 有序集合 sorted set/zset
    • 集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

image-20231120100715094

三 Redis常用命令

  • 字符串操作命令

    • SET key value
    • GET key
    • SETEX key seconds value:设置指定key的值,并将 key 的过期时间设为 seconds 秒
    • SETNX key value :只有在 key 不存在时设置 key 的值
  • 哈希操作命令

    • HSET key field value :将哈希表 key 中的字段 field 的值设为 value

    • HGET key field :获取存储在哈希表中指定字段的值

    • HDEL key field :删除存储在哈希表中的指定字段

    • HKEYS key :获取哈希表中所有字段

    • HVALS key :获取哈希表中所有值

      image-20231120101206111

  • 列表操作命令

    • LPUSH key value1 [value2] :将一个或多个值插入到列表头部(左边)

    • LRANGE key start stop :获取列表指定范围内的元素

    • RPOP key :移除并获取列表最后一个元素(右边)

    • LLEN key :获取列表长度

      image-20231120101217359

  • 集合操作命令

    • SADD key member1 [member2] :向集合添加一个或多个成员

    • SMEMBERS key :返回集合中的所有成员

    • SCARD key :获取集合的成员数

    • SINTER key1 [key2]:返回给定所有集合的交集

    • SUNION key1 [key2] :返回所有给定集合的并集

    • SREM key member1 [member2]:删除集合中一个或多个成员

      image-20231120101505467

  • 有序集合操作命令

    • ZADD key score1 member1 [score2 member2] :向有序集合添加一个或多个成员

    • ZRANGE key start stop [WITHSCORES] :通过索引区间返回有序集合中指定区间内的成员

    • ZINCRBY key increment member :有序集合中对指定成员的分数加上增量 increment

    • ZREM key member [member ...] :移除有序集合中的一个或多个成员

      image-20231120101738061

  • 通用命令

    • KEYS pattern :查找所有符合给定模式( pattern)的 key
    • EXISTS key :检查给定 key 是否存在
    • TYPE key :返回 key 所储存的值的类型
    • DEL key :该命令用于在 key 存在是删除 key

四 java中操作Redis

  • Redis的java客户端很多,常用的几种

    • Jedis

    • Lettuce

    • Spring Data Redis :是 Spring 的一部分,对 Redis 底层开发包进行了高度封装。

      在 Spring 项目中,可以使用Spring Data Redis来简化操作。

  • 步骤

    • 导入Spring Data Redis坐标

    • 配置数据源

      image-20231120103809024

      image-20231120103824045

    • 编写配置类,创建Redis Template对象

      image-20231120104116616

    • 通过Redis Template对象操作Redis

  • RedisTemplate:针对大量api进行了归类封装,将同一数据类型的操作封装为对应的Operation接口,具体分类如下:

    • ValueOperations:string数据操作
    • SetOperations:set类型数据操作
    • ZSetOperations:zset类型数据操作
    • HashOperations:hash类型的数据操作
    • ListOperations:list类型的数据操作

五 店铺营业状态设置

5.1 需求分析和设置

  • 接口设计

    • 设置营业状态

      image-20231120114209815

    • 管理端查询营业状态

      image-20231120114236302

    • 用户端查询营业状态

      image-20231120114251878

  • 数据存储方式:基于Redis的字符串来进行存储

    • 约定:1表示营业。0表示打烊

5.2 代码开发

5.3 功能测试

Ⅴ 微信登录 商品浏览

一 HttpClient

1.1 介绍

  • HttpClient是Apache的一个子项目,是高效的、功能丰富的支持HTTP协议的客户端编程工具包。

    image-20231120142148489

  • 作用

    • 发送HTTP请求
    • 接收响应数据
  • 核心API

    • HttpClient
    • HttpClients
    • CloseableHttpClient
    • HttpGet
    • HttpPost
  • 发送请求步骤

    • 创建HttpClient对象
    • 创建Http请求对象
    • 调用HttpClient的execute方法发送请求

1.2 入门案例

二 微信小程序开发

2.1 介绍

2.2 准备工作

  • 创建完善信息
  • 获取APPID以及密钥
    • ID:wx51bff83287f6cf1e
    • 密钥:8d1d0cba4123d1b03f772b50f0266abc

2.3 入门案例

  • 了解小程序的目录结构

    • 小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:

      image-20231120151300404

    • 一个小程序页面由四个文件组成:

      image-20231120151330404

  • 编写小程序代码

  • 编译小程序

三 微信登录

3.1 微信登录流程

image-20231120170720902

3.2 需求分析和设计

  • 业务规则

    • 基于微信登录实现小程序的登录功能

    • 如果是新用户需要自动完成注册

  • 接口设计

    image-20231120171640916

  • 数据表设计(user表)

    image-20231120171713035

3.3 代码开发

  • 配置微信登录所需配置项:
  • 配置为微信用户生成jwt令牌时使用的配置项:
  • DTO设计:
  • VO设计:
  • Controller、service、Mapper的编写

3.4 功能测试

四 导入商品浏览功能代码

4.1 需求分析和设计

  • 查询分类

    image-20231120194321065

  • 根据分类id查询菜品

    image-20231120194340174

  • 根据分类id查询套餐

    image-20231120194355621

  • 根据套餐id查询包含的菜品

    image-20231120194409786

Ⅵ 缓存商品、购物车

一 缓存菜品

1.1 问题说明

  • 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。

    image-20231121151948735

1.2 实现思路

  • 通过Redis来缓存菜品数据,减少数据库查询操作。

    image-20231121152017276

  • 缓存逻辑分析

    • 每个分类下的菜品保存一份缓存数据
    • 数据库中的菜品数据有变更时清理缓存数据

1.3 代码开发

  • 修改管理端接口 DishController 的相关方法,加入清理缓存的逻辑,需要改造的方法:
    • 新增菜品
    • 修改菜品
    • 批量删除菜品
    • 起售、停售菜品

1.4 功能测试

二 缓存套餐

2.1 Spring Cache

  • Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能

  • Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:

    • EHCache
    • Caffeine
    • Redis
  • 常用注解

    image-20231121171344515

2.2 实现思路

  • 导入坐标
  • 在启动类上加入@EnableCaching注解,开启缓存注解功能
  • 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
  • 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解

2.3 代码开发与功能测试

三 添加购物车

3.1 需求分析和设计

  • 接口设计

    image-20231121224256927

  • 数据库设计

    • 作用:暂时存放所选商品的地方

      • 选的什么商品,每个商品买了几个,不同的用户的购物车需要分开

      image-20231121224403598

四 查看购物车

4.1 需求分析和设计

  • 接口设计

    image-20231122141933057

五 清空购物车

  • 需求分析和设计

    image-20231122142543137

Ⅶ 用户下单 订单支付

一 导入地址簿功能

1.1 查询地址列表

  • 查询登录用户所有地址

    image-20231122193352335

  • 查询默认地址

    image-20231122193416024

1.2 新增地址

  • 接口

    image-20231122193334415

1.3 修改地址

image-20231122193425846

1.4 删除地址

  • 根据id删除地址

    image-20231122193445677

1.5 设置默认地址

image-20231122193529096

1.6 查询默认地址

  • 根据id查询地址

    image-20231122193516107

1.7 数据表(address_book)

image-20231122193553555

二 用户下单

2.1 需求分析和设计

  • 业务说明

    • 电商系统中,用户是通过下单的方式通知商家,用户已经购买了商品,需要商家进行备货和发货。
    • 用户下单后会产生订单相关数据,订单数据需要能够体现如下信息:
      • 总金额
      • 用户
      • 商品种类及数量
      • 收获地址
      • 手机号码
  • 业务流程

    • 购物车页面
    • 订单提交页面
    • 订单支付页面
    • 下单成功页面
  • 接口分析

    image-20231122202159725

  • 数据库设计

    • 订单表 orders

      image-20231122202411139

    • 订单明细表 order_detail

      image-20231122202403269

    • 订单表和订单明细表的关系:一对多

2.2 代码与测试

三 订单支付

3.1 微信支付介绍

  • 微信支付产品

    image-20231122210746038

  • 微信支付接入流程

    image-20231122210810830

  • 微信小程序支付时序图

    image-20231122210859604

  • 微信小程序调起支付:通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付

    image-20231122210950716

3.2 微信支付准备工作

  • 如何保证数据安全
  • 微信后台如何调用到商户系统?
  • 获取微信支付平台证书、商户私钥文件
  • 获取临时域名:支付成功后微信服务通过该域名回调我们的程序

3.3 代码与功能测试

  • (看看就好)

Ⅷ 订单处理

一 Spring Task

1.1 介绍

  • Spring Task 是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。

  • 作用:定时自动执行某段Java代码

  • 应用场景
    • 信用卡每月还款提醒
    • 银行贷款每月还款提醒
    • 火车票售票系统处理未支付订单
    • 入职纪念日为用户发送通知

1.2 cron表达式

  • cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间

  • 构成规则

    • 分为6或7个域,由空格分隔开,每个域代表一个含义

    • 每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)

      image-20231123195357807

1.3 demo

  • 导入坐标spring-context

  • 启动类添加注解@EnableScheduling开启任务调度

  • 自定义定时任务类(要加入@Component交给容器管理)

    image-20231123195755121

二 订单状态定时处理

2.1 需求分析

  • 场景

    • 下单后未支付,订单一直处于“待支付”状态

    • 用户收货后管理端未点击完成按钮,订单一直处于“派送中”状态

  • 逻辑

    • 通过定时任务每分钟检查一次是否存在支付超时订单(下单后超过15分钟仍未支付则判定为支付超时订单),如果存在则修改订单状态为“已取消”
    • 通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为“已完成”

2.2 代码与功能测试

  • 自定义定时任务类OrderTask
  • 在OrderMapper接口中扩展方法

三 WebSocket

3.1 介绍

  • WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输。

  • 与http对比

    image-20231123201650217

  • 应用场景

    • 视频弹幕
    • 网页聊天
    • 体育实况更新
    • 股票基金报价实时更新
  • 缺点

    • 服务器长期维护长连接需要一定的成本
    • 各个浏览器支持程度不一
    • WebSocket 是长连接,受网络限制比较大,需要处理好重连
    • 结论:WebSocket并不能完全取代HTTP,它只适合在特定的场景下使用

3.2 demo

  • 直接使用websocket.html页面作为WebSocket客户端
  • 导入WebSocket的maven坐标
  • 导入WebSocket服务端组件WebSocketServer,用于和客户端通信
  • 导入配置类WebSocketConfiguration,注册WebSocket的服务端组件
  • 导入定时任务类WebSocketTask,定时向客户端推送数据

四 来电提醒

4.1 需求分析与设计

  • 需求分析

    • 语音播报
    • 弹出提示框
  • 设计

    • 通过WebSocket实现管理端页面和服务端保持长连接状态
    • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息
    • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
    • 约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content
      • type 为消息类型,1为来单提醒 2为客户催单
      • orderId 为订单id
      • content 为消息内容

五 客户催单

  • 需求分析
    • 语音播报
    • 弹出提示框
  • 设计
    • 通过WebSocket实现管理端页面和服务端保持长连接状态
    • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息
    • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
    • 约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content
      • type 为消息类型,1为来单提醒 2为客户催单
      • orderId 为订单id
      • content 为消息内容

Ⅸ 数据统计-图形

一 Apache ECharts

1.1 介绍

  • Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。
  • 官网地址:https://echarts.apache.org/zh/index.html

  • 总结:使用Echarts,重点在于研究当前图表所需的数据格式。通常是需要后端提供符合格式要求的动态数据,然后响应给前端来展示图表。

二 营业额统计

2.1 需求分析和设计

  • 业务规则

    • 营业额指订单状态为已完成的订单金额合计
    • 基于可视化报表的折线图展示营业额数据,X轴为日期,Y轴为营业额
    • 根据时间选择区间,展示每天的营业额数据
  • 接口设计

    image-20231123214519493

三 用户统计

3.1 需求分析和设计

  • 业务规则

    • 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
    • 根据时间选择区间,展示每天的用户总量和新增用户量数据
  • 接口设计

    image-20231123221333769

四 订单统计

4.1 订单统计

  • 业务规则

    • 有效订单指状态为 “已完成” 的订单
    • 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
    • 根据时间选择区间,展示每天的订单总数和有效订单数
    • 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%
  • 接口

    image-20231123222330814

五 销量排名

  • 业务规则

    • 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
    • 基于可视化报表的柱状图降序展示商品销量
    • 此处的销量为商品销售的份数
  • 接口

    image-20231123223256614

Ⅹ 数据统计-excel

一 工作台

  • 展示数据

    • 今日数据
    • 订单管理
    • 菜品总览
    • 套餐总览
    • 订单信息
  • 接口设计

    • 今日数据接口

      image-20231124093537630

    • 订单管理接口

      image-20231124093545626

    • 菜品总览接口

      image-20231124093606798

    • 套餐总览接口

      image-20231124093615891

    • 订单搜索

    • 各个状态订单数量统计

二 Apache POI

2.1 介绍

  • Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。
  • 一般情况下,POI 都是用于操作 Excel 文件。

2.2 应用场景

  • 银行网银系统导出交易明细
  • 各种业务系统导出Excel报表
  • 批量导入业务数据

2.3 demo

  • 导入坐标
  • 读写

三 导出运营数据Excel报表

  • 业务规则

    • 导出Excel形式的报表文件

    • 导出最近30天的运营数据

  • 接口设计

    image-20231124111425930

  • 设计excel模板文件

  • 查询数据
  • 将数据写入到模板文件
  • 通过输出流将Excel文件下载到客户端浏览器

十一 苍穹外卖部署管理端到远程服务器

参考https://blog.csdn.net/weixin_74266825/article/details/134899613

https://zhuanlan.zhihu.com/p/660284743

  • 预期结果:实现本地和远程的一键启动,无需额外启动mysql redis nginx

目录结构

image-20240408171713405

  • sql生成脚本存储在mysql-init目录下,便于创建相关数据表及导入数据

sky-server工程

  • sky-server下新建Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 使用包含 Java 8 的官方 OpenJDK 基础镜像
    FROM openjdk:8-jdk-alpine

    # 创建一个目录来存储你的应用
    WORKDIR /app

    # 将你的 Spring Boot 应用的 jar 文件复制到镜像中
    # 假设你的 jar 文件名为 sky-server-1.0-SNAPSHOT.jar,并且位于 target 目录下
    COPY ./target/sky-server-1.0-SNAPSHOT.jar /app/sky-server-1.0-SNAPSHOT.jar

    # 向外界暴露 8080 端口
    EXPOSE 8080

    # 定义容器启动时运行的命令
    # 使用 java -jar 命令启动 Spring Boot 应用
    CMD ["java", "-jar", "/app/sky-server-1.0-SNAPSHOT.jar"]
  • 新建一个application-prod.yml,主要是修改了数据库和redis的host和port

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 远程服务器版
    sky:
    datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    host: sky-take-out-mysql # 通过容器的id来访问对应的容器
    port: 3306 # 应用和mysql容器是在同一个网络中,所以直接访问3306端口,如果是在不同网络中,需要访问外部映射端口,也就是3305
    database: sky_take_out
    username: xx
    password: xx

    #阿里oss文件上传的配置
    alioss:
    endpoint: xx
    access-key-id: xx
    access-key-secret: xx
    bucket-name: xx

    redis:
    host: sky-take-out-redis
    port: 6379
    #password:
    database: 0

    wechat:
    secret: xxx
    appid: xxx

    shop:
    address: xxx

    baidu:
    ak: xxx
  • 之后application.yml工作环境也修改为prod

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    server:
    port: 8080

    spring:
    config:
    use-legacy-processing: true

    profiles:
    active: prod

    ...

docker compose文件

  • 分为service和env两个,其中service主要是mysql、redis等依赖服务,env是项目服务

  • 在项目目录下新建docker-compose-service.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    version: '3'
    services:
    mysql:
    image: mysql:8 # 使用的镜像
    container_name: sky-take-out-mysql # 启动的实例名称,这里的name和刚刚在-prod.yml中指定的host一致
    environment:
    MYSQL_ROOT_PASSWORD: 1234 # root 用户密码

    # 可以在这里添加额外的环境变量, 但更改认证插件需要使用 command 选项 客户端连接mysql8.0有点问题,设置了这个
    command: --default-authentication-plugin=mysql_native_password

    ports:
    - "3305:3306" # 端口映射
    volumes:
    - ./.mysql-data:/var/lib/mysql # 将数据目录挂载到本地目录以进行持久化,这个目录存储的就是数据,可以自动生成
    - ./mysql-init:/docker-entrypoint-initdb.d # 自动执行启动脚本,这个mysql-init是需要手动创建的,目录里面存放sql脚本用来初始化数据库
    restart: always # 崩溃后自动重启
    networks:
    - mynetwork # 指定网络

    redis:
    image: redis:6
    container_name: sky-take-out-redis
    ports:
    - "6380:6379"
    networks:
    - mynetwork
    volumes:
    - ./.redis-data:/data # 持久化,目录可以自动生成

    # nginx后面讲
    nginx:
    image: nginx:latest
    container_name: sky-take-out-nginx
    ports:
    - "8081:80" # 将宿主机的 8081 端口映射到容器的 80 端口,项目访问入口:ip:8081
    volumes:
    - ./nginx/html:/usr/share/nginx/html:ro # 将宿主机的 /data/html 映射到容器的 /usr/share/nginx/html 以提供静态内容
    - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf # 使用宿主机的 Nginx 配置文件替换容器中的默认配置
    networks:
    - mynetwork

    networks:
    mynetwork: # 自定义网络,实现网络互通和隔离
  • 在项目目录下新建docker-compose-env.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    version: '3.8'
    services:
    sky-take-out-service:
    container_name: sky-take-out-service # 这里的name需要记住,后面nginx有用
    build: ./sky-server # 会去 sky-server 目录下寻找Dockerfile文件
    ports:
    - "8080:8080" # 将容器的 8080 端口映射到宿主机的 8080 端口
    volumes:
    - ./sky-server:/app/data # Optional: 如果你需要持久化日志等数据,或者直接运行编译后的代码
    networks:
    - mynetwork

    networks:
    mynetwork: # 定义一个网络,使得未来的服务能加入到同一网络中

nginx

  • 项目目录下的nginx文件夹

    image-20240408173241503

  • 这里的html和资料中的nginx里面的一样,conf也是,接下来对conf进行修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    ...

    upstream webservers{
    server sky-take-out-service:8080 weight=90 ; # 直接指定容器名称和容器内部的端口,这里的sky-take-out-service就是docker-compose-env.yml中配置的,端口也是
    }

    server {
    listen 80;
    server_name localhost;

    location / {
    root /usr/share/nginx/html/sky; # 这里的目录需要修改,这个目录是在docker-compose-service.yml中nginx部分配置的
    index index.html index.htm;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }

    # 反向代理,处理管理端发送的请求
    location /api/ {
    proxy_pass http://webservers/admin/;
    }

    # 反向代理,处理用户端发送的请求
    location /user/ {
    proxy_pass http://webservers/user/;
    }

    # WebSocket
    location /ws/ {
    proxy_pass http://webservers/ws/;
    proxy_http_version 1.1;
    proxy_read_timeout 3600s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "$connection_upgrade";
    }

    }

    ...

本地测试

  • 执行mvn cleanmvn package -DskipTests 在target目录下生成jar包

  • docker-compose-service.yml中点击启动(这里nginx会启动失败,先不管)

    image-20240408173901934

  • 工具测试是否可以连接,mysql端口是3305 redis是6380

  • 再运行docker-compose-env.yml,项目成功启动

    image-20240408174058947

  • 过一分钟会有超时订单的处理也可以判断是否成功连接数据库

    image-20240408174145053

  • 回去再把nginx容器启动了

  • 访问localhost:8081
  • 以后就可以直接这样本地启动了

部署到云服务器

  • 准备一个云服务器 centos 7,安装好maven、docker

  • 在根目录下创建 code/sky-take-out目录

  • 先在本地执行mvn clean删除jar包,删掉刚刚生成的文件夹,只需要图中右边的那些,然后上传整个项目目录到服务器的目录中

    image-20240408174550437

  • 进入到sky-take-out目录

  • 执行mvn package -DskipTests 打包

  • 启动环境依赖服务,也可以不用sudo

    sudo docker compose -f docker-compose-service.yml up -d

  • 启动sky-take-out服务,也可以不用sudo

    sudo docker compose -f docker-compose-env.yml up -d

  • 在docker restart一下nginx容器

image-20240408175006710

  • 最后访问 服务器ip:8081即可