基于SpringBoot+MyBatisPlus的外卖项目

  • 1、软件开发整体介绍
    • 软件开发流程
    • 角色分工
  • 2、外卖项目介绍
    • 项目介绍
    • 产品展示
      • 后台系统管理
      • 移动端
    • 技术选型
    • 功能结构
    • 角色
  • 3、开发环境的搭建
    • 开发环境说明
    • 建库
    • 建表
    • Maven项目搭建
      • 项目的目录结构
      • pom.xml
      • application.yml
      • ReggieApplication启动类
      • 配置静态资源映射
  • 4、登录功能
    • 4.1、后台登录功能
      • 需求分析
      • 代码编写
        • R.java
        • 实体类
        • EmployeeMapper
        • EmployeeService
        • EmployeeServiceImpl
        • EmployeeController
        • 页面展示
    • 4.2、后台登出功能
      • 需求分析
      • 代码编写
      • 页面展示
    • 4.3、完善登录功能
      • 问题分析
      • 代码编写
      • LoginCheckFilter
  • 5、员工管理
    • 5.1、新增员工
      • 需求分析
      • 数据模型
      • 代码开发
      • 代码编写
      • 异常捕获
    • 小结
    • 5.2、员工信息分页查询
      • 需求分析
      • 代码开发
        • MyBatisPlusConfig配置分页插件
    • 5.3、启用/禁用员工账号
      • 需求分析
      • 代码编写
        • 编写一个通用的update方法
      • 功能测试
      • 功能修复
    • 5.3、编辑员工
      • 需求分析
      • 代码编写
    • 5.4、公共字段自动填充
      • 问题分析
      • 代码实现
      • 功能完善
        • ThreadLocal
  • 6、分类管理
    • 6.1、新增菜品分类
      • 需求分析
      • 数据模型
      • 代码开发
    • 6.1、新增菜品的分页查询
      • 需求分析
      • 代码开发
    • 6.2、删除分类
      • 需求分析
      • 代码开发
      • 功能完善
        • GlobalExceptionHandler
        • **CustomException**
        • CategoryServiceImpl
    • 6.3、修改分类
      • 需求分析
      • 代码编写
  • 7、菜品管理
    • 7.1、文件上传下载
      • 文件上传介绍
      • 文件下载介绍
      • 文件上传代码实现
      • 文件下载代码实现
    • 7.2、新增菜品
      • 需求分析
      • 数据模型
      • 代码开发
        • DishServiceImpl
        • DishController
    • 7.3、菜品信息分页查询
      • 需求分析
      • 代码开发
        • 难点
    • 7.4、修改菜品
      • 需求分析
      • 代码开发
        • controller
        • DishServiceImpl
    • 7.5、修改菜品的停/起售状态
      • DishController
      • DishServiceImpl
    • 7.6、删除菜品
  • 8、套餐管理
    • 8.1、新增套餐
      • 需求分析
      • 数据模型
      • 代码开发
        • DishController
        • SetmealDishController
        • SetmealServiceImpl
    • 8.2、套餐信息分页查询
      • 需求分析
      • 代码开发
    • 8.3、删除套餐
      • 需求分析
      • 代码开发
        • SetmealController
        • SetmealServiceImpl
    • 8.4、修改套餐
      • SetmealController
      • SetmealService
      • SetmealServiceImpl
    • 8.5、停售、启售套餐
      • SetmealController
      • SetmealServiceImpl
  • 9、前端--手机验证码登录
    • 9.1、短信发送
      • 阿里云短信服务
      • 设置签名
      • 添加模板详情
      • 设置AccessKey
      • 添加权限
      • 购买短信免费试用包
      • 代码开发
        • pom
        • 导入utils工具类
    • 9.2、手机验证码登录
      • 需求分析
      • 数据模型
      • 代码开发
        • 移动端页面放行的请求
        • UserController
  • 10、前端--导入用户地址簿
    • 需求分析
    • 数据模型
    • 代码开发
      • AddressBookController
  • 11、前端--菜品展示
    • 需求分析
    • 代码开发
      • 展示flavor口味信息
      • 套餐信息展示
  • 12、前端--购物车
    • 需求分析
    • 数据模型
    • 代码开发
  • 13、前端--用户下单
    • 需求分析
    • 数据模型
    • 代码开发
      • OrderController
      • OrderService
      • OrderServiceImpl
  • 14、代码托管
    • Git版本管理
    • Gitee
    • Github
    • 项目所需资料

申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计86935字,阅读大概需要3分钟
更多学习内容, 欢迎关注我的个人公众号:不懂开发的程序猿

写在前面的几句话:
【警告】本篇博客较长,若引起阅读不适,建议收藏,稍后再读
【说明】该外卖项目是基于SpringBoot + MyBatisPlus为框架来开发的,前端页面框架都是现成的,只需要Java后端开发程序员编写对应的接口功能和服务,是一个很不错的练手项目。项目也非常适合作为大学生的课设,毕设
【文档】本篇博客详细介绍了该外卖项目的开发步骤,如果需要写课程设计或本科毕业论文文档,建议参考我下面这篇博客,内有详细的文档说明

点餐平台文档说明

1、软件开发整体介绍

软件开发流程

角色分工

2、外卖项目介绍

项目介绍

分为后台系统管理移动端两部分

后台系统管理供商家:对菜品、套餐、订单等进行管理维护等

移动端供消费者:在线浏览,添加购物车,下单 等

3步开发思路:

第一:主要实现基本需求,其中移动端应用通过H5实现,用户可以通过手机浏览器访问。

第二:主要针对移动端应用进行改进,使用微信小程序实现,用户使用起来更加方便。

第三:主要针对系统进行优化升级,提高系统的访问性能。

产品展示

后台系统管理

登录页

员工管理页

分类管理

菜品管理

套餐管理

订单明细

移动端

登录页

首页

下单确认页

下单成功页

个人中心页

地址管理页

历史订单页

技术选型

功能结构

角色

3、开发环境的搭建

开发环境说明

工具 版本
后台 SpringBoot + MyBatisPlus
服务器 Tomcat 8.5.73
数据库 MySQL 8.0.28
Build Tools Maven 3.8.5
前端 Vue + ElementUI
开发工具 IDEA 2022.3
版本管理工具 Git

建库

建表

/*
SQLyog Ultimate v12.08 (64 bit)
MySQL - 8.0.27 : Database - reggie
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`reggie` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;USE `reggie`;/*Table structure for table `address_book` */DROP TABLE IF EXISTS `address_book`;CREATE TABLE `address_book` (`id` bigint NOT NULL COMMENT '主键',`user_id` bigint NOT NULL COMMENT '用户id',`consignee` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '收货人',`sex` tinyint NOT NULL COMMENT '性别 0 女 1 男',`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '手机号',`province_code` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '省级区划编号',`province_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '省级名称',`city_code` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市级区划编号',`city_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市级名称',`district_code` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '区级区划编号',`district_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '区级名称',`detail` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '详细地址',`label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '标签',`is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '默认 0 否 1是',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',`is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='地址管理';/*Data for the table `address_book` */insert  into `address_book`(`id`,`user_id`,`consignee`,`sex`,`phone`,`province_code`,`province_name`,`city_code`,`city_name`,`district_code`,`district_name`,`detail`,`label`,`is_default`,`create_time`,`update_time`,`create_user`,`update_user`,`is_deleted`) values (1417414526093082626,1417012167126876162,'小明',1,'13812345678',NULL,NULL,NULL,NULL,NULL,NULL,'昌平区金燕龙办公楼','公司',1,'2021-07-20 17:22:12','2021-07-20 17:26:33',1417012167126876162,1417012167126876162,0),(1417414926166769666,1417012167126876162,'小李',1,'13512345678',NULL,NULL,NULL,NULL,NULL,NULL,'测试','家',0,'2021-07-20 17:23:47','2021-07-20 17:23:47',1417012167126876162,1417012167126876162,0),(1628270733663694849,1627997218788163586,'金阳',1,'17671789248',NULL,NULL,NULL,NULL,NULL,NULL,'湖北工业大学','学校',1,'2023-02-22 13:49:29','2023-02-22 13:49:32',1627997218788163586,1627997218788163586,0);/*Table structure for table `category` */DROP TABLE IF EXISTS `category`;CREATE TABLE `category` (`id` bigint NOT NULL COMMENT '主键',`type` int DEFAULT NULL COMMENT '类型   1 菜品分类 2 套餐分类',`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '分类名称',`sort` int NOT NULL DEFAULT '0' COMMENT '顺序',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `idx_category_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='菜品及套餐分类';/*Data for the table `category` */insert  into `category`(`id`,`type`,`name`,`sort`,`create_time`,`update_time`,`create_user`,`update_user`) values (1397844263642378242,1,'湘菜',1,'2021-05-27 09:16:58','2023-02-19 16:51:09',1,1),(1397844303408574465,1,'川菜',2,'2021-05-27 09:17:07','2021-06-02 14:27:22',1,1),(1397844391040167938,1,'粤菜',3,'2021-05-27 09:17:28','2021-07-09 14:37:13',1,1),(1413341197421846529,1,'饮品',11,'2021-07-09 11:36:15','2021-07-09 14:39:15',1,1),(1413342269393674242,2,'商务套餐',5,'2021-07-09 11:40:30','2021-07-09 14:43:45',1,1),(1413384954989060097,1,'主食',12,'2021-07-09 14:30:07','2021-07-09 14:39:19',1,1),(1413386191767674881,2,'儿童套餐',6,'2021-07-09 14:35:02','2021-07-09 14:39:05',1,1),(1627130608250593281,1,'湖北菜',4,'2023-02-19 10:19:02','2023-02-19 10:19:02',1,1);/*Table structure for table `dish` */DROP TABLE IF EXISTS `dish`;CREATE TABLE `dish` (`id` bigint NOT NULL COMMENT '主键',`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '菜品名称',`category_id` bigint NOT NULL COMMENT '菜品分类id',`price` decimal(10,2) DEFAULT NULL COMMENT '菜品价格',`code` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '商品码',`image` varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '图片',`description` varchar(400) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '描述信息',`status` int NOT NULL DEFAULT '1' COMMENT '0 停售 1 起售',`sort` int NOT NULL DEFAULT '0' COMMENT '顺序',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',`is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `idx_dish_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='菜品管理';/*Data for the table `dish` */insert  into `dish`(`id`,`name`,`category_id`,`price`,`code`,`image`,`description`,`status`,`sort`,`create_time`,`update_time`,`create_user`,`update_user`,`is_deleted`) values (1628019384179052546,'红烧肉',1397844263642378242,'3900.00','','90c9f385-5c18-491a-90f2-a4c8df198376.jpg','红烧肉',1,0,'2023-02-21 21:10:43','2023-02-21 21:10:43',1627997218788163586,1627997218788163586,0),(1628019727558332417,'麻辣鸡丝',1397844303408574465,'3900.00','','b19c64b2-378d-43d9-975f-2367bcc99e70.jpg','麻辣鸡丝',1,0,'2023-02-21 21:12:05','2023-02-21 21:12:05',1627997218788163586,1627997218788163586,0),(1628020011776954369,'辣子鸡',1627130608250593281,'4900.00','','d79ac164-8e43-4478-9d57-539764d1c5a8.jpg','来自鲜嫩美味的小鸡,值得一尝',1,0,'2023-02-21 21:13:13','2023-02-22 14:42:06',1627997218788163586,1627997218788163586,0),(1628020274659151874,'基围虾',1397844263642378242,'5900.00','','05010fb3-c055-41ff-8da8-4d941daea332.jpg','基围虾',1,0,'2023-02-21 21:14:15','2023-02-21 21:14:15',1627997218788163586,1627997218788163586,0),(1628020414488858625,'麻辣兔头',1397844303408574465,'12800.00','','703fb335-5593-49be-a629-e2522344212d.jpg','麻辣兔头',1,0,'2023-02-21 21:14:49','2023-02-21 21:14:49',1627997218788163586,1627997218788163586,0),(1628020624501854210,'邵阳猪血丸子',1397844391040167938,'5900.00','','79f6db2d-99d9-40f0-adee-a6750036d40e.jpg','邵阳猪血丸子',1,0,'2023-02-21 21:15:39','2023-02-21 21:15:39',1627997218788163586,1627997218788163586,0),(1628020855322791938,'烤乳猪',1397844391040167938,'9900.00','','8197826f-8bcd-44a1-9d0e-e742b0265e7d.jpeg','白切鸡',1,0,'2023-02-21 21:16:34','2023-02-21 21:19:39',1627997218788163586,1627997218788163586,0),(1628020978719215617,'脆皮烧鹅',1627130608250593281,'15800.00','','3d6188da-68f1-4299-89fd-04c7ab744110.jpeg','脆皮烧鹅',1,0,'2023-02-21 21:17:03','2023-02-22 14:41:44',1627997218788163586,1627997218788163586,0),(1628021120151146497,'上汤焗龙虾',1627130608250593281,'15800.00','','d2dbe897-3b8b-4e5c-99d8-b7ca159ba5b9.jpeg','上汤焗龙虾',1,0,'2023-02-21 21:17:37','2023-02-22 14:41:25',1627997218788163586,1627997218788163586,0),(1628021265471197185,'宫保鸡丁',1397844303408574465,'6900.00','','95f8b479-ae76-4107-9b08-3c62ae7f7fd0.jpg','宫保鸡丁',1,0,'2023-02-21 21:18:12','2023-02-22 14:40:23',1627997218788163586,1627997218788163586,0),(1628021771191013377,'白切鸡',1397844391040167938,'7900.00','','b5d537cf-0d6c-42ae-9210-94c981087d52.jpeg','白切鸡',1,0,'2023-02-21 21:20:12','2023-02-21 21:20:12',1627997218788163586,1627997218788163586,0),(1628022122845655041,'青椒炖鸡丁',1627130608250593281,'9900.00','','9b7494ee-1714-40ee-a94e-18c769678671.jpg','青椒炖鸡丁',1,0,'2023-02-21 21:21:36','2023-02-21 21:21:36',1627997218788163586,1627997218788163586,0),(1628022255993835522,'老火靓汤',1627130608250593281,'10900.00','','a72af50a-264c-4cf1-9da0-28e1eb98aa5c.jpeg','老火靓汤',1,0,'2023-02-21 21:22:08','2023-02-21 21:22:08',1627997218788163586,1627997218788163586,0),(1628022421907918850,'清蒸河鲜海鲜',1397844303408574465,'2900.00','','06b6c68f-db38-4bff-a8f4-131830291cec.jpg','清蒸河鲜海鲜',1,0,'2023-02-21 21:22:47','2023-02-21 21:22:47',1627997218788163586,1627997218788163586,0),(1628022523112280066,'王老吉',1413341197421846529,'500.00','','3e7ab2fe-01fa-4eb6-828e-b7998583a4e1.png','王老吉',1,0,'2023-02-21 21:23:11','2023-02-21 21:23:11',1627997218788163586,1627997218788163586,0),(1628022754352648193,'麻辣水煮鱼',1397844391040167938,'6500.00','','5f614bfa-f62c-4d5d-a4e3-852d6ce53d62.jpeg','麻辣水煮鱼',1,0,'2023-02-21 21:24:07','2023-02-22 14:40:56',1627997218788163586,1627997218788163586,0),(1628022918689673218,'清炒素食',1627130608250593281,'1900.00','','d8783e07-a8da-4e4e-8826-0c0e6990a08f.jpg','清炒素食',1,0,'2023-02-21 21:24:46','2023-02-21 21:24:46',1627997218788163586,1627997218788163586,0),(1628023021122965506,'啤酒',1413341197421846529,'1000.00','','bbfe22ba-9bd5-486a-ae83-22e108dddc47.png','啤酒',1,0,'2023-02-21 21:25:10','2023-02-21 21:25:10',1627997218788163586,1627997218788163586,0),(1628023133450620930,'麻辣鱼片',1397844303408574465,'3900.00','','ffdbeb37-0fbe-4190-a52a-3a16478f366e.jpg','麻辣鱼片',1,0,'2023-02-21 21:25:37','2023-02-21 21:25:37',1627997218788163586,1627997218788163586,0),(1628023363927625729,'烤乳鸽',1397844391040167938,'7900.00','','a1848e46-eb33-4957-bd77-039caaee79c2.jpeg','烤乳鸽',1,0,'2023-02-21 21:26:32','2023-02-21 21:26:32',1627997218788163586,1627997218788163586,0),(1628023490318782465,'大米饭',1413384954989060097,'500.00','','d19db29f-c016-410d-ac01-a3742ea1ea3c.png','大米饭',1,0,'2023-02-21 21:27:02','2023-02-21 21:27:02',1627997218788163586,1627997218788163586,0),(1628023694518472706,'辣子鸡丁',1397844263642378242,'3900.00','','c67657d7-4cbf-4d0c-b20c-7ab66ad52514.jpg','辣子鸡丁',1,0,'2023-02-21 21:27:51','2023-02-21 21:27:51',1627997218788163586,1627997218788163586,0),(1628023841423970305,'口味蛇',1627130608250593281,'8800.00','','3d486c18-6dd8-4464-a087-bd93cfc987bf.jpg','口味蛇',1,0,'2023-02-21 21:28:26','2023-02-21 21:28:26',1627997218788163586,1627997218788163586,0);/*Table structure for table `dish_flavor` */DROP TABLE IF EXISTS `dish_flavor`;CREATE TABLE `dish_flavor` (`id` bigint NOT NULL COMMENT '主键',`dish_id` bigint NOT NULL COMMENT '菜品',`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '口味名称',`value` varchar(500) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '口味数据list',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',`is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='菜品口味关系表';/*Data for the table `dish_flavor` */insert  into `dish_flavor`(`id`,`dish_id`,`name`,`value`,`create_time`,`update_time`,`create_user`,`update_user`,`is_deleted`) values (1628019384321658881,1628019384179052546,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:10:43','2023-02-21 21:10:43',1627997218788163586,1627997218788163586,0),(1628019384321658882,1628019384179052546,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:10:43','2023-02-21 21:10:43',1627997218788163586,1627997218788163586,0),(1628019727621246978,1628019727558332417,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:12:05','2023-02-21 21:12:05',1627997218788163586,1627997218788163586,0),(1628019727621246979,1628019727558332417,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:12:05','2023-02-21 21:12:05',1627997218788163586,1627997218788163586,0),(1628019727621246980,1628019727558332417,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:12:05','2023-02-21 21:12:05',1627997218788163586,1627997218788163586,0),(1628020274726260738,1628020274659151874,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:14:15','2023-02-21 21:14:15',1627997218788163586,1627997218788163586,0),(1628020274726260739,1628020274659151874,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:14:15','2023-02-21 21:14:15',1627997218788163586,1627997218788163586,0),(1628020274726260740,1628020274659151874,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:14:15','2023-02-21 21:14:15',1627997218788163586,1627997218788163586,0),(1628020414488858626,1628020414488858625,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:14:49','2023-02-21 21:14:49',1627997218788163586,1627997218788163586,0),(1628020414488858627,1628020414488858625,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:14:49','2023-02-21 21:14:49',1627997218788163586,1627997218788163586,0),(1628020624573157378,1628020624501854210,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:15:39','2023-02-21 21:15:39',1627997218788163586,1627997218788163586,0),(1628020624573157379,1628020624501854210,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:15:39','2023-02-21 21:15:39',1627997218788163586,1627997218788163586,0),(1628020855389900802,1628020855322791938,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:19:39','2023-02-21 21:19:39',1627997218788163586,1627997218788163586,0),(1628020855389900803,1628020855322791938,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:19:39','2023-02-21 21:19:39',1627997218788163586,1627997218788163586,0),(1628021771191013378,1628021771191013377,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:20:12','2023-02-21 21:20:12',1627997218788163586,1627997218788163586,0),(1628021771191013379,1628021771191013377,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:20:12','2023-02-21 21:20:12',1627997218788163586,1627997218788163586,0),(1628022122971484162,1628022122845655041,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:21:36','2023-02-21 21:21:36',1627997218788163586,1627997218788163586,0),(1628022122971484163,1628022122845655041,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:21:36','2023-02-21 21:21:36',1627997218788163586,1627997218788163586,0),(1628022256186773505,1628022255993835522,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:22:08','2023-02-21 21:22:08',1627997218788163586,1627997218788163586,0),(1628022256186773506,1628022255993835522,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:22:08','2023-02-21 21:22:08',1627997218788163586,1627997218788163586,0),(1628022421975027713,1628022421907918850,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:22:47','2023-02-21 21:22:47',1627997218788163586,1627997218788163586,0),(1628022421975027714,1628022421907918850,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:22:47','2023-02-21 21:22:47',1627997218788163586,1627997218788163586,0),(1628022523175194626,1628022523112280066,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:23:11','2023-02-21 21:23:11',1627997218788163586,1627997218788163586,0),(1628022918823890945,1628022918689673218,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:24:46','2023-02-21 21:24:46',1627997218788163586,1627997218788163586,0),(1628022918823890946,1628022918689673218,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:24:46','2023-02-21 21:24:46',1627997218788163586,1627997218788163586,0),(1628023021190074370,1628023021122965506,'温度','[\"热饮\",\"常温\",\"去冰\",\"少冰\",\"多冰\"]','2023-02-21 21:25:10','2023-02-21 21:25:10',1627997218788163586,1627997218788163586,0),(1628023133576450049,1628023133450620930,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:25:37','2023-02-21 21:25:37',1627997218788163586,1627997218788163586,0),(1628023133576450050,1628023133450620930,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:25:37','2023-02-21 21:25:37',1627997218788163586,1627997218788163586,0),(1628023364061843457,1628023363927625729,'甜味','[\"无糖\",\"少糖\",\"半糖\",\"多糖\",\"全糖\"]','2023-02-21 21:26:32','2023-02-21 21:26:32',1627997218788163586,1627997218788163586,0),(1628023364061843458,1628023363927625729,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:26:32','2023-02-21 21:26:32',1627997218788163586,1627997218788163586,0),(1628023490448805890,1628023490318782465,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:27:02','2023-02-21 21:27:02',1627997218788163586,1627997218788163586,0),(1628023694585581569,1628023694518472706,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:27:51','2023-02-21 21:27:51',1627997218788163586,1627997218788163586,0),(1628023694585581570,1628023694518472706,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:27:51','2023-02-21 21:27:51',1627997218788163586,1627997218788163586,0),(1628023841553993729,1628023841423970305,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-21 21:28:26','2023-02-21 21:28:26',1627997218788163586,1627997218788163586,0),(1628023841553993730,1628023841423970305,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-21 21:28:26','2023-02-21 21:28:26',1627997218788163586,1627997218788163586,0),(1628283539888816129,1628021265471197185,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-22 14:40:23','2023-02-22 14:40:23',1627997218788163586,1627997218788163586,0),(1628283539888816130,1628021265471197185,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-22 14:40:23','2023-02-22 14:40:23',1627997218788163586,1627997218788163586,0),(1628283681786314754,1628022754352648193,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-22 14:40:56','2023-02-22 14:40:56',1627997218788163586,1627997218788163586,0),(1628283681786314755,1628022754352648193,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-22 14:40:56','2023-02-22 14:40:56',1627997218788163586,1627997218788163586,0),(1628283800552226817,1628021120151146497,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-22 14:41:25','2023-02-22 14:41:25',1627997218788163586,1627997218788163586,0),(1628283800552226818,1628021120151146497,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-22 14:41:25','2023-02-22 14:41:25',1627997218788163586,1627997218788163586,0),(1628283883154849793,1628020978719215617,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-22 14:41:44','2023-02-22 14:41:44',1627997218788163586,1627997218788163586,0),(1628283883154849794,1628020978719215617,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-22 14:41:44','2023-02-22 14:41:44',1627997218788163586,1627997218788163586,0),(1628283974536151041,1628020011776954369,'忌口','[\"不要葱\",\"不要蒜\",\"不要香菜\",\"不要辣\"]','2023-02-22 14:42:06','2023-02-22 14:42:06',1627997218788163586,1627997218788163586,0),(1628283974536151042,1628020011776954369,'辣度','[\"不辣\",\"微辣\",\"中辣\",\"重辣\"]','2023-02-22 14:42:06','2023-02-22 14:42:06',1627997218788163586,1627997218788163586,0);/*Table structure for table `employee` */DROP TABLE IF EXISTS `employee`;CREATE TABLE `employee` (`id` bigint NOT NULL COMMENT '主键',`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '姓名',`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '用户名',`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '密码',`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '手机号',`sex` varchar(2) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '性别',`id_number` varchar(18) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '身份证号',`status` int NOT NULL DEFAULT '1' COMMENT '状态 0:禁用,1:正常',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='员工信息';/*Data for the table `employee` */insert  into `employee`(`id`,`name`,`username`,`password`,`phone`,`sex`,`id_number`,`status`,`create_time`,`update_time`,`create_user`,`update_user`) values (1,'管理员','admin','e10adc3949ba59abbe56e057f20f883e','13812312312','1','110101199001010047',1,'2021-05-06 17:20:07','2021-05-10 02:24:09',1,1),(1626857776597762049,'张三1','zhangsan','e10adc3949ba59abbe56e057f20f883e','17671789248','1','421181199805171311',1,'2023-02-18 16:14:54','2023-02-18 22:06:50',1,1),(1626945547559514113,'小李','test001','e10adc3949ba59abbe56e057f20f883e','17612345678','1','421181123456781234',1,'2023-02-18 22:04:04','2023-02-19 08:52:25',1,1);/*Table structure for table `order_detail` */DROP TABLE IF EXISTS `order_detail`;CREATE TABLE `order_detail` (`id` bigint NOT NULL COMMENT '主键',`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '名字',`image` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '图片',`order_id` bigint NOT NULL COMMENT '订单id',`dish_id` bigint DEFAULT NULL COMMENT '菜品id',`setmeal_id` bigint DEFAULT NULL COMMENT '套餐id',`dish_flavor` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '口味',`number` int NOT NULL DEFAULT '1' COMMENT '数量',`amount` decimal(10,2) NOT NULL COMMENT '金额',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='订单明细表';/*Data for the table `order_detail` */insert  into `order_detail`(`id`,`name`,`image`,`order_id`,`dish_id`,`setmeal_id`,`dish_flavor`,`number`,`amount`) values (1628281691748474882,'儿童套餐A','17fb2dcf-c06a-46c4-8ba6-8cb461d84031.jpg',1628281691555536898,NULL,1628024994765295618,NULL,1,'59.00'),(1628281691748474883,'辣子鸡丁','c67657d7-4cbf-4d0c-b20c-7ab66ad52514.jpg',1628281691555536898,1628023694518472706,NULL,'不要香菜,中辣',1,'39.00'),(1628281691748474884,'麻辣鱼片','ffdbeb37-0fbe-4190-a52a-3a16478f366e.jpg',1628281691555536898,1628023133450620930,NULL,'不要蒜,中辣',1,'39.00'),(1628281691748474885,'宫保鸡丁','95f8b479-ae76-4107-9b08-3c62ae7f7fd0.jpg',1628281691555536898,1628021265471197185,NULL,NULL,1,'69.00'),(1628281691748474886,'麻辣兔头','703fb335-5593-49be-a629-e2522344212d.jpg',1628281691555536898,1628020414488858625,NULL,'去冰,中辣',1,'128.00'),(1628281691811389441,'商务套餐A','fb706fe0-b57f-46da-9f70-f209cc489f39.jpg',1628281691555536898,NULL,1628024830898032642,NULL,1,'99.00'),(1628302223755788290,'辣子鸡丁','c67657d7-4cbf-4d0c-b20c-7ab66ad52514.jpg',1628302223562850306,1628023694518472706,NULL,'不要蒜,微辣',1,'39.00'),(1628302223755788291,'商务套餐A','fb706fe0-b57f-46da-9f70-f209cc489f39.jpg',1628302223562850306,NULL,1628024830898032642,NULL,1,'99.00'),(1628302223755788292,'儿童套餐A','17fb2dcf-c06a-46c4-8ba6-8cb461d84031.jpg',1628302223562850306,NULL,1628024994765295618,NULL,1,'59.00');/*Table structure for table `orders` */DROP TABLE IF EXISTS `orders`;CREATE TABLE `orders` (`id` bigint NOT NULL COMMENT '主键',`number` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '订单号',`status` int NOT NULL DEFAULT '1' COMMENT '订单状态 1待付款,2待派送,3已派送,4已完成,5已取消',`user_id` bigint NOT NULL COMMENT '下单用户',`address_book_id` bigint NOT NULL COMMENT '地址id',`order_time` datetime NOT NULL COMMENT '下单时间',`checkout_time` datetime NOT NULL COMMENT '结账时间',`pay_method` int NOT NULL DEFAULT '1' COMMENT '支付方式 1微信,2支付宝',`amount` decimal(10,2) NOT NULL COMMENT '实收金额',`remark` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '备注',`phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,`consignee` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='订单表';/*Data for the table `orders` */insert  into `orders`(`id`,`number`,`status`,`user_id`,`address_book_id`,`order_time`,`checkout_time`,`pay_method`,`amount`,`remark`,`phone`,`address`,`user_name`,`consignee`) values (1628281691555536898,'1628281691555536898',2,1627997218788163586,1628270733663694849,'2023-02-22 14:33:02','2023-02-22 14:33:02',1,'433.00','','17671789248','湖北工业大学',NULL,'金阳'),(1628302223562850306,'1628302223562850306',2,1627997218788163586,1628270733663694849,'2023-02-22 15:54:37','2023-02-22 15:54:37',1,'197.00','','17671789248','湖北工业大学',NULL,'金阳');/*Table structure for table `setmeal` */DROP TABLE IF EXISTS `setmeal`;CREATE TABLE `setmeal` (`id` bigint NOT NULL COMMENT '主键',`category_id` bigint NOT NULL COMMENT '菜品分类id',`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '套餐名称',`price` decimal(10,2) NOT NULL COMMENT '套餐价格',`status` int DEFAULT NULL COMMENT '状态 0:停用 1:启用',`code` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '编码',`description` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '描述信息',`image` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '图片',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',`is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `idx_setmeal_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='套餐';/*Data for the table `setmeal` */insert  into `setmeal`(`id`,`category_id`,`name`,`price`,`status`,`code`,`description`,`image`,`create_time`,`update_time`,`create_user`,`update_user`,`is_deleted`) values (1628024830898032642,1413342269393674242,'商务套餐A','9900.00',1,'','商务套餐A','fb706fe0-b57f-46da-9f70-f209cc489f39.jpg','2023-02-21 21:32:22','2023-02-21 21:32:22',1627997218788163586,1627997218788163586,0),(1628024994765295618,1413386191767674881,'儿童套餐A','5900.00',1,'','儿童套餐A','17fb2dcf-c06a-46c4-8ba6-8cb461d84031.jpg','2023-02-21 21:33:01','2023-02-21 21:33:01',1627997218788163586,1627997218788163586,0);/*Table structure for table `setmeal_dish` */DROP TABLE IF EXISTS `setmeal_dish`;CREATE TABLE `setmeal_dish` (`id` bigint NOT NULL COMMENT '主键',`setmeal_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '套餐id ',`dish_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '菜品id',`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '菜品名称 (冗余字段)',`price` decimal(10,2) DEFAULT NULL COMMENT '菜品原价(冗余字段)',`copies` int NOT NULL COMMENT '份数',`sort` int NOT NULL DEFAULT '0' COMMENT '排序',`create_time` datetime NOT NULL COMMENT '创建时间',`update_time` datetime NOT NULL COMMENT '更新时间',`create_user` bigint NOT NULL COMMENT '创建人',`update_user` bigint NOT NULL COMMENT '修改人',`is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='套餐菜品关系';/*Data for the table `setmeal_dish` */insert  into `setmeal_dish`(`id`,`setmeal_id`,`dish_id`,`name`,`price`,`copies`,`sort`,`create_time`,`update_time`,`create_user`,`update_user`,`is_deleted`) values (1628024830960947201,'1628024830898032642','1628023694518472706','辣子鸡丁','3900.00',1,0,'2023-02-21 21:32:22','2023-02-21 21:32:22',1627997218788163586,1627997218788163586,0),(1628024830960947202,'1628024830898032642','1628023490318782465','大米饭','500.00',1,0,'2023-02-21 21:32:22','2023-02-21 21:32:22',1627997218788163586,1627997218788163586,0),(1628024830960947203,'1628024830898032642','1628023021122965506','啤酒','1000.00',1,0,'2023-02-21 21:32:22','2023-02-21 21:32:22',1627997218788163586,1627997218788163586,0),(1628024830960947204,'1628024830898032642','1628023363927625729','烤乳鸽','7900.00',1,0,'2023-02-21 21:32:22','2023-02-21 21:32:22',1627997218788163586,1627997218788163586,0),(1628024994832404481,'1628024994765295618','1628023490318782465','大米饭','500.00',1,0,'2023-02-21 21:33:01','2023-02-21 21:33:01',1627997218788163586,1627997218788163586,0),(1628024994832404482,'1628024994765295618','1628022523112280066','王老吉','500.00',1,0,'2023-02-21 21:33:01','2023-02-21 21:33:01',1627997218788163586,1627997218788163586,0),(1628024994832404483,'1628024994765295618','1628022918689673218','清炒素食','1900.00',1,0,'2023-02-21 21:33:01','2023-02-21 21:33:01',1627997218788163586,1627997218788163586,0),(1628024994832404484,'1628024994765295618','1628023363927625729','烤乳鸽','7900.00',1,0,'2023-02-21 21:33:01','2023-02-21 21:33:01',1627997218788163586,1627997218788163586,0);/*Table structure for table `shopping_cart` */DROP TABLE IF EXISTS `shopping_cart`;CREATE TABLE `shopping_cart` (`id` bigint NOT NULL COMMENT '主键',`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '名称',`image` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '图片',`user_id` bigint NOT NULL COMMENT '主键',`dish_id` bigint DEFAULT NULL COMMENT '菜品id',`setmeal_id` bigint DEFAULT NULL COMMENT '套餐id',`dish_flavor` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '口味',`number` int NOT NULL DEFAULT '1' COMMENT '数量',`amount` decimal(10,2) NOT NULL COMMENT '金额',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='购物车';/*Data for the table `shopping_cart` *//*Table structure for table `user` */DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (`id` bigint NOT NULL COMMENT '主键',`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '姓名',`phone` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '手机号',`sex` varchar(2) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '性别',`id_number` varchar(18) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '身份证号',`avatar` varchar(500) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '头像',`status` int DEFAULT '0' COMMENT '状态 0:禁用,1:正常',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='用户信息';/*Data for the table `user` */insert  into `user`(`id`,`name`,`phone`,`sex`,`id_number`,`avatar`,`status`) values (1627997218788163586,NULL,'17612349248',NULL,NULL,NULL,1);/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

数据表

Maven项目搭建

项目的目录结构

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.jerry</groupId><artifactId>reggie</artifactId><version>1.0</version><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>compile</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.23</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.5</version></plugin></plugins></build>
</project>

application.yml

server:port: 8080
spring:application:# 应用名称,可选项name: reggiedatasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: root
mybatis-plus:configuration:#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:id-type: ASSIGN_ID

ReggieApplication启动类

package com.jerry.reggie;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** ClassName: ReggieApplication* Package: com.jerry.reggie* Description:** @Author jerry_jy* @Create 2023-02-16 13:50* @Version 1.0*/
@Slf4j
@SpringBootApplication
public class ReggieApplication {public static void main(String[] args) {SpringApplication.run(ReggieApplication.class, args);log.info("项目启动成功...");}
}

配置静态资源映射

SpringBoot访问静态资源默认会去resources/static或resources/templates目录下,如果不需要static或templates目录,那就手动使用配置类进行配置访问路径

package com.jerry.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;/*** ClassName: WebMvcConfig* Package: com.jerry.reggie.config* Description:** @Author jerry_jy* @Create 2023-02-16 14:16* @Version 1.0*/
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {/*** 设置静态资源映射* @param registry*/@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始进行静态资源的映射...");registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}
}

访问:http://localhost:8080/backend/index.html

4、登录功能

4.1、后台登录功能

需求分析

代码编写

vo类:将服务器和前端页面传递的数据封装好

R类是一个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端页面

R.java

package com.jerry.reggie.common;import lombok.Data;
import java.util.HashMap;
import java.util.Map;/*** 通用返回结果,服务器端响应的数据最终都会封装成此对象* @param <T>*/
@Data
public class R<T> {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据private Map map = new HashMap(); //动态数据public static <T> R<T> success(T object) {R<T> r = new R<T>();r.data = object;r.code = 1;return r;}public static <T> R<T> error(String msg) {R r = new R();r.msg = msg;r.code = 0;return r;}public R<T> add(String key, Object value) {this.map.put(key, value);return this;}}

实体类

package com.jerry.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;/*** 员工实体类*/
@Data
public class Employee implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String username;private String name;private String password;private String phone;private String sex;private String idNumber;//身份证号private Integer status;private LocalDateTime createTime;private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;}

EmployeeMapper

package com.jerry.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jerry.reggie.entity.Employee;
import org.apache.ibatis.annotations.Mapper;/*** ClassName: EmployeeMApper* Package: com.jerry.reggie.mapper* Description:** @Author jerry_jy* @Create 2023-02-16 14:45* @Version 1.0*/
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {}

EmployeeService

package com.jerry.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.jerry.reggie.entity.Employee;/*** ClassName: EmployeeService* Package: com.jerry.reggie.service* Description:** @Author jerry_jy* @Create 2023-02-16 14:46* @Version 1.0*/
public interface EmployeeService extends IService<Employee> {}

EmployeeServiceImpl

package com.jerry.reggie.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jerry.reggie.entity.Employee;
import com.jerry.reggie.mapper.EmployeeMapper;
import com.jerry.reggie.service.EmployeeService;
import org.springframework.stereotype.Service;/*** ClassName: EmployeeServiceImpl* Package: com.jerry.reggie.service.impl* Description:** @Author jerry_jy* @Create 2023-02-16 14:46* @Version 1.0*/@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {}

EmployeeController

package com.jerry.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jerry.reggie.common.R;
import com.jerry.reggie.entity.Employee;
import com.jerry.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;/*** ClassName: EmployeeController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-16 14:52* @Version 1.0*/
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;@PostMapping("/login")public R<Employee> login(@RequestBody Employee employee, HttpServletRequest request) {//@RequestBody用来接收前端传递给后端的`json`字符串中的数据的(请求体中的数据的),所以前端只能发送POST请求//1、将页面提交的密码password进行md5加密处理String pwd = employee.getPassword();pwd = DigestUtils.md5DigestAsHex(pwd.getBytes());// 2、根据页面提交的用户名username查询数据库]/*** 我自己写的是*         QueryWrapper<Employee> queryWrapper = new QueryWrapper<>();*         employeeService.getOne(queryWrapper.select(employee.getName()));* 查询出来的是null值*/LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();//方法引用的语法格式(语法糖)wrapper.eq(Employee::getUsername,employee.getUsername());Employee emp = employeeService.getOne(wrapper);// 3、如果没有查询到则返回登录失败结果if (emp == null) {return R.error("登录失败");}//4、密码比对,如果不一致则返回登录失败结果if (!pwd.equals(emp.getPassword())) {return R.error("登录失败");}//5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果if (emp.getStatus()!=1){return R.error("员工账号已禁用");}// 6、登录成功,将员工id存入Session并返回登录成功结果Long empId = emp.getId();request.getSession().setAttribute("empId",empId);return R.success(emp);}
}

页面展示

http://localhost:8080/backend/page/login/login.html

http://localhost:8080/backend/index.html

4.2、后台登出功能

需求分析

代码编写

/*** 员工后台登出功能* @param request* @return*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request) {//1、清理Session中的用户idrequest.getSession().removeAttribute("empId");// 2、返回结果return R.success("登出成功");
}

页面展示

4.3、完善登录功能

问题分析

代码编写

LoginCheckFilter

package com.jerry.reggie.filter;import com.alibaba.fastjson.JSON;
import com.jerry.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** ClassName: LoginCheckFilter* Package: com.jerry.reggie.filter* Description:** @Author jerry_jy* @Create 2023-02-16 21:50* @Version 1.0*/
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {//路径匹配,支持通配符public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;//1、获取本次请求的URIString uri = request.getRequestURI(); //   backend/index.htmllog.info("拦截到请求:{}", uri);//定义不需要处理的请求路径String[] urls = new String[]{"/employee/login","employee/logout","/backend/**","/front/**"};//2、判断本次请求是否需要处理boolean check = check(urls, uri);// 3、如果不需要处理,则直接放行if (check == true) {log.info("本次请求{}不需要处理" + uri);filterChain.doFilter(request, response);return;}//4、判断登录状态,如果已登录,则直接放行if (request.getSession().getAttribute("empId") != null) {log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("empId"));filterChain.doFilter(request, response);return;}log.info("用户未登录");// 5、如果未登录则返回未登录结果,通过输出流方式向客户端响应数据response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));return;}/*** 路径匹配,检查本次请求是否需要放行** @param urls* @param uri* @return*/public boolean check(String[] urls, String uri) {for (String url : urls) {boolean match = PATH_MATCHER.match(url, uri);if (match) {return true;}}return false;}
}

5、员工管理

5.1、新增员工

需求分析

数据模型

代码开发

代码编写

/*** 新增员工* @param employee* @return*/
@PostMapping
public R<String> save(@RequestBody Employee employee, HttpServletRequest request){log.info("新增员工,员工信息:{}",employee.toString());//设置员工的初始密码,需要进行MD5 加密处理employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//获得当前登录对象的idLong empId = (Long) request.getSession().getAttribute("empId");employee.setCreateUser(empId);employee.setUpdateUser(empId);employeeService.save(employee);return R.success("添加员工成功");
}

异常捕获

GlobalExceptionHandler

package com.jerry.reggie.common;/*** ClassName: GlobalExceptionHandler* Package: com.jerry.reggie.common* Description:** @Author jerry_jy* @Create 2023-02-18 16:21* @Version 1.0*/import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import java.sql.SQLIntegrityConstraintViolationException;/*** 全局异常捕获*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody //要返回json数据时就写
@Slf4j
public class GlobalExceptionHandler {/*** 异常处理方法* @return*/@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException exception){log.error(exception.getMessage());if (exception.getMessage().contains("Duplicate entry")){String[] strings = exception.getMessage().split(" ");String msg = strings[2] + "已存在";return R.error(msg);}return R.error("未知错误");}
}

小结

5.2、员工信息分页查询

需求分析

代码开发

MyBatisPlusConfig配置分页插件

package com.jerry.reggie.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** ClassName: MyBatisPlusConfig* Package: com.jerry.reggie.config* Description:** @Author jerry_jy* @Create 2023-02-18 17:16* @Version 1.0*//*** 配置MP的分页插件*/
@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mybatisPlusInterceptor;}
}
/*** 员工信息分页查询** @param page* @param pageSize* @param name* @return*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name) {log.info("page = {}, pageSize = {}, name = {}", page, pageSize, name);//这里:只需要new page对象和构造好lambdaQueryWrapper//构造分页构造器Page<Employee> pageInfo = new Page<>(page, pageSize);//构造条件构造器LambdaQueryWrapper<Employee> lambdaQueryWrapper = new LambdaQueryWrapper<>();//添加一个过滤条件lambdaQueryWrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name);//添加一个排序条件lambdaQueryWrapper.orderByDesc(Employee::getUpdateTime);//执行查询employeeService.page(pageInfo, lambdaQueryWrapper);return R.success(pageInfo);
}

5.3、启用/禁用员工账号

需求分析

代码编写

编写一个通用的update方法

/*** 根据id修改员工信息** @param employee* @return*/
@PutMapping
public R<String> update(HttpServletRequest request, @RequestBody Employee employee) {log.info(employee.toString());Long empId = (Long) request.getSession().getAttribute("empId");employee.setUpdateTime(LocalDateTime.now());employee.setUpdateUser(empId);employeeService.updateById(employee);return R.success("更新成功");
}

功能测试

原因:JS在处理Long型数据时,只能处理16位,也就是说,2^53次方,超过后就四舍五入,精度损失

功能修复

/*** 扩展mvc消息框架的转换器* @param converters*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {log.info("扩展消息转换器...");//创建消息转换器对象MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();//设置对象转换器,底层使用Jackson将Java对象转为jsonmessageConverter.setObjectMapper(new JacksonObjectMapper());//将上面的消息转换器对象追加到mvc框架的转换器集合中converters.add(0, messageConverter);
}

5.3、编辑员工

需求分析

代码编写

/*** 根据id查询员工信息** @param id* @return*/@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id) {log.info("根据id 查询员工信息...");Employee employee = employeeService.getById(id);if (employee != null) {return R.success(employee);}return R.error("没有查询到对应的员工信息");
}

5.4、公共字段自动填充

问题分析

代码实现

功能完善

ThreadLocal

BaseContext

package com.jerry.reggie.common;/*** ClassName: BaseContext* Package: com.jerry.reggie.common* Description:** @Author jerry_jy* @Create 2023-02-19 9:00* @Version 1.0*//*** 基于ThreadLocal封装的工具类,用于保存和获取当前登录用户的id*/
public class BaseContext {private static ThreadLocal<Long> threadLocal= new ThreadLocal<>();public static void setCurrentId(Long id){threadLocal.set(id);}public static Long getCurrentId(){return threadLocal.get();}
}

6、分类管理

6.1、新增菜品分类

需求分析

数据模型

代码开发

6.1、新增菜品的分页查询

需求分析

代码开发

/*** 菜品分页查询* @param page* @param pageSize* @return*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize){//分页构造器Page<Category> categoryPage = new Page<>();//条件构造器LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();//添加排序条件lambdaQueryWrapper.orderByAsc(Category::getSort);categoryService.page(categoryPage, lambdaQueryWrapper);return R.success(categoryPage);
}

6.2、删除分类

需求分析

代码开发

功能完善

GlobalExceptionHandler

/*** 异常处理方法* @return*/
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException exception){log.error(exception.getMessage());return R.error(exception.getMessage());
}

CustomException

package com.jerry.reggie.common;/*** ClassName: CustomException* Package: com.jerry.reggie.common* Description:** @Author jerry_jy* @Create 2023-02-19 11:55* @Version 1.0*//*** 自定义业务异常类*/
public class CustomException extends RuntimeException{public CustomException(String message){super(message);}
}

CategoryServiceImpl

package com.jerry.reggie.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jerry.reggie.common.CustomException;
import com.jerry.reggie.entity.Category;
import com.jerry.reggie.entity.Dish;
import com.jerry.reggie.entity.Setmeal;
import com.jerry.reggie.mapper.CategoryMapper;
import com.jerry.reggie.service.CategoryService;
import com.jerry.reggie.service.DishService;
import com.jerry.reggie.service.SetmealService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** ClassName: CategoryServiceImpl* Package: com.jerry.reggie.service.impl* Description:** @Author jerry_jy* @Create 2023-02-19 9:30* @Version 1.0*/
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {@Autowiredprivate DishService dishService;@Autowiredprivate SetmealService setmealService;/*** 根据id删除分类,删除之前需要进行判断* @param id*/@Overridepublic void remove(Long id) {LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();//添加查询条件,根据分类id查询dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);int count1 = dishService.count(dishLambdaQueryWrapper);//查询当前分类是否关联了菜品,如果已经关联,抛出一个业务异常if (count1>0){//已经关联,抛出一个业务异常throw new CustomException("当前分类下关联了菜品,不能删除");}//查询当前分类是否关联了套餐,如果已经关联,抛出一个业务异常LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);int count2 = setmealService.count(setmealLambdaQueryWrapper);if (count2>0){//已经关联套餐,抛出一个业务异常throw new CustomException("当前分类下关联了套餐,不能删除");}//正常删除分类super.removeById(id);}
}
    /*** 根据id删除分类* @param id* @return*/@DeleteMappingpublic R<String> delete(Long id){log.info("删除分类:{}",id);//        categoryService.removeById(id);categoryService.remove(id);return R.success("分类信息删除成功");}

6.3、修改分类

需求分析

代码编写

/*** 根据id修改分类信息* @param category* @return*/
@PutMapping
public R<String> update(@RequestBody Category category){log.info("修改分类信息:{}",category);categoryService.updateById(category);return R.success("修改分类信息成功");
}

7、菜品管理

7.1、文件上传下载

文件上传介绍

文件下载介绍

文件上传代码实现

package com.jerry.reggie.controller;import com.jerry.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.util.UUID;/*** ClassName: CommonController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-19 17:19* @Version 1.0*//*** 文件上传下载*/
@RestController
@Slf4j
@RequestMapping("/common")
public class CommonController {@Value("${reggie.path}")//这里的value不要导包成了lombok,用${}动态取值private String basePath;/*** 文件上传** @param file* @return*/@PostMapping("/upload")public R<String> uploadFile(MultipartFile file) {//file是临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除log.info(file.toString());//获取原始文件名String originalFilename = file.getOriginalFilename();//获取原始文件名的后缀名,这里是带点的String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));//使用UUID重新生成文件名,防止文件名称重复造成的文件覆盖String fileName = UUID.randomUUID().toString() + suffix;//创建一个目录对象File dir = new File(basePath);if (!dir.exists()){//目录不存在,创建一个dir.mkdirs();}try {//将临时文件转存到指定位置file.transferTo(new File(basePath + fileName));} catch (IOException e) {throw new RuntimeException(e);}return R.success(fileName);}
}

文件下载代码实现

/*** 文件下载** @param name* @param response*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response) {try {// 输入流,通过输入流读取文件内容FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));//输出流,通过输出流将文件写回浏览器,在浏览器显示图片ServletOutputStream outputStream = response.getOutputStream();//设置输出流的类型为图片response.setContentType("image/jpeg");int len = 0;byte[] bytes = new byte[1024];while ((len = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);outputStream.flush();}// 关闭资源outputStream.close();fileInputStream.close();} catch (Exception e) {throw new RuntimeException(e);}}

7.2、新增菜品

需求分析

数据模型

代码开发

由于新增菜品涉及到多张表的插入操作,因此需要在Service业务层中单独写一个save方法

DishServiceImpl

package com.jerry.reggie.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jerry.reggie.dto.DishDto;
import com.jerry.reggie.entity.Dish;
import com.jerry.reggie.entity.DishFlavor;
import com.jerry.reggie.mapper.DishFlavorMapper;
import com.jerry.reggie.mapper.DishMapper;
import com.jerry.reggie.service.DishFlavorService;
import com.jerry.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.stream.Collectors;/*** ClassName: DishServiceImpl* Package: com.jerry.reggie.service.impl* Description:** @Author jerry_jy* @Create 2023-02-19 10:53* @Version 1.0*/
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {@Autowiredprivate DishFlavorService dishFlavorService;/*** 新增菜品同时保存口味数据* @param dishDto*/@Transactional@Overridepublic void saveWithFlavor(DishDto dishDto) {//保存菜品基本信息到菜品表dishthis.save(dishDto);Long dishId = dishDto.getId();//菜品口味List<DishFlavor> flavors = dishDto.getFlavors();flavors = flavors.stream().map((item) -> {item.setDishId(dishId);return item;}).collect(Collectors.toList());//保存菜品口味到到菜品口味表dish_flavordishFlavorService.saveBatch(flavors);}
}

DishController

package com.jerry.reggie.controller;import com.jerry.reggie.common.R;
import com.jerry.reggie.dto.DishDto;
import com.jerry.reggie.entity.Dish;
import com.jerry.reggie.service.DishFlavorService;
import com.jerry.reggie.service.DishService;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** ClassName: DishController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-19 19:11* @Version 1.0*/
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {@AutowiredDishFlavorService dishFlavorService;@AutowiredDishService dishService;/*** 新增菜品* @param dishDto* @return*/@PostMappingpublic R<String> addMeal(@RequestBody DishDto dishDto){log.info(dishDto.toString());dishService.saveWithFlavor(dishDto);return R.success("保存成功");}
}

7.3、菜品信息分页查询

需求分析

代码开发

难点

这里的分页查询涉及到2个对象的拷贝复赋值问题,使用BeanUtils.copyProperties()来完成操作的

把Dish对象赋值给DishDto对象,并设置上categoryName

流式处理的表达式是重点!!!

/*** 菜品信息--分页查询** @param page* @param pageSize* @param name* @return*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name) {//分页构造器Page<Dish> pageInfo = new Page<>(page, pageSize);Page<DishDto> dishDtoPage = new Page<>();//条件构造器LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();//添加过滤条件lambdaQueryWrapper.like(name != null, Dish::getName, name);//添加过滤条件lambdaQueryWrapper.orderByDesc(Dish::getUpdateTime);dishService.page(pageInfo, lambdaQueryWrapper);//对象拷贝BeanUtils.copyProperties(pageInfo, dishDtoPage,"records");List<Dish> records = pageInfo.getRecords();List<DishDto> list =  records.stream().map((item) -> {DishDto dishDto = new DishDto();//对象拷贝BeanUtils.copyProperties(item, dishDto);Long categoryId = item.getCategoryId();//分类idCategory category = categoryService.getById(categoryId);//分类对象if (category!=null){String categoryName = category.getName();dishDto.setCategoryName(categoryName);}return dishDto;}).collect(Collectors.toList());dishDtoPage.setRecords(list);return R.success(dishDtoPage);
}

7.4、修改菜品

需求分析

代码开发

controller

/**** @param dishDto* @return*/
@PutMapping
public R<String> updateMeal(@RequestBody DishDto dishDto){log.info(dishDto.toString());dishService.updateWithFlavor(dishDto);return R.success("保存菜品成功");
}

DishServiceImpl

/*** 更新菜品信息,同时更新对应的口味信息** @param dishDto*/
@Override
@Transactional
public void updateWithFlavor(DishDto dishDto) {//更新dish表基本信息this.updateById(dishDto);//先清理当前菜品对应的口味信息---dish_flavor表的 delete 操作LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(DishFlavor::getDishId, dishDto.getId());dishFlavorService.remove(lambdaQueryWrapper);//再添加当前提交过来的口味数据--dish_flavor表的 insert 操作List<DishFlavor> flavors = dishDto.getFlavors();flavors = flavors.stream().map((item) -> {item.setDishId(dishDto.getId());return item;}).collect(Collectors.toList());dishFlavorService.saveBatch(flavors);
}

7.5、修改菜品的停/起售状态

DishController

    /*** 修改菜品的 停/启 售状态** @param ids* @return*/@PostMapping("/status/{status}")public R<Dish> status(long ids) {Dish dish = dishService.getById(ids);dishService.setStatus(dish);return R.success(dish);}

DishServiceImpl

/*** 修改菜品的停/启售状态* @param dish*/
@Override
public void setStatus(Dish dish) {if (dish.getStatus()==1){dish.setStatus(0);}else {dish.setStatus(1);}this.updateById(dish);
}

7.6、删除菜品

    /*** 菜品管理--批量删除菜品--跟单个删除一样的,复用同一份代码* @param ids* @return*/@DeleteMappingpublic R<String> delete(Long[] ids){for (Long id : ids) {dishService.delete(id);}return R.success("删除菜品成功!");}

8、套餐管理

8.1、新增套餐

需求分析

数据模型

代码开发

DishController

/*** 根据条件来查询对应的菜品数据* @param dish* @return*/
@GetMapping("/list")
public R<List<Dish>> list(Dish dish){//构造查询条件LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());//查询状态为1,启售状态lambdaQueryWrapper.eq(Dish::getStatus,1);//添加排序条件lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);List<Dish> list = dishService.list(lambdaQueryWrapper);return R.success(list);
}

SetmealDishController

/*** 新增套餐* @param setmealDto* @return*/
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){log.info("套餐信息:{}",setmealDto.toString());setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");
}

SetmealServiceImpl

/*** 新增套餐,同时需要保存套餐和菜品的关联关系* @param setmealDto*/
@Override
@Transactional
public void saveWithDish(SetmealDto setmealDto) {//保存套餐的基本信息 操作setmeal  执行insertthis.save(setmealDto);List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes.stream().map((item)->{item.setSetmealId(setmealDto.getId());return item;}).collect(Collectors.toList());//保存套餐和菜品的关联信息,操作setmeal_dish,执行insertsetmealDishService.saveBatch(setmealDishes);
}

8.2、套餐信息分页查询

需求分析

代码开发

/*** 套餐管理--套餐信息分页查询* @param page* @param pageSize* @param name* @return*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name) {//分页构造器Page<Setmeal> pageInfo = new Page<>(page, pageSize);Page<SetmealDto> dtoPage = new Page<>();//条件构造器LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();//添加过滤条件lambdaQueryWrapper.like(name != null, Setmeal::getName, name);//添加过滤条件lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);setmealService.page(pageInfo, lambdaQueryWrapper);//对象拷贝BeanUtils.copyProperties(pageInfo, dtoPage, "records");List<Setmeal> records = pageInfo.getRecords();List<SetmealDto> list = records.stream().map((item) -> {SetmealDto setmealDto = new SetmealDto();//对象拷贝BeanUtils.copyProperties(item, setmealDto);//分类idLong categoryId = item.getCategoryId();//根据分类id查询对象Category category = categoryService.getById(categoryId);if (category != null) {//获取分类名称String categoryName = category.getName();setmealDto.setCategoryName(categoryName);}return setmealDto;}).collect(Collectors.toList());dtoPage.setRecords(list);return R.success(dtoPage);
}

8.3、删除套餐

需求分析

代码开发

SetmealController

/*** (批量)删除套餐** @param ids* @return*/
@DeleteMapping
public R<String> delete(@RequestParam List<Long> ids) {log.info("id: {}", ids);setmealService.removeWithDish(ids);return R.success("套餐数据删除成功");
}

SetmealServiceImpl

/*** 删除套餐,同时输出套餐和菜品关联的数据** @param ids*/
@Override
public void removeWithDish(List<Long> ids) {// 先查询套餐状态,确实是否可以删除// select count(*) from setmeal where id in (1, 2, 3) and status = 1;LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.in(Setmeal::getId, ids);lambdaQueryWrapper.eq(Setmeal::getStatus, 1);int count = this.count(lambdaQueryWrapper);if (count > 0) {// 如果不能删除,抛出一个业务异常throw new CustomException("套餐正在售卖中,不能删除");}// 如果可以删除,先删除套餐表中的数据-- setmealthis.removeByIds(ids);//再删除关系表中的数据-- setmeal_dish// delete from setmeal_dish where id in (1, 2, 3);LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.in(SetmealDish::getSetmealId, ids);setmealDishService.remove(queryWrapper);
}

8.4、修改套餐

SetmealController

    /*** 根据id查询套餐信息和对应的套餐内容---回显套餐信息* @param id* @return*/@GetMapping("/{id}")public R<SetmealDto> getMealDtoById(@PathVariable long id){SetmealDto setmealDto = setmealService.getByIdWithSetmeal(id);return R.success(setmealDto);}/*** 修改套餐信息,并保存* @param setmealDto* @return*/@PutMappingpublic R<String> updateSetmeal(@RequestBody SetmealDto setmealDto) {log.info(setmealDto.toString());setmealService.updateWithSetmeal(setmealDto);return R.success("保存菜品成功");}

SetmealService

//根据id查询套餐信息和对应的套餐内容---回显套餐信息
SetmealDto getByIdWithSetmeal(long id);//修改套餐信息,并保存
void updateWithSetmeal(SetmealDto setmealDto);

SetmealServiceImpl

    /*** 根据id查询套餐信息和对应的套餐内容---回显套餐信息** @param id* @return*/@Overridepublic SetmealDto getByIdWithSetmeal(long id) {//查询套餐基本信息,从setmeal表查询Setmeal setMeal = this.getById(id);SetmealDto setmealDto = new SetmealDto();BeanUtils.copyProperties(setMeal, setmealDto);//查询当前套餐对应的套餐信息,从setmeal_dish表中查LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(SetmealDish::getSetmealId, setMeal.getId());List<SetmealDish> setmealDishes = setmealDishService.list(lambdaQueryWrapper);setmealDto.setSetmealDishes(setmealDishes);return setmealDto;}/*** 修改套餐信息,并保存** @param setmealDto*/@Override@Transactionalpublic void updateWithSetmeal(SetmealDto setmealDto) {//更新 setmeal 表基本信息this.updateById(setmealDto);//先清理当前套餐对应的套餐信息--- setmeal_dish 表的 delete 操作LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(SetmealDish::getSetmealId, setmealDto.getId());setmealDishService.remove(lambdaQueryWrapper);//再添加当前提交过来的套餐数据-- setmeal_dish表的 insert 操作List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes = setmealDishes.stream().map((item) -> {item.setSetmealId(setmealDto.getId());return item;}).collect(Collectors.toList());setmealDishService.saveBatch(setmealDishes);}

8.5、停售、启售套餐

SetmealController

/*** 修改套餐的 停/启 售状态* @param ids* @return*/
@PostMapping("/status/{status}")
public R<Setmeal> status(long ids) {Setmeal setmeal = setmealService.getById(ids);setmealService.setStatus(setmeal);return R.success(setmeal);
}

SetmealServiceImpl

/*** 修改套餐的 停/启 售状态* @param setmeal*/
@Override
public void setStatus(Setmeal setmeal) {if (setmeal.getStatus() == 1) {setmeal.setStatus(0);} else {setmeal.setStatus(1);}this.updateById(setmeal);
}

9、前端–手机验证码登录

9.1、短信发送

阿里云短信服务

https://www.aliyun.com/product/sms?spm=5176.19720258.J_3207526240.37.4cf376f4PiAUnY

https://dysms.console.aliyun.com/quickstart?spm=5176.25163407.domtextsigncreate-index-1ec3c_58c50_0.1.5097bb6euk5OnF

设置签名

https://dysms.console.aliyun.com/domestic/text/sign

切换到【模板管理】标签页

添加模板详情

设置AccessKey

创建用户

自己保存好【AccessKey Secret】

添加权限

购买短信免费试用包

代码开发

pom

    <!--阿里云短信服务--><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.5.16</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>2.1.0</version></dependency>

导入utils工具类

9.2、手机验证码登录

需求分析

数据模型

代码开发

移动端页面放行的请求

LoginCheckFilter

//4-2、判断移动端用户登录状态,如果已登录,则直接放行
if (request.getSession().getAttribute("user") != null) {log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("user"));Long userId = (Long) request.getSession().getAttribute("user");BaseContext.setCurrentId(userId);filterChain.doFilter(request, response);return;
}

UserController

package com.jerry.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jerry.reggie.common.R;
import com.jerry.reggie.entity.User;
import com.jerry.reggie.service.UserService;
import com.jerry.reggie.utils.SMSUtils;
import com.jerry.reggie.utils.ValidateCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpSession;
import java.util.Map;/*** ClassName: UserController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-21 18:00* @Version 1.0*/
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 发送手机验证码短信* @param user* @return*/@PostMapping("/sendMsg")public R<String> sendMsg(@RequestBody User user, HttpSession session){//获取手机号String phone = user.getPhone();if (StringUtils.isNotEmpty(phone)){//生成随机的4位验证码String code = ValidateCodeUtils.generateValidateCode(4).toString();log.info("code={}",code);//调用阿里云提供的短信服务API完成短信发送// 没有买短信包,就不发手机短信了
//            SMSUtils.sendMessage("reggie外卖","SMS_270890116",phone,code);// 需要将生成的验证码保存到 session 中session.setAttribute(phone,code);return R.success("手机短信验证码发送成功");}return R.error("短信发送失败");}/*** 移动端用户登录* @param map* @param session* @return*/@PostMapping("/login")public R<User> login(@RequestBody Map map, HttpSession session){log.info(map.toString());//获取手机号String phone = map.get("phone").toString();// 获取验证码String code = map.get("code").toString();// 从session中获取保存的验证码Object codeInSession = session.getAttribute(phone);//进行验证码的比对 (页面提交过来的验证码和session中保存的验证码进行比对)if (codeInSession != null && codeInSession.equals(code)){// 如果比对成功,说明登录成功LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(User::getPhone,phone);User user = userService.getOne(lambdaQueryWrapper);if (user==null){// 判断当前手机号是否为新用户,如果是新用户就能自动完成注册user= new User();user.setPhone(phone);user.setStatus(1);userService.save(user);}session.setAttribute("user", user.getId());return R.success(user);}return R.error("登录失败");}
}

10、前端–导入用户地址簿

需求分析

数据模型

代码开发

AddressBookController

package com.jerry.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jerry.reggie.common.BaseContext;
import com.jerry.reggie.common.R;
import com.jerry.reggie.entity.AddressBook;
import com.jerry.reggie.service.AddressBookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** ClassName: AddressBookController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-21 20:42* @Version 1.0*//*** 地址簿管理*/
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {@Autowiredprivate AddressBookService addressBookService;/*** 新增*/@PostMappingpublic R<AddressBook> save(@RequestBody AddressBook addressBook) {addressBook.setUserId(BaseContext.getCurrentId());log.info("addressBook:{}", addressBook);addressBookService.save(addressBook);return R.success(addressBook);}/*** 设置默认地址*/@PutMapping("default")public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) {log.info("addressBook:{}", addressBook);LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());wrapper.set(AddressBook::getIsDefault, 0);//SQL:update address_book set is_default = 0 where user_id = ?addressBookService.update(wrapper);addressBook.setIsDefault(1);//SQL:update address_book set is_default = 1 where id = ?addressBookService.updateById(addressBook);return R.success(addressBook);}/*** 根据id查询地址*/@GetMapping("/{id}")public R get(@PathVariable Long id) {AddressBook addressBook = addressBookService.getById(id);if (addressBook != null) {return R.success(addressBook);} else {return R.error("没有找到该对象");}}/*** 查询默认地址*/@GetMapping("default")public R<AddressBook> getDefault() {LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());queryWrapper.eq(AddressBook::getIsDefault, 1);//SQL:select * from address_book where user_id = ? and is_default = 1AddressBook addressBook = addressBookService.getOne(queryWrapper);if (null == addressBook) {return R.error("没有找到该对象");} else {return R.success(addressBook);}}/*** 查询指定用户的全部地址*/@GetMapping("/list")public R<List<AddressBook>> list(AddressBook addressBook) {addressBook.setUserId(BaseContext.getCurrentId());log.info("addressBook:{}", addressBook);//条件构造器LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(null != addressBook.getUserId(), AddressBook::getUserId, addressBook.getUserId());queryWrapper.orderByDesc(AddressBook::getUpdateTime);//SQL:select * from address_book where user_id = ? order by update_time descreturn R.success(addressBookService.list(queryWrapper));}
}

11、前端–菜品展示

需求分析

代码开发

展示flavor口味信息

// 前端需要展示flavor口味信息
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish) {//构造查询条件LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());//查询状态为1,启售状态lambdaQueryWrapper.eq(Dish::getStatus, 1);//添加排序条件lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);List<Dish> list = dishService.list(lambdaQueryWrapper);List<DishDto> dishDtoList = list.stream().map((item) -> {DishDto dishDto = new DishDto();//对象拷贝BeanUtils.copyProperties(item, dishDto);Long categoryId = item.getCategoryId();//分类idCategory category = categoryService.getById(categoryId);//分类对象if (category != null) {String categoryName = category.getName();dishDto.setCategoryName(categoryName);}//当前菜品idLong dishId = item.getId();LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(DishFlavor::getDishId,dishId);List<DishFlavor> dishFlavorList = dishFlavorService.list(queryWrapper);dishDto.setFlavors(dishFlavorList);return dishDto;}).collect(Collectors.toList());return R.success(dishDtoList);
}

套餐信息展示

/*** 根据条件查询套餐数据** @param setmeal* @return*/
@GetMapping("/list")
public R<List<Setmeal>> list(Setmeal setmeal) {//构造查询条件LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());//查询状态为1,启售状态lambdaQueryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());//添加排序条件lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);List<Setmeal> list = setmealService.list(lambdaQueryWrapper);return R.success(list);
}

12、前端–购物车

需求分析

数据模型

代码开发

购物车需要实现查看/增加/减少/清空商品

package com.jerry.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jerry.reggie.common.BaseContext;
import com.jerry.reggie.common.R;
import com.jerry.reggie.entity.ShoppingCart;
import com.jerry.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.time.LocalDateTime;
import java.util.List;/*** ClassName: ShoppingCartController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-22 10:14* @Version 1.0*/
@RestController
@RequestMapping("/shoppingCart")
@Slf4j
public class ShoppingCartController {@Autowiredprivate ShoppingCartService shoppingCartService;/*** 添加购物车** @param shoppingCart* @return*/@PostMapping("/add")public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart) {log.info("购物车数据封装,{}", shoppingCart.toString());// 设置用户id,指定当前是哪个用户的购物车数据Long currentId = BaseContext.getCurrentId();shoppingCart.setUserId(currentId);Long dishId = shoppingCart.getDishId();LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(ShoppingCart::getUserId, shoppingCart.getUserId());if (dishId != null) {// 添加到购物车的是菜品lambdaQueryWrapper.eq(ShoppingCart::getDishId, dishId);} else {// 添加到购物车的是套餐lambdaQueryWrapper.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId());}// 查询当前菜品或套餐是否在购物车中,ShoppingCart cart = shoppingCartService.getOne(lambdaQueryWrapper);if (cart != null) {//如果已经存在,就在原来数量基础上加一Integer number = cart.getNumber();cart.setNumber(number + 1);shoppingCartService.updateById(cart);} else {// 如果不存在,则x添加到购物车,数量默认就是 1shoppingCart.setNumber(1);shoppingCart.setCreateTime(LocalDateTime.now());shoppingCartService.save(shoppingCart);cart = shoppingCart;}return R.success(cart);}/*** 减少购物车的菜品** @return*/@PostMapping("/sub")public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart) {log.info("购物车数据封装,{}", shoppingCart.toString());LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());if (shoppingCart.getDishId() != null) {// 减少到购物车的是菜品lambdaQueryWrapper.eq(ShoppingCart::getDishId, shoppingCart.getDishId());} else {// 减少到购物车的是套餐lambdaQueryWrapper.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId());}// 查询当前菜品或套餐是否在购物车中,ShoppingCart cart = shoppingCartService.getOne(lambdaQueryWrapper);//如果已经存在并且数量 > 1,就在原来数量基础上 - 1if ((cart.getNumber() > 1)) {Integer number = cart.getNumber();cart.setNumber(number - 1);shoppingCartService.updateById(cart);} else {//移除改菜品或套餐shoppingCartService.remove(lambdaQueryWrapper);}return R.success(cart);}/*** 清空购物车** @return*/@DeleteMapping("/clean")public R<String> clean() {LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());shoppingCartService.remove(lambdaQueryWrapper);return R.success("清空购物车成功");}/*** 查看购物车** @return*/@GetMapping("/list")public R<List<ShoppingCart>> list() {log.info("查看购物车...");LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());lambdaQueryWrapper.orderByAsc(ShoppingCart::getCreateTime);List<ShoppingCart> list = shoppingCartService.list(lambdaQueryWrapper);return R.success(list);}
}

13、前端–用户下单

需求分析

数据模型

代码开发

OrderController

package com.jerry.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jerry.reggie.common.R;
import com.jerry.reggie.entity.Orders;
import com.jerry.reggie.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** ClassName: OrderController* Package: com.jerry.reggie.controller* Description:** @Author jerry_jy* @Create 2023-02-22 13:53* @Version 1.0*/@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderService orderService;/*** 用户下单* @param orders* @return*/@PostMapping("/submit")public R<String> submit(@RequestBody Orders orders){log.info("订单数据:{}",orders);orderService.submit(orders);return R.success("下单成功");}/*** 订单查询* @param page* @param pageSize* @return*/@GetMapping("/userPage")public R<Page> userPage(int page, int pageSize){//分页构造器Page<Orders> pageInfo = new Page<>();//条件构造器LambdaQueryWrapper<Orders> lambdaQueryWrapper = new LambdaQueryWrapper<>();//添加排序条件lambdaQueryWrapper.orderByDesc(Orders::getOrderTime);orderService.page(pageInfo, lambdaQueryWrapper);return R.success(pageInfo);}
}

OrderService

package com.jerry.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.jerry.reggie.entity.Orders;/*** ClassName: OrderService* Package: com.jerry.reggie.service* Description:** @Author jerry_jy* @Create 2023-02-22 13:52* @Version 1.0*/
public interface OrderService extends IService<Orders> {//用户下单void submit(Orders orders);
}

OrderServiceImpl

package com.jerry.reggie.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jerry.reggie.common.BaseContext;
import com.jerry.reggie.common.CustomException;
import com.jerry.reggie.entity.*;
import com.jerry.reggie.mapper.OrderMapper;
import com.jerry.reggie.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;/*** ClassName: OrderServiceImpl* Package: com.jerry.reggie.service.impl* Description:** @Author jerry_jy* @Create 2023-02-22 13:52* @Version 1.0*/@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {@Autowiredprivate ShoppingCartService shoppingCartService;@Autowiredprivate UserService userService;@Autowiredprivate AddressBookService addressBookService;@Autowiredprivate OrderDetailService orderDetailService;/*** 用户下单* @param orders*/@Transactional@Overridepublic void submit(Orders orders) {// 获取用户idLong userId = BaseContext.getCurrentId();// 查询当前用户购物车的数据LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(ShoppingCart::getUserId,userId);List<ShoppingCart> shoppingCartList = shoppingCartService.list(lambdaQueryWrapper);if (shoppingCartList == null || shoppingCartList.size()==0){throw new CustomException("购物车为空,不能下单");}// 查询用户数据User user = userService.getById(userId);// 查询地址数据Long addressBookId = orders.getAddressBookId();AddressBook addressBook = addressBookService.getById(addressBookId);if (addressBook == null){throw new CustomException("用户地址信息有误,不能下单");}long orderId = IdWorker.getId();//生成订单号AtomicInteger amount = new AtomicInteger(0);List<OrderDetail> orderDetails= shoppingCartList.stream().map((item)->{OrderDetail orderDetail = new OrderDetail();orderDetail.setOrderId(orderId);orderDetail.setNumber(item.getNumber());orderDetail.setDishFlavor(item.getDishFlavor());orderDetail.setDishId(item.getDishId());orderDetail.setSetmealId(item.getSetmealId());orderDetail.setName(item.getName());orderDetail.setImage(item.getImage());orderDetail.setAmount(item.getAmount());amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue());return orderDetail;}).collect(Collectors.toList());orders.setId(orderId);orders.setOrderTime(LocalDateTime.now());orders.setCheckoutTime(LocalDateTime.now());orders.setStatus(2);orders.setAmount(new BigDecimal(amount.get()));//总金额orders.setUserId(userId);orders.setNumber(String.valueOf(orderId));orders.setUserName(user.getName());orders.setConsignee(addressBook.getConsignee());orders.setPhone(addressBook.getPhone());orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())+ (addressBook.getCityName() == null ? "" : addressBook.getCityName())+ (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())+ (addressBook.getDetail() == null ? "" : addressBook.getDetail()));// 向订单表插入,一条数据this.save(orders);// 向订单明细表插入,多条数据orderDetailService.saveBatch(orderDetails);//清空购物车数据shoppingCartService.remove(lambdaQueryWrapper);}
}

14、代码托管

Git版本管理

Gitee

https://gitee.com/jinyang-jy/reggie.git

Github

https://github.com/Jerry-jy/reggie.git

项目所需资料

链接:https://pan.baidu.com/s/182tTb1rmGkTCbq9aXrbjMg?pwd=2022
提取码:2022

基于SpringBoot的外卖项目(详细开发过程)相关推荐

  1. 基于SpringBoot监控Java项目,暴漏springboot内置端点

    基于SpringBoot监控Java项目的指标 文章目录 基于SpringBoot监控Java项目的指标 监控java项目有哪些方案 springboot内置端口 prometheus 如何使用 sp ...

  2. 基于springboot在线外卖系统

    末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SpringBoot 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软 ...

  3. 基于springboot+vue物流项目

    基于springboot+vue物流项目 ✌全网粉丝20W+,csdn特邀作者.博客专家.CSDN新星计划导师.java领域优质创作者,博客之星.掘金/华为云/阿里云/InfoQ等平台优质作者.专注于 ...

  4. 一款基于SpringBoot 音乐网站项目

    本音乐网站的客户端和管理端使用 VUE 框架来实现,服务端使用 Spring Boot + MyBatis 来实现,数据库使用了 MySQL. 项目功能 音乐播放 用户登录注册 用户信息编辑.头像修改 ...

  5. 瑞吉外卖项目详细分析笔记及所有功能补充代码

    目录 项目刨析简介 技术栈 项目介绍 项目源码 一.架构搭建 1.初始化项目结构 2.数据库表结构设计 3.项目基本配置信息添加 公共字段的自动填充 全局异常处理类 返回结果封装的实体类 二.管理端业 ...

  6. 月度总结 | 2022年05、06 、07 月 | 找工作 | 大三顺利结束,课程基本结束 | 基于SpringBoot 的 JavaWeb 项目 | 人生第一次实习启程 | 心路历程与想法分享

    前言 时间过得真快,继上一次自我总结(如下)竟然已过去三个月 : 月度总结 | 2022年04月 | 大数据技术学习心得 | 大三下校内课程的处理 这三个月里有很忙的时候,也有很闲的时候. 回顾四月的 ...

  7. 创建一个基于SpringBoot + MyBatis-Plus 的项目

    什么是MyBatis-Plus ? MyBatis-Plus(简称:MP),它是基于MyBatis框架基础上开发的增强型工具,主要是为了简化开发,提高效率. MyBatis-Plus中文网:MyBat ...

  8. 基于springboot多模块项目使用maven命令打成war包放到服务器上运行的问题

    首先,大家看到这个问题,可能并不陌生,而且脑子里第一映像就是使用mava中的clear package 或者 clear install进行打包,然后在项目中的target文件夹下面找到xxx.war ...

  9. 基于SpringBoot的书城项目,带真支付功能的微服务电商项目

    目录 1.简介 2.技术栈 3.环境 4.配置 5.搭建 6.核心代码 7.界面展示 8.下载地址 1.简介 该系统分为前台展示和后台管理两大模块. 前台主要是为消费者服务.该子系统实现了注册,登录, ...

最新文章

  1. MMKV集成与原理,详细学习指南
  2. mysql表在线转成分区表_11g普通表在线转换分区表
  3. python dataframe 取一行_python – Pandas dataframe获取每个组的第一行
  4. 告别大妈的灵魂拷问,Python 教你轻松完成垃圾分类!
  5. struts2+spring+hibernte整合示例
  6. 游戏素材网站推荐!!!
  7. 是指直接进行国际联网的计算机信息网络,网络安全合规指引题库:计算机信息网络直接进行国际联网,可以使用邮电部国家公用电信网提供的国际出入口信道。单位和个人也可以自行建立信道进行国际联网。()...
  8. Android 10 SystemUI中Android.bp文件中集成第三方JAR包或者so文件的方法
  9. flac转mp3教程flac怎么转mp3才能减小音质的丢失
  10. 麒麟座MINI板串口乱码(HAL库晶振配置)
  11. 南京申瓯SOC1000-UC IPPBX为中小企业提供电话系统解决方案
  12. 企业微信如何给客户打标签?
  13. win10切换视图快捷键and其他
  14. Setuptools(Python打包工具)
  15. 敏捷宣言:四大核心价值观和十二条原则
  16. 人人都是产品经理总结 第五章
  17. HG30-3B型多功能校准仪
  18. python卸载及python 0x80070643 安装发生严重错误
  19. 智能餐桌需要实现的最基本的功能是什么?
  20. FFmpeg之视频封装格式、流媒体协议、视频编解码协议和传输流格式、时间戳和时间基、视频像素数据

热门文章

  1. Ajax系列之异步调用导致的不同步问题
  2. arduino端口凭空出现_凭空宣传的视觉广告制作工作流程
  3. 阿里巴巴Java开发手册简介(终极版、华山版、泰山版)(附下载地址)
  4. plc300c语言对温度的编程,S7-300PLC 模拟量温度编程
  5. 2021年中国制药设备行业产业链上中下游及未来发展趋势分析,政策利好促进行业市场规模稳定增长「图」
  6. HTML怎么样把图片换行,我的css代码如下,为什么读出来的图片每一行只有1个,能不能每行三个,第四个换行_html/css_WEB-ITnose...
  7. web服务器和后端语言的关系
  8. html页面自动适应pc端,自适应PC端网页制作使用REM(示例代码)
  9. Ubuntu16.04 安装UHD GNU Radio教程
  10. DeepFreeze (冰点还原)完全使用手册