瑞吉外卖项目2

目录

六、菜品模块

1.文件上传

2.新增菜品

2.1.引入文件

2.2.菜品分类菜单下拉

2.3.引入dto

2.4.编写代码

3.分页查询菜品

4.修改菜品

4.1.回显页面

4.2.确定修改菜品

七、套餐模块

1.引入文件

2.新建套餐

3.分页查询套餐

4.删除套餐

5.修改套餐

5.1.套餐的启售和停售

5.2.套餐回显

5.3.套餐修改

八、短信模块

1.阿里云

2.引入文件

2.1.短信

2.2.实体类

3.完善代码

4.获取短信

九、移动端开发

1.地址模块

2.菜品模块

3.购物车模块

3.1.引入文件

3.2.添加购物车

3.5.删除购物车食物数量

4.订单模块

4.1.引入文件

4.2.代码


本项目来自哔哩哔哩-黑马程序员icon-default.png?t=N7T8https://www.bilibili.com/video/BV13a411q753/?spm_id_from=333.337.search-card.all.click&vd_source=444d080d8d83e3a8f6c0ff7ce6c8a075上一篇-瑞吉外卖1icon-default.png?t=N7T8https://blog.csdn.net/m0_56562712/article/details/133465282?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22133465282%22%2C%22source%22%3A%22m0_56562712%22%7D

六、菜品模块

1.文件上传

引入文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传</title>
  <!-- 引入样式 -->
  <link rel="stylesheet" href="../../plugins/element-ui/index.css" />
  <link rel="stylesheet" href="../../styles/common.css" />
  <link rel="stylesheet" href="../../styles/page.css" />

  <link rel="shortcut icon" href="../../favicon.ico">
</head>
<body>
   <div class="addBrand-container" id="food-add-app">
    <div class="container">
        <el-upload class="avatar-uploader"
                action="/common/upload"
                :show-file-list="false"
                :on-success="handleAvatarSuccess"
                :before-upload="beforeUpload"
                ref="upload">
            <img v-if="imageUrl" :src="imageUrl" class="avatar"></img>
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
    </div>
  </div>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="../../plugins/vue/vue.js"></script>
    <!-- 引入组件库 -->
    <script src="../../plugins/element-ui/index.js"></script>
    <!-- 引入axios -->
    <script src="../../plugins/axios/axios.min.js"></script>
    <script src="../../js/index.js"></script>
    <script>
      new Vue({
        el: '#food-add-app',
        data() {
          return {
            imageUrl: ''
          }
        },
        methods: {
          handleAvatarSuccess (response, file, fileList) {
              this.imageUrl = `/common/download?name=${response.data}`
          },
          beforeUpload (file) {
            if(file){
              const suffix = file.name.split('.')[1]
              const size = file.size / 1024 / 1024 < 2
              if(['png','jpeg','jpg'].indexOf(suffix) < 0){
                this.$message.error('上传图片只支持 png、jpeg、jpg 格式!')
                this.$refs.upload.clearFiles()
                return false
              }
              if(!size){
                this.$message.error('上传文件大小不能超过 2MB!')
                return false
              }
              return file
            }
          }
        }
      })
    </script>
</body>
</html>

在application.yml中添加路径

reggie:
  path: C:\0DW8W8W8\Computer\date\

新建图片控制类

package com.zaixial.reggie.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;

/**
 * 文件上传和下载
 */
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {

    // 引入路径
    @Value("${reggie.path}")
    private String basePath;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile 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) {
            e.printStackTrace();
        }

        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 servletOutputStream = response.getOutputStream();

            // 设置输出文件的类型
            response.setContentType("image/jpeg");

            int len = 0;
            byte[] bytes = new byte[1024];
            // 读
            while ((len = fileInputStream.read(bytes)) != -1) {
                // 写
                servletOutputStream.write(bytes, 0, len);
                // 刷新
                servletOutputStream.flush();
            }

            // 关闭资源
            fileInputStream.close();
            servletOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.新增菜品

2.1.引入文件

DishFlavor
package com.zaixial.reggie.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
菜品口味
 */
@Data
public class DishFlavor implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //菜品id
    private Long dishId;


    //口味名称
    private String name;


    //口味数据list
    private String value;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;

}
DishFlavorMapper
package com.zaixial.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zaixial.reggie.entity.DishFlavor;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
}
DishFlavorService
package com.zaixial.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zaixial.reggie.entity.DishFlavor;

public interface DishFlavorService extends IService<DishFlavor> {
}
DishFlavorServiceImpl
package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.entity.DishFlavor;
import com.zaixial.reggie.mapper.DishFlavorMapper;
import com.zaixial.reggie.service.DishFlavorService;
import org.springframework.stereotype.Service;

@Service
public class DishFlavorServiceImpl extends ServiceImpl<DishFlavorMapper,DishFlavor> implements DishFlavorService {
}
DishController
package com.zaixial.reggie.controller;

import com.zaixial.reggie.service.DishFlavorService;
import com.zaixial.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 菜品管理
 */
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {
    @Autowired
    private DishService dishService;

    @Autowired
    private DishFlavorService dishFlavorService;
}

2.2.菜品分类菜单下拉

在CategoryController中添加

/**
     * 根据条件查询分类数据
     * @param category
     * @return
     */
    @GetMapping("/list")
    public R<List<Category>> list(Category category) {
        // 条件构造器
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        // 添加条件
        queryWrapper.eq(category.getType() != null, Category::getType, category.getType());
        // 添加排序条件
        queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);

        List<Category> list = categoryService.list(queryWrapper);
        return R.success(list);
    }

2.3.引入dto

package com.zaixial.reggie.dto;

import com.zaixial.reggie.entity.Dish;
import com.zaixial.reggie.entity.DishFlavor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;

@Data
public class DishDto extends Dish {

    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}

2.4.编写代码

业务层

package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.dto.DishDto;
import com.zaixial.reggie.entity.Dish;
import com.zaixial.reggie.entity.DishFlavor;
import com.zaixial.reggie.mapper.DishMapper;
import com.zaixial.reggie.service.DishFlavorService;
import com.zaixial.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;

@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper,Dish> implements DishService {

    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 新增菜品,同时保证口味数据
     * @param dishDto
     */
    @Transactional
    public void saveWithFlavor(DishDto dishDto) {
        // 保存菜品的基本信息到菜品表
        this.save(dishDto);

        // 获取菜品id
        Long dishId = dishDto.getId();

        // 菜品口味
        List<DishFlavor> flavors = dishDto.getFlavors();

        // 给每个菜品口味附上id
        flavors = flavors.stream().map((item) -> {
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());

        // 保存菜品口味数据到菜品口味表
        dishFlavorService.saveBatch(flavors);
    }
}

表示层

package com.zaixial.reggie.controller;

import com.zaixial.reggie.common.R;
import com.zaixial.reggie.dto.DishDto;
import com.zaixial.reggie.service.DishFlavorService;
import com.zaixial.reggie.service.DishService;
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;

/**
 * 菜品管理
 */
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {
    @Autowired
    private DishService dishService;

    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 新增菜品
     * @param dishDto
     * @return
     */
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto) {

        log.info("新增菜品:{}", dishDto);

        dishService.saveWithFlavor(dishDto);

        return R.success("新增菜品成功");
    }
}

2.5.测试

3.分页查询菜品

DishController
    /**
     * 菜品信息分页查询
     * dish = 菜品, dishdto = 菜品 + 忌口
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name) {
        // 构造分页构造器对象
        Page<Dish> dishPage = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>(page, pageSize);
        // 条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.like(name != null, Dish::getName, name);
        // 添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        // 执行分页查询
        dishService.page(dishPage, queryWrapper);

        // 取出dishs
        List<Dish> records = dishPage.getRecords();
        // 获取每一个dish
        List<DishDto> list = records.stream().map((item) -> {
            // 从dish获取到分类的id
            Long categoryId = item.getCategoryId();
            // 根据从dish获取的id查询菜品分类的对象
            Category category = categoryService.getById(categoryId);
            // 获取对应dish的id的菜品分类名
            String categoryName = category.getName();

            // 新建dishdto对象
            DishDto dishDto = new DishDto();
            // 将dish的数据拷贝到dishdto中
            BeanUtils.copyProperties(item, dishDto);
            // 把名字传回dish中
            dishDto.setCategoryName(categoryName);

            return dishDto;
        }).collect(Collectors.toList());

        // dish的构造器对象的数据拷贝到dishdto的构造器对象中
        BeanUtils.copyProperties(dishPage, dishDtoPage, "records");
        // 抓取菜品分类数据
        dishDtoPage.setRecords(list);

        return R.success(dishDtoPage);
    }

4.修改菜品

4.1.回显页面

DishServiceImpl
/**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    @Override
    public DishDto getByIdWhithFlavor(Long id) {
        // 查询菜品基本信息,从dish中查询
        Dish dish = this.getById(id);
        // 新建dishdto
        DishDto dishDto = new DishDto();
        // 拷贝
        BeanUtils.copyProperties(dish, dishDto);

        // 查口味信息 条件构造器
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(DishFlavor::getDishId, dish.getId());
        // 输出查到的数据
        List<DishFlavor> list = dishFlavorService.list(queryWrapper);
        // 将口味数据放到dishdto中
        dishDto.setFlavors(list);

        return dishDto;
    }

4.2.确定修改菜品

DishServiceImpl
    /**
     * 更新菜品信息,同时更新口味信息
     * @param dishDto
     */
    @Override
    @Transactional
    public void updateWithFlavor(DishDto dishDto) {
        // 更新dish表的基本信息
        this.updateById(dishDto);
        // 清理全部口味
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorService.remove(queryWrapper);

        // 添加新口味
        List<DishFlavor> flavors = dishDto.getFlavors();

        // 给每个菜品口味附上id
        flavors.stream().map((item) -> {
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());
        dishFlavorService.saveBatch(flavors);
    }
DishController
    /**
     * 修改菜品
     * @param dishDto
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto) {
        log.info("修改菜品:{}", dishDto);
        dishService.updateWithFlavor(dishDto);
        return R.success("修改菜品成功");
    }

七、套餐模块

1.引入文件

SetmealDish
package com.zaixial.reggie.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 套餐菜品关系
 */
@Data
public class SetmealDish implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //套餐id
    private Long setmealId;


    //菜品id
    private Long dishId;


    //菜品名称 (冗余字段)
    private String name;

    //菜品原价
    private BigDecimal price;

    //份数
    private Integer copies;


    //排序
    private Integer sort;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;
}
SetmealDto
package com.zaixial.reggie.dto;

import com.zaixial.reggie.entity.Setmeal;
import com.zaixial.reggie.entity.SetmealDish;
import lombok.Data;
import java.util.List;

@Data
public class SetmealDto extends Setmeal {

    private List<SetmealDish> setmealDishes;

    private String categoryName;
}
SetmealDishMapper
package com.zaixial.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zaixial.reggie.entity.SetmealDish;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}
SetmealDishService
package com.zaixial.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zaixial.reggie.entity.SetmealDish;

public interface SetmealDishService extends IService<SetmealDish> {
}
SetmealDishServiceImpl
package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.entity.SetmealDish;
import com.zaixial.reggie.mapper.SetmealDishMapper;
import com.zaixial.reggie.service.SetmealDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper,SetmealDish> implements SetmealDishService {
}
SetmealController
package com.zaixial.reggie.controller;

import com.zaixial.reggie.service.CategoryService;
import com.zaixial.reggie.service.SetmealDishService;
import com.zaixial.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 套餐管理
 */

@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {

    @Autowired
    private SetmealService setmealService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SetmealDishService setmealDishService;

}

2.新建套餐

SetmealServiceImpl
    /**
     * 新建套餐 保证关系
     * @param setmealDto
     */
    @Override
    public void saveWithDish(SetmealDto setmealDto) {
        // 保存基本信息到套餐表
        this.save(setmealDto);

        // 获取套餐id
        Long id = setmealDto.getId();

        // 获取套餐和菜品关系表
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();

        setmealDishes = setmealDishes.stream().map(itme -> {
            // 给关系表附上套餐id
            itme.setSetmealId(id);
            return itme;
        }).collect(Collectors.toList());

        // 将关系表保存
        setmealDishService.saveBatch(setmealDishes);
    }

3.分页查询套餐

SetmealController
    /**
     * 分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name) {
        // 分页构造器对象
        Page<Setmeal> setmealPage = new Page<>(page, pageSize);
        // 查询构造器
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件
        queryWrapper.like(name != null, Setmeal::getName, name);
        // 添加条件
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
        // page
        setmealService.page(setmealPage, queryWrapper);

        // 新建套餐表
        List<SetmealDto> list = new ArrayList<>();

        // 取出套餐表
        List<Setmeal> records = setmealPage.getRecords();
        // 遍历套餐表
        records = records.stream().map(itme -> {
            // 新建dto
            SetmealDto setmealDto = new SetmealDto();

            // 把套餐表数据复制到dto中
            BeanUtils.copyProperties(itme, setmealDto);

            // 取出套餐分类id
            Long categoryId = itme.getCategoryId();
            // 根据套餐id查套餐数据
            Category serviceById = categoryService.getById(categoryId);
            // 取到套餐名
            String serviceByIdName = serviceById.getName();
            // 把套餐名放到dto
            setmealDto.setCategoryName(serviceByIdName);
            // 放到套餐表里
            list.add(setmealDto);

            return itme;
        }).collect(Collectors.

4.删除套餐

SetmealServiceImpl
    /**
     * 删除套餐,同时删除有关的菜品数据
     * @param ids
     */
    @Override
    @Transactional
    public void removeWithDish(List<Long> ids) {
        // select count(*) form setmeal where id in (1,2) and status = 1
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Setmeal::getId, ids);
        queryWrapper.eq(Setmeal::getStatus, 1);

        //查询套餐状态,确定是否可以删除
        int count = this.count(queryWrapper);
        // 如果不能删除就抛异常
        if (count > 0) throw new CustomException("套餐正在售卖,不能删除");

        // 如果可以删除,先删除套餐表中的数据
        this.removeByIds(ids);

        // delete from setmeal_dish where setmeal id in (1,2)
        LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SetmealDish::getSetmealId, ids);

        // 删除关系表
        setmealDishService.remove(lambdaQueryWrapper);
    }

5.修改套餐

5.1.套餐的启售和停售

SetmealController
    /**
     * 停售启售
     * 用PathVariable获取路径的值,0代表停售,1代表启售
     * @param ids
     * @return
     */
    @PostMapping("/status/{status}")
    public R<String> status(@PathVariable("status") Integer status ,@RequestParam List<Long> ids) {
        log.info("停售:{}", ids);
        // 构造查询条件
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Setmeal::getId, ids);
        // 获取数据
        List<Setmeal> setmeals = setmealService.list(queryWrapper);
        // 流
        setmeals = setmeals.stream().map((item -> {
            // 设置状态
            item.setStatus(status);
            setmealService.updateById(item);
            return item;
        })).collect(Collectors.toList());

        return R.success("状态设置成功");
    }

5.2.套餐回显

SetmealServiceImpl
    /**
     * 修改前的数据回显
     * 根据id查询套餐信息
     * @param id
     * @return
     */
    @Override
    public SetmealDto get(Long id) {
        // 查询套餐数据
        Setmeal setmeal = this.getById(id);

        // 新建套餐dto
        SetmealDto setmealDto = new SetmealDto();
        // 拷贝
        BeanUtils.copyProperties(setmeal, setmealDto);

        // 查询套餐下的菜品
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SetmealDish::getSetmealId, id);
        List<SetmealDish> list = setmealDishService.list(queryWrapper);

        // 把套餐下的菜品放到套餐dto中
        setmealDto.setSetmealDishes(list);

        return setmealDto;
    }

5.3.套餐修改

SetmealServiceImpl
    /**
     * 套餐修改
     * @param setmealDto
     * @return
     */
    @Override
    @Transactional
    public void updateWithDish(SetmealDto setmealDto) {
        // 更新套餐信息
        this.updateById(setmealDto);
        // 获取套餐id
        Long setmealId = setmealDto.getId();

        // 过滤出原先的套餐-菜品表里被操作的数据
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SetmealDish::getSetmealId, setmealId);
        // 删除数据
        setmealDishService.remove(queryWrapper);

        // 获取要修改套餐-菜品表
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        // 把数据id修改一下
        setmealDishes = setmealDishes.stream().map((item) -> {
            item.setSetmealId(setmealId);
            return  item;
        }).collect(Collectors.toList());
        // 保存进去
        setmealDishService.saveBatch(setmealDishes);
    }

八、短信模块

1.阿里云

注册

开启短信服务

申请签名

申请模板

AccessKey

子用户

创建用户

新增授权

添加2个SMS

2.引入文件

2.1.短信

依赖

<!--阿里云短信服务-->
        <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>
SMSUtils
package com.zaixial.reggie.Utils;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;

/**
 * 短信发送工具类
 */
public class SMSUtils {

	/**
	 * 发送短信
	 * @param signName 签名
	 * @param templateCode 模板
	 * @param phoneNumbers 手机号
	 * @param param 参数
	 */
	public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
		DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
		IAcsClient client = new DefaultAcsClient(profile);

		SendSmsRequest request = new SendSmsRequest();
		request.setSysRegionId("cn-hangzhou");
		request.setPhoneNumbers(phoneNumbers);
		request.setSignName(signName);
		request.setTemplateCode(templateCode);
		request.setTemplateParam("{\"code\":\""+param+"\"}");
		try {
			SendSmsResponse response = client.getAcsResponse(request);
			System.out.println("短信发送成功");
		}catch (ClientException e) {
			e.printStackTrace();
		}
	}

}
ValidateCodeUtils
package com.zaixial.reggie.Utils;

import java.util.Random;

/**
 * 随机生成验证码工具类
 */
public class ValidateCodeUtils {
    /**
     * 随机生成验证码
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer generateValidateCode(int length){
        Integer code =null;
        if(length == 4){
            code = new Random().nextInt(9999);//生成随机数,最大为9999
            if(code < 1000){
                code = code + 1000;//保证随机数为4位数字
            }
        }else if(length == 6){
            code = new Random().nextInt(999999);//生成随机数,最大为999999
            if(code < 100000){
                code = code + 100000;//保证随机数为6位数字
            }
        }else{
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 随机生成指定长度字符串验证码
     * @param length 长度
     * @return
     */
    public static String generateValidateCode4String(int length){
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        String capstr = hash1.substring(0, length);
        return capstr;
    }
}

2.2.实体类

user

package com.zaixial.reggie.entity;

import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
/**
 * 用户信息
 */
@Data
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //姓名
    private String name;


    //手机号
    private String phone;


    //性别 0 女 1 男
    private String sex;


    //身份证号
    private String idNumber;


    //头像
    private String avatar;


    //状态 0:禁用,1:正常
    private Integer status;
}
UserMapper
package com.zaixial.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zaixial.reggie.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User>{
}
UserService
package com.zaixial.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zaixial.reggie.entity.User;

public interface UserService extends IService<User> {
}
UserServiceImpl
package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.entity.User;
import com.zaixial.reggie.mapper.UserMapper;
import com.zaixial.reggie.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
}
UserController
package com.zaixial.reggie.controller;

import com.zaixial.reggie.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

}

3.完善代码

LoginCheckFilter
package com.zaixial.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.zaixial.reggie.common.BaseContext;
import com.zaixial.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;

@WebFilter(filterName = "LoginCheckFilter", urlPatterns = "/*")
@Slf4j
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 requestURI = request.getRequestURI();
        log.info("拦截到请求:{}", requestURI);
        String[] urls = new String[] {
                // 定义不需要处理的请求路径
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/common/**",
                "/user/sendMsg",// 移动端发生短信
                "/user/login"// 移动端登录
        };

        // 2.判断请求是否需要进行处理
        boolean check = check(urls, requestURI);

        // 3.如果不需要处理,直接放行
        if (check) {
            log.info("本次请求:{}不需要处理", requestURI);
            filterChain.doFilter(request, response);
            return;
        }

        // 4.1判断登录状态,如果登录了,直接放行
        Object empId = request.getSession().getAttribute("employee");
        if (empId != null) {
            log.info("用户已登录,登录id为:{}", empId);

            // 获取登录的id
            Long empIdL = (Long) request.getSession().getAttribute("employee");
            // 设置线程的id
            BaseContext.setCurrentId(empIdL);

            filterChain.doFilter(request, response);
            return;
        }

        // 4.2判断登录状态,如果登录了,直接放行
        Object userId = request.getSession().getAttribute("user");
        if (userId != null) {
            log.info("用户已登录,登录id为:{}", userId);

            // 获取登录的id
            Long userIdL = (Long) request.getSession().getAttribute("user");
            // 设置线程的id
            BaseContext.setCurrentId(userIdL);

            filterChain.doFilter(request, response);
            return;
        }



        log.info("用户未登录");

        // 5.如果未登录
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }

    /**
     * 路径匹配,是否要放行
     * @param urls
     * @param requestURI
     * @return
     */
    public boolean check(String[] urls, String requestURI) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if (match) return true;
        }
        return false;
    }
}

找到src/main/resources/front/page/login.html的66行注释掉然后自己添加一行

getCode(){
    this.form.code = ''
    const regex = /^(13[0-9]{9})|(15[0-9]{9})|(17[0-9]{9})|(18[0-9]{9})|(19[0-9]{9})$/;
    if (regex.test(this.form.phone)) {
        this.msgFlag = false
        //this.form.code = (Math.random()*1000000).toFixed(0)
        sendMsgApi({phone:this.form.phone})  //添加的
    }else{
        this.msgFlag = true
    }
},

还有75行

async btnLogin(){
                    if(this.form.phone && this.form.code){
                        this.loading = true
                        //const res = await loginApi({phone:this.form.phone})
                        const res = await loginApi(this.form)  //这里是自己加的
                        this.loading = false

然后找到src/main/resources/front/api/login.js在后面加上

function sendMsgApi(data){
    return $axios({
        'url':'/user/sendMsg',
        'method':'post',
        data
    })
}

4.获取短信

UserController
    /**
     * 发送手机短信验证码
     * @param user
     * @param session
     * @return
     */
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session) {
        // 获取手机号
        String phone = user.getPhone();

        if (StringUtils.isNotEmpty(phone)) {
            // 生成验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code:{}", code);

            // 阿里云发送
            //SMSUtils.sendMessage("瑞吉外卖", "SMS_288215545", phone, code);

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

            return R.success("手机验证码发送成功");
        }
        return R.error("发送失败");
    }
UserController
     /**
     * 移动端登录
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session) {
        // 获取手机号
        String phone = map.get("phone").toString();
        // 获取验证码
        Object code = map.get("code");
        // 从Session中保存的验证码
        Object codeS = session.getAttribute(phone);

        // 进行验证码对比
        if (codeS != null && codeS.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);
                userService.save(user);
            }

            // 保存用户登录状态
            session.setAttribute("user", user.getId());

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

九、移动端开发

1.地址模块

AddressBook
package com.zaixial.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 AddressBook implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //用户id
    private Long userId;


    //收货人
    private String consignee;


    //手机号
    private String phone;


    //性别 0 女 1 男
    private String sex;


    //省级区划编号
    private String provinceCode;


    //省级名称
    private String provinceName;


    //市级区划编号
    private String cityCode;


    //市级名称
    private String cityName;


    //区级区划编号
    private String districtCode;


    //区级名称
    private String districtName;


    //详细地址
    private String detail;


    //标签
    private String label;

    //是否默认 0 否 1是
    private Integer isDefault;

    //创建时间
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    //更新时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    //创建人
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    //修改人
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;
}
AddressBookMapper
package com.zaixial.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zaixial.reggie.entity.AddressBook;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AddressBookMapper extends BaseMapper<AddressBook> {

}
AddressBookService
package com.zaixial.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zaixial.reggie.entity.AddressBook;

public interface AddressBookService extends IService<AddressBook> {

}
AddressBookServiceImpl
package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.entity.AddressBook;
import com.zaixial.reggie.mapper.AddressBookMapper;
import com.zaixial.reggie.service.AddressBookService;
import org.springframework.stereotype.Service;

@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements AddressBookService {

}
AddressBookController
package com.zaixial.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zaixial.reggie.common.BaseContext;
import com.zaixial.reggie.common.R;
import com.zaixial.reggie.entity.AddressBook;
import com.zaixial.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;

/**
 * 地址簿管理
 */
@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.菜品模块

找到src/main/resources/front/api/main.js的30行修改

//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        //'url': '/shoppingCart/list',
        'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

cartData.json

{"code":1,"msg":null,"data":[],"map":{}}
DishController
/**
     * 根据条件查询对应的菜品数据
     * 这里可以传categoryId,这里直接使用dish类来接受
     * @param dish
     * @return
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        // 构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        // 添加分类条件
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
        // 添加条件,查询起售的菜品
        queryWrapper.eq(Dish::getStatus,1);
        // 添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        // 取出菜品
        List<Dish> list = dishService.list(queryWrapper);
        
        List<DishDto> listD = new ArrayList<>();

        // 进行集合的泛型转化
        List<DishDto> dishDtoList = list.stream().map((item) ->{
            // 创建dto
            DishDto dishDto = new DishDto();
            // 复制到dto
            BeanUtils.copyProperties(item,dishDto);
            // 取出分类id
            Long categoryId = item.getCategoryId();
            // 新建分类实体类
            Category category = categoryService.getById(categoryId);
            
            // 将分类名给dto
            if (category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
           
            // 获取菜品id
            Long dishId = item.getId();
            // 构造器
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper();
            // 添加id条件
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            // select * from dish_flavor where dish_id = ?
            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            // 将口味表放到dto
            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.引入文件

ShoppingCart
package com.zaixial.reggie.entity;

import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 购物车
 */
@Data
public class ShoppingCart implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    //名称
    private String name;

    //用户id
    private Long userId;

    //菜品id
    private Long dishId;

    //套餐id
    private Long setmealId;

    //口味
    private String dishFlavor;

    //数量
    private Integer number;

    //金额
    private BigDecimal amount;

    //图片
    private String image;

    private LocalDateTime createTime;
}
ShoppingCartMapper
package com.zaixial.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zaixial.reggie.entity.ShoppingCart;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {

}
ShoppingCartService
package com.zaixial.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zaixial.reggie.entity.ShoppingCart;

public interface ShoppingCartService extends IService<ShoppingCart> {

}
ShoppingCartServiceImpl
package com.zaixial.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zaixial.reggie.entity.ShoppingCart;
import com.zaixial.reggie.mapper.ShoppingCartMapper;
import com.zaixial.reggie.service.ShoppingCartService;
import org.springframework.stereotype.Service;

@Service
public class ShoppingCartServiceImpl extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {

}
ShoppingCartController
package com.zaixial.reggie.controller;

import com.zaixial.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 购物车
 */
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
public class ShoppingCartController {

    @Autowired
    private ShoppingCartService shoppingCartService;


}

3.2.添加购物车

    /**
     * 添加购物车
     * @param shoppingCart
     * @return
     */
    @PostMapping("/add")
    public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart) {
        // 获取用户id
        Long currentId = BaseContext.getCurrentId();
        // 设置id
        shoppingCart.setUserId(currentId);

        // 获取菜品id
        Long dishId = shoppingCart.getDishId();

        // 把之前就在购物车的菜品添加进去
        LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,currentId);

        // 判断是否时菜品
        if (dishId != null) queryWrapper.eq(ShoppingCart::getDishId, dishId);
        else queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());

        // 查询当前菜品是否在购物车中
        ShoppingCart shoppingCartServiceOne = shoppingCartService.getOne(queryWrapper);

        if (shoppingCartServiceOne != null) {
            // 如果已经在购物车中 + 1
            Integer number = shoppingCartServiceOne.getNumber();
            shoppingCartServiceOne.setNumber(number + 1);
            shoppingCartService.updateById(shoppingCartServiceOne);
        } else {
            // 不存在就加
            shoppingCart.setNumber(1);
            shoppingCartService.save(shoppingCart);
            shoppingCartServiceOne = shoppingCart;
        }
        return R.success(shoppingCartServiceOne);
    }

3.3.查询购物车

找到src/main/resources/front/api/main.js的30行修改

//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        'url': '/shoppingCart/list',
        //'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

3.3.查看购物车

    /**
     * 查看购物车
     * @return
     */
    @GetMapping("/list")
    public R<List<ShoppingCart>> list(){
        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);
    }

3.4.清空购物车

     /**
     * 清空购物车
     * @return
     */
    @DeleteMapping("/clean")
    public R<String> clean(){
        //sql:delete from shopping_cart where userId =?
        LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
        shoppingCartService.remove(queryWrapper);

        return R.success("清空购物车成功");
    }

3.5.删除购物车食物数量

    /**
     * 客户端的套餐或者是菜品数量减少设置
     * 没必要设置返回值
     * @param shoppingCart
     */
    @PostMapping("/sub")
    @Transactional
    public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart){
 
        Long dishId = shoppingCart.getDishId();
        LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
 
        //代表数量减少的是菜品数量
        if (dishId != null){
            //通过dishId查出购物车对象
            queryWrapper.eq(ShoppingCart::getDishId,dishId);
            //这里必须要加两个条件,否则会出现用户互相修改对方与自己购物车中相同套餐或者是菜品的数量
            queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
            ShoppingCart cart1 = shoppingCartService.getOne(queryWrapper);
            cart1.setNumber(cart1.getNumber()-1);
            Integer LatestNumber = cart1.getNumber();
            if (LatestNumber > 0){
                //对数据进行更新操作
                shoppingCartService.updateById(cart1);
            }else if(LatestNumber == 0){
                //如果购物车的菜品数量减为0,那么就把菜品从购物车删除
                shoppingCartService.removeById(cart1.getId());
            }else if (LatestNumber < 0){
                return R.error("操作异常");
            }
 
            return R.success(cart1);
        }
 
        Long setmealId = shoppingCart.getSetmealId();
        if (setmealId != null){
            //代表是套餐数量减少
            queryWrapper.eq(ShoppingCart::getSetmealId,setmealId).eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
            ShoppingCart cart2 = shoppingCartService.getOne(queryWrapper);
            cart2.setNumber(cart2.getNumber()-1);
            Integer LatestNumber = cart2.getNumber();
            if (LatestNumber > 0){
                //对数据进行更新操作
                shoppingCartService.updateById(cart2);
            }else if(LatestNumber == 0){
                //如果购物车的套餐数量减为0,那么就把套餐从购物车删除
                shoppingCartService.removeById(cart2.getId());
            }else if (LatestNumber < 0){
                return R.error("操作异常");
            }
            return R.success(cart2);
        }
            //如果两个大if判断都进不去
            return R.error("操作异常");
    }

4.订单模块

4.1.引入文件

Orders
package com.zaixial.reggie.entity;

import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 订单
 */
@Data
public class Orders implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    //订单号
    private String number;

    //订单状态 1待付款,2待派送,3已派送,4已完成,5已取消
    private Integer status;


    //下单用户id
    private Long userId;

    //地址id
    private Long addressBookId;


    //下单时间
    private LocalDateTime orderTime;


    //结账时间
    private LocalDateTime checkoutTime;


    //支付方式 1微信,2支付宝
    private Integer payMethod;


    //实收金额
    private BigDecimal amount;

    //备注
    private String remark;

    //用户名
    private String userName;

    //手机号
    private String phone;

    //地址
    private String address;

    //收货人
    private String consignee;
}
OrderDetail
package com.zaixial.reggie.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;

/**
 * 订单明细
 */
@Data
public class OrderDetail implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    //名称
    private String name;

    //订单id
    private Long orderId;


    //菜品id
    private Long dishId;


    //套餐id
    private Long setmealId;


    //口味
    private String dishFlavor;


    //数量
    private Integer number;

    //金额
    private BigDecimal amount;

    //图片
    private String image;
}

4.2.代码

OrderServiceImpl
package com.zaixial.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.zaixial.reggie.common.BaseContext;
import com.zaixial.reggie.common.CustomException;
import com.zaixial.reggie.entity.*;
import com.zaixial.reggie.mapper.OrderMapper;
import com.zaixial.reggie.service.*;
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.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@Slf4j
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
    public void submit(Orders orders) {
        //获得当前用户id
        Long userId = BaseContext.getCurrentId();

        //查询当前用户的购物车数据
        LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ShoppingCart::getUserId,userId);
        List<ShoppingCart> shoppingCarts = shoppingCartService.list(wrapper);

        if(shoppingCarts == null || shoppingCarts.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 = 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.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(wrapper);
    }
}

瑞吉外卖3

后续请移步瑞吉外卖3icon-default.png?t=N7T8https://blog.csdn.net/m0_56562712/article/details/133748371?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22133748371%22%2C%22source%22%3A%22m0_56562712%22%7D

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值