编码阶段五 —— 购物车功能实现
这是对应的视频链接【黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis plus开发核心技术的真java实战项目-哔哩哔哩】 https://b23.tv/3nr8oMw
大家如果做了可以一起探讨一下,我在这实现了那些视频中没有完成的功能
地址簿:指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息。同一个用户可以有多个地址信息,但是只能有一个默认地址。
用户的具体地址会存储在address_book表,即地址表中,具体表结构如下。
先导入相关实体类
@Data
public class AddressBook implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//用户id
private 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 updatedTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer deleted;
}
由于这个service和mapper层都没什么东西,大家自行创建即可,我们重点来看controller层
/**
* 地址簿管理
*/
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {
@Autowired
private IAddressBookService 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);
List<AddressBook> list = addressBookService.list(queryWrapper);
//SQL:select * from address_book where user_id = ? order by update_time desc
return R.success(list);
}
}
菜品展示功能
用户登录成功后跳转到系统首页,在首页需要根据分类来展示菜品和套餐。如果菜品设置了口味信息,需要展示选择规格
按钮,否则显示+
号
梳理交互过程
- 页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
- 页面发送ajax请求,获取第一个分类下的菜品或者套餐
注意:首页加载完成后,还发送了一次ajax请求用于加载购物车数据,此处可以将这次请求的地址暂时修改一下,从静态json文件获取数据,等后续开发购物车功能时再修改回来
把这个url改了就相当于传一个假数据
{"code":1,"msg":null,"data":[],"map":{}}
购物车功能
移动端用户可以将菜品或者套餐添加到购物车。对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车;对于套餐来说,可以直接点击+
将当前套餐加入购物车。在购物车中可以修改菜品和套餐的数量,也可以清空购物车。来看看购物车对应的表
交互过程
- 点击
加入购物车
或者+
按钮,页面发送ajax请求,请求服务器,将菜品或者套餐添加到购物车 - 点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐
- 点击清空购物车,页面发送ajax请求,请求服务端来执行清空购物车操作
对应实体类
@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;
}
Service接口
/**
* @author William
* @create 2022-04-28 15:41
*/
public interface IShoppingCartService extends IService<ShoppingCart> {
//添加购物车
ShoppingCart addShoppingCart(ShoppingCart shoppingCart);
//减少购物车
ShoppingCart subShoppingCart(ShoppingCart shoppingCart);
//查看购物车列表
List<ShoppingCart> getShoppingCartList();
//清空购物车
void clean();
}
Service实现类
/**
* @author William
* @create 2022-04-28 15:43
*/
@Service
public class ShoppingCartServiceImpl extends ServiceImpl<ShoppingCartDAO, ShoppingCart> implements IShoppingCartService {
/**
* 添加购物车
*@Param [shoppingCart]
*@Return
*/
@Override
public ShoppingCart addShoppingCart(ShoppingCart 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 = this.getOne(queryWrapper);
if(cartServiceOne != null){
//如果已经存在,就在原来数量基础上加一
Integer number = cartServiceOne.getNumber();
cartServiceOne.setNumber(number + 1);
this.updateById(cartServiceOne);
}else{
//如果不存在,则添加到购物车,默认数量就是一
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(LocalDateTime.now());
this.save(shoppingCart);
cartServiceOne = shoppingCart;
}
return cartServiceOne;
}
/**
* 减少购物车
*@Param [shoppingCart]
*@Return
*/
@Override
public ShoppingCart subShoppingCart(ShoppingCart 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 = this.getOne(queryWrapper);
if(cartServiceOne != null){
//如果已经存在,就在原来数量基础上减一
Integer number = cartServiceOne.getNumber();
if(number >= 1){
cartServiceOne.setNumber(number - 1);
this.updateById(cartServiceOne);
if(number == 1){//这样就能配合前端,当数字为0的时候就可以让购物车变色
this.clean();
}
}
}
return cartServiceOne;
}
/**
* 查询购物车列表
*@Param []
*@Return
*/
@Override
public List<ShoppingCart> getShoppingCartList() {
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId())
.orderByAsc(ShoppingCart::getCreateTime);
List<ShoppingCart> list = this.list(queryWrapper);
return list;
}
/**
* 清空购物车
*@Param []
*@Return
*/
@Override
public void clean() {
// SQL: delete from shopping_cart where user_id = ?
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
this.remove(queryWrapper);
}
}
Controller层
/**
* @author William
* @create 2022-04-28 15:46
*/
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
public class ShoppingCartController {
@Autowired
private IShoppingCartService shoppingCartService;
@ApiOperation(value = "添加", notes = "添加购物车")
@PostMapping(value = "/add")
public R<ShoppingCart> addShoppingCart(@RequestBody ShoppingCart shoppingCart){
log.info("购物车数据:{}", shoppingCart);
ShoppingCart shoppingCartOne = shoppingCartService.addShoppingCart(shoppingCart);
return R.success(shoppingCartOne);
}
@ApiOperation(value = "减少", notes = "减少购物车")
@PostMapping(value = "/sub")
public R<ShoppingCart> subShoppingCart(@RequestBody ShoppingCart shoppingCart){
log.info("购物车数据:{}", shoppingCart);
ShoppingCart shoppingCartOne = shoppingCartService.subShoppingCart(shoppingCart);
return R.success(shoppingCartOne);
}
@ApiOperation(value = "查询", notes = "查询购物车")
@GetMapping("/list")
public R<List<ShoppingCart>> list(){
log.info("查看购物车...");
List<ShoppingCart> list = shoppingCartService.getShoppingCartList();
return R.success(list);
}
@ApiOperation(value = "删除", notes = "清空购物车")
@DeleteMapping("/clean")
public R<String> clear(){
shoppingCartService.clean();
return R.success("清空购物车成功");
}
}