文章目录
- 瑞吉外卖 — day7
- 1. 导入用户地址簿相关功能代码
- 1.1 需求分析
- 1.2 数据模型
- 1.3 代码开发
- 2. 菜品展示
- 2.1 需求分析
- 2.2 代码开发
- 3. 购物车
- 3.1 需求分析
- 3.2 数据模型
- 3.3 代码开发
- 4. 下单
- 4.1 需求分析
- 4.2 数据模型
- 4.3 代码开发
瑞吉外卖 — day7
- 移动端相关业务功能 —— 菜品展示、购物车、下单
1. 导入用户地址簿相关功能代码
1.1 需求分析
- 地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息。同一个用户可以有多个地址信息,但是只能有一个默认地址。
1.2 数据模型
- 用户的地址信息会存储在address_book表,即地址簿表中。
1.3 代码开发
-
导入功能代码
实体类AddressBook(直接从课程资料中导入即可)
Mapper接口AddressBookMapper
业务层接口AddressBookService
业务层实现类AddressBookServicelmpl
控制层AddressBookController(直接从课程资料中导入即可)
-
AddressBookController代码
/** * 地址簿管理 */ @Slf4j @RestController @RequestMapping("/addressBook") public class AddressBookController { @Autowired private AddressBookService addressBookService; /** * 新增 */ @PostMapping public R<AddressBook> save(@RequestBody AddressBook addressBook) { addressBook.setUserId(BaseContext.getCurrentId()); log.info("addressBook:{}", addressBook); addressBookService.save(addressBook); return R.success(addressBook); } /** * 设置默认地址 */ @PutMapping("default") public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) { log.info("addressBook:{}", addressBook); LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId()); wrapper.set(AddressBook::getIsDefault, 0); //SQL:update address_book set is_default = 0 where user_id = ? addressBookService.update(wrapper); addressBook.setIsDefault(1); //SQL:update address_book set is_default = 1 where id = ? addressBookService.updateById(addressBook); return R.success(addressBook); } /** * 根据id查询地址 */ @GetMapping("/{id}") public R get(@PathVariable Long id) { AddressBook addressBook = addressBookService.getById(id); if (addressBook != null) { return R.success(addressBook); } else { return R.error("没有找到该对象"); } } /** * 查询默认地址 */ @GetMapping("default") public R<AddressBook> getDefault() { LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId()); queryWrapper.eq(AddressBook::getIsDefault, 1); //SQL:select * from address_book where user_id = ? and is_default = 1 AddressBook addressBook = addressBookService.getOne(queryWrapper); if (null == addressBook) { return R.error("没有找到该对象"); } else { return R.success(addressBook); } } /** * 查询指定用户的全部地址 */ @GetMapping("/list") public R<List<AddressBook>> list(AddressBook addressBook) { addressBook.setUserId(BaseContext.getCurrentId()); log.info("addressBook:{}", addressBook); //条件构造器 LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(null != addressBook.getUserId(), AddressBook::getUserId, addressBook.getUserId()); queryWrapper.orderByDesc(AddressBook::getUpdateTime); //SQL:select * from address_book where user_id = ? order by update_time desc return R.success(addressBookService.list(queryWrapper)); } }
2. 菜品展示
2.1 需求分析
- 用户登录成功后跳转到系统首页,在首页需要根据分类来展示菜品和套餐
。如果菜品设置了口味信息,需要展示洗择规格按钮,否则显示==+==按钮。
2.2 代码开发
-
前端与服务端交互过程
1、页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
2、页面发送ajax请求,获取第一个分类下的菜品或者套餐
-
页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
-
页面发送ajax请求,获取第一个分类下的菜品或者套餐
DishController中:
@GetMapping("list") public R<List<DishDto>> list(Dish dish){ //构造查询条件 LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(dish.getCategoryId()!=null, Dish::getCategoryId, dish.getCategoryId()); //添加条件,查询状态为1的菜品 queryWrapper.eq(Dish::getStatus,1); //添加排序条件 queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime); List<Dish> list = dishService.list(queryWrapper); List<DishDto> dishDtoList = list.stream().map((item) -> { DishDto dishDto = new DishDto(); BeanUtils.copyProperties(item,dishDto); Long categoryId = item.getCategoryId(); //根据id查询分类对象 Category category = categoryService.getById(categoryId); if(category != null){ String categoryName = category.getName(); dishDto.setCategoryName(categoryName); } //当前菜品的id Long dishId = item.getId(); LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId); List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper); dishDto.setFlavors(dishFlavorList); return dishDto; }).collect(Collectors.toList()); return R.success(dishDtoList); }
SetmealController中:
/** * 根据条件查询套餐数据 * @param setmeal * @return */ @GetMapping("list") public R<List<Setmeal>> list(Setmeal setmeal){ LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(setmeal.getCategoryId()!= null,Setmeal::getCategoryId,setmeal.getCategoryId()); queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus()); queryWrapper.orderByDesc(Setmeal::getUpdateTime); List<Setmeal> list = setmealService.list(queryWrapper); return R.success(list); }
3. 购物车
3.1 需求分析
- 移动端用户可以将菜品或者套餐添加到购物车。对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车;对于套餐来说,可以直接点击将当前套餐加入购物车。在购物车中可以修改菜品和套餐的数量,也可以清空购物车。
3.2 数据模型
- 购物车对应的数据表为shopping_cart表
3.3 代码开发
-
前段与服务端交互过程
1、点击加入购物车或者+按钮,页面发送ajax请求,请求服务端,将菜品或者套餐添加到购物车
2、点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐
3、点击清空购物车按钮,页面发送ajax请求,请求服务端来执行清空购物车操作
-
创建需要的类和接口
实体类ShoppingCart ( 直接从课程资料中导入即可)
Mapper接口ShoppingCartMapper
业务层接口ShoppingCartService
业务层实现类ShoppingCartServicelmpl
控制层ShoppingCartController
-
将菜品或者套餐添加到购物车
@RestController @RequestMapping("shoppingCart") @Slf4j public class ShoppingCartController { @Autowired private ShoppingCartService shoppingCartService; /** * 添加购物车 * @param shoppingCart * @return */ @PostMapping("add") public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){ log.info("购物车数据:{}",shoppingCart); //设置用户id,指定当前是哪个用户的购物车数据 Long currentId = BaseContext.getCurrentId(); shoppingCart.setUserId(currentId); LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ShoppingCart::getUserId,currentId); //查询当前菜品或套餐,是否在购物车中 Long dishId = shoppingCart.getDishId(); if(dishId != null){ //添加到购物车的是菜品 queryWrapper.eq(ShoppingCart::getDishId,dishId); }else{ //添加到购物车的是套餐 queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId()); } ShoppingCart cart = shoppingCartService.getOne(queryWrapper); //如果已存在,在原来数量基础上+1 if(cart != null){ Integer number = cart.getNumber(); cart.setNumber(number+1); shoppingCartService.updateById(cart); }else{ //如果不存在,则添加到购物车,数量默认就是1 shoppingCart.setNumber(1); shoppingCart.setCreateTime(LocalDateTime.now()); shoppingCartService.save(shoppingCart); cart = shoppingCart; } return R.success(cart); } }
-
查询购物车中的菜品和套餐
/** * 查看购物车当前数据 * @return */ @GetMapping("list") public R<List<ShoppingCart>> list(){ log.info("查看购物车..."); LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId()); queryWrapper.orderByAsc(ShoppingCart::getCreateTime); List<ShoppingCart> list = shoppingCartService.list(queryWrapper); return R.success(list); }
-
清空购物车操作
/** * 清空购物车 * @return */ @DeleteMapping("clean") public R<String> clean(){ LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId()); shoppingCartService.remove(queryWrapper); return R.success("清空购物车成功!"); }
4. 下单
4.1 需求分析
- 移动端用户将菜品或者套餐加入购物车后,可以点击购物车中的去结算按钮,页面跳转到订单确认页面,点击去支付按钮则完成下单操作。
4.2 数据模型
-
orders:订单表
order_ detail::订单明细表
4.3 代码开发
-
前端页面与服务端交互过程
1、在购物车中点击去结算按钮,页面跳转到订单确认页面
2、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址
3、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据
4、在订单确认页面点击去支付按钮, 发送ajax请求, 请求服务端完成下单操作
-
基本的类和接口
实体类Orders、OrderDetail (直接从课程资料中导入即可)
Mapper接口OrderMapper、OrderDetailMapper
业务层接口OrderService、OrderDetailService
业务层实现类OrderServicelmpl、OrderDetailServicelmpl
控制层OrderController、OrderDetailController
-
OrderController代码:
@RestController @RequestMapping("order") @Slf4j public class OrderController { @Autowired private OrdersService ordersService; /** * 用户下单 * @param orders * @return */ @PostMapping("submit") public R<String> submit(@RequestBody Orders orders){ log.info("订单数据:{}",orders); ordersService.submit(orders); return R.success("下单成功"); } }
-
OrdersServiceImpl代码:
@Service public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService{ @Autowired private ShoppingCartService shoppingCartService; @Autowired private UserService userService; @Autowired private AddressBookService addressBookService; @Autowired private OrderDetailService orderDetailService; /** * 用户下单 * @param orders */ @Override @Transactional public void submit(Orders orders) { //获取当前用户id Long currentId = BaseContext.getCurrentId(); //查询当前用户购物车数据 LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ShoppingCart::getUserId,currentId); List<ShoppingCart> shoppingCarts = shoppingCartService.list(queryWrapper); if(shoppingCarts == null || shoppingCarts.size() == 0){ throw new CustomerException("购物车为空,不能下单"); } //查询用户数据 User user = userService.getById(currentId); //查询地址数据 Long addressBookId = orders.getAddressBookId(); AddressBook addressBook = addressBookService.getById(addressBookId); if(addressBook == null){ throw new CustomerException("用户地址信息有误,不能下单"); } long orderId = IdWorker.getId();//订单号 //原子操作,保证线程安全 AtomicInteger amount = new AtomicInteger(0); List<OrderDetail> orderDetails = shoppingCarts.stream().map((item)->{ OrderDetail orderDetail = new OrderDetail(); orderDetail.setOrderId(orderId); orderDetail.setNumber(item.getNumber()); orderDetail.setDishFlavor(item.getDishFlavor()); orderDetail.setDishId(item.getDishId()); orderDetail.setSetmealId(item.getSetmealId()); orderDetail.setName(item.getName()); orderDetail.setImage(item.getImage()); orderDetail.setAmount(item.getAmount()); amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue()); return orderDetail; }).collect(Collectors.toList()); //向orders表插入数据,一条数据 orders.setId(orderId); orders.setOrderTime(LocalDateTime.now()); orders.setCheckoutTime(LocalDateTime.now()); orders.setStatus(2); orders.setAmount(new BigDecimal(amount.get()));//总金额 orders.setUserId(currentId); orders.setNumber(String.valueOf(orderId)); orders.setUserName(user.getName()); orders.setConsignee(addressBook.getConsignee()); orders.setPhone(addressBook.getPhone()); orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName()) + (addressBook.getCityName() == null ? "" : addressBook.getCityName()) + (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName()) + (addressBook.getDetail() == null ? "" : addressBook.getDetail())); this.save(orders); //向order_detail表插入数据,多条数据 orderDetailService.saveBatch(orderDetails); //清空购物车数据 shoppingCartService.remove(queryWrapper); } }