瑞吉外卖(7)—移动端业务开发

目录

一、地址簿管理

1.1 需求分析

1.2 数据模型

 1.3 代码开发

二、手机端展示

2.1 菜品展示

2.2 套餐展示

三、购物车功能

3.1 需求分析

3.2 数据模型

 3.3 代码开发

四、用户下单

4.1 需求分析

4.2 数据模型

4.3 代码开发


一、地址簿管理

1.1 需求分析

1.2 数据模型

 1.3 代码开发

准备工作,导入AddressBook实体类,检查一下实体类的属性是否和数据库中的表字段一一对应;

创建mapper:

package com.learn.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.learn.reggie.entity.AddressBook;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AddressBookMapper extends BaseMapper<AddressBook> {

}
package com.learn.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.learn.reggie.entity.AddressBook;


public interface AddressBookService extends IService<AddressBook> {

}

实现类:

package com.learn.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.learn.reggie.entity.AddressBook;
import com.learn.reggie.mapper.AddressBookMapper;
import com.learn.reggie.service.AddressBookService;
import org.springframework.stereotype.Service;

@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements AddressBookService {

}

controller层编写:

package com.learn.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.learn.reggie.common.BaseContext;
import com.learn.reggie.common.R;
import com.learn.reggie.entity.AddressBook;
import com.learn.reggie.service.AddressBookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 地址簿管理
 */
@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.1 菜品展示

前端重点代码:

 

//获取所有的菜品分类
function categoryListApi() {
    return $axios({
      'url': '/category/list',
      'method': 'get',
    })
  }
 
//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        'url': '/shoppingCart/list',
        'method': 'get',
        params:{...data}
    })
}

 

 我们发现前端的展示页面中请求到了category的数据,服务器也响应了数据给前端页面,但是我们也看见了手机端并没有展示相关的套餐数据;这是因为在加载页面的时候,前端一共发了两个list请求,具体的请求看上面的前端代码,请求购物车信息的请求返回404,所以导致category的数据也没有被展示;

这里我们先在其他地方静态的接收购物车的请求,这样就可以先显示category的数据;先用假数据测试一下:

修改购物车的请求地址,
 

//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        //'url': '/shoppingCart/list',
        'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}
// 假数据文件
{"code":1,"msg":null,"data":[],"map":{}}

但是我们也发现了bug,就是展示的菜品没有对应的口味信息,比如甜度,辣度。。。我们之前是添加过相关的口味数据的;

这是因为我们在请求获取菜品信息的时候,我们返回的数据是R<List<Dish>> ,Dish这个类是没有相关的口味信息的,所以即便前端请求了这个口味的信息,但是后端是没有给它返回的,所以体现在前端就是口味信息没有展示出来;所以我们需要对DishController中的list接口进行修改;

bug修复:

//方法改造
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish){ //会自动映射的
    //这里可以传categoryId,但是为了代码通用性更强,这里直接使用dish类来接受(因为dish里面是有categoryId的),以后传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();
        //为一个新的对象赋值,一定要考虑你为它赋过几个值,否则你自己都不知道就返回了null的数据
        //为dishDto对象的基本属性拷贝
        BeanUtils.copyProperties(item,dishDto);
        Long categoryId = item.getCategoryId();
        Category category = categoryService.getById(categoryId);
        if (category != null){
            String categoryName = category.getName();
            dishDto.setCategoryName(categoryName);
        }
        //为dishdto赋值flavors属性
        //当前菜品的id
        Long dishId = item.getId();
        //创建条件查询对象
        LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
        //select * from dish_flavor where dish_id = ?
        //这里之所以使用list来条件查询那是因为同一个dish_id 可以查出不同的口味出来,就是查询的结果不止一个
        List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
        dishDto.setFlavors(dishFlavorList);
 
        return dishDto;
    }).collect(Collectors.toList());
 
    return R.success(dishDtoList);
}

2.2 套餐展示

套餐展示的前端请求地址和携带的参数:

  在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.1 需求分析

3.2 数据模型

 3.3 代码开发

 

加入购物车功能:

加入购物车的前端请求和携带的参数:

 

开发准备工作:

导入实体类ShoppingCart;

创建对应的mapper:

package com.learn.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.learn.reggie.entity.ShoppingCart;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author 咕咕猫
 * @version 1.0
 */
@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {
}

创建service:

package com.learn.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.learn.reggie.entity.ShoppingCart;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public interface ShoppingCartService extends IService<ShoppingCart> {
}

实现类:

package com.learn.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.learn.reggie.entity.ShoppingCart;
import com.learn.reggie.mapper.ShoppingCartMapper;
import com.learn.reggie.service.ShoppingCartService;
import org.springframework.stereotype.Service;

/**
 * @author 咕咕猫
 * @version 1.0
 */
@Service
public class ShoppingCartServiceImpl extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {

}

controller层开发:

package com.learn.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.learn.reggie.common.BaseContext;
import com.learn.reggie.common.R;
import com.learn.reggie.entity.ShoppingCart;
import com.learn.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 购物车
 * @author 咕咕猫
 * @version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
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);

        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) {
            //如果已经存在,就在原来的数量上+1
            Integer number = cartServiceOne.getNumber();
            cartServiceOne.setNumber(number + 1);
            shoppingCartService.updateById(cartServiceOne);
        } else {
            //如果不存在,则添加到购物车,数量默认是1
            shoppingCart.setNumber(1);
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCartService.save(shoppingCart);
            cartServiceOne = shoppingCart;
        }

        return R.success(cartServiceOne);
    }

}

功能测试:

  不过这个只能把菜品或者是套餐加入到购物车,那个减号点了是没效果的;

 查看购物车

把相关的前端请求地址给改掉, 不再请求假数据,至于存放假数据的json文件是否删除,看你自己,删不删都没什么影响;

//获取购物车内商品的集合
function cartListApi(data) {
    return $axios({
        'url': '/shoppingCart/list',
        //'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

注意:一定要有用户的概念,不同用户看到的购物车是不一样的!!!

controller:

    /**
     * 查看购物车
     * @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(){
        //SQL: delete from shopping_cart where user_id = ?
        LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());

        shoppingCartService.remove(queryWrapper);

        return R.success("清空购物车成功");
    }

四、用户下单

4.1 需求分析

注意:这里只是把用户的支付订单保存到数据库,因为真正的支付功能是需要去申请支付资质的,个人用户很难申请到;

4.2 数据模型

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

order:订单表;

 order_detail:订单明细表

4.3 代码开发

前端和服务器的交互过程:

第一次交互:

 然后点击去支付:然后前端就会发生http://localhost:8080/order/submit这个请求;并且携带三个参数:一个是地址,一个是字符方式,一个是客户的备注;

开发准备工作:

导入实体类:order,order_details

创建mapper:

package com.learn.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.learn.reggie.entity.Orders;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author 咕咕猫
 * @version 1.0
 */
@Mapper
public interface OrderMapper extends BaseMapper<Orders> {
}
package com.learn.reggie.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.learn.reggie.entity.OrderDetail;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author 咕咕猫
 * @version 1.0
 */
@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}

创建service及其实现:

package com.learn.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.learn.reggie.entity.Orders;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public interface OrderService extends IService<Orders> {

    //用户下单
    public void submit(Orders orders);
}
package com.learn.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.learn.reggie.entity.OrderDetail;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public interface OrderDetailService extends IService<OrderDetail> {
}
package com.learn.reggie.service.impl;
 
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 
import com.itheima.reggie.entity.*;
import com.itheima.reggie.mapper.OrderMapper;
import com.itheima.reggie.service.*;
import org.springframework.stereotype.Service;
 
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {
}
package com.learn.reggie.service.impl;
 
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.OrderDetail;
import com.itheima.reggie.mapper.OrderDetailMapper;
import com.itheima.reggie.service.OrderDetailService;
import org.springframework.stereotype.Service;
 
@Service
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements OrderDetailService {
 
}

controller层开发:

前端请求的地址和携带的参数前面已经分析过了;

package com.learn.reggie.controller;

import com.learn.reggie.common.R;
import com.learn.reggie.entity.Orders;
import com.learn.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;

/**
 * 订单
 * @author 咕咕猫
 * @version 1.0
 */
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 用户下单
     * @param orders
     * @return
     */
    @PostMapping("/submit")
    public R<String> submit(@RequestBody Orders orders){
        log.info("订单数据:{}",orders);
        orderService.submit(orders);
        return R.success("下单成功");
    }

}

service添加submit方法:

/**
 * 用户下单
 * @param orders
 */
public void submit(Orders orders);

方法的实现:

package com.learn.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.learn.reggie.common.BaseContext;
import com.learn.reggie.common.CustomException;
import com.learn.reggie.entity.*;
import com.learn.reggie.mapper.OrderMapper;
import com.learn.reggie.service.*;
import lombok.extern.slf4j.Slf4j;
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;

/**
 * @author 咕咕猫
 * @version 1.0
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {

    @Autowired
    private ShoppingCartService shoppingCartService;

    @Autowired
    private UserService userService;

    @Autowired
    private AddressBookService addressBookService;

    @Autowired
    private OrderDetailService orderDetailService;

    /**
     * 用户下单
     * @param orders
     * @return
     */
    @Transactional
    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(); //订单号

        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(queryWrapper);
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值