Java项目实战——瑞吉外卖day6、7

本文详细介绍了移动端外卖应用的主要功能模块的开发过程,包括地址簿管理、菜品展示、购物车操作和订单提交。在地址簿管理中,实现了新增地址和设置默认地址的功能。菜品展示部分涉及分类展示和菜品详情,购物车功能包括商品添加和数量管理。订单提交涉及从购物车到订单详情的流程。此外,文章还提到了代码优化,如退出登录、查看最近订单和再来一单等功能,以及订单详情的显示和状态操作。
摘要由CSDN通过智能技术生成

大致内容

根据上篇笔记阿里云获取验证码进行登录移动端

一、在移动端显示地址簿(接收外卖的地址)、菜品展示(包括分类以及菜品详情)、购物车(点击购物车图标显示添加的商品)、提交订单(点击去结算,到订单详情)、退出当前账户、查看最近订单再来一单(订单已完成时)

二、在客户端显示订单详情、操作订单状态

目录

1、在移动端显示地址簿(接收外卖的地址)

1.1、需求分析

1.2、代码开发

 2、菜品展示(包括分类以及菜品详情)

2.1、需求分析

2.2、代码开发

3、购物车(点击购物车图标显示添加的商品)

3.1、需求分析

3.2、代码开发 

4、提交订单(点击去结算,到订单详情)

4.1、需求分析

4.2、代码开发

5、代码优化-功能补充 

5.1、需求分析

5.2、代码开发


1、在移动端显示地址簿(接收外卖的地址)

1.1、需求分析

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

--导入数据模型,配置相关接口和类

  • 实体类AddressBook(直接从课程资料中导入即可)
  • Mapper接口AddressBookMapper
  • 业务层接口AddressBookService
  • 业务层实现类AddressBookServicelmpl
  • 控制层AddressBookController(直接从课程资料中导入即可)

1.2、代码开发

/**
 * 地址簿管理
 */
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {

    @Autowired
    private AddressBookService addressBookService;

    /**
     * 新增
     */
    @PostMapping
    public R<AddressBook> save(@RequestBody AddressBook addressBook) {
        addressBook.setUserId(BaseContextUtil.getNowId());
        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, BaseContextUtil.getNowId());
        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, BaseContextUtil.getNowId());
        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(BaseContextUtil.getNowId());
        log.info("addressBook:{}", addressBook);

        //条件构造器
        LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(null != addressBook.getUserId(), AddressBook::getUserId, addressBook.getUserId());
        queryWrapper.orderByDesc(AddressBook::getUpdateTime);

        //SQL:select * from address_book where user_id = ? order by update_time desc
        return R.success(addressBookService.list(queryWrapper));
    }
}

效果展示:

 2、菜品展示(包括分类以及菜品详情)

2.1、需求分析

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

2.2、代码开发

注意:首页加载完成后,还发送了一次ajax请求用于加载购物车数据,此处可以将这次请求的地址暂时修改一下,从静态json文件获取数据,等后续开发购物车功能时再修改回来,如下:

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

--需要显示具体的口味信息,所以我们在此改造DishController中的list方法

 /**
     * 根据分类id查询对应的菜品,并回显数据
     * @param dish
     * @return
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        List<Dish> list = dishService.list(qw);
        ArrayList<DishDto> dishDtos = new ArrayList<>();
        for (Dish dish1:list){
            Long id = dish1.getId();
            DishDto dishDto = dishService.getWithFlavor(id);
            dishDtos.add(dishDto);
        }
        return R.success(dishDtos);
    }
}

--在SetmealController里添加list方法显示套餐信息

   /**
     * 在移动端显示套餐里面的套餐1、套餐2............
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    public R<List<Setmeal>>list(Setmeal setmeal){
        LambdaQueryWrapper<Setmeal> qw = new LambdaQueryWrapper<>();
        qw.eq(setmeal.getCategoryId()!=null,Setmeal::getCategoryId,setmeal.getCategoryId());
        qw.eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus());
        List<Setmeal> setmeals = setmealService.list(qw);
        return R.success(setmeals);
    }

    /**
     * 点击套餐显示套餐内部菜品详情
     * @param id
     * @return
     */
    @GetMapping("/dish/{id}")
    public R<SetmealDto>getSetMeal(@PathVariable Long id){
        SetmealDto setmealDto = setmealService.getByIdWithDish(id);
        return R.success(setmealDto);
    }

效果展示:

3、购物车(点击购物车图标显示添加的商品)

3.1、需求分析

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

3.2、代码开发 

  • 实体类ShoppingCart(直接从课程资料中导入即可)
  • Mapper接口ShoppingCartMapper
  • 业务层接口ShoppingcartService
  • 业务层实现类ShoppingCartServicelmpl
  • 控制层ShoppingCartController

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

    /**
     * 将商品添加购物车,需要注意:判断用户id,每个用户的购物车内容不一样,确保添加数据时准确对应数据库
     * 注意判断数据库中是否存在该用户的该菜品/套餐数据,若存在直接在num加一,不存在则新建
     * @param shoppingCart
     * @return
     */
    @PostMapping("/add")
    public R<ShoppingCart>add(@RequestBody ShoppingCart shoppingCart){
        log.info("加入购物车的内容:{}",shoppingCart);
        //获取当前用户id,确保在数据库中添加购物车内容时不出错
        Long userId = BaseContextUtil.getNowId();
        shoppingCart.setUserId(userId);

        LambdaQueryWrapper<ShoppingCart> qw = new LambdaQueryWrapper<>();
        qw.eq(ShoppingCart::getUserId,userId);
        if(shoppingCart.getDishId() != null){
        //添加到购物车的是菜品------锁定当前用户userid,查找对应菜品id
            qw.eq(ShoppingCart::getDishId,shoppingCart.getDishId());
        }else {
            //添加到购物车的是套餐--------锁定当前用户userid,查找对应套餐id
            qw.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
        }
        //已存在,根据条件查询
        ShoppingCart shoppingCartOne = shoppingCartService.getOne(qw);
        if (shoppingCartOne != null){
        //当前用户数据库中已有该添加内容,直接在数量上加一
            Integer number = shoppingCartOne.getNumber();
            shoppingCartOne.setNumber(number+1);
            shoppingCartService.updateById(shoppingCartOne);
        }else {
        //如果不存在
            shoppingCart.setNumber(1);
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCartService.save(shoppingCart);
            shoppingCartOne = shoppingCart;
        }

        return R.success(shoppingCartOne);
    }

    /**
     * 点击购物车图标,显示购物车里面的商品
     * @return
     */
    @GetMapping("/list")
    public R<List<ShoppingCart>>list(){
        log.info("购物车.。。。。。。。。");
        Long userId = BaseContextUtil.getNowId();
        LambdaQueryWrapper<ShoppingCart> qw = new LambdaQueryWrapper<>();
        qw.eq(ShoppingCart::getUserId,userId);
        qw.orderByDesc(ShoppingCart::getCreateTime);
        List<ShoppingCart> list = shoppingCartService.list(qw);
        return R.success(list);
    }

    /**
     * 删除购物车商品
     * @param shoppingCart
     * @return
     */
    @PostMapping("/sub")
    public R<ShoppingCart>sub(@RequestBody ShoppingCart shoppingCart){

        LambdaQueryWrapper<ShoppingCart> qw = new LambdaQueryWrapper<>();
        if (shoppingCart.getDishId()!=null) {
            //菜品
            qw.eq(ShoppingCart::getDishId,shoppingCart.getDishId());
        }else {
            //套餐
            qw.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
        }
        ShoppingCart cartServiceOne = shoppingCartService.getOne(qw);
        if (cartServiceOne.getNumber()>1) {
            cartServiceOne.setNumber(cartServiceOne.getNumber() - 1);
            shoppingCartService.updateById(cartServiceOne);
        }else {
            cartServiceOne.setNumber(cartServiceOne.getNumber() - 1);
            shoppingCartService.removeById(cartServiceOne);
        }
        return R.success(cartServiceOne);
    }

    /**
     * 清空商品
     * @return
     */
    @DeleteMapping("/clean")
    public R<String>clean(){
        Long userId = BaseContextUtil.getNowId();
        LambdaQueryWrapper<ShoppingCart> qw = new LambdaQueryWrapper<>();
        qw.eq(ShoppingCart::getUserId,userId);
        shoppingCartService.remove(qw);
//        List<ShoppingCart> list = shoppingCartService.list();
//        for (ShoppingCart shoppingCart:list){
//            Long id = shoppingCart.getId();
//            shoppingCartService.removeById(id);
//        }
        return R.success("清空成功");
    }
}

4、提交订单(点击去结算,到订单详情)

4.1、需求分析

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

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

4.2、代码开发

在开发代码之前,需要梳理一下用户下单操作时前端页面和服务端的交互过程:

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

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

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

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

开发用户下单功能,其实就是在服务端编写代码去处理前端页面发送的请求即可。

代码开发-准备工作

在开发业务功能前,先将需要用到的类和接口基本结构创建好:

  • 实体类Orders、OrderDetail(直接从课程资料中导入即可)
  • Mapper接口OrderMapper、OrderDetailMapper
  • 业务层接口OrderService、OrderDetailService
  • 业务层实现类OrderServicelmpl、OrderDetailServicelmpl
  • 控制层OrderController、OrderDetailController

操作如下:

设计多表,自定义方法

在OrderController的submit方法处理post请求实现上面的方法


    /**
     * 提交订单--支付
     * @param orders
     * @return
     */
    @PostMapping("/submit")
    public R<String>submit(@RequestBody Orders orders){
        log.info("去支付{}", orders);
        ordersService.submit(orders);
        return R.success("支付成功");
    }

在OrderService添加submit方法用于用户下单

  /**
     * 提交订单:也就是在订单表和订单明细表插入数据
     * @param orders
     */
//    @Transactional
    public void submit(Orders orders) {
        //获得当前用户id
        Long userId = BaseContextUtil.getNowId();

        //查询当前用户的购物车数据
        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();//MP提供的自动生成id订单号

        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);
    }
}

5、代码优化-功能补充 

5.1、需求分析

退出当前账户、查看最近订单再来一单(订单已完成时)

在客户端显示订单详情、操作订单状态

5.2、代码开发

退出-清除session中保存的userid

    /**
     * 退出登录
     * @param httpServletRequest
     * @return
     */
    @PostMapping("/loginout")
    public R<String>loginOut(HttpServletRequest httpServletRequest){
        //用户信息保存在当前会话session中,清除即可
        httpServletRequest.getSession().removeAttribute("user");
        return R.success("退出成功");
    }

查看最近订单

导入OrderDto需手动添加private int sumNum;(前端会计算数量)

在OrderController添加userPage方法

/**
     * 查询订单详情,分页展示
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Transactional
    @GetMapping("/userPage")
    public R<Page> getOrderWithDetail(int page, int pageSize) {
        //构造分页构造器
        Page<Orders> pageInfo = new Page<>(page, pageSize);

        Page<OrdersDto> ordersDtoPage = new Page<>();

        //构造条件构造器
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();

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

        //进行分页查询
        ordersService.page(pageInfo,queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(pageInfo,ordersDtoPage,"records");

        //获取原页面数据
        List<Orders> records=pageInfo.getRecords();

        //原数据缺少订单数量,进行更改
        List<OrdersDto> list = records.stream().map((item) -> {
            OrdersDto ordersDto = new OrdersDto();

            BeanUtils.copyProperties(item, ordersDto);
            Long Id = item.getId();
            //根据id查分类对象
            Orders orders = ordersService.getById(Id);
            String number = orders.getNumber();
            LambdaQueryWrapper<OrderDetail> lambdaQueryWrapper=new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(OrderDetail::getOrderId,number);
            List<OrderDetail> orderDetailList = orderDetailService.list(lambdaQueryWrapper);
            //初始化订单数
            int num=0;
            //从订单详情表OrderDetail获取number
            for(OrderDetail detail:orderDetailList){
                num+=detail.getNumber().intValue();
            }
            ordersDto.setSumNum(num);
            return ordersDto;
        }).collect(Collectors.toList());
        //将修改之后的页面数据赋值
        ordersDtoPage.setRecords(list);
        return R.success(ordersDtoPage);
    }

再来一单(订单已完成时)

在OrderController中添加again方法

  //再来一单
    @PostMapping("/again")
    public R<String>again(@RequestBody Orders order){
        log.info("再来一单");
        //更改订单表
        Long id = order.getId();
        Orders orders = ordersService.getById(id);
        long orderId = IdWorker.getId();//MP提供的自动生成id订单号
        //将获取到的订单信息中的id 时间 等进行更改
        //设置订单id
        orders.setId(orderId);
        orders.setNumber(String.valueOf(orderId));
        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2);
        //将改好信息之后的订单表提交
        ordersService.save(orders);
        //更改订单详情表
        LambdaQueryWrapper<OrderDetail> qw = new LambdaQueryWrapper<>();
        qw.eq(OrderDetail::getOrderId,id);
        List<OrderDetail> list = orderDetailService.list(qw);
        list.stream().map((item)->{
            //订单明细表id
            long detailId = IdWorker.getId();
            //设置订单表id
            item.setOrderId(orderId);
            //设置订单详情表id
            item.setId(detailId);
            return item;
        }).collect(Collectors.toList());
        orderDetailService.saveBatch(list);
        return R.success("再来一单成功");
    }

在客户端显示订单详情、操作订单状态

OrderController添加page方法处理get请求--显示订单详情

在OrderController处理post请求修改status--操作订单状态

    /**
     * 客户端显示订单详情
     * @param page
     * @param pageSize
     * @param number
     * @param beginTime
     * @param endTime
     * @return
     */
    @GetMapping("/page")
    public R<Page>page(int page,int pageSize,String number,String beginTime,String endTime){
        Page<Orders> ordersPage = new Page<>(page,pageSize);
//        Page<OrdersDto> ordersDtoPage = new Page<>();


        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        //条件1、根据number进行模糊查询
        qw.like(StringUtils.isNotEmpty(number),Orders::getNumber,number);
        //条件2、根据Datetime进行时间范围查询
        if (beginTime!=null&&endTime!=null){
            qw.le(Orders::getOrderTime,endTime);
            qw.le(Orders::getOrderTime,beginTime);
        }
        //条件3、根据订单创建时间排序
        qw.orderByDesc(Orders::getOrderTime);
        //根据前面三个条件查询分页数据
        ordersService.page(ordersPage,qw);
        //原订单表里无UserName属性值,在此处添加
        List<Orders> records = ordersPage.getRecords();
        records.stream().map((item)->{
            item.setUserName("用户"+item.getUserId());
            return item;
        }).collect(Collectors.toList());
        return R.success(ordersPage);
    }

    /**、
     * 修改订单状态
     * @param orders
     * @return
     */
    @PutMapping
    public R<String> send(@RequestBody Orders orders){
        Long id = orders.getId();
        Integer status = orders.getStatus();
        Orders orders1 = ordersService.getById(id);
        orders1.setStatus(status);
        ordersService.updateById(orders1);
        return R.success("派送成功");
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值