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

在这里插入图片描述

文章目录

  • 瑞吉外卖 — 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);
        }
    }
    
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java实验4

实验内容 考试题 要求在一个界面内至少显示5道选择题&#xff0c;每道题4个选项。题目从数据库读取。表结构自定义。 另有2个命令按钮&#xff0c;分别为“重新答题”&#xff08;全部选项及正确答题数清空&#xff09;和“提交”&#xff08;计算&#xff09;&#xff0c;在…

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

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

27.js实现鼠标拖拽

e.offsetX是鼠标距离准确事件源的左上角距离 e.clientX是鼠标距离浏览器可视窗口左上角的距离 e.pageX是鼠标距离文档左上角的距离 /* 当鼠标点击div时开始挪动&#xff0c;当鼠标抬起&#xff0c;div静止——事件源是div 当鼠标点击后,鼠标在移动——事件源…

Web开发:卡片翻转效果(HTML、CSS)

目录 一、实现效果 二、完整代码 三、实现过程 1、页面结构 2、初始样式 3、翻转效果 4、图片大小问题 一、实现效果 如下图所示&#xff0c;当鼠标移入某个盒子&#xff0c;就反转这个盒子&#xff0c;并显示其背面的内容——卡片翻转效果&#xff1b; 卡片翻转效果 二…

【STM32 IDE】使用STM32CubeIDE创建一个工程

关于IDE的下载安装和环境配置这里暂且不介绍&#xff0c;我们直接使用STM32F407ZGT6创建工程。 这里需要注意两点&#xff1a; 创建工程时&#xff0c;默认使用最新版本的固件包&#xff08;HAL库&#xff09;&#xff0c;好像还不让更改。如果本地电脑位置没有该版本的包&…

webpack优化

优化方向 热更新 概念 /** hmr: hot module replacement 热模块替换 / 模块热更新作用&#xff1a; 一个模块发生改变&#xff0c;只会重新打包这一个模块&#xff08;而不是打包所有模块&#xff09;&#xff0c;极大的提升了构建速度样式文件&#xff1a; 可以使用hmr功能…

防火墙-NAT策略和智能选路

一、背景技术 在日常网络环境&#xff0c;内部网络想要访问外网无法直接进行通信&#xff0c;这时候就需要进行NAT地址转换&#xff0c;而在防火墙上配置NAT和路由器上有点小区别&#xff0c;思路基本一致&#xff0c;这次主要就以防火防火墙配置NAT策略为例&#xff0c;防火墙…

【学习css3】使用flex和grid实现等高元素布局

过往的实现方法是使用浮动加计算布局来实现&#xff0c;当flex和grid问世时&#xff0c;这一切将变得简单起来 一、简单的两列实现 1、先看页面效果 2、css代码 .container {padding: 10px;width: 100ch;margin: 0 auto;box-shadow: inset 0 0 0 2px #ccc;}.column {margin: 2…

git clone 报错 Unable to negotiate

Unable to negotiate with 192.168.110.10 port 39418: no matching cipher found. Their offer: aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc fatal: Could not read from remote repository. 查询支持哪些加密算法 ssh -Q cipher 修改文件 /etc/ssh/ssh_config…

AR0132AT 1/3 英寸 CMOS 数字图像传感器(AR0132AT6R、AR0132AT6C)适用于监控和高清视频等多种应用

AR0132AT 1/3 英寸 CMOS 数字图像传感器&#xff0c;带 1280H x 960V 有效像素阵列。它能在线性或高动态模式下捕捉图像&#xff0c;且带有卷帘快门读取。它包含了多种复杂的摄像功能&#xff0c;如自动曝光控制、开窗&#xff0c;以及视频和单帧模式。它适用于低光度和高动态范…

基于AT89C51单片机构造波形发生器设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机构造波形发生器设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 摘要 仿真图 总体结构框图 仿真程序效果图 原理图 代码 系统论文&#xff08;部分&…

Qcom平台通过Hexagon IDE 测试程序性能指导

Qcom平台通过Hexagon IDE 测试程序性能指导 1 安装Hexagon IDE工具2 测试工程2.1 打开Hexagon IDE2.2 新建工程2.3 添加测试案例2.3.1 方法一&#xff1a;新建2.3.2 方法二&#xff1a;拷贝 2.4 配置测试环境2.4.1 包含头文件2.4.2 添加程序优化功能(需先bulid一下)2.4.3 添加g…

【14】Github Copilot环境搭建

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

阿里云CDN- https(设计支付宝春节开奖业务)

HTTP相关概念 1. HTTP概述 http是最广泛的网络协议&#xff0c;是客户端与服务器之间的请求与应答的标准&#xff08;TCP&#xff09;&#xff0c;用于www服务器传输超文本到本地浏览器的传输协议&#xff0c;使浏览器更加高效&#xff0c;网络传输减少。 2.HTTPS概述 http…

OpenHarmony移植之编译工具链

OpenHarmony移植之编译工具链 1、下载工具链 选择适合自己芯片的arm编译工具链&#xff0c;因为我的是arm cortex-a9的芯片&#xff0c;所以我选择如下交叉工具链 Downloads | GNU-A Downloads – Arm DeveloperDownload the The GNU Toolchain for the Cortex-A Family are…

稀疏3D检测-Sparse4Dv1v2v3

0. Multi-view 3D detection LSS(Lift-Splat-Shoot)利用深度估计将图像特征提升到3D空间&#xff0c;并将特征拍到BEV平面。后续工作将lift-splats操作应用于3D检测领域。 Bevformer将时序信息以BEV特征cat一起引入时序信息。 DETR3D中通过预测的3D点投影到图像平面后获取图像…

HTTPS请求头缺少HttpOnly和Secure属性解决方案

问题描述&#xff1a; 建立Filter拦截器类 package com.ruoyi.framework.security.filter;import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.…

vue仿甘特图开发工程施工进度表

前言 本文是根据项目实际开发中一个需求开发的demo&#xff0c;仅用了elementUI&#xff0c;可当作独立组件使用&#xff0c;C V即用。 当然没考虑其他的扩展性和一些数据的校验&#xff0c;主要是提供一个处理思路&#xff0c;有需要的小伙伴可以直接复制&#xff1b;本demo的…

厂家置换电费如何达到最大化收益

新能源行业知识体系-------主目录-----持续更新https://blog.csdn.net/grd_java/article/details/140004020 文章目录 一、电能电费二、同时刻不同厂家置换&#xff0c;不会影响最终电能电费结果三、风险防范补偿和回收机制四、我们的数据如何考虑补偿和回收五、如何利用补偿和…

K8S私有云裸金属服务器负载均衡器OpenELB——筑梦之路

OpenELB介绍 OpenELB 是一个专为裸机 Kubernetes 集群设计的开源负载均衡器实现。 在云服务环境中的 Kubernetes 集群里&#xff0c;通常可以用云服务提供商提供的负载均衡服务来暴露 Service&#xff0c;但是在本地没办法这样操作。而 OpenELB 可以让用户在裸金属服务器、边缘…