JAVA项目实战《苍穹外卖》

前言

你好:

首先感谢你使用这份笔记手册,本学习笔记是我在自学过程(网课视频在下方链接)中的随手笔记,可能出现遗漏,顺序错误或语法,单词等错误,你可以在自己的学习过程中对这份笔记更正即可。

说明: 本笔记为本人学习过程中随手写的笔记,为复习使用,笔记中可能存在遗漏或错误,具体请以官方文档和权威书籍为准!谢谢! 笔记中的一些图片等元素因路径配置问题,可能会发生丢失。 笔记中展示的知识点仅为部分内容,完整内容请查阅官方开发文档内容!

参考资料

【黑马程序员Java项目实战《苍穹外卖》,最适合新手的SpringBoot+SSM的企业级Java项目实战】 https://www.bilibili.com/video/BV1TP411v7v6/?p=3&share_source=copy_web&vd_source=ea0cf64e8dac6f0193a7e28187a0fccb

 

项目开发整体介绍

软件开发流程

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

 

开发分工

项目经理:对整个项目负责,任务分配、把控进度 产品经理:进行需求调研,输出需求调研文档、产品原型等 UI设计师:根据产品原型输出界面效果图 架构师:项目整体架构设计、技术选型等 开发工程师:代码实现 测试工程师:编写测试用例,输出测试报告 运维工程师:软件环境搭建、项目上线

 

软件环境

 

苍穹外卖项目介绍

项目介绍

产品原型

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

image-20250623215421295

image-20250623215430722

image-20250623215440152image-20250623215451300

image-20250623215509031

image-20250623215528598

image-20250623215539435

更多页面原型,需要下载课程资料。

技术选型

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

image-20250623221509625

 

 

开发环境搭建

前端环境搭建(管理端)

启动资料中提供的Nginx服务器

image-20250624154710504

 

后端环境搭建

使用IDEA打开资料中提供的初始工程,并了解该项目的整体结构。

image-20250624154830893

image-20250624154922337

项目结构介绍

序号名称说明
1sky-take-outmaven父工程,统一管理依赖版本,聚合其他子模块
2sky-common子模块,存放公共类,如:工具类,常量类,异常类等
3sky-pojo子模块,存放实体类,VO、DTO等
4sky-server子模块,后端服务,存放配置文件,controller,server,Mapper等

实体说明

image-20250624155648632

 

使用Git版本控制

 

数据库环境搭建

通过资料中的数据库脚本创建数据库表结构

image-20250625172144097

恢复数据库信息

image-20250625172211222

image-20250625172609301

【补充】数据库设计文档

序号数据表名中文名称
1employee员工表
2category分类表
3dish菜品表
4dish_flavor菜品口味表
5setmeal套餐表
6setmeal_dish套餐菜品关系表
7user用户表
8address_book地址表
9shopping_cart购物车表
10orders订单表
11order_detail订单明细表
  1. employee

employee表为员工表,用于存储商家内部的员工信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)姓名 
usernamevarchar(32)用户名唯一
passwordvarchar(64)密码 
phonevarchar(11)手机号 
sexvarchar(2)性别 
id_numbervarchar(18)身份证号 
statusint账号状态1正常 0锁定
create_timedatetime创建时间 
update_timedatetime最后修改时间 
create_userbigint创建人id 
update_userbigint最后修改人id 
  1. category

category表为分类表,用于存储商品的分类信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)分类名称唯一
typeint分类类型1菜品分类 2套餐分类
sortint排序字段用于分类数据的排序
statusint状态1启用 0禁用
create_timedatetime创建时间 
update_timedatetime最后修改时间 
create_userbigint创建人id 
update_userbigint最后修改人id 
  1. dish

dish表为菜品表,用于存储菜品的信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)菜品名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)菜品价格 
imagevarchar(255)图片路径 
descriptionvarchar(255)菜品描述 
statusint售卖状态1起售 0停售
create_timedatetime创建时间 
update_timedatetime最后修改时间 
create_userbigint创建人id 
update_userbigint最后修改人id 
  1. dish_flavor

dish_flavor表为菜品口味表,用于存储菜品的口味信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
dish_idbigint菜品id逻辑外键
namevarchar(32)口味名称 
valuevarchar(255)口味值 
  1. setmeal

setmeal表为套餐表,用于存储套餐的信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)套餐名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)套餐价格 
imagevarchar(255)图片路径 
descriptionvarchar(255)套餐描述 
statusint售卖状态1起售 0停售
create_timedatetime创建时间 
update_timedatetime最后修改时间 
create_userbigint创建人id 
update_userbigint最后修改人id 
  1. setmeal_dish

setmeal_dish表为套餐菜品关系表,用于存储套餐和菜品的关联关系。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
setmeal_idbigint套餐id逻辑外键
dish_idbigint菜品id逻辑外键
namevarchar(32)菜品名称冗余字段
pricedecimal(10,2)菜品单价冗余字段
copiesint菜品份数 
  1. user

user表为用户表,用于存储C端用户的信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
openidvarchar(45)微信用户的唯一标识 
namevarchar(32)用户姓名 
phonevarchar(11)手机号 
sexvarchar(2)性别 
id_numbervarchar(18)身份证号 
avatarvarchar(500)微信用户头像路径 
create_timedatetime注册时间 
  1. address_book

address_book表为地址表,用于存储C端用户的收货地址信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
user_idbigint用户id逻辑外键
consigneevarchar(50)收货人 
sexvarchar(2)性别 
phonevarchar(11)手机号 
province_codevarchar(12)省份编码 
province_namevarchar(32)省份名称 
city_codevarchar(12)城市编码 
city_namevarchar(32)城市名称 
district_codevarchar(12)区县编码 
district_namevarchar(32)区县名称 
detailvarchar(200)详细地址信息具体到门牌号
labelvarchar(100)标签公司、家、学校
is_defaulttinyint(1)是否默认地址1是 0否
  1. shopping_cart

shopping_cart表为购物车表,用于存储C端用户的购物车信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)商品名称 
imagevarchar(255)商品图片路径 
user_idbigint用户id逻辑外键
dish_idbigint菜品id逻辑外键
setmeal_idbigint套餐id逻辑外键
dish_flavorvarchar(50)菜品口味 
numberint商品数量 
amountdecimal(10,2)商品单价 
create_timedatetime创建时间 
  1. orders

orders表为订单表,用于存储C端用户的订单数据。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
numbervarchar(50)订单号 
statusint订单状态1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
user_idbigint用户id逻辑外键
address_book_idbigint地址id逻辑外键
order_timedatetime下单时间 
checkout_timedatetime付款时间 
pay_methodint支付方式1微信支付 2支付宝支付
pay_statustinyint支付状态0未支付 1已支付 2退款
amountdecimal(10,2)订单金额 
remarkvarchar(100)备注信息 
phonevarchar(11)手机号 
addressvarchar(255)详细地址信息 
user_namevarchar(32)用户姓名 
consigneevarchar(32)收货人 
cancel_reasonvarchar(255)订单取消原因 
rejection_reasonvarchar(255)拒单原因 
cancel_timedatetime订单取消时间 
estimated_delivery_timedatetime预计送达时间 
delivery_statustinyint配送状态1立即送出 0选择具体时间
delivery_timedatetime送达时间 
pack_amountint打包费 
tableware_numberint餐具数量 
tableware_statustinyint餐具数量状态1按餐量提供 0选择具体数量
  1. order_detail

order_detail表为订单明细表,用于存储C端用户的订单明细数据。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)商品名称 
imagevarchar(255)商品图片路径 
order_idbigint订单id逻辑外键
dish_idbigint菜品id逻辑外键
setmeal_idbigint套餐id逻辑外键
dish_flavorvarchar(50)菜品口味 
numberint商品数量 
amountdecimal(10,2)商品单价 

 

前后端联调测试

设置好数据库连接信息,启动后端程序

image-20250625173445357

启动前端程序,登录,测试,可以进入管理平台,成功 image-20250625173510753

在本项目中,后端登录接口为/admin/employee/login

image-20250625200533843

而前端请求的地址是:http://localhost/api/employee/login

image-20250625200636754

实现以上功能,使用的是nginx反向代理,就是将前端发送的动态请求由nginx转发到后端服务器

image-20250625200914015

使用反向代理的好处

 

nginx反向代理的配置

image-20250625201239196

负载均衡配置

image-20250625201508425

image-20250625201543534

更多详细的Nginx服务器配置相关操作,参考《Nginx教程》

 

登陆完善

当前登录问题:员工表中的密码是明文存储,安全性太低。

image-20250625202711971

解决方案:将密码加密后存储,提高安全性

 

功能完善

小技巧:在注释中添加TODO 可以标记当前未完成的功能

image-20250625204458097

  1. 修改数据库中的明文密码为加密后的密码

     

  2. 修改Java代码,对前端的密码进行加密

     

导入接口文档

前后端分离开发的流程图

image-20250625205106477

将资料中提供的接口数据导入到接口管理平台中。

image-20250625205226814

image-20250625210433969

【注】接口管理平台推荐

平台自动同步更新公司/社区
Swagger实时Linux基金会
Swagger+Knife4j实时xiaoymin
RAP2N/AAlibaba
YApi定时去哪儿
Apifox定时睿狐科技
Redoc实时Rebilly

 

Swagger

介绍

Swagger 是一套用于设计、构建、文档化和测试 RESTful API 的开源工具集。

Swagger 提供了一种标准化的方式来描述 API 的结构、请求参数、响应格式等信息,使得前后端开发人员能够更高效地协作。

官网:API Documentation & Design Tools for Teams | Swagger

 

Knife4j

Knife4i是为JavaMVC框架集成Swagger生成Api文档的增强解决方案。

Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-uiui皮肤项目

一开始项目初衷是为了写一个增强版本的swagger的前端ui,但是随着项目的发展,面对越来越多的个性化需求,不得不编写后端Java代码以满足新的需求,在swagger-bootstrap-ui的1.8.5~1.9.6版本之间,采用的是后端Java代码和Ui都混合在一个Jar包里面的方式提供给开发者使用.这种方式虽说对于集成swagger来说很方便,只需要引入jar包即可,但是在微服务架构下显得有些臃肿。

因此,项目正式更名为knife4j,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端.

swagger-bootstrap-ui的所有特性都会集中在knife4j-spring-ui包中,并且后续也会满足开发者更多的个性化需求.

主要的变化是,项目的相关类包路径更换为com.github.xiaoymin.knife4j前缀,开发者使用增强注解时需要替换包路径

后端Java代码和ui包分离为多个模块的jar包,以面对在目前微服务架构下,更加方便的使用增强文档注解(使用SpringCloud微服务项目,只需要在网关层集成UI的jar包即可,因此分离前后端)

官网:Knife4j · 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j

 

使用方式

  1. 在pom中导入Knife4j的starter,Maven坐标

  2. 在配置类中加入knife4j相关配置

    image-20250625212943033

  3. 设置静态资源映射,否则接口文档页面无法访问

    image-20250625212911902 image-20250625213307169

  4. 配置完成后重启项目,访问:http://localhost:8080/doc.html image-20250625213502123 可以看到生成的接口文档

 

常见注解

注解说明
@Api用在类上,例如Controller,表示对类的说明
@ApiModel用在类上,例如:entity,DTO,VO
@ApiModelProperty用在属性上,描述属性
@ApiOperation用在方法上,例如Controller的方法,说明方法的用途、作用

image-20250625221534944

image-20250625221626150

 

项目接口功能实现

本项目约定: 管理端发出的请求,统一使用/admin作为前缀 用户端发出的请求,统一使用/user作为前缀

员工管理模块

新增员工

产品原型 输入账号,员工姓名,手机号,性别,身份证号,完成员工账号的注册,默认密码123456

image-20250627145154348

代码开发

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

image-20250627151450889

Controller 层业务代码示例

server层业务代码

Mapper层

 

代码优化

问题1:当用户名已存在时,前端会出现500响应码

image-20250627170501707

image-20250627170600133

image-20250627171205002

问题2:在创建人ID和修改人ID部分使用了固定值,应动态获取

image-20250627170514709

后续请求中,前端会携带JWT令牌,通过WT令牌可以解析出当前登录员工id

【补充】ThreadLocal介绍 ThreadLocal并不是一个Thread,而是Thread的局部变量。 ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

定义工具类

在解析JWT令牌后存入ThreadLocal

image-20250627172245659

在使用时通过Get方法获取值

image-20250627172340267

 

 

员工分页查询

接口设计

image-20250627175851261

Controller

server

Mapper

Mapper.XML

image-20250627202538753

代码完善

在时间显示中,操作时间格式显示不正确,需要对时间进行格式化输出

image-20250627202755432

解决方案:

  1. 在属性上加上注解,对日期进行格式化

     

  2. 在WebMvcConfiguration中扩展Spring MVC的消息转换器统一对时间进行格式化处理。

    前后端联调测试,成功 image-20250627204300033

 

 

启用禁用员工账号

接口设计

image-20250628121959698

Controller

Server

Mapper.xml

SQL设置成适配多种修改信息的。提高适用性

功能测试成功

image-20250628134637242

 

编辑员工信息

需求分析与接口设计

代码实现示例

 

菜品分类与上方代码类似

菜品分类与上方代码类似

菜品分类与上方代码类似

 

 

【补充】公共字段自动填充

问题分析

在业务表中,有许多公共字段。例如:

字段名数据类型备注操作类型
create_timedatetime创建时间insert
create_userbigint创建人IDinsert
update_timedatetime修改时间insert,update
update_userbigint修改人IDinsert,update

image-20250628192856586 image-20250628192917199

 

代码冗余。不便于后期维护

 

解决方案

技术点:枚举、注解、AOP、反射

 

 

菜品管理模块

新增菜品

接口设计与描述

业务规则:

需要的接口

image-20250628230548084

image-20250628230609295

image-20250628230629744

示例代码展示

controller

Service

Mapper

XML (DishMapper)

(DishFlavorMapper)

 

菜品分页查询

接口设计

image-20250629200831104

image-20250629200933413

代码示例

在返回值字段中,有一个新的字段categoryName没有合适的实体类进行封装,需要设计一个新的VO

sql映射文件xml

 

修改菜品信息

接口设计:

 

菜品信息删除

业务需求分析

image-20250630170921712

业务代码实现示例

controller

Service

Mapper.XML

 

Redis

Redis介绍

Redis - 官网

Redis中文网

 

什么是Redis?

Redis 是一个强大的内存数据结构存储,用作数据库、缓存和消息代理。

Redis 与Mysql的区别

image-20250701085601869

Redis 的优势

 

下载与安装

Releases · tporadowski/redis

redis为绿色版,直接解压后就可以使用

Another Redis Desktop Manager | Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux

 

 

Redis数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:

image-20250701093406639

Redis常用指令

字符串操作命令

语句描述
SET key value设置指定Key的值
GET key获取指定Key的值
SETEX key seconds value设置指定Key的值,并设置过期时间seconds秒
SETEX key value只在key不存在时,设置key的值

image-20250701094758171

 

哈希操作命令

Redishash是一个string类型的field和value的映射表,hash特别适合用于存储对象,常用命令:

指令描述
HSET key field value将哈希表key中的字段field的值设为value
HGET key field获取存储在哈希表中指定字段的值
HDEL key field删除存储在哈希表中的指定字段
HKEYS key获取哈希表中所有字段
HVALS key获取哈希表中所有值

image-20250701095305801

 

列表操作命令

指令 
LPUSH key value1 [value2]将一个或多个值插入到列表头部
LRANGE key start stop获取列表指定范围内的元素
RPOP key移除并获取列表的最后一个元素
LLEN key获取列表长度

image-20250701112535057

 

集合操作命令

Redis set是string类型的无序集合。集合成员是唯一的,集合中不能出现重复的数据,常用命令:

指令描述
sadd key member1 [member2]向集合添加一个或多个成员
smembers key返回集合中的所有成员
scard key获取集合的成员数
sinter key1 [key2]返回给定所有集合的交集
sunion key1 [key2]返回所有给定集合的并集
srem key member1 [member2]删除集合中一个或多个成员

image-20250701113150331

 

 

有序集合操作命令

Redis有序集合是string类型元素的集合,且不允许有重复成员。每个元素都会关联一个double类型的分数。常用命令:

语法描述
zadd key score1 member1 [score2 member2]向有序集合添加一个或多个成员
zrange key start stop [withscores]通过索引区间返回有序集合中指定区间内的成员
zincrby key increment member有序集合中对指定成员的分数加上增量increment
zrem key member [member ]移除有序集合中的一个或多个成员

image-20250701113548914

 

通用命令

Redis通用命令是不分数据类型的,都可以使用的命令:

指令描述
keys pattern查找所有符合给定模式(pattern)的key
exists key检查给定key是否存在
type key返回key所储存的值的类型
del key该命令用于在key存在是删除key

 

Java中操作Redis

 

Spring Data Redis使用方式

 

 

店铺营业状态设置

接口设计:

营业状态数据存储方式:基基于Redis的字符串来进行存储

keyvalue
SHOP_STATUS1/0

image-20250701175711522

image-20250701175721529

 

 

HttpClient

介绍

HttpClient是Apache JakartaCommon下的子项目,可以用来提供高效的、最新的、功能丰富的支持HTTP 协议 的客户端编程工具包,并且它支持HTTP 协议最新的版本和建议。

引入Maven坐标

核心API:

 

发送请求步骤:

  1. 创建HttpClient对象

  2. 创建Http请求对象

  3. 调用HttpClient的execute方法发送请求

 

使用示例

发送Get请求

发送POST请求

 

微信小程序开发

介绍

小程序是一种新的开放能力,开发者可以快速地开发一个小程序。小程序可以在微信内被便捷地获取和传播,同时具有出色的使用体验。

微信公众平台-小程序

微信开放文档 / 开发

 

小程序开发准备工作

 

小程序目录结构

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

文件作用
app.js小程序逻辑
app.json小程序公共配置
app.wxss小程序公共样式表

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

文件是否必须作用
js页面逻辑
wxml页面结构
json页面配置
wxss页面样式

编写小程序代码

编译小程序

 

微信登录

 

导入商品浏览功能代码

接口功能

 

 

数据缓存

缓存菜品

问题 用户端在访问量非常大时,会频繁的操作数据库数据,会造成数据库压力急剧增大,系统响应会变慢,非常影响用户的使用体验

image-20250713131411619

实现方法

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

image-20250713131913833

示例代码

 

问题:

修改管理端接口DishController的相关方法,加入清理缓存的逻辑,需要改造的方法:

 

Spring Cache

介绍

Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。 SpringCache 提供了一层抽象,底层可以切换不同的缓存实现,例如:

引入Maven Spring Cache坐标

 

Spring Cache注解

注解说明
@EnableCaching开启缓存注解功能,通常加在启动类上
@Cacheable在方法执行前先查询缓存中是否有数据,
如果有数据,则直接返回缓存数据;
如果没有缓存数据,调用方法并将方法返回值放到缓存中
@CachePut将方法的返回值放到缓存中
@CacheEvict将一条或多条数据从缓存中删除

 

缓存套餐

实现思路

具体的实现思路如下:

代码开发

Controller(Admin)

(User)

 

添加购物车

 

image-20250714140058543

 

接口设计

image-20250714140300803

示例代码

Controller

Service

Mapper

XML

 

用户下单

主要逻辑代码

 

 

Spring Task

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

应用场景:

cron表达式

 

SpringTask使用步骤:

 

WebSocket

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

image-20250801124829969image-20250801124842740

HTTP协议和WebSocket协议对比:

 

应用场景

 

来单提醒

设计:

 

WebSocketServer.java

 

ECharts数据展示

一个基于 JavaScript 的开源可视化图表库

官网:Apache ECharts

官方文档:快速上手 - 使用手册 - Apache ECharts