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("下單成功");
}
功能測試
下單介面:
下單成功介面: