1. 程式人生 > 其它 >Java專案實戰——瑞吉外賣Day06

Java專案實戰——瑞吉外賣Day06

瑞吉外賣開發筆記 六

筆記內容為黑馬程式設計師視訊內容

匯入使用者地址簿相關功能程式碼

需求分析

地址簿,指的是移動端消費者使用者的地址資訊,使用者登入成功後可以維護自己的地址資訊。同一個使用者可以有多個地址資訊,但是隻能有一個預設地址

資料模型

使用者的地址資訊會儲存在address_book表,即地址簿表中。具體表結構如下:

匯入功能程式碼

功能程式碼清單:

  • 實體類AddressBook(直接從課程資料中匯入即可)
  • Mapper介面AddressBookMapper
  • 業務層介面AddressBookService
  • 業務層實現類AddressBookServicelmpl
  • 控制層AddressBookController(直接從課程資料中匯入即可)
@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));
    }
}

功能測試

菜品展示

需求分析

使用者登入成功後跳轉到系統首頁,在首頁需要根據分類來展示菜品和套餐。如果菜品設定了口味資訊需要展示 [選擇規格] 按鈕,否則顯示 [+] 按鈕。

程式碼開發

程式碼開發-梳理互動過程

在開發程式碼之前,需要梳理一下前端頁面和服務端的互動過程:

1、頁面(front/index.html)傳送ajax請求,獲取分類資料(菜品分類和套餐分類)

2、頁面傳送ajax請求,獲取第一個分類下的菜品或者套餐

開發菜品展示功能,其實就是在服務端編寫程式碼去處理前端頁面傳送的這2次請求即可。

注意:首頁載入完成後,還發送了一次ajax請求用於載入購物車資料,此處可以將這次請求的地址暫時修改一下,從靜態json檔案獲取資料,等後續開發購物車功能時再修改回來,如下:

//獲取購物車內商品的集合
function cartListApi(data) {
    return $axios({
        // 'url': '/shoppingCart/list',
        'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

cartData.json:

{"code":1,"msg":null,"data":[],"map":{}}

改造DishController中的list方法

@GetMapping("/list")
public R<List<DishDto>> list(Dish dish) {

    //構造查詢條件
    LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    //新增條件,查詢狀態為1的(起售狀態)
    lambdaQueryWrapper.eq(Dish::getStatus, 1);
    lambdaQueryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
    //條件排序條件
    lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

    List<Dish> list = dishService.list(lambdaQueryWrapper);

    List<DishDto> dishDtoList = list.stream().map((item) -> {
        DishDto dishDto = new DishDto();

        BeanUtils.copyProperties(item, dishDto);
        Long categoryId = item.getCategoryId();
        //根據id查分類物件
        Category category = categoryService.getById(categoryId);
        if (category != null) {
            String categoryName = category.getName();
            dishDto.setCategoryName(categoryName);
        }

        //當前菜品id
        Long dishId = item.getId();
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId, dishId);
        //SQL: select* from dishflavor where dish_id=?;
        List<DishFlavor> dishFlavorlist = dishFlavorService.list(queryWrapper);
        dishDto.setFlavors(dishFlavorlist);
        return dishDto;
    }).collect(Collectors.toList());

    return R.success(dishDtoList);
}

在SetmealController裡新增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);
}

功能測試

購物車

需求分析

移動端使用者可以將菜品或者套餐新增到購物車。對於菜品來說,如果設定了口味資訊,則需要選擇規格後才能加入購物車;對於套餐來說,可以直接點選 [+] 將當前套餐加入購物車。在購物車中可以修改菜品和套餐的數量,也可以清空購物車。

資料模型

購物車對應的資料表為shopping_cart表,具體表結構如下:

程式碼開發

程式碼開發-梳理互動過程

在開發程式碼之前,需要梳理一下購物車操作時前端頁面和服務端的互動過程:

1、點選 [加入購物車] 或者 [+] 按鈕,頁面傳送ajax請求,請求服務端,將菜品或者套餐新增到購物車

2、點選購物車圖示,頁面傳送ajax請求,請求服務端查詢購物車中的菜品和套餐

3、點選清空購物車按鈕,頁面傳送ajax請求,請求服務端來執行清空購物車操作

開發購物車功能,其實就是在服務端編寫程式碼去處理前端頁面傳送的這3次請求即可。

程式碼開發-準備工作

在開發業務功能前,先將需要用到的類和介面基本結構建立好:

  • 實體類ShoppingCart(直接從課程資料中匯入即可)
  • Mapper介面ShoppingCartMapper
  • 業務層介面ShoppingcartService
  • 業務層實現類ShoppingCartServicelmpl
  • 控制層ShoppingCartController

程式碼開發-新增購物車

@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) {
        //如果已經存在,則在原來的基礎上加一
        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 R.success(cartServiceone);
}

程式碼開發-檢視購物車

把前端假資料改回來

function cartListApi(data) {
    return $axios({
        'url': '/shoppingCart/list',
        // 'url':'/front/cartData.json',
        'method': 'get',
        params:{...data}
    })
}

檢視購物車

@GetMapping("/list")
public R<List<ShoppingCart>> list(){
    log.info("檢視購物車");
    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);
}

程式碼開發-清空購物車

@DeleteMapping("/clean")
public R<String> clean(){

    LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
    queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
    shoppingcartService.remove(queryWrapper);
    return R.success("清空購物車成功");
}

程式碼開發-減少菜品

@PostMapping("/sub")
public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart){
    Long setmealId = shoppingCart.getSetmealId();
    Long dishId = shoppingCart.getDishId();
    LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
    queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());

    if (setmealId!=null){
        queryWrapper.eq(ShoppingCart::getSetmealId,setmealId);
    }else {
        queryWrapper.eq(ShoppingCart::getDishId,dishId);
    }
    ShoppingCart one = shoppingcartService.getOne(queryWrapper);
    Integer number = one.getNumber();
    if(number==1){
        shoppingcartService.remove(queryWrapper);
    }else {
        one.setNumber(number-1);
        shoppingcartService.updateById(one);
    }

    return R.success(one);
}

下單

需求分析

移動端使用者將菜品或者套餐加入購物車後,可以點選購物車中的 【去結算】 按鈕,頁面跳轉到訂單確認頁面,點選 【去支付】 按鈕則完成下單操作。

資料模型

使用者下單業務對應的資料表為orders表和order_detail表:

  • orders:訂單表

  • order_detail:訂單明細表

程式碼開發

程式碼開發-梳理互動過程

在開發程式碼之前,需要梳理一下使用者下單操作時前端頁面和服務端的互動過程:

1、在購物車中點選 【去結算】 按鈕,頁面跳轉到訂單確認頁面

2、在訂單確認頁面,傳送ajax請求,請求服務端獲取當前登入使用者的預設地址

3、在訂單確認頁面,傳送ajax請求,請求服務端獲取當前登入使用者的購物車資料

4、在訂單確認頁面點選 【去支付】 按鈕,傳送ajax請求,請求服務端完成下單操作

開發使用者下單功能,其實就是在服務端編寫程式碼去處理前端頁面傳送的請求即可。

程式碼開發-準備工作

在開發業務功能前,先將需要用到的類和介面基本結構建立好:

  • 實體類Orders、OrderDetail(直接從課程資料中匯入即可)
  • Mapper介面OrderMapper、OrderDetailMapper
  • 業務層介面OrderService、OrderDetailService
  • 業務層實現類OrderServicelmpl、OrderDetailServicelmpl
  • 控制層OrderController、OrderDetailController

程式碼開發

在OrderService新增submit方法用於使用者下單

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

    @Override
    @Transactional
    public void submit(Orders orders) {
        //獲取當前使用者id
        Long currentId = BaseContext.getCurrentId();
        //查詢當前使用者的購物車資料
        LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(ShoppingCart::getUserId,currentId);
        List<ShoppingCart> list = shoppingcartService.list(queryWrapper);

        if (list==null||list.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("地址有誤,不能下單");
        }

        long orderId = IdWorker.getId();//訂單號

        AtomicInteger amount=new AtomicInteger(0);

        List<OrderDetail> orderDetails=list.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);
        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2);
        orders.setAmount(new BigDecimal(amount.get()));//計算總金額
        orders.setUserId(currentId);
        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);
    }
}

在OrderController的submit方法處理post請求實現上面的方法

//使用者下單
@PostMapping("/submit")
public R<String> submit(@RequestBody Orders orders){
    log.info("訂單資料:{}",orders);
    orderService.submit(orders);
    return R.success("下單成功");
}

功能測試

下單介面:

下單成功介面: