瑞吉外卖 — 手机移动端业务开发

目录

手机验证码登录

短信发送

手机验证码登录

用户退出登录 

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

菜品展示 

点击套餐图片显示详细信息

购物车

加入购物车

减少商品数量

查看购物车

清空购物车

下单

用户下单

一个小bug:下单页面的地址显示

个人订单 

再来一单


手机验证码登录

瑞吉外卖 — 手机移动端业务开发_第1张图片瑞吉外卖 — 手机移动端业务开发_第2张图片

短信发送

短信服务介绍

目前市面上有很多第三方提供的短信服务,这些第三方短信服务会和各个运营商(移动、联通、电信)对接,
我们只需要注册成为会员并且按照提供的开发文档进行调用就可以发送短信。
需要说明的是,这些短信服务一般都是收费服务。
常用短信服务:
阿里云    华为云    腾讯云    京东    梦网    乐信

阿里云短信服务

瑞吉外卖 — 手机移动端业务开发_第3张图片

 瑞吉外卖 — 手机移动端业务开发_第4张图片

 瑞吉外卖 — 手机移动端业务开发_第5张图片

代码开发

使用阿里云短信服务发送短信,可以参照官方提供的文档即可
具体开发步骤
1、导入maven坐标
2、调用API

导入maven坐标 

        
            com.aliyun
            aliyun-java-sdk-core
            4.5.16
        
        
            com.aliyun
            aliyun-java-sdk-dysmsapi
            2.1.0
        

 瑞吉外卖 — 手机移动端业务开发_第6张图片

手机验证码登录

需求分析

瑞吉外卖 — 手机移动端业务开发_第7张图片

数据模型

瑞吉外卖 — 手机移动端业务开发_第8张图片

代码开发

瑞吉外卖 — 手机移动端业务开发_第9张图片

 瑞吉外卖 — 手机移动端业务开发_第10张图片

 瑞吉外卖 — 手机移动端业务开发_第11张图片

 瑞吉外卖 — 手机移动端业务开发_第12张图片

注意,资料里的login.html代码不完整,去补全
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
            }
}

在对应的login.js里添加方法
function sendMsgApi(data) {
    return $axios({
        'url': '/user/sendMsg',
        'method': 'post',
        data
    })
}
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 发送手机验证码
     *
     * @param user
     * @param request
     * @return
     */
    @PostMapping("/sendMsg")
    public R sendMsg(@RequestBody User user, HttpServletRequest request) {

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

        //手机号不为空
        if (StringUtils.isNotEmpty(phone)) {
            //生成随机的4位验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();

            log.info("code={}", code);

            //调用阿里云的短信服务API完成发送的短信
            //短信签名名称  短信模板CODE  接收短信的手机号码  验证码
            //SMSUtils.sendMessage("瑞吉外卖", "", phone, code);

            //将要生成的验证码保存到Session
            request.getSession().setAttribute(phone, code);
            return R.success("短信验证码发送成功");
        }
        return R.success("短信验证码发送失败");
    }
}

 登录

请求网址: http://localhost:8080/user/login
请求方法: POST
发送登录请求时携带回来的参数只有phone,查看前端代码,修改参数
将async btnLogin()方法里的
//const res = await loginApi({phone:this.form.phone}) 修改成
const res = await loginApi(this.form)

请求的JSON数据:
{
  "phone": "13423232323",
  "code": "132"
}

思考后端的表现层使用什么类型来接收请求的数据?
user?  不行,User类里面只有phone,没有code
两种解决方式
1、创建dto继承User这个类,添加code属性
2、使用map接收,键值对的形式
    /**
     * 移动端登录
     *
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R login(@RequestBody Map map, HttpSession session) {
        log.info(map.toString());

        //获取手机号
        String phone = map.get("phone").toString();

        //获取验证码
        String code = map.get("code").toString();

        //从session中获取保存的验证码
        Object codeInSession = session.getAttribute(phone);

        //进行验证码比对(session中保存的验证码和页面提交的验证码)
        if (codeInSession != null && codeInSession.equals(code)){
            //如果比对成功,说明登录成功
            //判断当前手机号是否为新用户,如果是新用户就自动完成注册
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
            //select * from User where user_phone = phone
            queryWrapper.eq(User::getPhone,phone);

            User user = userService.getOne(queryWrapper);
            if (user == null){
                //进行新用户注册
                user = new User();
                user.setPhone(phone);
                //可设置也可不设置
                user.setStatus(1);
                userService.save(user);//添加用户
            }
            //保存用户登录状态,将用户id存储进Session,用于判断用户是否登录,放行拦截
            session.setAttribute("user",user.getId());
            return R.success(user);
        }
            return R.error("登录失败");
    }

瑞吉外卖 — 手机移动端业务开发_第13张图片

用户退出登录 

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

需求分析

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

瑞吉外卖 — 手机移动端业务开发_第14张图片

数据模型

瑞吉外卖 — 手机移动端业务开发_第15张图片

导入功能代码

功能代码清单:
实体类AddressBook (直接从课程资料中导入即可)
Mapper接口 AddressBookMapper
业务层接口 AddressBookService
业务层实现类 AddressBookServiceImpl
控制层 AddressBookController (直接从课程资料中导入即可)
/**
 * 地址簿管理
 */
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {

    @Autowired
    private AddressBookService addressBookService;

    /**
     * 新增
     */
    @PostMapping
    public R save(@RequestBody AddressBook addressBook) {
        //获得当前登录的用户id
        addressBook.setUserId(BaseContext.getCurrentId());
        log.info("addressBook:{}", addressBook);
        addressBookService.save(addressBook);
        return R.success(addressBook);
    }

    /**
     * 设置默认地址
     */
    @PutMapping("default")
    public R setDefault(@RequestBody AddressBook addressBook) {
        log.info("addressBook:{}", addressBook);
        LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
        //先将当前用户的所有默认地址改为0
        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 getDefault() {
        LambdaQueryWrapper 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 addressBook) {
        addressBook.setUserId(BaseContext.getCurrentId());
        log.info("addressBook:{}", addressBook);

        //条件构造器
        LambdaQueryWrapper 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));
    }

    /**
     * 修改地址
     * 请求网址: http://localhost:8080/addressBook
     * 请求方法: PUT
     * 请求参数: addressBook
     *
     * @param addressBook
     * @return
     */
    @PutMapping
    public R put(@RequestBody AddressBook addressBook) {
        addressBookService.updateById(addressBook);
        return R.success("修改地址成功");
    }

    /**
     * 删除地址
     * 请求网址: http://localhost:8080/addressBook?ids=
     * 请求方法: DELETE
     *
     * @param ids
     * @return
     */
    @DeleteMapping
    public R delete(Long ids) {
        log.info("删除地址的id:{}", ids);
        addressBookService.removeById(ids);
        return R.success("删除地址成功");
    }
}

菜品展示 

需求分析

瑞吉外卖 — 手机移动端业务开发_第16张图片

代码开发

瑞吉外卖 — 手机移动端业务开发_第17张图片

用户登录成功后,发送了两次请求加载页面信息
 Promise.all([categoryListApi(),cartListApi({})]).then(res=>{})
需要先将购物车的请求修改一下,从静态的JSON中获取数据,响应页面,后续开发完购物车功能再修改回去
//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        // 'url': '/shoppingCart/list',
        'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

//json数据
{"code":1,"msg":null,"data":[],"map":{}}  
原来的/dish/list请求只是查询Dish菜品信息,现在要加多一个口味查询,所以将其进行改造
    //改造
    @GetMapping("/list")
    public R> setmealByDishName(Dish dish) {

        //构建查询条件
        LambdaQueryWrapper 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 list = dishService.list(queryWrapper);

        List dishDtoList = list.stream().map((item -> {
            DishDto dishDto = new DishDto();

            BeanUtils.copyProperties(item, dishDto);

            Long categoryId = item.getCategoryId();//分类id

            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);

            if (category != null) {
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            //当前菜品id
            Long dishId = item.getId();

            //根据菜品id查询口味信息
            LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            //SQL:select * from dish_flavor where dish_id = dishId
            List dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);

            dishDto.setFlavors(dishFlavorList);

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

        return R.success(dishDtoList);
    }

获取套餐数据

    /**
     * 根据条件查询套餐数据
     * http://localhost:8080/setmeal/list?categoryId=1413342269393674242&status=1
     * @param setmeal
     * @return 
     */
    @GetMapping("/list")
    public R> list(Setmeal setmeal) {

        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
        //select * from setmeal where category_id = ? and status = 1;

        //添加排序条件
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        //执行查询
        List setmealList = setmealService.list(queryWrapper);

        return R.success(setmealList);
    }

点击套餐图片显示详细信息

    /**
     * 移动端查看套餐详情
     * 请求网址: http://localhost:8080/setmeal/dish/1664223387185500162
     * 请求方法: GET
     * 前端接收过来的是套餐id,需要响应给前端的是与套餐相关的菜品数据
     * dish表的name、price、image、description  菜品的份数copies,所以这里用DishDto
     *
     * @param id
     * @return
     */
    @GetMapping("/dish/{id}")
    public R> getSetmeal(@PathVariable Long id) {

        //根据套餐id获取与之关联的套餐菜品id
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SetmealDish::getSetmealId, id);

        //查询出套餐菜品数据
        List setmealDishes = setmealDishService.list(queryWrapper);

        //根据setmeal_dish表 获取 dish_Id
        List dishDtoList = setmealDishes.stream().map((item -> {
            DishDto dishDto = new DishDto();

            Dish dish = dishService.getById(item.getDishId());

            //将dish的数据拷贝给dishDto
            BeanUtils.copyProperties(dish, dishDto);

            //获取菜品的份数
            dishDto.setCopies(item.getCopies());

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

        return R.success(dishDtoList);
    }

购物车

加入购物车

需求分析

瑞吉外卖 — 手机移动端业务开发_第18张图片

数据模型

瑞吉外卖 — 手机移动端业务开发_第19张图片

代码开发

瑞吉外卖 — 手机移动端业务开发_第20张图片

在开发业务功能前,先将需要用到的类和接口基本结构创建好
实体类 shoppingCart (直接从课程资料中导入即可)
Mapper接口 ShoppingCartMapper
业务层接口 shoppingCartService
业务层实现类 shoppingCartServiceImpl
控制层 ShoppingCartController

@RestController
@RequestMapping("/shoppingCart")
@Slf4j
public class ShoppingCartController {
    @Autowired
    private ShoppingCartService shoppingCartService;

    /**
     * 加入购物车
     * http://localhost:8080/shoppingCart/add
     * @param shoppingCart
     * @return
     */
    @PostMapping("/add")
    public R add(@RequestBody ShoppingCart shoppingCart){
        log.info(shoppingCart.toString());
        //设置用户id,指定当前是哪个用户的购物车数据 获取用户id有两种方式(session 或 BaseContext)
        Long currentId = BaseContext.getCurrentId();
        shoppingCart.setUserId(currentId);

        //查询当前菜品或套餐是否在购物车中
        Long dishId = shoppingCart.getDishId();
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,currentId);

        if (dishId != null){
            //添加到购物车的是菜品
            //查询是否在购物车中
            queryWrapper.eq(ShoppingCart::getDishId,dishId);

        }else {
            //添加到购物车的是套餐
            queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
        }

        //select * from shoppingCart where user_id = currentId and dish_id = ?/setmeal_id = ?
        ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper);

        if (cartServiceOne != null){
            //如果已经存在,就在购物车原来的基础上数量加1
            Integer number = cartServiceOne.getNumber();
            cartServiceOne.setNumber(number + 1);
            shoppingCartService.updateById(cartServiceOne);
        }else {
            //如果不存在,则添加进购物车,数量默认是1
            shoppingCart.setNumber(1);
            shoppingCartService.save(shoppingCart);
            cartServiceOne = shoppingCart;
        }
        return R.success(cartServiceOne);
    }
}

减少商品数量

    /**
     * 请求网址: http://localhost:8080/shoppingCart/sub
     * 请求方法: POST
     * 修改购物车商品数量
     * 请求数据:{"dishId": "1413384757047271425"}
     * @param shoppingCart
     * @return
     */
    @PostMapping("/sub")
    public R sub(@RequestBody ShoppingCart shoppingCart) {
        log.info("shoppingCart:{}", shoppingCart);
        //获取当前用户id
        Long userId = BaseContext.getCurrentId();

        //获取需要修改的购物车商品id dishId?setmealId
        Long dishId = shoppingCart.getDishId();
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId, userId);

        if (dishId != null) {
            //修改菜品数量
            //根据菜品id查询数量
            queryWrapper.eq(ShoppingCart::getDishId, dishId);

        } else {
            //修改套餐数量
            //根据套餐id查询数量
            queryWrapper.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId());
        }

        //select * from shoppingCart where user_id = currentId and dish_id = ?/setmeal_id = ?
        ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper);

        //获取购物车中需要修改商品的数量
        Integer number = cartServiceOne.getNumber();

        //商品数量减1
        cartServiceOne.setNumber(number - 1);
        if (number == 1) {
            //如果number = 1 ,直接删除购物车中的该商品
            shoppingCartService.removeById(cartServiceOne.getId());
        } else {
            //如果number>1,直接修改
            shoppingCartService.updateById(cartServiceOne);
        }

        return R.success(cartServiceOne);
    }

查看购物车

前面完成登录时需要加载两个请求,为了不报错加载页面,用了假数据来响应页面,
现在将其修改回来,实现查看购物车请求
//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        'url': '/shoppingCart/list',    //修改回来
        // 'url':'/front/cartData.json', //注释掉
        'method': 'get',
        params:{...data}
    })
}
    /**
     * 查看购物车
     * http://localhost:8080/shoppingCart/list
     * {"code":1,"msg":null,"data":[],"map":{}}
     * @return
     */
    @GetMapping("/list")
    public R> list(){
        log.info("查看购物车...");
        //不同的用户,购物车信息不一样
        //根据用户id查询数据
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());

        //添加排序条件,根据创建时间降序排序
        queryWrapper.orderByDesc(ShoppingCart::getCreateTime);

        //查询数据
        List list = shoppingCartService.list(queryWrapper);

        return R.success(list);
    }
}

清空购物车

    /**
     * http://localhost:8080/shoppingCart/clean
     * 清空购物车
     * @return
     */
    @DeleteMapping("/clean")
    public R clean(){
        //根据用户id清空购物车
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
        shoppingCartService.remove(queryWrapper);
        return R.success("清空购物车成功");
    }

下单

用户下单

需求分析

瑞吉外卖 — 手机移动端业务开发_第21张图片

数据模型

用户下单业务对应的数据表为orders表和order_detail表
orders:订单表
order_detail: 订单明细表

 瑞吉外卖 — 手机移动端业务开发_第22张图片

瑞吉外卖 — 手机移动端业务开发_第23张图片

代码开发

在开发业务功能前,先将需要用到的类和接口基本结构创建好
实体类 Orders、OrderDetail (直接从课程资料中导入即可)
Mapper接口 OrderMapper、OrderDetailMapper
业务层接口 OrderService、OrderDetailService
业务层实现类 OrderServiceImpl、OrderDetailServiceImpl
控制层 OrderController、OrderDetailController
业务层接口
public interface OrderService extends IService {
    /**
     * 用户下单
     * @param orders
     */
    public void Submit(Orders orders);
}
业务层实现类
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl implements OrderService {


    @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 userId = BaseContext.getCurrentId();

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

        if (shoppingCarts == null || shoppingCarts.size() == 0) {
            throw new CustomException("购物车为空,不能下单");
        }

        //除了页面返回的信息,还要查询用户信息和地址信息的相关信息,插入订单表
        //查询用户信息
        User user = userService.getById(userId);

        //查询地址信息
        AddressBook addressBook = addressBookService.getById(orders.getAddressBookId());
        if (addressBook == null) {
            throw new CustomException("地址信息有误,不能下单");
        }

        //生成订单号
        long orderId = IdWorker.getId();

        //原子操作,保证数据的一致性和正确性,线程安全的整数类型,支持原子性的自增、自减等操作
        AtomicInteger amount = new AtomicInteger(0);

        List 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(queryWrapper);
    }
}
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 用户下单
     * 请求网址: http://localhost:8080/order/submit
     * 请求方法: POST
     *
     * @return
     */
    @PostMapping("/submit")
    public R submit(@RequestBody Orders orders) {
        log.info("orders:{}", orders);
        orderService.Submit(orders);
        return R.success("下单成功");
    }

    /**
     * 我的订单页面分页查询
     * 请求网址: http://localhost:8080/order/userPage?page=1&pageSize=5
     * 请求方法: GET
     *
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/userPage")
    public R userPage(int page, int pageSize) {

        log.info("page = {},pageSize = {}", page, pageSize);

        //创建分页构造器
        Page ordersPage = new Page<>(page, pageSize);

        //获取当前用户id
        Long userId = BaseContext.getCurrentId();
        //查询当前用户的订单信息
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getUserId, userId);

        //添加排序条件
        queryWrapper.orderByDesc(Orders::getOrderTime);

        //执行查询
        orderService.page(ordersPage, queryWrapper);

        return R.success(ordersPage);
    }
}

一个小bug:下单页面的地址显示

瑞吉外卖 — 手机移动端业务开发_第24张图片

在下单时,收货地址使用的是默认地址,但是更改收货地址时发现了一个bug:
更改了收货地址,返回下单页面后,后台数据库的地址表是直接修改了默认地址,
但收货地址的显示页面没变,没有及时更新回显回来,

查看相应的前端代码address.html进行修改
itemClick(item){
    const url = document.referrer
    //表示是从订单页面跳转过来的
    if(url.includes('order')){
        this.setDefaultAddress(item)
        window.requestAnimationFrame(()=>{
            window.location.href ='/front/page/add-order.html'
        })
        //history.go(-1)//原来的返回页面不带刷新数据
    }
}

个人订单 

瑞吉外卖 — 手机移动端业务开发_第25张图片瑞吉外卖 — 手机移动端业务开发_第26张图片

需要响应给前端页面的数据除了orders订单表里的数据,还需要order_detail订单明细表中的数据
关联两个表操作,所以创建dto类OrdersDto
@Data
public class OrdersDto extends Orders {
    //订单详细表数据
    private List orderDetails;
}
业务层接口
    //分页查询订单页面
    public Page userPage(int page, int pageSize);

业务层实现类
    /**
     * 分页查询订单
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    @Transactional
    public Page userPage(int page, int pageSize) {
        //创建分页构造器
        Page ordersPage = new Page<>(page, pageSize);
        Page dtoPage = new Page<>();

        //获取当前用户id
        Long userId = BaseContext.getCurrentId();
        //查询当前用户的订单信息
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getUserId, userId);

        //添加排序条件
        queryWrapper.orderByDesc(Orders::getOrderTime);

        //执行查询
        this.page(ordersPage, queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(ordersPage, dtoPage, "records");

        //查询出来的订单数据集合
        List records = ordersPage.getRecords();

        //循环遍历集合,根据Orders数据中的订单id查询OrderDetail数据
        List ordersDtos = records.stream().map((item -> {
            OrdersDto ordersDto = new OrdersDto();

            //拷贝orders数据到ordersDto中
            BeanUtils.copyProperties(item, ordersDto);

//            //获取订单id
            Long id = item.getId();

            //根据订单id查询OrderDetail数据
            LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OrderDetail::getOrderId, id);
            List list = orderDetailService.list(wrapper);

            ordersDto.setOrderDetails(list);

            return ordersDto;

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

        dtoPage.setRecords(ordersDtos);

        return dtoPage;
    }
    /**
     * 我的订单页面分页查询
     * 请求网址: http://localhost:8080/order/userPage?page=1&pageSize=5
     * 请求方法: GET
     *
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/userPage")
    public R userPage(int page, int pageSize) {

        log.info("page = {},pageSize = {}", page, pageSize);

        Page ordersDtoPage = orderService.userPage(page, pageSize);

        return R.success(ordersDtoPage);
    }

再来一单

 瑞吉外卖 — 手机移动端业务开发_第27张图片

再来一单的请求网址: http://localhost:8080/order/again
post请求方式,携带的参数是订单id
请求成功后跳转到index.html页面
具体实现步骤:
先将当前用户的购物车数据清空
根据页面传过来的订单id查询订单详细表获取商品信息
将商品信息插入购物车表中

 瑞吉外卖 — 手机移动端业务开发_第28张图片

    /**
     * 再来一单
     * 请求网址: http://localhost:8080/order/again
     * 请求方法: POST
     */
    @PostMapping("/again")
    public R> again(@RequestBody Orders orders) {

        Long ordersId = orders.getId();
        log.info("ordersId:{}", ordersId);

        //加入购物车前先清空购物车

        //根据用户id清空购物车
        LambdaQueryWrapper Wrapper = new LambdaQueryWrapper<>();
        Wrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
        shoppingCartService.remove(Wrapper);

        //根据订单id,查询订单明细表里的商品,将商品加入购物车
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderDetail::getOrderId, ordersId);

        List orderDetails = orderDetailService.list(queryWrapper);

        List shoppingCarts = orderDetails.stream().map((item -> {
            //加入购物车
            ShoppingCart shoppingCart = new ShoppingCart();

            shoppingCart.setName(item.getName());
            shoppingCart.setImage(item.getImage());
            shoppingCart.setUserId(BaseContext.getCurrentId());
            if (item.getDishId() != null) {
                shoppingCart.setDishId(item.getDishId());
            } else {
                shoppingCart.setDishId(item.getSetmealId());
            }
            if (item.getDishFlavor() != null) {
                shoppingCart.setDishFlavor(item.getDishFlavor());
            }
            shoppingCart.setNumber(item.getNumber());
            shoppingCart.setAmount(item.getAmount());
            //创建的时间
            shoppingCart.setCreateTime(LocalDateTime.now());

            return shoppingCart;

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

        //批量插入数据
        shoppingCartService.saveBatch(shoppingCarts);

        return R.success(shoppingCarts);
    }

你可能感兴趣的:(从0-1的后端学习,java,spring)