注:本文章基于黑马程序员相关视频及资料进行编写,代码简单,较容易理解,若有问题或者源码资料获取可以在评论区留言或者联系作者!
文章目录
开篇
接下来将对项目的购物车和下单功能进行编写,以下为效果图
一、菜品展示
(1)需求分析:
用户登录成功之后跳转到系统首页,在首页需要根据分类来展示菜品和套餐。如果菜品设置了口 味信息,需要展示选择规格按钮,否则展示**+**按钮
(2)代码开发-梳理交互流程
- 页面发送ajax请求,获取分类数据(菜品分类和套餐分类)
- 页面发送ajax请求,获取第一个分类下的菜品或套餐
注意:首页加载完成之后,还发送了一次ajax请求用于加载购物车数据,此处可以将这次请求的地址暂时改一下,从静态json文件获取数据,等后续购物车开发时再改回来
(3)代码开发-修改DishController中的list方法
从主页面可以发现,所有的菜品都是以 ** + ** 进行进行选择,并没有达到我们开始规定的若有口味信息,则按照口味信息进行选择,若没有口味信心,则直接可以添加菜品;究其原因,是在与前端页面此处是按照请求菜品返回数据中有无flavor信息,若有,则将其进行渲染,若没有则直接可以进行添加;
而查看DishController中的list方法,发现返回的是Dis对象,而Dish对象中并没有封装flavor信息。所以我们这里需要进行修改;返回一个含有flavor信息的Dishdto对象;
/*根据条件来查询对应的菜品--新*/
@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);
//设置DishFlavor中categoryName的值
Long categoryId = item.getCategoryId();
//根据菜品分类id到分类列表中查询菜品这条数据
Category category = categoryService.getById(categoryId);
if (category!=null){
//获取菜品分类名
String categoryName = category.getName();
//在dishDto中对categoryName属性进行赋值
dishDto.setCategoryName(categoryName);
}
//设置DishFlavor中的Flavor的值
LambdaQueryWrapper<DishFlavor> flavorLambdaQueryWrapper=new LambdaQueryWrapper<>();
flavorLambdaQueryWrapper.eq(DishFlavor::getDishId,item.getId());
List<DishFlavor> dishFlavors = dishFlavorService.list(flavorLambdaQueryWrapper);
dishDto.setFlavors(dishFlavors);
return dishDto;
}).collect(Collectors.toList());
return R.success(dishDtoList);
}
运行项目,菜品能够正常选择规格和进行添加;
(4)代码开发-创建SetmealController的list方法
这里和上面的DIshController中的list方法一样,用于返回当前请求套餐下的数据,然后前端页面进行渲染;
/*根据条件查询套餐数据*/
@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);
}
运行结果如下:
二、购物车
(1)需求分析:
移动端用户可以将菜品或者套餐添加到购物车。对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车,对于套餐来说,可以直接点击 *加号 将当前套餐加入购物车,在购物车中可以修改菜品和套餐的数量,也可以清空购物车;
购物车对应shopping_cart表
(2) 交互过程:
- 点击加入购物车或者加号按钮,页面发送ajax请求,请求服务端,将菜品或者套餐添加到购物车
- 点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐
- 点击清空购物车按钮,页面发送ajax请求,请求服务端来执行清空购物车操作;
搭建好需要使用的基本框架;
(3)代码开发-添加购物车
将菜品添加到购物车,页面会传来dishid和setmealid,也就是说,用户可能会添加菜品,也可能会添加套餐,但是只会传入两者中的一个值,所以我们可以对此进行判断,如果传来的是菜品id,则根据菜品id构造查询条件,然后查询到这个菜品,反之他套餐也是这样,根据它套餐id构造查询条件,然后根据查询条件查询购物车数据,若能查到数据,说明是购买的第二份,将查到的数据number加一,若不能查到,则将数据加入到购物车中
@PostMapping("/add")
public R<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());
}
ShoppingCart shoppingCartServiceOne = shoppingCartService.getOne(queryWrapper);
if (shoppingCartServiceOne!=null){
//如果已经存在,就在原来的数量上加1
Integer number = shoppingCartServiceOne.getNumber();
shoppingCartServiceOne.setNumber(number+1);
shoppingCartService.updateById(shoppingCartServiceOne);
}
else {
//如果不存在,则添加到购物车中,数量默认都是1
shoppingCart.setNumber(1);
shoppingCartService.save(shoppingCart);
shoppingCartServiceOne=shoppingCart;
}
return R.success(shoppingCartServiceOne);
}
(4)代码开发-查看购物车&清空购物车
查看购物车相对较容易实现,只需要根据用户id查询购物车信息即可
@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);
}
删除购物车也是和查询一样的原理,只需要根据用户id删除相关信息即可,这里就不再演示
三、导入用户地址簿
(1)需求分析:
地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息,同一个用户可以有多个地址信息,但是只能有一个默认地址
用户的地址信息会存储在address__book(地址簿)表中
(2)功能代码大体框架:
- 实体类AddressBook
- Mapper接口AddressBookMapper
- 业务层接口AddressService
- 业务层实现接口 AddressServiceImpl
- 控制层 AddressBookController
(3)代码实现
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {
@Autowired
private AddressBookService addressBookService;
/**
* 新增
*/
@PostMapping
public R<AddressBook> save(@RequestBody AddressBook addressBook) {
//线程中获取用户id
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 = ?
//将当前用户 所对应的所有地址的is_default值改为0 (非默认地址)
addressBookService.update(wrapper);
addressBook.setIsDefault(1);
//SQL:update address_book set is_default = 1 where id = ?
//将此地址的is_default改为1(默认地址)
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));
}
}
这里对地址簿的演示可以自行演示
四、用户下单
(1)需求分析:
移动端用户可以将套餐或者菜品加入购物车,可以点击购物车中的去结算按钮,页面跳转到订单确认页面,点击去支付按钮完成下单操作;
主要涉及到Order表(订单表)和Order_detail表(订单明细表)
(2)代码开发-梳理交互过程
- 在购物车中点击 去结算 按钮,页面跳转到订单确认页面(已完成)
- 在页面确认页面,发送ajax请求,请求服务端获取当前 登录用户的默认地址(已完成)
- 在订单确认页面,发送ajax’请求,请求服务端获取当前登录用户 的购物车数据(已完成)
- 在订单确认页面点击 去支付 按钮,发送ajax请求,请求服务端完成下单操作
创建大体的结构(和前面一样controller,mapper,service,serviceimpl)
(3)代码开发
用户下单后需要对orders表进行操作,添加相关信息,也需要对orderdetail表进行数据的添加,然后删除购物车表中该用户的相关数据,要对三张表进行操作,所以可以在 orderServiceImpl中进行相关逻辑的编写;
@Transactional
@Override
public void submit(Orders orders) {
//获取当前用户id
Long userId= BaseContext.getCurrentId();
//根据上传数据查询用户购物车数据
LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId,userId);
List<ShoppingCart> shoppingCarts = shoppingCartService.list(queryWrapper);
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();//mybatisplus随机生成一个订单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.setNumber(String.valueOf(orderId));
orders.setId(orderId);//id使用订单号
orders.setUserId(userId);//用户id
orders.setOrderTime(LocalDateTime.now());//下单时间
orders.setCheckoutTime(LocalDateTime.now());//支付时间
orders.setStatus(2);//状态
orders.setAmount(new BigDecimal(amount.get()));//设置金额
orders.setUserName(user.getName());//用户名
orders.setPhone(user.getPhone());//手机号
orders.setConsignee(addressBook.getConsignee());//收货人
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);
如果感觉内容写的还不错的话,一键三连不迷路!!!!
后面将会更新更多学习内容,一起学习吧!!!!!!