外卖项目05---套餐管理业务开发

news2024/12/23 14:01:59

套餐:一组菜品的集合

点击之后就会弹出下面的界面:

上面是后台的管理操作,下面是处理完成后在用户端展示的界面效果:

目录

一、新增套餐 70

1.1需求分析 70

1.2数据模型 70

​编辑1.3新增套餐---代码开发---准备工作&梳理交互过程 71

1.3.1代码准备工作(类的导入,服务层的编写)71

1.4新增套餐---代码开发---根据分类查询菜品 72

1.5新增套餐---代码开发---服务端接收页面提交的数据 73

1.6新增套餐---代码开发---保存数据到对应表 74

1.7新增套餐---功能测试 75

二、套餐信息分页查询 76

2.1需求分析 76

2.2代码开发---梳理交互过程 76

2.3套餐信息分页查询---代码开发&功能测试 77

三、删除套餐 (关联表之间的删除)78

3.1需求分析 78

3.2代码开发---梳理交互过程 78

3.3删除套餐---代码开发&功能测试 79

四、手机验证码登陆 80

五、短信发送 81

5.1短信服务介绍和阿里云短信服务介绍 81

5.2短信发送---阿里云短信服务 82 

5.2.1阿里云短信服务---注册账号 82

​编辑5.3短信发送---代码开发---参照官方文档封装短信发送工具类 83

六、手机验证码登陆 84 

6.1需求分析 84

6.2数据模型 84 

6.3手机验证码登陆---代码开发---梳理交互过程&修改LoginCheckFliter 85

6.3.1代码开发---梳理交互过程 85

6.3.2代码开发---准备工作 85

6.4手机验证码登陆---代码开发 86

6.5手机验证码登陆---代码开发---登陆校验 86


 

一、新增套餐 70

1.1需求分析 70

1.2数据模型 70

 

1.3新增套餐---代码开发---准备工作&梳理交互过程 71

1.3.1代码准备工作(类的导入,服务层的编写)71

1.4新增套餐---代码开发---根据分类查询菜品 72

1.3.1中的交互过程包含六次交互请求,前两次的请求交互在CategoryController中进行。

选用其中的List集合中的数据信息。

这两种类都在List中进行。

实现的是下面的效果内容:

 本部分代码实现的效果: 

本部分使用的代码如下所示:

    /**
     * 根据条件查询对应的菜品数据
     * @param dish
     * @return
     */
    @GetMapping("/list")
    public R<List<Dish>> list(Dish dish){//这个部分传递的参数,可以是Long categoryid,
                                        // 但是可以将其进行扩展使用,使用Dish类中的参数,它包含了很多的参数信息,包含categoryid
        //构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null , Dish::getCategoryId,dish.getCategoryId());
                                                            //该部分是设置一个判断语句,确定id传递过来,并不是空的指针
        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
                                        //使用了两个判断条件,一个是根据sort进行升序排序,如果sort排序一致,再根据更新时间进行降序判断
        //添加条件,查询状态为1(起售状态)的菜品
        queryWrapper.eq(Dish::getStatus,1);
        List<Dish> list = dishService.list(queryWrapper);//使用该方法,获取得到了一个集合

        return R.success(list);
    }

1.5新增套餐---代码开发---服务端接收页面提交的数据 73

下面部分代码开发实现的内容: 

 使用的是CommonController层的图片上传和下载的功能。

下面本部分实现的是下面的效果:

将客户端的数据信息发布反馈到后端当中:

反馈到后端的内容数据信息: 

本部分代码:

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

1.6新增套餐---代码开发---保存数据到对应表 74

套餐表中插入数据、套餐和菜品对应的关系表里面进行插入数据处理。这两个表都需要进行处理。

对两张表的操作。

在SetmealService接口中进行处理。

本部分的代码如下所示:底层对两个表之间处理。

步骤一:对SetmealService接口进行修改

代码:

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

步骤二:在SetmealServiceImpl驱动类中进行修改。

    /**
     * 新增套餐,同时需要保存套餐和菜品的关联关系
     * @param setmealDto
     */
    @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);

    }

1.7新增套餐---功能测试 75

二、套餐信息分页查询 76

2.1需求分析 76

2.2代码开发---梳理交互过程 76

一共能涉及到2次请求信息 

 注:

1、中的name参数获取

 2、图片进行展示

2.3套餐信息分页查询---代码开发&功能测试 77

        目前下面的代码能够实现主要的内容,但是在套餐分类的这一类当中是不进行显示的。是由于pageInfo中继承的泛型是Setmeal。

 但是Setmeal中不包含套餐分类的功能,只是返回的是套餐分类的id。

本部分解决套餐分类中分类的类别显示问题:

问题描述如下:

本部分代码:

    /**
     * 套餐分页查询
     * @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<>();//使用SetmealDto中的内容对象,进行使用操作处理,
                                                // 由于SetmealDto继承Setmeal,并且还包含那个套餐分类的名称,所以使用该类

        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件,根据name进行like模糊查询
        queryWrapper.like(name != null,Setmeal::getName,name);//括号内是进行条件的查询的判断,判断内容不为空,
                                                                    // 并且进行name模糊查询
        //添加排序条件,根据更新时间降序排序
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        setmealService.page(pageInfo,queryWrapper);
        //对象拷贝
        BeanUtils.copyProperties(pageInfo,dtoPage,"records");//是将pageInfo中的数据拷贝到dtoPage中
                                    //并且忽略pageInfo中的records的保存数据的信息记录。由于pageInfo中的泛型为Setmeal,
                                    //我们新创建的是dtoPage的泛型为SetmealDto,所以需要进行先排除
        List<Setmeal> records = pageInfo.getRecords();//获取pageInfo中的records,对后面的这个records进行处理解决

        List<SetmealDto> list =  records.stream().map((item) ->{
            SetmealDto setmealDto = new SetmealDto();
            //对象拷贝,因为创建的集合SetmealDto中是空的,所以需要将原来item的数据内容拷贝到新的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);//将查询到的categoryName添加到setmealDto中
                                            //因为创建的setmealDto是个新的集合,所以使用set进行添加到集合中
            }
            return setmealDto;
        }).collect(Collectors.toList());

        dtoPage.setRecords(list);
        return R.success(dtoPage);
    }

三、删除套餐 (关联表之间的删除)78

3.1需求分析 78

需求:

1、点击删除按钮删除商品

2、批量删除商品的实现

3、停售按键的正常使用,售卖的套餐不能被删除,停售后才能够被删除 

3.2代码开发---梳理交互过程 78

 注:

1、请求方式和请求地址是相同的

2、区别在于两者的传递的id的个数不一样

3.3删除套餐---代码开发&功能测试 79

步骤一:在SetmealController层中进行书写删除的主代码

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

步骤二:在SetmealSerice接口中创建新的方法

    public void removeWithDish(List<Long> list);

步骤三:添加服务驱动类

    /**
     * 删除套餐,同时需要删除套餐和菜品的关联数据
     * @param ids
     */
    @Override
    public void removeWithDish(List<Long> ids) {
        //select count(*) from setmeal where id in (1,2,3) and status =1
        //查询套餐状态,确定是否可用删除
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Setmeal::getId,ids);//是查询判断的第一部分条件是在(1,2,3)中进行查询进行表达
        queryWrapper.eq(Setmeal::getStatus,1);//判断条件等值查询判断,判断该商品的状态,1:在售;2:停售

        int count = this.count(queryWrapper);//ServiceImpl实现的框架下的一个count,封装生成
        if(count > 0 ){//异常提示报错,>0表示状态为1,处于售卖的状态。
            //如果不能被删除,抛出一个业务异常
            throw new CustomException("套餐正在售卖中,不能删除");
        }
        //如果可以删除,先删除套餐表中的数据---setmeal  这个是套餐(批量删除)

        this.removeByIds(ids);

        //删除关系表中的数据---setmeal_dish(关联数据)
        //创建一个新的处理方式,mysql中的编程处理的代码 delete from setmeal_dish where setmeal_id in (1,2,3...)
        LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);//该部分表示mysql的代码编写
        //删除关系表中的数据---setmeal_dish
        setmealDishService.remove(lambdaQueryWrapper);

    }

步骤四:在主方法中进行调用使用该方法

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

四、手机验证码登陆 80

五、短信发送 81

5.1短信服务介绍和阿里云短信服务介绍 81

5.2短信发送---阿里云短信服务 82 

5.2.1阿里云短信服务---注册账号 82

 

 

5.3短信发送---代码开发---参照官方文档封装短信发送工具类 83

 

六、手机验证码登陆 84 

6.1需求分析 84

6.2数据模型 84 

6.3手机验证码登陆---代码开发---梳理交互过程&修改LoginCheckFliter 85

6.3.1代码开发---梳理交互过程 85

6.3.2代码开发---准备工作 85

 修改部分一:

修改部分二:

6.4手机验证码登陆---代码开发 86

 本部分代码如下:

代码:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    public R<String> sendMsg(@RequestBody User user, HttpSession session){

        //获取手机号
        String phone = user.getPhone();

        if (StringUtils.isNotEmpty(phone)){//首先进行条件判断
            //生成4位随机的验证码,通过ailiyun提供的功能类
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code={}",code);

            //调用阿里云提供的短信服务API完成发送短信
//            SMSUtils.sendMessage("瑞吉外卖","",phone,code);

            //需要将生成的验证码保存到Session
            session.setAttribute(phone,code);

            return R.success("手机验证码短信发送成功");

        }
        return R.error("短信发送失败");
    }

}

6.5手机验证码登陆---代码开发---登陆校验 86

使得前端能够进行登陆

本部分代码:

    /**
     * 移动端用户登陆
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){//使用Map类

        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> queryWrapper =new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone,phone);

            User user = userService.getOne(queryWrapper);
            if(user == null){
                //判断当前手机号对应的用户是否位新用户,如果是新用户就自动完成注册
                user = new User();
                user.setPhone(phone);
                user.setStatus(1);
                userService.save(user);

            }
            return R.success(user);
        }
        return R.error("登陆失败");
    }

效果:实现在移动端进行登陆

注:如果登陆时出现登陆不上的情况,可以尝试清理下浏览器的缓存,在进行登陆。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vtk.js滚动切片

关于滚动切片&#xff0c;官方有一个很好的例子,如下图&#xff1a; 关键代码 const mapper vtkImageMapper.newInstance(); mapper.setInputConnection(rtSource.getOutputPort()); mapper.setSliceAtFocalPoint(true);//这一行切片的光照焦点必须要设置为true&#xff0c;否…

CSDN周赛第十期总结

文章目录竞赛概述题解熊孩子摆拜访问题目描述数据范围样例输入样例输出代码走楼梯题目描述输入描述输出描述样例输入 1样例输出 1代码括号上色输入描述&#xff1a;输出描述&#xff1a;输入样例&#xff1a;输出样例&#xff1a;代码喜水青蛙题目描述输入描述&#xff1a;输出…

spark3.0.2搭建教程

spark3.0.2搭建教程 spark3.0.2安装教程 文章目录spark3.0.2安装教程一、前期准备二、spark搭建&#xff08;一&#xff09;搭建1、将spark上传到虚拟机上2、解压安装包&#xff08;二&#xff09;、standalone&#xff08;独立部署&#xff09;模型1、修改配置文件&#xff0…

学生HTML静态网页基础水平制作DIV+CSS+JavaScript技术制作美食网页——美食城6页面

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

高等数学(第七版)同济大学 习题10-2(前10题) 个人解答

高等数学&#xff08;第七版&#xff09;同济大学 习题10-2&#xff08;前10题&#xff09; 函数作图软件&#xff1a;Mathematica 1.计算下列二重积分:\begin{aligned}&1. \ 计算下列二重积分:&\end{aligned}​1. 计算下列二重积分:​​ (1)∬D(x2y2)dσ&#xff0c;…

【构建ML驱动的应用程序】第 7 章 :使用分类器编写推荐

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

动态内存管理❀C

目录❀动态内存管理的意义❀动态内存管理函数malloc - 申请空间free - 释放空间calloc - 申请空间realloc - 调整空间大小❀常见的动态内存错误对NULL指针的解引用操作 - err对动态开辟空间的越界访问 - err对非动态开辟内存使用free释放 - err使用free释放一块动态开辟内存的一…

Pycharm安装配置Pyside6

PySide6是在Python环境下的一套Qt6 API库。使用PySide6可以轻松创建基于Qt6的GUI程序&#xff1b;PySide6由Qt官方维护。 1. Pyside6的安装&#xff1a; 直接安装在原python上面&#xff0c;在cmd里运行&#xff1a;(网速慢使用阿里源源) pip3 install Pyside6 -i https://p…

网络安全——逻辑漏洞之越权漏洞

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

高通导航器软件开发包使用指南(8)

高通导航器软件开发包使用指南&#xff08;8&#xff09;7 电子速度控制器7.1 ESC固件更新7.1.1相关参数说明7.1.3在初始化期间启用更新7.1.4固件配置7.1.5固件从版本7.1.6更新程序7 电子速度控制器 7.1 ESC固件更新 高通公司Navigator支持ESC固件更新&#xff0c;无需连接或…

2022亚太C题详细思路

2022年亚太今日已经正式开赛&#xff0c;为了帮助大家更好的选题建模&#xff0c;这里首先对ABC三道题目进行浅要评析&#xff0c;以方便大家更好的择题。同时相关资料也会后续进行补充。预计明日公布各题统计选题人数以及较为完善的资料。今天作为第一天重要的是择好题&#x…

Tableau阈值设置及其使用

阈值又叫临界值&#xff0c;是指一个效应能够产生的最低值或最高值。 ——百度百科 文章目录前言一、案例中阈值的使用背景介绍二、设置阈值参数三、颜色区分四、可筛选设置总结前言 介绍Tableau阈值的设置&#xff0c;供各位小伙伴参考。本文案例来源于Tableau自带示例工作薄…

mysql 数据备份与恢复使用详解

一、前言 对一个运行中的线上系统来说&#xff0c;定期对数据库进行备份是非常重要的&#xff0c;备份不仅可以确保数据的局部完整性&#xff0c;一定程度上也为数据安全性提供了保障&#xff0c;设想如果某种极端的场景下&#xff0c;比如磁盘损坏导致某个时间段数据丢失&…

冒泡排序法

目录 一、问题 二、冒泡排序的思想 三、举例 四、算法分析 五、代码实现 一、问题 现有一个整型数组&#xff08;乱序&#xff09;&#xff0c;并且写一个函数&#xff08;Sort&#xff09;对数组进行排序&#xff0c;顺序要求升序。 二、冒泡排序的思想 两两相邻的元素…

【100个 Unity实用技能】 | Unity自定义脚本的初始模版

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…

java每日一练(2)

java每日一练(2) 单选部分 1.A 派生出子类 B &#xff0c; B 派生出子类 C &#xff0c;并且在 java 源代码有如下声明&#xff1a; A a0new A();A a1new B();A a2new C(); 问以下哪个说法是正确的&#xff08;&#xff09; A 只有第一行能通过编译 B 第1、2行能通过编译&…

【Servlet】6:一篇文章搞懂Servlet对象的相互调用、数据共享

目录 | 请求对象和响应对象 生命周期 | Servlet之间的相互调用 Servlet调用 基本概述 重定向Servlet调用 请求转发Servlet调用 | Servlet之间的数据共享 Servlet数据共享 基本概述 ServletContext接口 数据共享 Cookie类 数据共享 HttpSession接口 数据共享 HttpServletRequest…

2022亚太A题赛题分享

序列图像特征提取及模具熔融结晶建模分析 连铸过程中的模具通量对钢半月板进行热绝缘&#xff0c;防止液态钢连铸过程中液态钢再氧化&#xff0c;控制传热&#xff0c;提供链润滑&#xff0c;吸收非金属夹杂物。模具通量的冶金功能主要由温度控制曲线下的熔化速率和结晶速率决定…

【论文简述及翻译】MVSNet:Depth Inference for Unstructured Multi-view Stereo(ECCV 2018)

一、论文简述 1. 第一作者&#xff1a;Yao Yao 2. 发表年份&#xff1a;2018 Oral 3. 发表期刊&#xff1a;ECCV 4. 关键词&#xff1a;MVS、端到端网络、代价体、深度图、可微分单应变换 5. 探索动机&#xff1a;传统方法存在一些常见的局限性&#xff0c;很难处理场景的…