瑞吉外卖--套餐的添加修改等功能,短信验证登录原理操作及用户地址管理功能
创始人
2024-06-02 15:40:02
0

整理记录下学习整个瑞吉外卖项目,详细代码可在我的Gitee仓库瑞吉外卖实战克隆下载学习使用!

9.套餐管理

9.1 新增套餐

9.1.1 需求分析

![[Pasted image 20230304152742.png]]

9.1.2 数据模型

新增套餐就是将新增页面录入的套餐信息插入到setmeal表,还向setmeal_dish表插入套餐和菜品关联数据,涉及到两个表:

  • setmeal表,如图![[Pasted image 20230304153100.png]]
  • setmeal_dish表,如图![[Pasted image 20230304153116.png]]

9.1.3 代码开发

  • 导入实体类setmealDish类,之前setmeal类已导入过,这里不再说明,setmealDish类如下:
@Data  
public class SetmealDish implements Serializable {  private static final long serialVersionUID = 1L;  private Long id;  //套餐id  private Long setmealId;  //菜品id  private Long dishId;  //菜品名称 (冗余字段)  private String name;  //菜品原价  private BigDecimal price;  //份数  private Integer copies;  //排序  private Integer sort;  @TableField(fill = FieldFill.INSERT)  private LocalDateTime createTime;  @TableField(fill = FieldFill.INSERT_UPDATE)  private LocalDateTime updateTime;  @TableField(fill = FieldFill.INSERT)  private Long createUser;  @TableField(fill = FieldFill.INSERT_UPDATE)  private Long updateUser;  //是否删除  private Integer isDeleted;  
}
  • 创建setmealDish对应Mapper,Service接口及ServiceImpl类
  • 创建SetmealController类,如下:
@RestController  
@RequestMapping("/setmeal")  
@Slf4j  
@RequiredArgsConstructor  
public class SetmealhController {
}
  • 添加SetmealDTO数据传输类,用于保存菜品套餐信息,如下:
@Data  
public class SetmealDto extends Setmeal {  private List setmealDishes;  private String categoryName;  
}
  • 在DishController中创建查询所有菜品方法,如下:
@GetMapping("/list")  
public Result> list(Dish dish){  //构造查询条件  LambdaQueryWrapper 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 list = dishService.list(queryWrapper);  return Result.success(list);  
}
  • 在SetmealService接口添加保存套餐方法并重新,如下:
@Transactional  
public void saveWithFlavor(DishDto dishDto) {  //保存菜品的基本信息到菜品表dish  this.save(dishDto);  Long dishId = dishDto.getId();//菜品id  //菜品口味  List flavors = dishDto.getFlavors();  flavors = flavors.stream().map((item) -> {  item.setDishId(dishId);  return item;  }).collect(Collectors.toList());  //保存菜品口味数据到菜品口味表dish_flavor  dishFlavorService.saveBatch(flavors);  
}
  • 在SetmealDishController编写保存套餐方法save,如下
    @PostMapping   public Result save(@RequestBody SetmealDto setmealDto) {  log.info("套餐信息:{}", setmealDto);  setmealService.saveWithDish(setmealDto);  return Result.success("新增套餐成功");  }

9.1.4 测试

添加信息,如图![[Pasted image 20230304163744.png]]
看到数据库添加成功,如图在这里插入图片描述

9.2 分页查询套餐

9.2.1 代码开发

  • controller层编写如下查询代码
@GetMapping("/page")  
public Result page(int page, int pageSize, String name) {  Page setmealPage = new Page<>(page,pageSize);  Page setmealDtoIPage = new Page<>();  LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();  lambdaQueryWrapper.like(name != null,Setmeal::getName,name);  setmealService.page(setmealPage,lambdaQueryWrapper);  BeanUtils.copyProperties(setmealPage,setmealDtoIPage,"records");  List list = setmealPage.getRecords().stream().map((iterm)->{  SetmealDto setmealDto = new SetmealDto();  BeanUtils.copyProperties(iterm,setmealDto);  Long categoryId = iterm.getCategoryId();  String categoryName = categoryService.getById(categoryId).getName();  if(categoryName != null)  setmealDto.setCategoryName(categoryName);  return setmealDto;  }).collect(Collectors.toList());  setmealDtoIPage.setRecords(list);  return Result.success(setmealDtoIPage);  
}

9.2.3 测试

重启项目后结果如图![[Pasted image 20230304165749.png]]

9.3 删除套餐

9.3.1 需求分析

![[Pasted image 20230304165829.png]]

9.3.2 代码开发

  • 业务层编写删除方法,如下:
@Transactional  
public void removeWithDish(List ids) {  //select count(*) from setmeal where id in (1,2,3) and status = 1  //查询套餐状态,确定是否可用删除  LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper();  queryWrapper.in(Setmeal::getId,ids);  queryWrapper.eq(Setmeal::getStatus,1);  int count = (int) this.count(queryWrapper);  if(count > 0){  //如果不能删除,抛出一个业务异常  throw new CustomException("套餐正在售卖中,不能删除");  }  //如果可以删除,先删除套餐表中的数据---setmeal  this.removeByIds(ids);  //delete from setmeal_dish where setmeal_id in (1,2,3)  LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();  lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);  //删除关系表中的数据----setmeal_dish  setmealDishService.remove(lambdaQueryWrapper);  
}
  • controller中调用业务层方法,如下:
@DeleteMapping  
public Result delete(@RequestParam List ids) {  log.info("ids:{}", ids);  setmealService.removeWithDish(ids);  return Result.success("套餐数据删除成功");  
}

9.3.3 测试

修改数据库套餐为停售状态,并进行删除操作,如图
![[Pasted image 20230304172353.png]]
![[Pasted image 20230304172835.png]]
删除成功![[Pasted image 20230304172917.png]]

10. 短信验证模块

10.1 需求分析

用户通过输入手机号后收到相应的短信验证码,输入验证码后才能进行登录。一般用的是阿里云、腾讯云等平台提供的API接口来做,这里仅仅是用普通方式进行模拟操作。

10.2 数据模型

这里用户只有手机号和验证码来进行验证登录,表是User表,结构如下:
![[Pasted image 20230304212751.png]]

10.3 代码开发

  • 导入或编写用户实体类
@Data  
public class User implements Serializable {  private static final long serialVersionUID = 1L;  private Long id;  //姓名  private String name;  //手机号  private String phone;  //性别 0 女 1 男  private String sex;  //身份证号  private String idNumber;  //头像  private String avatar;  //状态 0:禁用,1:正常  private Integer status;  
}
  • 导入或编写验证码生成类工具,如下:
public class ValidateCodeUtils {  /**  * 随机生成验证码  * @param length 长度为4位或者6位  * @return  */  public static Integer generateValidateCode(int length){  Integer code =null;  if(length == 4){  code = new Random().nextInt(9999);//生成随机数,最大为9999  if(code < 1000){  code = code + 1000;//保证随机数为4位数字  }  }else if(length == 6){  code = new Random().nextInt(999999);//生成随机数,最大为999999  if(code < 100000){  code = code + 100000;//保证随机数为6位数字  }  }else{  throw new RuntimeException("只能生成4位或6位数字验证码");  }  return code;  }  /**  * 随机生成指定长度字符串验证码  * @param length 长度  * @return  */  public static String generateValidateCode4String(int length){  Random rdm = new Random();  String hash1 = Integer.toHexString(rdm.nextInt());  String capstr = hash1.substring(0, length);  return capstr;  }  
}
  • 新建对应的Mapper、Service接口及实现类
  • 编写UserController类,实现登录时验证码发送,用户登录及退出功能
@RestController  
@RequestMapping("/user")  
@Slf4j  
@RequiredArgsConstructor  
public class UserController {  private final UserService userService;   //移动端用户登录时发送短信  @PostMapping("/sendMsg")  public Result sendMsg(@RequestBody User user, HttpSession session) throws MessagingException {  String phone = user.getPhone();  if (!phone.isEmpty()) {  //随机生成一个验证码  String code = ValidateCodeUtils.generateValidateCode4String(4);  log.info(code);  //验证码存session,方便后面拿出来比对  session.setAttribute(phone, code);  return Result.success("验证码发送成功");  }  return Result.error("验证码发送失败");  }  /**  * 移动端用户登录  * @param map  * @param session  * @return  */  @PostMapping("/login")  public Result login(@RequestBody Map map, HttpSession session){  log.info(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 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 Result.success(user);  }  return Result.error("登录失败");  }  //移动端用户退出  @PostMapping("/loginout")  public Result logout(HttpServletRequest request) {  request.getSession().removeAttribute("user");  return Result.success("退出成功");  }  
}
  • 过滤器配置处理移动端登录url并处理已登录情况,如图
    ![[Pasted image 20230304213709.png]]
    ![[Pasted image 20230304215757.png]]

10.4 测试

打开移动端登录页面,设置浏览器模式为手机,如图
在这里插入图片描述
输入手机号并点击获取验证码填在前台完成登录,如图
![[Pasted image 20230304215639.png]]
![[Pasted image 20230304215958.png]]

11.导入用户地址薄相关功能

11.1 需求分析

![[Pasted image 20230304205146.png]]
![[Pasted image 20230304205226.png]]

11.2 数据模型

用户地址信息存储在address_book表中,结构如下:
![[Pasted image 20230304205330.png]]

11.3 代码开发

  • 编写实体类或导入实体类代码
@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 updateTime;  //创建人  @TableField(fill = FieldFill.INSERT)  private Long createUser;  //修改人  @TableField(fill = FieldFill.INSERT_UPDATE)  private Long updateUser;  //是否删除  private Integer isDeleted;  
}
  • 新建相应的Mapper、Service及实现类和AddressBookController类
  • 编写新增地址,查询所有地址,设置默认地址,查询默认地址,修改或删除用户地址等功能,代码如下:
@Slf4j  
@RestController  
@RequestMapping("/addressBook")  
@RequiredArgsConstructor  
public class AddressBookController {  private final AddressBookService addressBookService;  /**  * 新增  */  @PostMapping  public Result save(@RequestBody AddressBook addressBook) {  addressBook.setUserId(BaseContext.getCurrentId());  log.info("addressBook:{}", addressBook);  addressBookService.save(addressBook);  return Result.success(addressBook);  }  /**  * 设置默认地址  */  @PutMapping("default")  public Result setDefault(@RequestBody AddressBook addressBook) {  log.info("addressBook:{}", addressBook);  LambdaUpdateWrapper 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 Result.success(addressBook);  }  /**  * 查询默认地址  */  @GetMapping("/default")  public Result getDefault() {  LambdaQueryWrapper 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 Result.error("没有找到该对象");  } else {  return Result.success(addressBook);  }  }    /**  * 查询指定用户的全部地址  */  @GetMapping("/list")  public Result> list(AddressBook addressBook) {  addressBook.setUserId(BaseContext.getCurrentId());  log.info("addressBook:{}", addressBook);  //条件构造器  LambdaQueryWrapper 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 Result.success(addressBookService.list(queryWrapper));  }  //查询当前用户使用的地址  @GetMapping("/{id}")  public Result getById(@PathVariable Long id) {  AddressBook addressBook = addressBookService.getById(id);  if (addressBook == null){  throw new CustomException("地址信息不存在");  }  return Result.success(addressBook);  }  //修改用户地址  @PutMapping  public Result updateAdd(@RequestBody AddressBook addressBook) {  if (addressBook == null) {  throw new CustomException("地址信息不存在,请刷新重试");  }  addressBookService.updateById(addressBook);  return Result.success("地址修改成功");  }  //删除用户地址  @DeleteMapping  public Result deleteAdd(@RequestParam("ids") Long id) {  if (id == null) {  throw new CustomException("地址信息不存在,请刷新重试");  }  AddressBook addressBook = addressBookService.getById(id);  if (addressBook == null) {  throw new CustomException("地址信息不存在,请刷新重试");  }  addressBookService.removeById(id);  return Result.success("地址删除成功");  }  
}

11.4 测试

  • 登录后点击左上角头像进入个人信息如图![[Pasted image 20230304220317.png]]
    进入个人信息栏后再点地址栏即可![[Pasted image 20230304220450.png]]
    新增地址,如图
    ![[Pasted image 20230304235401.png]]
    添加成功后如图![[Pasted image 20230304235425.png]]
    修改地址如图![[Pasted image 20230304235530.png]]
    结果如图
    ![[Pasted image 20230304235545.png]]

相关内容

热门资讯

【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
ChatGPT 怎么用最新详细... ChatGPT 以其强大的信息整合和对话能力惊艳了全球,在自然语言处理上面表现出了惊人...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...