瑞吉外卖(五)
套餐業(yè)務開發(fā)
新增套餐
需求分析
新增套餐,其實就是將新增頁面錄入的套餐信息插入到setmeal表,還需要向setmeal_dish表插入套餐和菜品關聯(lián)數(shù)據(jù)。所以在新增套餐時,涉及到兩個表:
在開發(fā)業(yè)務功能前,先將需要用到的類和接口基本結構創(chuàng)建好:
- 實體類SetmealDish(直接從課程資料中導入即可,Setmeal實體前面+ 課程中已經導入過了)
- DTO SetmealDto(直接從課程資料中導入即可)
- Mapper接口SetmealDishMapper
- 業(yè)務層接口SetmealDishService
- 業(yè)務層實現(xiàn)類SetmealDishServicelmpl
- 控制層SetmealController
代碼開發(fā)
在開發(fā)代碼之前,需要梳理一下新增套餐時前端頁面和服務端的交互過程:
1、頁面(backend/ page/comboladd.html)發(fā)送ajax請求,請求服務端獲取套餐分類數(shù)據(jù)并展示到下拉框中
這個方法我們在前面在新增菜品獲取菜品分類的時候我們已經寫過了,只不過是請求參數(shù)不同而已。
2、頁面發(fā)送ajax請求,請求服務端獲取菜品分類數(shù)據(jù)并展示到添加菜品窗口中
3、頁面發(fā)送ajax請求,請求服務端,根據(jù)菜品分類查詢對應的菜品數(shù)據(jù)并展示到添加菜品窗口中
前端頁面可以根據(jù)菜品分類和菜品名稱查找,這兩個接口都是通用的,
根據(jù)菜品分類獲取菜品信息:
根據(jù)菜品名稱獲取菜品信息:
const queryDishList = (params) => {return $axios({url: '/dish/list',method: 'get',params}) }代碼編寫:
@GetMapping("/list") public Result<List<Dish>> getDishByCategory(Dish dish){LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();dishLambdaQueryWrapper.eq(Dish::getStatus,1);dishLambdaQueryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());dishLambdaQueryWrapper.like(dish.getName()!=null,Dish::getName,dish.getName());dishLambdaQueryWrapper.orderByDesc(Dish::getUpdateTime);List<Dish> dishes = dishService.list(dishLambdaQueryWrapper);return Result.success(dishes); }4、頁面發(fā)送請求進行圖片上傳,請求服務端將圖片保存到服務器
5、頁面發(fā)送請求進行圖片下載,將上傳的圖片進行回顯
6、點擊保存按鈕,發(fā)送ajax請求,將套餐相關數(shù)據(jù)以json形式提交到服務端
前端接口:
const addSetmeal = (params) => {return $axios({url: '/setmeal',method: 'post',data: { ...params }}) }前端請求的數(shù)據(jù):
@Override public void saveSetmealDto(SetmealDto setmealDto) {this.save(setmealDto);Long setmealId = setmealDto.getId();List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes.forEach(setmealDish -> setmealDish.setSetmealId(setmealId));setmealDishService.saveBatch(setmealDishes); }套餐分頁查詢
需求開發(fā)
前端接口:
const getSetmealPage = (params) => {return $axios({url: '/setmeal/page',method: 'get',params}) }代碼開發(fā)
@GetMapping("page") public Result<Page> page(@RequestParam(value = "page",defaultValue = "1") Integer page,@RequestParam(value = "pageSize",defaultValue = "10") Integer pageSize,String name){log.info("page={},pageSize={},name={}",page,pageSize,name);Page<Setmeal> setmealPage = new Page<>();//查詢條件LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();setmealLambdaQueryWrapper.like(StringUtils.hasLength(name),Setmeal::getName,name);//按名稱查找setmealLambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);//按更新時間查找setmealService.page(setmealPage,setmealLambdaQueryWrapper);Page<SetmealDto> setmealDtoPage = new Page<>();BeanUtils.copyProperties(setmealPage,setmealDtoPage,"records");List<Setmeal> setmeals = setmealPage.getRecords();List<SetmealDto> setmealDtos=new LinkedList<>();setmeals.forEach(setmeal -> {SetmealDto setmealDto = new SetmealDto();//講setmeal對象內容移到setmealDtoBeanUtils.copyProperties(setmeal,setmealDto);//查找套裝分類并給每個setmealDto的categoryName屬性賦值Long categoryId = setmealDto.getCategoryId();Category category = categoryService.getById(categoryId);if (category!=null){setmealDto.setCategoryName(category.getName());}setmealDtos.add(setmealDto);});setmealDtoPage.setRecords(setmealDtos);return Result.success(setmealDtoPage); }刪除套餐
需求開發(fā)
前端接口:
const deleteSetmeal = (ids) => {return $axios({url: '/setmeal',method: 'delete',params: { ids }}) }代碼開發(fā)
@Override @Transactional public void removeSetmealDtoBatch(List<Long> ids) {List<Setmeal> setmeals = this.listByIds(ids);setmeals.forEach(setmeal -> {if(setmeal.getStatus()==1){throw new SetmealException("啟售中的套餐不能刪除");}LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();setmealDishLambdaQueryWrapper.eq(SetmealDish::getSetmealId,setmeal.getId());setmealDishService.remove(setmealDishLambdaQueryWrapper);});this.removeByIds(ids);setmeals.forEach(setmeal -> {File file = new File(basePath + setmeal.getImage());file.delete();}); }修改套餐信息
需求開發(fā)
在修改套裝之前要獲取套餐的信息
前端接口:
async init() {querySetmealById(this.id).then((res) => {if (String(res.code) === '1') {this.ruleForm = res.datathis.ruleForm.status = res.data.status === '1'this.ruleForm.price = res.data.price / 100this.imageUrl = `/common/download?name=${res.data.image}`this.checkList = res.data.setmealDishesthis.dishTable = res.data.setmealDishesthis.ruleForm.idType = res.data.categoryId// this.ruleForm.password = ''} else {this.$message.error(res.msg || '操作失敗')}}) }const querySetmealById = (id) => {return $axios({url: `/setmeal/${id}`,method: 'get'}) }代碼開發(fā)
根據(jù)套餐ID獲取套餐信息:
@Override public SetmealDto getSetmealDtoById(Long id) {Setmeal setmeal = this.getById(id);SetmealDto setmealDto = new SetmealDto();BeanUtils.copyProperties(setmeal,setmealDto);LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();setmealDishLambdaQueryWrapper.eq(SetmealDish::getSetmealId,id);setmealDishLambdaQueryWrapper.orderByDesc(SetmealDish::getUpdateTime);List<SetmealDish> setmealDishes = setmealDishService.list(setmealDishLambdaQueryWrapper);setmealDto.setSetmealDishes(setmealDishes);return setmealDto; }點擊保存按鈕之后,前端會發(fā)送以下請求給服務器,與添加套餐功能類似:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FOSrnlxf-1678802048382)(null)]
@Override @Transactional public void updateSetmealDto(SetmealDto setmealDto) {this.updateById(setmealDto);Long setmealId = setmealDto.getId();LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>();setmealDishLambdaQueryWrapper.eq(SetmealDish::getSetmealId,setmealId);setmealDishService.remove(setmealDishLambdaQueryWrapper);List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes.forEach(setmealDish -> setmealDish.setSetmealId(setmealId));setmealDishService.saveBatch(setmealDishes); }手機驗證碼登錄
短信發(fā)送
短信服務介紹
目前市面上有很多第三方提供的短信服務,這些第三方短信服務會和各個運營商(移動、聯(lián)通、電信)對接,我們只需要注冊成為會員并且按照提供的開發(fā)文檔進行調用就可以發(fā)送短信。需要說明的是,這些短信服務一般都是收費服務。
常用短信服務:
- 阿里云
- 華為云
- 騰訊云
- 京東
- 夢網(wǎng)
- 樂信
阿里云短信服務-介紹
阿里云短信服務(Short Message Service)是廣大企業(yè)客戶快速觸達手機用戶所優(yōu)選使用的通信能力。調用API或用群發(fā)助手,即可發(fā)送驗證碼、通知類和營銷類短信;國內驗證短信秒級觸達,到達率最高可達99%;國際/港澳臺短信覆蓋200多個國家和地區(qū),安全穩(wěn)定,廣受出海企業(yè)選用。
應用場景:
- 驗證碼
- 短信通知
- 推廣短信
阿里云短信服務-注冊賬號
阿里云官網(wǎng): https://www.aliyun.com/
點擊官網(wǎng)首頁注冊按鈕。
阿里云短信服務-設置短信簽名
注冊成功后,點擊登錄按鈕進行登錄。登錄后進入短信服務管理頁面,選擇國內消息菜單:
短信簽名是短信發(fā)送者的署名,表示發(fā)送方的身份。
阿里云短信服務-設置短信模板
切換到【模板管理】標簽頁:
短信模板包含短信發(fā)送內容、場景、變量信息。
阿里云短信服務-設置AccessKey
光標移動到用戶頭像上,在彈出的窗口中點擊【AccessKey管理】∶
代碼開發(fā)
在開發(fā)代碼之前,需要梳理一下登錄時前端頁面和服務端的交互過程:
1、在登錄頁面(front/page/login.html)輸入手機號,點擊【獲取驗證碼】按鈕,頁面發(fā)送ajax請求,在服務端調用短信服務API給指定手機號發(fā)送驗證碼短信
2、在登錄頁面輸入驗證碼,點擊【登錄】按鈕,發(fā)送ajax請求,在服務端處理登錄請求
開發(fā)手機驗證碼登錄功能,其實就是在服務端編寫代碼去處理前端頁面發(fā)送的這2次請求即可。
在開發(fā)業(yè)務功能前,先將需要用到的類和接口基本結構創(chuàng)建好:
- 實體類User(直接從課程資料中導入即可)
- Mapper接口UserMapper
- 業(yè)務層接口UserService
- 業(yè)務層實現(xiàn)類UserServicelmpl
- 控制層UserController
- 工具類SMSutils、 ValidateCodeutils(直接從課程資料中導入即可)
前面我們已經完成了LogincheckFilter過濾器的開發(fā),此過濾器用于檢查用戶的登錄狀態(tài)。我們在進行手機驗證碼登錄時,發(fā)送的請求需要在此過濾器處理時直接放行。
LoginCheckFilter過濾器添加
// 4-2、判斷登錄狀態(tài),如果已登錄,則直接放行 if (request.getSession().getAttribute("user") != null) {log.info("用戶已登錄,用戶id為:{}", request.getSession().getAttribute("user"));Long userId= (Long) request.getSession().getAttribute("user");BaseContext.setCurrentId(userId);filterChain.doFilter(request, response);return; }由于資料中代碼不全login.js自行添加
function sendMsgApi(data) {return $axios({'url':'/user/sendMsg','method':'post',data}) }login.html
// this.form.code = (Math.random()*1000000).toFixed(0) sendMsgApi({phone:this.form.phone})UserController處理post請求(發(fā)送驗證碼的請求)
@PostMapping("/sendMsg") public R<String> sendMsg(@RequestBody User user, HttpSession session){//獲取手機號String phone=user.getPhone();if(!StringUtils.isEmpty(phone)) {//生成隨機的4位驗證碼String code = ValidateCodeUtils.generateValidateCode(4).toString();log.info("code={}",code);//調用阿里云提供的短信服務API完成發(fā)送短信//SMSUtils.sendMessage("瑞吉外賣","",phone,code);//需要將生成的驗證碼保存到Sessionsession.setAttribute(phone,code);return R.success("手機驗證碼短信發(fā)送成功");}return R.error("手機短信發(fā)送失敗"); }由于前端頁面有部分代碼缺失,建議拷貝資料中day05的front代碼
在UserController編寫login處理post請求
@PostMapping("/login") public R<User> login(@RequestBody Map map, HttpSession session) {log.info("map:{}", map.toString());//獲取手機號String phone = map.get("phone").toString();//獲取驗證碼String code = map.get("code").toString();//從Session中獲取保存的驗證碼Object codeInSession = session.getAttribute(phone);//進行驗證碼比對(頁面提交的驗證碼和Session中保存的驗證碼比對)if (codeInSession != null && codeInSession.equals(code)) {//如果能夠比對成功,說明登錄成功LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(User::getPhone, phone);User user = userService.getOne(queryWrapper);if (user == null) {//判斷當前手機號是否為新用戶,如果是新用戶則自動完成注冊user = new User();user.setPhone(phone);user.setStatus(1);userService.save(user);}session.setAttribute("user",user.getId());return R.success(user);}return R.error("登陸失敗"); }總結
- 上一篇: 客户 外币账龄报表
- 下一篇: PLC通过编码器反馈值计算速度的推荐做法