业务开发Day6-01-本章内容介绍

目录

  1. 导入用户地址簿相关功能代码
  2. 菜品展示
  3. 购物车
  4. 下单

效果展示

业务开发Day6-02-导入用户地址簿相关代码

需求分析

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

页面展示

  • 新增收货地址页面
  • 地址管理页面
  • 编辑收货地址页面

数据模型

用户的地址信息会存储在address_book表,即地址簿表中。具体表结构如下:

导入功能代码

功能代码清单:

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

实体类AddressBook

package com.itzq.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;/*** 地址簿*/
@Data
public class AddressBook implements Serializable {private static final long serialVersionUID = 1L;private Long id;//用户idprivate Long userId;//收货人private String consignee;//手机号private String phone;//性别 0 女 1 男private String sex;//省级区划编号private String provinceCode;//省级名称private String provinceName;//市级区划编号private String cityCode;//市级名称private String cityName;//区级区划编号private String districtCode;//区级名称private String districtName;//详细地址private String detail;//标签private String label;//是否默认 0否 1是private Integer isDefault;//创建时间@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;//更新时间@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;//创建人@TableField(fill = FieldFill.INSERT)private Long createUser;//修改人@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;//是否删除private Integer isDeleted;
}

Mapper接口AddressBookMapper

package com.itzq.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzq.reggie.entity.AddressBook;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface AddressBookMapper extends BaseMapper<AddressBook> {}

业务层接口AddressBookService

package com.itzq.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itzq.reggie.entity.AddressBook;public interface AddressBookService extends IService<AddressBook> {}

业务层实现类AddressBookServicelmpl

package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.entity.AddressBook;
import com.itzq.reggie.mapper.AddressBookMapper;
import com.itzq.reggie.service.AddressBookService;
import org.springframework.stereotype.Service;@Service
public class AddressBookServicelmpl extends ServiceImpl<AddressBookMapper, AddressBook> implements AddressBookService {}

控制层AddressBookController

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;@RestController
@RequestMapping("/addressBook")
@Slf4j
public class AddressBookController {@Autowiredprivate AddressBookService addressBookService;

完善地址管理页面

前端分析

点击方框里的图标,跳转到个人中心

在个人中心界面,点击地址管理

点击地址管理后,前端发送ajax请求,以下是该请求的地址和方式

新增代码

在AddressBookController控制层中,添加list方法
目的:查询指定用户的全部地址

    @GetMapping("/list")public R<List<AddressBook>> list(AddressBook addressBook){addressBook.setUserId(BaseContext.getCurrentId());log.info("addressBook={}",addressBook);//条件构造器LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(addressBook.getUserId() != null, AddressBook::getUserId,addressBook.getUserId());queryWrapper.orderByDesc(AddressBook::getUpdateTime);List<AddressBook> list = addressBookService.list(queryWrapper);return R.success(list);}

新增收货地址页面

前端分析

来到新增收货地址界面,输入相关信息,点击保存

前端发送ajax请求,以及请求的方式,服务端未响应,所以报404错误

新增代码

在AddressBookController控制层中,添加save方法
目的:将前端以json格式传输到后端的数据,保存到数据库中

 @PostMappingpublic R<AddressBook> save(@RequestBody AddressBook addressBook){addressBook.setUserId(BaseContext.getCurrentId());log.info("addressBook={}",addressBook);addressBookService.save(addressBook);return R.success(addressBook);}

测试-1

重启项目,来到新增收货地址页面,输入地址信息后,点击保存地址

页面跳转到地址管理界面,前端发送ajax请求—显示出该用户所有地址

测试成功

  • 查询指定用户的全部地址
  • 将新增地址保存到数据库

设置默认地址

前端分析

在地址管理界面,点击圆圈—将该地址设置为默认地址

点击后,前端发送ajax请求,以下为请求地址和请求方式

新增代码

在AddressBookController控制层中,添加getDefault方法
目的:设置默认地址

 @PutMapping("/default")public R<AddressBook> getDefault(@RequestBody AddressBook addressBook){addressBook.setUserId(BaseContext.getCurrentId());//条件构造器LambdaUpdateWrapper<AddressBook> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.eq(addressBook.getUserId() != null,AddressBook::getUserId,addressBook.getUserId());updateWrapper.set(AddressBook::getIsDefault,0);//将与用户id所关联的所有地址的is_default字段更新为0addressBookService.update(updateWrapper);addressBook.setIsDefault(1);//再将前端传递的地址id的is_default字段更新为1addressBookService.updateById(addressBook);return R.success(addressBook);}

测试-2

重启项目,来到地址管理界面,点击设置为默认地址

测试成功

成功将该地址设置为默认地址

该用户address_book表中,该地址is_default字段从0变为1,表示该地址为该用户的默认地址

业务开发Day6-03-菜品展示_需求分析

需求分析

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

页面效果展示

业务开发Day6-04-菜品展示_代码开发_梳理交互过程

梳理交互过程

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

  1. 页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
  2. 页面发送ajax请求,获取第一个分类下的菜品或者套餐

开发菜品展示功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可

前端分析

注意:首页加载完成后,页面还发送了一次ajax请求用于加载购物车数据

  1. 前端页面初始化数据发送ajax请求—获取所有菜品和套餐分类

该请求方法在此之前已存在—查询分类信息

  1. 前端页面初始化数据发送ajax请求— 获取购物车类商品集合

注此处可以将这次请求的地址暂时修改一下,从静态json文件中获取数据,等后续开发购物车功能时再修改回来,如下:

在front包下添加json文件

  • json文件名:cartData.json
  • json文件代码:
{"code":1,"msg":null,"data":[],"map":{}}

为什么只有以上两个ajax请求同时接收到页面返回的数据后才能正常显示?

因为Promse.all在处理多个异步请求时,需要等待绑定的每个ajax请求返回数据以后才能正常显示

页面在初始化时,发送ajax请求,获取第一个分类下的菜品或套餐

下面是请求地址和请求方式—(由请求地址可知,该请求为获取第一个分类下的菜品信息)

该请求也是在此之前已存在—通过条件查询获取该种类下的所有菜品信息,并且查询的菜品必须为起售状态(status=1)

测试

  • 因修改过前端代码,所以需要清空浏览器的缓存数据(Ctrl+Shift+Delete),并重启项目
  • 若还是不能正常访问,重启idea代码编辑器

显示成功

注意:

  • 前端页面的需求:如果菜品设置了口味信息,需要展示选择规格按钮,否则显示+按钮
  • 但返回的Dish类型中未包含菜品口味信息
  • 所以需要修改部分代码让返回值既包含菜品的基本信息,也包含了口味的信息

业务开发Day6-05-菜品展示_代码开发_修改DishController的list方法并测试

修改DishController的list方法

  • 添加的SQL语句为:select * from dish_flavors where dish_id = ?—转化为代码形式
  • 查询出数据后,将查询的数据放入dishDto(dish的数据转换对象)对象中
  • 返回list集合,list中对象类型为: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(1为起售,0为停售)的菜品queryWrapper.eq(Dish::getStatus,1);List<Dish> list = dishService.list(queryWrapper);List<DishDto> dishDtoList = list.stream().map((item) -> {DishDto dishDto = new DishDto();//对象拷贝(每一个list数据)BeanUtils.copyProperties(item,dishDto);Long categoryId = item.getCategoryId();  //分类id//通过categoryId查询到category内容Category category = categoryService.getById(categoryId);//判空if(category != null){String categoryName = category.getName();dishDto.setCategoryName(categoryName);}//获取当前菜品idLong dishId = item.getId();//构造条件构造器LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper= new LambdaQueryWrapper<>();//添加查询条件dishFlavorLambdaQueryWrapper.eq(dishId != null,DishFlavor::getDishId,dishId);//select * from dish_flavors where dish_id = ?List<DishFlavor> dishFlavors = dishFlavorService.list(dishFlavorLambdaQueryWrapper);dishDto.setFlavors(dishFlavors);return dishDto;}).collect(Collectors.toList());return R.success(dishDtoList);}

测试

启动项目,点击登录,来到客户端首页,若该菜品有相应的口味选择,前端页面展示选择规格按钮;反之,前端页面展示+
按钮

业务开发Day6-06-菜品展示_代码开发_创建SetmealController的list方法并测试

前端分析

点击套餐分类时,报404异常,因为还未在服务端做相应的映射地址

  • 点击套餐分类时的请求地址以及请求方式
  • 通过url方式传参,参数类型为key-value键值对形式

创建SetmealController的list方法

在SetmealController控制层中,添加list方法
目的:通过套餐种类Id和套餐对应的状态查询出符合条件的套餐

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

测试

前端页面成功显示出儿童套餐种类包含的套餐

业务开发Day6-07-购物车_需求分析&数据模型&梳理交互过程&准备工作

需求分析

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

前端页面展示

数据模型

购物车对应的数据表为shopping_cart表,具体表结构如下:

梳理交互过程

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

  1. 点击加入购物车按钮或者*+*按钮,页面发送ajax请求,请求服务端,将菜品或者套餐添加到购物车
  2. 点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐
  3. 点击清空购物车按钮,页面发送ajax请求,请求服务端来执行清空购物车操作

开发购物车功能,其实就是在服务端编写代码去处理前端页面发送的这3次请求即可

准备工作

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

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

实体类ShoppingCart

package com.itzq.reggie.entity;import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 购物车*/
@Data
public class ShoppingCart implements Serializable {private static final long serialVersionUID = 1L;private Long id;//名称private String name;//用户idprivate Long userId;//菜品idprivate Long dishId;//套餐idprivate Long setmealId;//口味private String dishFlavor;//数量private Integer number;//金额private BigDecimal amount;//图片private String image;private LocalDateTime createTime;
}

Mapper接口ShoppingCartMapper

package com.itzq.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzq.reggie.entity.ShoppingCart;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {}

业务层接口ShoppingCartService

package com.itzq.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itzq.reggie.entity.ShoppingCart;public interface ShoppingCartService extends IService<ShoppingCart> {}

业务层实现类ShoppingCartServicelmpl

package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.entity.ShoppingCart;
import com.itzq.reggie.mapper.ShoppingCartMapper;
import com.itzq.reggie.service.ShoppingCartService;
import org.springframework.stereotype.Service;@Service
public class ShoppingCartServicelmpl extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {}

控制层ShoppingCartController

package com.itzq.reggie.controller;import com.itzq.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/shoppingCart")
@Slf4j
public class ShoppingCartController {@Autowiredprivate ShoppingCartService shoppingCartService;
}

业务开发Day6-08-购物车_代码开发_添加购物车

前端分析

启动项目,用户登录外卖系统,选择喜欢的菜品或套餐,若用户选择菜品并且该菜品有相应的口味则需要选择口味,点击加入购物车

  • 页面效果展示

  • 前端页面发送的请求地址以及请求方式

  • 前端页面以json格式将数据提交给服务端

代码

测试服务端是否能够接收前端页面提交的数据

在ShoppingCartController控制层,新增add方法(测试服务端是否可以成功接收前端页面提交的数据)

@RestController
@RequestMapping("/shoppingCart")
@Slf4j
public class ShoppingCartController {@Autowiredprivate ShoppingCartService shoppingCartService;@PostMapping("/add")public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){log.info("shoppingCart={}",shoppingCart);return null;}
}

在指定位置添加断点,便于查看是否成功接收数据

debug方式启动项目,添加菜品或套餐到购物车

跳转到服务端,服务端成功接收到前端提交的数据

完善代码

在ShoppingCartController控制层中的add方法添加代码
目的:将用户添加到购物车的菜品或套餐信息保存到数据库中,若添加相同菜品或相同套餐,则只需要在shopping_cart表更新该菜品或者套餐的数量(number字段);反之,则将菜品或套餐直接保存数据库中

package com.itzq.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itzq.reggie.common.BaseContext;
import com.itzq.reggie.common.R;
import com.itzq.reggie.entity.ShoppingCart;
import com.itzq.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/shoppingCart")
@Slf4j
public class ShoppingCartController {@Autowiredprivate ShoppingCartService shoppingCartService;@PostMapping("/add")public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){log.info("shoppingCart={}",shoppingCart);//设置用户id指定当前是哪个用户的购物车数据Long currentId = BaseContext.getCurrentId();shoppingCart.setUserId(currentId);//获取当前菜品idLong dishId = shoppingCart.getDishId();//条件构造器LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();//判断添加的是菜品还是套餐if (dishId != null){queryWrapper.eq(ShoppingCart::getDishId,dishId);}else {queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());}//查询当前菜品或者套餐是否在购物车中ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper);if (cartServiceOne != null){//如果已存在就在当前的数量上加1Integer number = cartServiceOne.getNumber();cartServiceOne.setNumber(number + 1);shoppingCartService.updateById(cartServiceOne);}else {//如果不存在,则添加到购物车,数量默认为1shoppingCartService.save(shoppingCart);cartServiceOne = shoppingCart;}return R.success(cartServiceOne);}
}

测试

重启项目,选择菜品或套餐,加入到购物车中

shopping_cart表中添加上用户选择的菜品信息

点击加号或减号可以修改该菜品的数量
目前还未开发减号相关的代码,所以只有加号可以正常操作

shopping_cart表中的number字段值得到更新

注意:amount字段的值为该菜品价格,而与数量无关

业务开发Day6-09-购物车_代码开发_查看购物车&清空购物车

查看购物车

前端分析

查看购物车,前端页面发送ajax请求,以下是请求的方式和请求的地址

代码开发

在ShoppingCartController类中,添加list方法

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

测试

重启项目,选择所需菜品或套餐,若需选择口味,则在选择口味后点击加入购物车

点击加入购物车后,页面发送三个ajax请求到服务端

  • add— 》 将所选菜品或套餐添加到数据库表中
  • list— 》 查询用户的购物车信息(需要测试的方法)
  • download— 》 图片下载

查询用户购物车信息成功,并在页面展示

清空购物车

前端分析

点击清空用户购物车,页面发送ajax请求,以下是请求的方式和请求的地址

代码开发

在ShoppingCartController类中,添加clean方法

 @DeleteMapping("/clean")public R<String> clean(){LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());//SQL:delete from shopping_cart where user_id = ?shoppingCartService.remove(queryWrapper);return R.success("成功清空购物车");}

测试

重启项目,来到购物车界面,点击清空按钮

执行成功

业务开发Day6-10-用户下单_需求分析&数据模型

需求分析

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

前端页面效果展示

数据模型

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

  • orders:订单表,具体表结构如下:

  • order_detail:订单明细表,具体表结构如下:

业务开发Day6-11-用户下单_梳理交互过程&准备工作

梳理交互过程

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

  1. 在购物车中点击去结算按钮,页面跳转到订单确认页面
  2. 在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址
  3. 在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据
  4. 在订单确认页面点击去支付按钮,发送ajax请求,请求服务端完成下单操作

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

准备工作

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

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

实体类

Orders

package com.itzq.reggie.entity;import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 订单*/
@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;//下单用户idprivate Long userId;//地址idprivate 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;
}

OrderDetail

package com.itzq.reggie.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;/*** 订单明细*/
@Data
public class OrderDetail implements Serializable {private static final long serialVersionUID = 1L;private Long id;//名称private String name;//订单idprivate Long orderId;//菜品idprivate Long dishId;//套餐idprivate Long setmealId;//口味private String dishFlavor;//数量private Integer number;//金额private BigDecimal amount;//图片private String image;
}

Mapper接口

OrderMapper

package com.itzq.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzq.reggie.entity.Orders;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderMapper extends BaseMapper<Orders> {}

OrderDetailMapper

package com.itzq.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzq.reggie.entity.OrderDetail;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {}

业务层接口

OrderService

package com.itzq.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itzq.reggie.entity.Orders;public interface OrderService extends IService<Orders> {}

OrderDetailService

package com.itzq.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itzq.reggie.entity.OrderDetail;public interface OrderDetailService extends IService<OrderDetail> {}

业务层实现类

OrderServicelmpl

package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.entity.Orders;
import com.itzq.reggie.mapper.OrderMapper;
import com.itzq.reggie.service.OrderService;
import org.springframework.stereotype.Service;@Service
public class OrderServicelmpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {}

OrderDetailServicelmpl

package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.entity.OrderDetail;
import com.itzq.reggie.mapper.OrderDetailMapper;
import com.itzq.reggie.service.OrderDetailService;
import org.springframework.stereotype.Service;@Service
public class OrderDetailServicelmpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements OrderDetailService {}

控制层

OrderController

package com.itzq.reggie.controller;import com.itzq.reggie.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {@Autowiredprivate OrderService orderService;}

OrderDetailController

package com.itzq.reggie.controller;import com.itzq.reggie.service.OrderDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/orderDetail")
@Slf4j
public class OrderDetailController {@Autowiredprivate OrderDetailService orderDetailService;}

业务开发Day6-12-用户下单_代码开发1

前端分析

启动项目,来到外卖初始界面,点击去结算按钮

页面跳转到确认订单界面,前端界面发送ajax请求,用于获取该用户的默认地址,发现请求失败,服务端没有对应的映射

在AddressBookController控制层,添加getDefault,请求方式为get请求

 @GetMapping("/default")public R<AddressBook> getDefault(){//当前用户idLong currentId = BaseContext.getCurrentId();//创建条件构造器LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(AddressBook::getUserId,currentId);queryWrapper.eq(AddressBook::getIsDefault,1);AddressBook addressBook = addressBookService.getOne(queryWrapper);return R.success(addressBook);}

重启项目,点击去结算按钮,跳转到确认订单页面,成功接收到该用户的默认地址

处理好确认订单页面后,点击去支付,系统报404错误—服务端还未添加相应的映射

以下展示了前端页面发送ajax请求的方式以及请求的地址

提交给服务端的数据格式为json数据

代码开发1

在业务层接口OrderService中添加submit方法

package com.itzq.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itzq.reggie.entity.Orders;public interface OrderService extends IService<Orders> {/*** 用户下单* @param orders*/void submit(Orders orders);
}

在业务层实现类OrderServicelmpl中,实现业务层接口OrderService添加的submit方法

package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.entity.Orders;
import com.itzq.reggie.mapper.OrderMapper;
import com.itzq.reggie.service.OrderService;
import org.springframework.stereotype.Service;@Service
public class OrderServicelmpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {/*** 用户下单* @param orders*/@Overridepublic void submit(Orders orders) {//获取当前用户id//查询当前用户的购物车数据//向订单表插入数据,一条数据//向订单明细表插入数据,多条数据//清空购物车数据}
}

在OrderController类中,添加submit方法—通过调用orderService接口实现对数据库的操作

package com.itzq.reggie.controller;import com.itzq.reggie.common.R;
import com.itzq.reggie.entity.Orders;
import com.itzq.reggie.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {@Autowiredprivate OrderService orderService;@PostMapping("/submit")public R<String> submit(@RequestBody Orders orders){log.info("orders={}",orders);orderService.submit(orders);return R.success("用户下单成功");}
}

业务开发Day6-13-用户下单_代码开发2

代码开发2

在业务层实现类OrderServicelmpl的submit方法中,添加逻辑代码

  • 获取当前用户id
  • 查询当前用户的购物车数据
  • 查询用户数据
  • 查询地址信息
 /*** 用户下单* @param orders*/@Override@Transactionalpublic void submit(Orders orders) {//获取当前用户idLong currentId = BaseContext.getCurrentId();//查询当前用户的购物车数据LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ShoppingCart::getUserId,currentId);List<ShoppingCart> shoppingCarts = shoppingCartService.list();if (shoppingCarts == null || shoppingCarts.size() == 0){throw new CustomException("购物车为空,不能下单");}//查询用户数据User user = userService.getById(currentId);//查询地址数据Long addressBookId = orders.getAddressBookId();AddressBook addressBook = addressBookService.getById(addressBookId);if (addressBook == null){throw new CustomException("地址信息有误,不能下单");}//向订单表插入数据,一条数据//向订单明细表插入数据,多条数据//清空购物车数据}

业务开发Day6-14-用户下单_代码开发3

代码开发3

提供完整的submit方法代码

  • 设置订单id
  • 向订单表设置属性
  • 向订单表插入数据,一条数据
  • 通过stream流,遍历购物车数据来获取的订单明细
  • 向订单明细表插入数据,多条数据
  • 清空购物车—通过用户id作为约束条件
package com.itzq.reggie.service.Impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itzq.reggie.common.BaseContext;
import com.itzq.reggie.common.CustomException;
import com.itzq.reggie.entity.*;
import com.itzq.reggie.mapper.OrderMapper;
import com.itzq.reggie.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;@Service
public class OrderServicelmpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {@Autowiredprivate ShoppingCartService shoppingCartService;@Autowiredprivate UserService userService;@Autowiredprivate AddressBookService addressBookService;@Autowiredprivate OrderDetailService orderDetailService;/*** 用户下单* @param orders*/@Override@Transactionalpublic void submit(Orders orders) {//获取当前用户idLong currentId = BaseContext.getCurrentId();//查询当前用户的购物车数据LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ShoppingCart::getUserId,currentId);List<ShoppingCart> shoppingCarts = shoppingCartService.list();if (shoppingCarts == null || shoppingCarts.size() == 0){throw new CustomException("购物车为空,不能下单");}//查询用户数据User user = userService.getById(currentId);//查询地址数据Long addressBookId = orders.getAddressBookId();AddressBook addressBook = addressBookService.getById(addressBookId);if (addressBook == null){throw new CustomException("地址信息有误,不能下单");}//设置订单idlong orderId = IdWorker.getId();AtomicInteger amount = new AtomicInteger(0);List<OrderDetail> orderDetailList= shoppingCarts.stream().map((item) -> {OrderDetail orderDetail = new OrderDetail();orderDetail.setOrderId(orderId);orderDetail.setName(item.getName());orderDetail.setImage(item.getImage());orderDetail.setDishId(item.getDishId());orderDetail.setSetmealId(item.getSetmealId());orderDetail.setDishFlavor(item.getDishFlavor());orderDetail.setNumber(item.getNumber());orderDetail.setAmount(item.getAmount());amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue());return orderDetail;}).collect(Collectors.toList());//向订单表设置属性orders.setId(orderId);orders.setNumber(String.valueOf(orderId));orders.setStatus(2);orders.setUserId(currentId);orders.setAddressBookId(addressBookId);orders.setOrderTime(LocalDateTime.now());orders.setCheckoutTime(LocalDateTime.now());orders.setAmount(new BigDecimal(amount.get()));orders.setPhone(addressBook.getPhone());orders.setUserName(user.getName());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()));//向订单表插入数据,一条数据super.save(orders);//向订单明细表插入数据,多条数据orderDetailService.saveBatch(orderDetailList);//清空购物车数据shoppingCartService.remove(queryWrapper);}
}

业务开发Day6-15-用户下单_功能测试

功能测试

重启项目,登录用户,来到确定订单页面,点击去支付

支付成功

数据库中orders表的变化:

数据库中order_detail表的变化:

操作成功

瑞吉外卖-全网最全笔记-Day06相关推荐

  1. 瑞吉外卖项目详细分析笔记及所有功能补充代码

    目录 项目刨析简介 技术栈 项目介绍 项目源码 一.架构搭建 1.初始化项目结构 2.数据库表结构设计 3.项目基本配置信息添加 公共字段的自动填充 全局异常处理类 返回结果封装的实体类 二.管理端业 ...

  2. 做完瑞吉外卖项目的一点笔记和源码

    源码在 https://gitee.com/pluto8/take-out 一.软件开发整体介绍 1.软件开发流程 需求分析 :产品原型,需求规格说明书(文档形式) 设计:产品文档.UI界面设计.概要 ...

  3. 瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接

    本项目是基于自学b站中 黑马程序员 的瑞吉外卖项目:视频链接: 黑马程序员Java项目实战<瑞吉外卖>,轻松掌握springboot + mybatis plus开发核心技术的真java实 ...

  4. 【瑞吉外卖开发笔记】

    瑞吉外卖开发笔记 源码地址 一.业务开发Day01 1.软件开发整体介绍 软件开发流程 角色分工 软件环境 2.瑞奇外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 3.环境搭建 开发环 ...

  5. 瑞吉外卖项目笔记+踩坑1——基础功能

     导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 1 ...

  6. 【瑞吉外卖】学习笔记-day1:项目介绍及后台初识

    项目介绍 本项目(瑞吉外卖)是专门为餐饮企业(餐厅.饭店)定制的一款软件产品,包括 系统管理后台 和 移动端应用 两部分.其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的分类.菜品.套餐. ...

  7. 瑞吉外卖项目学习笔记01

    项目背景 在开发瑞吉外卖这个项目之前,我们需要全方位的来介绍一下当前我们学习的这个项目.接下来,我们将从以下的五个方面, 来介绍瑞吉外卖这个项目. 项目介绍 本项目(瑞吉外卖)是专门为餐饮企业(餐厅. ...

  8. Eatting外卖基于瑞吉外卖代码全功能优化含源码

    Eatting外卖基于瑞吉外卖代码全功能优化含源码 文章目录 项目的最终部署 源码地址 github:[源码地址](https://github.com/yangxingyue0623/Eating_ ...

  9. 黑马瑞吉外卖项目开发笔记

    目录 软件开发整体介绍 开发流程 角色分工 软件环境 瑞吉外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 开发环境搭建 数据库环境搭建 Maven环境搭建 1.直接创建maven项目( ...

最新文章

  1. 集成学习需要理解的一些内容
  2. 2018年前35名Python面试问题和答案
  3. 比特币和比特币现金就隐私保护展开辩论
  4. 设计模式学习之Factory Method模式和Abstract Factory模式
  5. 使用spring boot创建fat jar APP
  6. 【51单片机快速入门指南】4.3.2: MPU6050:一阶互补滤波、二阶互补滤波和卡尔曼滤波获取欧拉角
  7. 【转】解决WCF大数据量传输 ,System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接...
  8. bigdecimal除法保留4位小数_小猿圈分享-MySQL保留几位小数的4种方法
  9. linux进程闭锁,4. ps 进程查看器
  10. C++并发编程 (1) 基本知识
  11. php定义一个学生类_3分钟短文 | PHP获取函数参数名,和类定义的常量,都要反射...
  12. ERP项目实施记录05
  13. mysql触发器中访问mssql数据表_[数据库]一个利用触发器(trigger)实现数据库表的审计功能(audit)的例子--针对ms sql实现...
  14. 挑选了适合测试边界的汉字及截图
  15. java volatile 和Transient 关键字
  16. java制作qq自动回复,qq自动回复机器人-qq自动回复机器人 v1.6 电脑版
  17. 量化金融经典理论、重要模型、发展简史大全
  18. 【codevs4093】 EZ的间谍网络 强连通分量+tarjan缩点
  19. linux安装杀毒软件
  20. Route-Policy

热门文章

  1. 三阶魔方大中小魔公式_三阶魔方的入门玩法教程|魔方玩法|魔方视频教程|魔方公式图解|--想成为魔方高手就来魔方乐园吧...
  2. linux tahoma字体,linux - 更好的Ubuntu字体 - Ubuntu问答
  3. Git Re-Basin: Merging Models modulo Permutation Symmetries解读
  4. 微商相册服务器维护,微商相册
  5. 2011-07-13 wince上面plg插件生成
  6. 满减优惠用多了,想过怎么运作的吗?
  7. 捣鼓车间 | 学生获奖作品:戒烟帽
  8. python猴子分桃_猴子分桃 - Ryan in C++ - 博客园
  9. bigworld源码分析(3)——dbMgr分析
  10. 团队的英文翻译缩写_团队的英语是什么?简写呢?