整理记录下学习整个瑞吉外卖项目,详细代码可在我的Gitee仓库瑞吉外卖实战克隆下载学习使用!
12.菜品展示
12.1 需求分析
12.2 更改前台页面使其正常显示
由于购物车功能还未进行开发,所以修改main.js中的cartListJson函数中访问固定数据,如图
重启清除缓存后如图
12.3 修改查询菜品方法
12.3.1 代码开发
前台访问的是查询菜品接口方法list,但移动端还需要菜品的口味信息,所以必须得修改DishController中原有的方法,修改如下:
@GetMapping("/list") public Result<List<DishDto>> list(Dish dish) { List<DishDto> dishDtoList; //构造查询条件 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); dishDtoList = list.stream().map((item) -> { DishDto dishDto = new DishDto(); BeanUtils.copyProperties(item, dishDto); Long categoryId = item.getCategoryId();//分类id //当前菜品的id Long dishId = item.getId(); LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DishFlavor::getDishId, dishId); //SQL:select * from dish_flavor where dish_id = ? List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper); dishDto.setFlavors(dishFlavorList); return dishDto; }).collect(Collectors.toList()); return Result.success(dishDtoList); }
12.3.2 测试
- 测试后如图,点击添加规格有口味信息来选择
12.4 查询套餐
12.4.1 代码开发
SetmealController编写查询套餐代码,如下:
@GetMapping("/list") public Result<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 Result.success(list); }
12.4.2 测试
如图所示,不再报错
13. 购物车模块
13.1需求分析
13.2 数据模型
购物车对应表为shopping_cart表,结构如下:
13.3 代码开发
13.3.1 导入实体类或编写实体类
@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;
}
13.3.2 新建对应的Mapper、Service及实现类和controller类
这里自行建立就行,和之前一样
13.3.3 购物车添加功能
- controller编写添加功能,如下:
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
@RequiredArgsConstructor
public class ShoppingCartController { private final ShoppingCartService shoppingCartService; /** * 添加购物车 * @param shoppingCart * @return */ @PostMapping("/add") public Result<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){ log.info("购物车数据:{}",shoppingCart); //设置用户id,指定当前是哪个用户的购物车数据 Long currentId = BaseContext.getCurrentId(); shoppingCart.setUserId(currentId); 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()); } //查询当前菜品或者套餐是否在购物车中 //SQL:select * from shopping_cart where user_id = ? and dish_id/setmeal_id = ? ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper); if(cartServiceOne != null){ //如果已经存在,就在原来数量基础上加一 Integer number = cartServiceOne.getNumber(); cartServiceOne.setNumber(number + 1); shoppingCartService.updateById(cartServiceOne); }else{ //如果不存在,则添加到购物车,数量默认就是一 shoppingCart.setNumber(1); shoppingCart.setCreateTime(LocalDateTime.now()); shoppingCartService.save(shoppingCart); cartServiceOne = shoppingCart; } return Result.success(cartServiceOne); }}
13.3.4 测试
测试添加功能,如图操作
数据库查看结果
13.3.5 购物车查看
- 更改main.js为原来,如图
- 编写查看方法,如下:
@GetMapping("/list")
public Result<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 Result.success(list);
}
13.3.6 测试
测试,登录之前账号查看,如图
13.3.7 购物车套餐或菜品数量减少
- 编写减少方法,如下:
@PostMapping("/sub")
public Result<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart) { Long dishId = shoppingCart.getDishId(); Long setmealId = shoppingCart.getSetmealId(); //条件构造器 LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); //只查询当前用户ID的购物车 queryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId()); //代表数量减少的是菜品数量 if (dishId != null) { //通过dishId查出购物车菜品数据 queryWrapper.eq(ShoppingCart::getDishId, dishId); ShoppingCart dishCart = shoppingCartService.getOne(queryWrapper); //将查出来的数据的数量-1 dishCart.setNumber(dishCart.getNumber() - 1); Integer currentNum = dishCart.getNumber(); //然后判断 if (currentNum > 0) { //大于0则更新 shoppingCartService.updateById(dishCart); } else if (currentNum == 0) { //小于0则删除 shoppingCartService.removeById(dishCart.getId()); } return Result.success(dishCart); } if (setmealId != null) { //通过setmealId查询购物车套餐数据 queryWrapper.eq(ShoppingCart::getSetmealId, setmealId); ShoppingCart setmealCart = shoppingCartService.getOne(queryWrapper); //将查出来的数据的数量-1 setmealCart.setNumber(setmealCart.getNumber() - 1); Integer currentNum = setmealCart.getNumber(); //然后判断 if (currentNum > 0) { //大于0则更新 shoppingCartService.updateById(setmealCart); } else if (currentNum == 0) { //等于0则删除 shoppingCartService.removeById(setmealCart.getId()); } return Result.success(setmealCart); } return Result.error("系统繁忙,请稍后再试");
}
- 测试,再次登录之前账号,点击+号结果如图,添加成功
点击-号,如图
数据库结果正确
13.3.8 购物车清空
@DeleteMapping("/clean")
public Result<String> clean(){ //SQL:delete from shopping_cart where user_id = ? LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId()); shoppingCartService.remove(queryWrapper); return Result.success("清空购物车成功");
}
13.3.9 测试
再次登录之前账号,点击清空,结果如图
14. 用户下单
14.1 需求分析
14.2 数据模型
涉及到两张表orders表和order-detials表,结构如图
- 订单表orders,如图
- 订单详情表order_details,如图
14.3 代码开发
14.3.1 编写导入实体类
@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;
}//订单详情类
@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;
}
14.3.2 新建对应的Mapper、Service及实现类
和之前一样
14.3.3 添加数据传输对象OrdersDto
用于将订单和对应的订单详情结合在一个类里,代码如下:
@Data
public class OrdersDto extends Orders { private List<OrderDetail> orderDetails;
}
14.3.4 编写提交订单业务
OrderService加入submit方法并进行实现。代码如下:
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService { private final ShoppingCartService shoppingCartService; private final UserService userService; private final AddressBookService addressBookService; private final 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); }
}
14.3.5 编写Controller类
controller层调用提交订单方法即可,如图
14.4 测试
启动项目后,登录之前的账号,点击结算后填写地址并设置为默认地址,如图
再次点击结算后跳转到支付页面,如图
支付成功后如图
15. 历史订单
15.1需求分析
- 当用户想再次点购上次吃的菜品或套餐时可以通过查看历史订单来知道
- 当用户下单后管理员必须进行相应的操作,派送或者查看订单详情
15.2 代码开发
- 直接在OrdesController类中编写查找历史订单,修改订单状态及查看订单方法,如下:
@GetMapping("/userPage")
public Result<Page> page(int page, int pageSize) { //获取当前id Long userId = BaseContext.getCurrentId(); Page<Orders> pageInfo = new Page<>(page, pageSize); Page<OrdersDto> ordersDtoPage = new Page<>(page, pageSize); //条件构造器 LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>(); //查询当前用户id订单数据 queryWrapper.eq(userId != null, Orders::getUserId, userId); //按时间降序排序 queryWrapper.orderByDesc(Orders::getOrderTime); orderService.page(pageInfo, queryWrapper); List<OrdersDto> list = pageInfo.getRecords().stream().map((item) -> { OrdersDto ordersDto = new OrdersDto(); //获取orderId,然后根据这个id,去orderDetail表中查数据 Long orderId = item.getId(); LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(OrderDetail::getOrderId, orderId); List<OrderDetail> details = orderDetailService.list(wrapper); BeanUtils.copyProperties(item, ordersDto); //之后set一下属性 ordersDto.setOrderDetails(details); return ordersDto; }).collect(Collectors.toList()); BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records"); ordersDtoPage.setRecords(list); //日志输出看一下 log.info("list:{}", list); return Result.success(ordersDtoPage);
}
@PostMapping("/again")
public Result<String> again(@RequestBody Map<String,String> map){ //获取order_id Long orderId = Long.valueOf(map.get("id")); //条件构造器 LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>(); //查询订单的口味细节数据 queryWrapper.eq(OrderDetail::getOrderId,orderId); List<OrderDetail> details = orderDetailService.list(queryWrapper); //获取用户id,待会需要set操作 Long userId = BaseContext.getCurrentId(); List<ShoppingCart> shoppingCarts = details.stream().map((item) ->{ ShoppingCart shoppingCart = new ShoppingCart(); //Copy对应属性值 BeanUtils.copyProperties(item,shoppingCart); //设置一下userId shoppingCart.setUserId(userId); //设置一下创建时间为当前时间 shoppingCart.setCreateTime(LocalDateTime.now()); return shoppingCart; }).collect(Collectors.toList()); //加入购物车 shoppingCartService.saveBatch(shoppingCarts); return Result.success("喜欢吃就再来一单吖~");
}
/** * 订单明细 * @param page * @param pageSize * @param number * @param beginTime * @param endTime * @return */
@GetMapping("/page")
public Result<Page> page(int page, int pageSize, Long number, String beginTime, String endTime) { //获取当前id Page<Orders> pageInfo = new Page<>(page, pageSize); Page<OrdersDto> ordersDtoPage = new Page<>(page, pageSize); //条件构造器 LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>(); //按时间降序排序 queryWrapper.orderByDesc(Orders::getOrderTime); //订单号 queryWrapper.eq(number != null, Orders::getId, number); //时间段,大于开始,小于结束 queryWrapper.gt(!StringUtils.isEmpty(beginTime), Orders::getOrderTime, beginTime) .lt(!StringUtils.isEmpty(endTime), Orders::getOrderTime, endTime); orderService.page(pageInfo, queryWrapper); List<OrdersDto> list = pageInfo.getRecords().stream().map((item) -> { OrdersDto ordersDto = new OrdersDto(); //获取orderId,然后根据这个id,去orderDetail表中查数据 Long orderId = item.getId(); LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(OrderDetail::getOrderId, orderId); List<OrderDetail> details = orderDetailService.list(wrapper); BeanUtils.copyProperties(item, ordersDto); //之后set一下属性 ordersDto.setOrderDetails(details); return ordersDto; }).collect(Collectors.toList()); BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records"); ordersDtoPage.setRecords(list); //日志输出看一下 log.info("list:{}", list); return Result.success(ordersDtoPage);
} @PutMapping
public Result<String> changeStatus(@RequestBody Map<String, String> map) { int status = Integer.parseInt(map.get("status")); Long orderId = Long.valueOf(map.get("id")); log.info("修改订单状态:status={status},id={id}", status, orderId); LambdaUpdateWrapper<Orders> updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(Orders::getId, orderId); updateWrapper.set(Orders::getStatus, status); orderService.update(updateWrapper); return Result.success("订单状态修改成功");
}
15.3 测试
- 还是登录之前账号,点击头像后选择历史订单,结果如图
- 后台登录管理员进行点击派送,如图
显示订单派送完成,如图
- 点击完成订单,如图
显示 - 点击查看订单详情后如图
- 输入订单号进行查询后,如图