【瑞吉外卖day06】

1.手机验证码登录

1.1 需求分析

客户输入手机号码,获取验证码后,输入后能成功登录。
在这里插入图片描述
在这里插入图片描述

1.2 用户登录

在这里插入图片描述
在这里插入图片描述
首先修改拦截器,将手机端的发送短信和登录请求加到过滤器的放行请求中。
在这里插入图片描述
然后在拦截器中加入这些,利用session判断用户是否登录,用户如果没有登录就进行拦截。

//4-2、判断移动端登录状态,如果已登录,则直接放行
        if(request.getSession().getAttribute("user") != null){
            log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("user"));

            //利用基于ThreadLocal的工具类来获取用户id
            Long userId=(Long) request.getSession().getAttribute("user");
            BaseContext.setCurrentId(userId);

            long id = Thread.currentThread().getId();
            log.info("线程id:{}",id);

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

在这里插入图片描述
然后就是处理手机端发出的请求。首先是发送短信请求,我们在userController中进行处理。

/**
     * 发送验证码
     * @return
     */
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session){
        //获取手机号
        String phone = user.getPhone();
        //生成4位验证码
        if(StringUtils.isNotEmpty(phone)){
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("验证码:{}",code);

            //调用阿里云的短信发送api
            //将验证码保存到session
            session.setAttribute(phone,code);
            return R.success("短信发送成功");
        }else{
            return R.error("短信发送失败");
        }

    }

然后是登录请求:
在这里插入图片描述
请求体:
在这里插入图片描述
我们使用Map来接收数据:
在这里插入图片描述
总体逻辑就是
1.比对map中获取的验证码和我们在session中暂存的phone对应的验证码是否相等,相等则登录
2.如果是新用户(即user表中没有相同phone的记录),要自动完成注册(即存入user表中)
3.设置session的user

/**
     * 移动端用户登录
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){
        log.info(map.toString());
        String phone = (String) map.get("phone");
        String code = (String) map.get("code");

        String relCode = (String) session.getAttribute(phone);
        if(relCode!=null&&relCode.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);
        }else{
            return R.error("验证码错误");
        }


    }

测试。发现新用户已经存入user表中。
在这里插入图片描述

1.3 用户退出

/**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/loginout")
    public R<String> logout(HttpServletRequest request){
        //清理session
        request.getSession().removeAttribute("user");
        return R.success("退出成功");
    }

2.用户地址簿

2.1 需求分析

在这里插入图片描述

导入AddressBook实体类,创建Mapper、Service、ServiceImpl,此处不详细赘述

2.2 新增用户地址簿

在这里插入图片描述
在这里插入图片描述

请求URL:
在这里插入图片描述
请求体:
在这里插入图片描述
编写controller方法:
利用BaseContext的ThreadLocal与当前线程绑定的userId作为userid属性的值。

/**
     * 新增
     */
    @PostMapping
    public R<AddressBook> save(@RequestBody AddressBook addressBook) {
        addressBook.setUserId(BaseContext.getCurrentId());
        log.info("userId:{}",BaseContext.getCurrentId());
        log.info("addressBook:{}", addressBook);
        addressBookService.save(addressBook);
        return R.success(addressBook);
    }

测试,添加地址成功。
在这里插入图片描述

2.3 将某地址设为默认地址

在这里插入图片描述

addressBook实体类有一个属性isDefault,为1则是默认地址,为0则不是。
看看请求:
在这里插入图片描述
编写controller代码
总体思路为:
1.获取所有userId与当前用户id相同的记录;
2.将这些记录的isDefault字段全部设置为0;
3.再将传进来的addressBook的usDefault设置为1,去更新数据库。

/**
     * 设置默认地址
     */
    @PutMapping("default")
    public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) {
        log.info("addressBook:{}", addressBook);
        LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();
        log.info(BaseContext.getCurrentId().toString());
        wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
        wrapper.set(AddressBook::getIsDefault, 0);
        //先将所有这个用户的isdefault字段改为0
        //SQL:update address_book set is_default = 0 where user_id = ?
        addressBookService.update(wrapper);
        //再将所有这个用户的isdefault字段改为1
        addressBook.setIsDefault(1);
        //SQL:update address_book set is_default = 1 where id = ?
        addressBookService.updateById(addressBook);
        return R.success(addressBook);
    }

测试,变成了默认地址
在这里插入图片描述

2.4 查询全部地址

在这里插入图片描述

在这里插入图片描述
服务代码:

/**
     * 查询指定用户的全部地址
     */
    @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.5 修改地址(自己写的)

在这里插入图片描述
修改地址总体分两步:
1.根据id查询地址详细信息,用于回显;
2.提交修改后的地址详细信息。

其中第一个请求已经写好了:
在这里插入图片描述
controller:

/**
     * 根据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("没有找到该对象");
        }
    }

我们只需要写第二个请求:
在这里插入图片描述

/**
     * 提交修改
     * @param addressBook 
     * @return
     */
    @PutMapping
    public R<AddressBook> update(@RequestBody AddressBook addressBook){
        addressBookService.updateById(addressBook);
        return R.success(addressBook);
    }

测试,修改成功

2.6 删除地址(自己写的)

在这里插入图片描述

在这里插入图片描述

@DeleteMapping
    public R<String> delAddress(Long ids){
        addressBookService.removeById(ids);
        return R.success("删除成功");
    }

测试,删除成功。

3.菜品展示

3.1 需求分析

在这里插入图片描述

3.2 代码开发

在这里插入图片描述
在登录到首页的过程中,前端发出了两次请求:
首先是category/list请求,这个请求之前已经开发好了,能够获取所有的分类数据
在这里插入图片描述
第二个请求是获取购物车数据
在这里插入图片描述
这里我们先使用假数据代替。
在这里插入图片描述
测试
在这里插入图片描述

点击每个分类,还会发出按分类条件查询菜品信息的请求,这个请求我们之前也写过了。
在这里插入图片描述
搬出来之前的dishcontroller代码

 @GetMapping("/list")
    public R<List<Dish>> queryList(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> dishList = dishService.list(queryWrapper);
        return R.success(dishList);
    }

但是这里我们希望每个菜品后面能够选取对应口味,而不是只是加到购物车。而我们目前的这个请求,只能获取到菜品信息,没有办法拿到口味信息返给前端。为此,我们需要改造这个方法,返回值类型从Dish改为DishDto,用stream流修改内容。

@GetMapping("/list")
    public R<List<DishDto>> queryList(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> dishList = dishService.list(queryWrapper);
        //stream流处理每个dish对象,去口味表中查询对应菜品的口味数据,最终包装为DishDto类型
        List<DishDto> dishDtoList = dishList.stream().map((item) -> {
            //新建DishDto对象
            DishDto dishDto = new DishDto();
            //属性拷贝
            BeanUtils.copyProperties(item, dishDto);
            //根据dishId查出口味list
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DishFlavor::getDishId, dishId);
            List<DishFlavor> flavorList = dishFlavorService.list(queryWrapper1);
            //赋值
            dishDto.setFlavors(flavorList);
            return dishDto;
        }).collect(Collectors.toList());

        return R.success(dishDtoList);
    }

在这里插入图片描述
现在就能选对应的菜品口味啦。
但是目前仍然有问题,就是选择套餐的话会报400
在这里插入图片描述
编写controller代码

/**
     * 根据条件查询套餐数据
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    public R<List<Setmeal>> getSetDishes(Setmeal setmeal){
        //get请求没有请求体,不能加requestBody注解

        LambdaQueryWrapper<Setmeal> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId()!=null,Setmeal::getCategoryId,setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus());
        queryWrapper.orderByAsc(Setmeal::getUpdateTime);
        List<Setmeal> setmealList = setmealService.list(queryWrapper);
        return R.success(setmealList);
    }

发现套餐也能点开查看了
在这里插入图片描述

4.购物车功能

4.1 需求分析

在这里插入图片描述

4.2 添加购物车

在这里插入图片描述
将菜品添加到购物车请求:
在这里插入图片描述
准备工作:
在这里插入图片描述
编写添加购物车controller代码
总体步骤为:
1.利用在threadLocal上绑定的userId设置userid;
2.查数据库套餐表中有没有相同的菜或套餐(id);
3.有则获取原数量,update时+1;
4.没有则新增

/**
     * 添加购物车
     * @param shoppingCart
     * @return
     */
    @PostMapping("/add")
    public R<ShoppingCart> addShop(@RequestBody ShoppingCart shoppingCart){
        log.info("购物车数据:{}",shoppingCart.toString());

        //设置用户id(利用在threadLocal上绑定的userId)
        Long currentId = BaseContext.getCurrentId();
        shoppingCart.setUserId(currentId);
        //查数据库套餐表中有没有相同的菜或套餐(id)
        //根据userId和dishId/setmealId查询
        LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,currentId);

        Long dishId = shoppingCart.getDishId();
        if(dishId==null){
            //添加的是套餐
            queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
        }else {
            //添加的是菜品
            queryWrapper.eq(ShoppingCart::getDishId,dishId);
        }

        //查询
        ShoppingCart cartGetOne = shoppingCartService.getOne(queryWrapper);
        if(cartGetOne !=null){
            //如果有,相同记录数量直接加1
            Integer number = cartGetOne.getNumber();
            cartGetOne.setNumber(number+1);
            shoppingCartService.updateById(cartGetOne);
        }else {
            //没有的话就插入一条数据
            shoppingCart.setNumber(1);
            shoppingCartService.save(shoppingCart);
            cartGetOne =shoppingCart;
        }

        return R.success(cartGetOne);
    }

4.3 查看购物车

然后就是点击购物车图标,需要显示当前用户购物车商品。页面发送ajax请求(假数据改回去):
在这里插入图片描述
编写controller代码:

 /**
     * 查看购物车
     * @return
     */
    @GetMapping("/list")
    public R<List<ShoppingCart>> list(){
        //根据userid
        Long userId = BaseContext.getCurrentId();
        LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,userId);
        queryWrapper.orderByDesc(ShoppingCart::getCreateTime);
        List<ShoppingCart> list = shoppingCartService.list(queryWrapper);
        return R.success(list);
    }

测试,购物车商品显示成功。
在这里插入图片描述

4.4 清空购物车

点击删除按钮,页面发送请求:
在这里插入图片描述
本质是根据userid去删除对应购物车数据
编写controller代码:

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

测试,清空成功。

5.用户下单

5.1需求分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 代码开发

在这里插入图片描述
前三个请求功能已经有了:
在这里插入图片描述
只有第四个功能,点击“去支付”,完成下单操作:

在这里插入图片描述
在这里插入图片描述
开发具体代码之前仍然是订单类和订单明细类的基础功能:
在这里插入图片描述
接下来就是开发用户下单功能,由于下单业务稍微复杂点,我们在orderService层编写主要的业务逻辑代码。

总体有几个步骤:
1.获取当前用户id;
2.根据当前用户id,查询用户数据、购物车数据、地址簿数据;
3.向订单表插入一条数据;
4.向订单明细表插入多条数据;
5.清空用户购物车数据;

业务代码如下:

/**
     * 用户下单
     * @param orders
     */
    @Transactional
    @Override
    public void submit(Orders orders) {
        //获得当前用户id
        Long userId = BaseContext.getCurrentId();
        //获取当前用户购物车数据
        LambdaQueryWrapper<ShoppingCart> shopQueryWrapper=new LambdaQueryWrapper<>();
        shopQueryWrapper.eq(ShoppingCart::getUserId,userId);
        List<ShoppingCart> shopList = shoppingCartService.list(shopQueryWrapper);

        if(shopList==null||shopList.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("地址信息有误,不能下单");
        }
        //向订单表插入数据(1条)
        //计算购物车总金额,同时获取订单明细list
        long orderId = IdWorker.getId();//生成订单号
        AtomicInteger amount=new AtomicInteger(0);//原子int
        List<OrderDetail> orderDetails=shopList.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.setNumber(String.valueOf(orderId));

        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2);
        orders.setAmount(new BigDecimal(amount.get()));//总金额
        orders.setUserId(userId);

        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(shopQueryWrapper);
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值