【瑞吉外卖 | day07】移动端菜品展示、购物车、下单

news2024/11/25 12:33:52

在这里插入图片描述

文章目录

  • 瑞吉外卖 — day7
    • 1. 导入用户地址簿相关功能代码
      • 1.1 需求分析
      • 1.2 数据模型
      • 1.3 代码开发
    • 2. 菜品展示
      • 2.1 需求分析
      • 2.2 代码开发
    • 3. 购物车
      • 3.1 需求分析
      • 3.2 数据模型
      • 3.3 代码开发
    • 4. 下单
      • 4.1 需求分析
      • 4.2 数据模型
      • 4.3 代码开发

瑞吉外卖 — day7

  • 移动端相关业务功能 —— 菜品展示、购物车、下单

1. 导入用户地址簿相关功能代码

1.1 需求分析

  • 地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息。同一个用户可以有多个地址信息,但是只能有一个默认地址

1.2 数据模型

  • 用户的地址信息会存储在address_book表,即地址簿表中。

1.3 代码开发

  • 导入功能代码

    实体类AddressBook(直接从课程资料中导入即可)

    Mapper接口AddressBookMapper

    业务层接口AddressBookService

    业务层实现类AddressBookServicelmpl

    控制层AddressBookController(直接从课程资料中导入即可)

  • AddressBookController代码

    /**
     * 地址簿管理
     */
    @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));
        }
    }
    

2. 菜品展示

2.1 需求分析

  • 用户登录成功后跳转到系统首页,在首页需要根据分类来展示菜品和套餐
    。如果菜品设置了口味信息,需要展示洗择规格按钮,否则显示==+==按钮。

2.2 代码开发

  • 前端与服务端交互过程

    1、页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)

    2、页面发送ajax请求,获取第一个分类下的菜品或者套餐

  • 页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)

  • 页面发送ajax请求,获取第一个分类下的菜品或者套餐

    DishController中:

    @GetMapping("list")
        public R<List<DishDto>> list(Dish dish){
            //构造查询条件
            LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(dish.getCategoryId()!=null, Dish::getCategoryId, dish.getCategoryId());
            //添加条件,查询状态为1的菜品
            queryWrapper.eq(Dish::getStatus,1);
            //添加排序条件
            queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
    
            List<Dish> list = dishService.list(queryWrapper);
    
            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> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
                List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
                dishDto.setFlavors(dishFlavorList);
    
                return dishDto;
            }).collect(Collectors.toList());
    
            return R.success(dishDtoList);
        }
    

    SetmealController中:

    /**
         * 根据条件查询套餐数据
         * @param setmeal
         * @return
         */
        @GetMapping("list")
        public R<List<Setmeal>> list(Setmeal setmeal){
            LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(setmeal.getCategoryId()!= null,Setmeal::getCategoryId,setmeal.getCategoryId());
            queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
            queryWrapper.orderByDesc(Setmeal::getUpdateTime);
    
            List<Setmeal> list = setmealService.list(queryWrapper);
    
            return R.success(list);
        }
    

3. 购物车

3.1 需求分析

  • 移动端用户可以将菜品或者套餐添加到购物车。对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车;对于套餐来说,可以直接点击将当前套餐加入购物车。在购物车中可以修改菜品和套餐的数量,也可以清空购物车。

3.2 数据模型

  • 购物车对应的数据表为shopping_cart表

3.3 代码开发

  • 前段与服务端交互过程

    1、点击加入购物车或者按钮,页面发送ajax请求,请求服务端,将菜品或者套餐添加到购物车

    2、点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐

    3、点击清空购物车按钮,页面发送ajax请求,请求服务端来执行清空购物车操作

  • 创建需要的类和接口

    实体类ShoppingCart ( 直接从课程资料中导入即可)

    Mapper接口ShoppingCartMapper

    业务层接口ShoppingCartService

    业务层实现类ShoppingCartServicelmpl

    控制层ShoppingCartController

  • 将菜品或者套餐添加到购物车

    @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);
    
            //设置用户id,指定当前是哪个用户的购物车数据
            Long currentId = BaseContext.getCurrentId();
            shoppingCart.setUserId(currentId);
    
            LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ShoppingCart::getUserId,currentId);
    
            //查询当前菜品或套餐,是否在购物车中
            Long dishId = shoppingCart.getDishId();
            if(dishId != null){
                //添加到购物车的是菜品
                queryWrapper.eq(ShoppingCart::getDishId,dishId);
            }else{
                //添加到购物车的是套餐
                queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
            }
    
            ShoppingCart cart = shoppingCartService.getOne(queryWrapper);
    
            //如果已存在,在原来数量基础上+1
            if(cart != null){
                Integer number = cart.getNumber();
                cart.setNumber(number+1);
                shoppingCartService.updateById(cart);
    
            }else{
                //如果不存在,则添加到购物车,数量默认就是1
                shoppingCart.setNumber(1);
                shoppingCart.setCreateTime(LocalDateTime.now());
                shoppingCartService.save(shoppingCart);
                cart = shoppingCart;
            }
    
            return R.success(cart);
        }
    }
    
  • 查询购物车中的菜品和套餐

    /**
         * 查看购物车当前数据
         * @return
         */
        @GetMapping("list")
        public R<List<ShoppingCart>> list(){
            log.info("查看购物车...");
    
            LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
            queryWrapper.orderByAsc(ShoppingCart::getCreateTime);
    
            List<ShoppingCart> list = shoppingCartService.list(queryWrapper);
    
            return R.success(list);
        }
    
  • 清空购物车操作

    /**
         * 清空购物车
         * @return
         */
        @DeleteMapping("clean")
        public R<String> clean(){
            LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
    
            shoppingCartService.remove(queryWrapper);
    
            return R.success("清空购物车成功!");
        }
    

4. 下单

4.1 需求分析

  • 移动端用户将菜品或者套餐加入购物车后,可以点击购物车中的去结算按钮,页面跳转到订单确认页面,点击去支付按钮则完成下单操作。

4.2 数据模型

  • orders:订单表
    order_ detail::订单明细表

4.3 代码开发

  • 前端页面与服务端交互过程

    1、在购物车中点击去结算按钮,页面跳转到订单确认页面

    2、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址

    3、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据

    4、在订单确认页面点击去支付按钮, 发送ajax请求, 请求服务端完成下单操作

  • 基本的类和接口

    实体类Orders、OrderDetail (直接从课程资料中导入即可)

    Mapper接口OrderMapper、OrderDetailMapper

    业务层接口OrderService、OrderDetailService

    业务层实现类OrderServicelmpl、OrderDetailServicelmpl

    控制层OrderController、OrderDetailController

  • OrderController代码:

    @RestController
    @RequestMapping("order")
    @Slf4j
    public class OrderController {
    
        @Autowired
        private OrdersService ordersService;
    
        /**
         * 用户下单
         * @param orders
         * @return
         */
        @PostMapping("submit")
        public R<String> submit(@RequestBody Orders orders){
            log.info("订单数据:{}",orders);
            ordersService.submit(orders);
            return R.success("下单成功");
        }
    }
    
    
  • OrdersServiceImpl代码:

    @Service
    public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders>
            implements OrdersService{
    
        @Autowired
        private ShoppingCartService shoppingCartService;
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private AddressBookService addressBookService;
    
        @Autowired
        private OrderDetailService orderDetailService;
    
        /**
         * 用户下单
         * @param orders
         */
        @Override
        @Transactional
        public void submit(Orders orders) {
            //获取当前用户id
            Long currentId = BaseContext.getCurrentId();
    
            //查询当前用户购物车数据
            LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ShoppingCart::getUserId,currentId);
            List<ShoppingCart> shoppingCarts = shoppingCartService.list(queryWrapper);
    
            if(shoppingCarts == null || shoppingCarts.size() == 0){
                throw new CustomerException("购物车为空,不能下单");
            }
    
            //查询用户数据
            User user = userService.getById(currentId);
    
            //查询地址数据
            Long addressBookId = orders.getAddressBookId();
            AddressBook addressBook = addressBookService.getById(addressBookId);
            if(addressBook == null){
                throw new CustomerException("用户地址信息有误,不能下单");
            }
    
            long orderId = IdWorker.getId();//订单号
    
            //原子操作,保证线程安全
            AtomicInteger amount = new AtomicInteger(0);
    
            List<OrderDetail> orderDetails = shoppingCarts.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表插入数据,一条数据
            orders.setId(orderId);
            orders.setOrderTime(LocalDateTime.now());
            orders.setCheckoutTime(LocalDateTime.now());
            orders.setStatus(2);
            orders.setAmount(new BigDecimal(amount.get()));//总金额
            orders.setUserId(currentId);
            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);
    
            //向order_detail表插入数据,多条数据
            orderDetailService.saveBatch(orderDetails);
    
            //清空购物车数据
            shoppingCartService.remove(queryWrapper);
        }
    }
    
    

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

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

相关文章

《绝区零》是一款什么类型的游戏,Mac电脑怎么玩《绝区零》苹果电脑玩游戏怎么样

米哈游的《绝区零》最近在网上爆火呀&#xff0c;不过很多人都想知道mac电脑能不能玩《绝区零》&#xff0c;今天麦麦就给大家介绍一下《绝区零》是一款什么样的游戏&#xff0c;Mac电脑怎么玩《绝区零》。 一、《绝区零》是一款什么样的游戏 《绝区零》是由上海米哈游自主研发…

求立方体面积体积以及判断(c++)

代码&#xff1a; #include<iostream> using namespace std;class Cube { public:void setL(int l){m_L l;}int getL(){return m_L;}void setW(int w){m_W w;}int getW(){return m_W;}void setH(int h){m_H h;}int getH(){return m_H;}int calculateS(){return 2 * (…

使用jenkins进行自动化部署

记录一下查看的文档和遇到的坑 什么是jenkins Jenkins是一个开源的持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;工具&#xff0c;主要用于自动化软件开发的各个阶段&#xff0c;包括构建、测试、部署等。 Jenkins基于Java开发&#xff0c;支持与…

【数据集处理工具】将COCO格式数据集的val.json与tett.json文件合并为一个json

合并COCO数据集JSON文件的Python脚本 1、目的2、功能概述3、使用方法4、注意事项5、 代码部分 1、目的 此Python脚本旨在帮助用户合并多个COCO格式的数据集JSON文件&#xff0c;特别适用于将验证集和测试集的标注数据整合到单一文件中。 该脚本假设各个数据集的类别信息&…

OpenCV中的GrabCut图像分割算法的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 功能描述 GrabCut 算法是一种用于图像分割的技术&#xff0c;由 Carsten Rother、Vladimir Kolmogorov 和 Andrew Blake 在 2004 年 SIGGRAPH 会议的论文《…

Pr 2024下载安装,Adobe Premiere pro2024剪辑软件下载合集获取

Premiere Pro 2023中文版简称Pr&#xff0c;pr2023是一款视频编辑软件。 pr 2023不仅可以帮助用户对各种视频进行剪辑、旋转、分割、合并、字幕添加、背景音乐等基础的处理&#xff0c;还能帮助用户进行视频颜色校正、颜色分级、稳定镜头、调整层、更改片段的持续时间和速度、效…

软件架构之基于中间件开发

软件架构之基于中间件开发 第 15 章&#xff1a;基于中间件的开发15.1 中间件技术15.1.1 中间件的概念15.1.2 中间件的分类 15.1.3 中间件产品介绍15.2 应用服务器技术15.2.1 应用服务器的概念15.2.2 主要的应用服务器15.3.1 表示层15.3.2 应用服务层 15.4 .NET15.4.1 .NET 平台…

LeetCode热题100刷题16:74. 搜索二维矩阵、33. 搜索旋转排序数组、153. 寻找旋转排序数组中的最小值、98. 验证二叉搜索树

74. 搜索二维矩阵 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int row matrix.size();int col matrix[0].size();for(int i0;i<row;i) {//先排除一下不存在的情况if(i>0&&matrix[i][0]>target…

自动驾驶车道线检测系列—3D-LaneNet: End-to-End 3D Multiple Lane Detection

文章目录 1. 摘要概述2. 背景介绍3. 方法3.1 俯视图投影3.2 网络结构3.2.1 投影变换层3.2.2 投影变换层3.2.3 道路投影预测分支 3.3 车道预测头3.4 训练和真实值关联 4. 实验4.1 合成 3D 车道数据集4.2 真实世界 3D 车道数据集4.3 评估结果4.4 评估图像仅车道检测 5. 总结和讨论…

技能 | postman接口测试工具安装及使用

哈喽小伙伴们大家好!今天来给大家分享一款轻量级,高效好用的接口测试工具-postman. Postman是一个流行的API开发工具&#xff0c;主要用于测试、开发和文档化API。以下是关于Postman的介绍及其主要使用场景&#xff1a; Postman介绍&#xff1a; 1. 功能丰富的API客户端&#…

【14】Github Copilot环境搭建

环境搭建 这里以Visual Studio Code为例&#xff0c;安装好vs code&#xff0c;打开扩展侧边菜单栏&#xff0c;搜索“Github Copilot”&#xff0c;会出现如下图的两个插件&#xff0c;点击安装第一个&#xff0c;另一个会附带一起安装&#xff0c;然后弹出提示重新启动vs co…

怎么调整硬盘分区?让电脑运行更加高效!

硬盘分区是电脑存储管理的重要组成部分&#xff0c;合理的分区设置不仅能提高数据管理的效率&#xff0c;还能在一定程度上提升系统的运行性能。然而&#xff0c;随着使用需求的变化&#xff0c;我们可能需要对已有的硬盘分区进行调整。那么&#xff0c;我们该怎么调整硬盘分区…

zookeeper+kafka消息队列群集部署

消息队列(Message Queue)&#xff0c;是分布式系统中重要的组件&#xff0c;其通用的使用场景可以简单地描述为:当不需要立即获得结果&#xff0c;但是并发量又需要进行控制的时候&#xff0c;差不多就是需要使用消息队列的时候。 一、消息队列 1.什么是消息队列 消息(Messag…

Windows命令行(CMD)中,tasklist | findstr(搜索并显示包含特定字符串的进程信息)

文章目录 示例注意事项示例&#xff1a;使用 /FI 选项过滤进程 在Windows命令行&#xff08;CMD&#xff09;中&#xff0c; tasklist 命令用于显示当前运行的进程列表&#xff0c;而 findstr 命令则用于搜索字符串。当你将 tasklist 命令的输出通过管道&#xff08; |&…

支持大量边缘盒子集中管理调度的智慧物流开源了。

智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用户只需在界面上…

解读|http和https的区别,谁更好用

在日常我们浏览网页时&#xff0c;有些网站会看到www前面是http&#xff0c;有些是https&#xff0c;这两种有什么区别呢&#xff1f;为什么单单多了“s”&#xff0c;会有人说这个网页会更安全些&#xff1f; HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;…

【芯片设计- RTL 数字逻辑设计入门 9.1 -- CRG模块】

请阅读【芯片设计 RTL 数字逻辑设计扫盲 】 转自&#xff1a;芯片设计基础 – CRG模块 文章目录 CRG模块CRG时钟系统CRG复位系统同步复位同步复位的优点同步复位的缺点 异步复位异步复位的优点异步复位的缺点 异步复位同步释放 CRG模块 CRG是芯片里的时钟和复位生成模块&#…

Databend 开源周报第 153 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend。 支持必须更改密码…

npm 报错Error: EEXIST: file already exists, mkdir ‘C:\Windows\System32\cmd.exe‘

npm 报错Error: EEXIST: file already exists, mkdir C:\Windows\System32\cmd.exe 不管输npm 什么命令都报这个错&#xff1a; 报错图&#xff1a; 网上说恢复操作系统&#xff0c;最后定位为应该是配置问题&#xff0c; 我是配置问题 网上查了&#xff0c;最后定位为配置问…

【Mamba】Mamba的部署

ubuntu系统安装11.6版本的cuda 可以参考这两篇博客 ubuntu22.04多版本安装cuda及快速切换&#xff08;cuda11.1和11.8&#xff09;_ubuntu调整cuda版本 【Linux】在一台机器上同时安装多个版本的CUDA&#xff08;切换CUDA版本&#xff09;_linux安装多个cuda 安装CUDA https…