基于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: reggie
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: root
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-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
*/
@Override
protected 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 {
@Autowired
private 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中的用户id
request.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();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取本次请求的URI
String uri = request.getRequestURI(); // backend/index.html
log.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());
//获得当前登录对象的id
Long 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 {
@Bean
public 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对象转为json
messageConverter.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 {
@Autowired
private DishService dishService;
@Autowired
private SetmealService setmealService;
/**
* 根据id删除分类,删除之前需要进行判断
* @param id
*/
@Override
public 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
*/
@DeleteMapping
public 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 {
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品同时保存口味数据
* @param dishDto
*/
@Transactional
@Override
public void saveWithFlavor(DishDto dishDto) {
//保存菜品基本信息到菜品表dish
this.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_flavor
dishFlavorService.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 {
@Autowired
DishFlavorService dishFlavorService;
@Autowired
DishService dishService;
/**
* 新增菜品
* @param dishDto
* @return
*/
@PostMapping
public 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();//分类id
Category 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
*/
@DeleteMapping
public 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 执行insert
this.save(setmealDto);
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
setmealDishes.stream().map((item)->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
//保存套餐和菜品的关联信息,操作setmeal_dish,执行insert
setmealDishService.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);
//分类id
Long 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("套餐正在售卖中,不能删除");
}
// 如果可以删除,先删除套餐表中的数据-- setmeal
this.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
*/
@PutMapping
public 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
*/
@Override
public 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
@Transactional
public 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 {
@Autowired
private 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 {
@Autowired
private AddressBookService addressBookService;
/**
* 新增
*/
@PostMapping
public 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 = 1
AddressBook 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 desc
return 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();//分类id
Category category = categoryService.getById(categoryId);//分类对象
if (category != null) {
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
//当前菜品id
Long 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 {
@Autowired
private 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添加到购物车,数量默认就是 1
shoppingCart.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,就在原来数量基础上 - 1
if ((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 {
@Autowired
private 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 {
@Autowired
private ShoppingCartService shoppingCartService;
@Autowired
private UserService userService;
@Autowired
private AddressBookService addressBookService;
@Autowired
private OrderDetailService orderDetailService;
/**
* 用户下单
* @param orders
*/
@Transactional
@Override
public void submit(Orders orders) {
// 获取用户id
Long 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