瑞吉外卖 ---- 移动端

﹏ヽ暗。殇╰゛Y 2023-09-27 09:44 188阅读 0赞

目录

一、手机验证码登录

二、导入用户地址簿相关功能代码

2.1、需求分析

2.2、数据模型

2.3、导入功能代码

2.4、代码开发

2.4.1、添加收货功能

2.4.2、查询移动端登录的用户对应的收货地址功能

2.4.3、设为默认地址功能

三、菜品展示

3.1、需求分析

四、购物车

4.1、需求分析

4.2、数据模型

4.3、代码开发

五、查看购物车 & 清空购物车

清空购物车:

六、用户下单

6.1、需求分析

6.2、数据模型

代码实现:

6.3、代码开发 —— 前期准备

6.4、代码开发


#

一、手机验证码登录

456d3ebf6bd74ddbb7925a158551078e.png

caf065c270bc489f8a3f6ecb383b2df3.png

因此我们后端接收到请求后的代码如下所示:

  1. package com.Bivin.reggie.controller;
  2. import com.Bivin.reggie.pojo.User;
  3. import com.Bivin.reggie.service.impl.UserServiceImpl;
  4. import com.Bivin.reggie.utils.ValidateCodeUtils;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.apache.commons.lang.StringUtils;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.web.bind.annotation.PostMapping;
  10. import org.springframework.web.bind.annotation.RequestBody;
  11. import org.springframework.web.bind.annotation.RequestMapping;
  12. import org.springframework.web.bind.annotation.RestController;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpSession;
  15. import java.util.Map;
  16. /**
  17. * 手机验证码登录表现层
  18. */
  19. @RestController
  20. @RequestMapping("/user")
  21. @Slf4j
  22. public class UserController {
  23. // 注入业务层对象
  24. @Autowired
  25. private UserServiceImpl userService;
  26. /**
  27. * 接收客户端发送的获取验证码的请求功能
  28. * <p>
  29. * 因此我们可以用User实体类接收客户端发送的请求携带的json格式的phone数据
  30. */
  31. @PostMapping("/sendMsg")
  32. public R sendMsg(HttpServletRequest request, @RequestBody User user) { // @RequestBody: json格式注解
  33. /**
  34. * // User实体类当中接收封装到客户端想要发送验证码的手机号后,我们就可以做为该手机号生成验证码了
  35. */
  36. // 1、获取封装在User实体类当中的客户端手机号
  37. String phone = user.getPhone();
  38. if (StringUtils.isNotEmpty(phone)) { // 如果手机号不为null的话
  39. // 2、为该客户端的手机号随机生成验证码 (调用随机生成验证码工具类即可生成,该工具类当中可以设定生成几位验证码)
  40. String s = ValidateCodeUtils.generateValidateCode(4).toString();
  41. log.info("随机生成的验证码:" + s);
  42. /**
  43. * 注: 我们又不是真正开发项目的,因此我们这里的用阿里云短信服务给客户端手机号发送验证码功能这步就不演示了,
  44. * 因为第二步生成的验证码,我们后台通过输出或者日志的形式就能知道随机生成的验证码是多少(只不过没有给这个手机发送短信告知而已,我们自己玩还告知个啥)
  45. */
  46. // 3、调用阿里云的短信服务,并且让这个生成的验证码传递给短信服务类就可以让阿里云为该客户端手机发送第二步中生成的验证码了。
  47. // SMSUtils.sendShortMessage(phone,s); // 把客户端的手机号和第二步中随机生成的验证码传递给阿里云的短信服务类,就可以为该手机号发送该生成的验证码了
  48. // 4、将生成的验证码储存到Session域当中
  49. HttpSession session = request.getSession();
  50. session.setAttribute(phone, s); // key为客户端手机号 value为该客户端手机号生成的验证码
  51. return new R(1, "手机验证码短信发送成功");
  52. }
  53. // 这里的话就说明客户端传递的手机号是空的,因此直接返回信息即可
  54. return new R(0, "手机验证码短信发送失败");
  55. }
  56. /**
  57. * 手机验证码登录功能
  58. * 客户端的POST请求: http://localhost:8080/user/login
  59. *
  60. * 携带的请求数据格式:
  61. * code "7288"
  62. * phone "13512451245"
  63. */
  64. /**
  65. * 我们后台这里可以做一些逻辑:就是判断一下该手机号用户是不是第一次登录该功能,如果是的话就把他的手机号保存在我们的数据库当中记录吧。
  66. * <p>
  67. * 就保存到我们的user用户数据库当中进行保存记录即可。
  68. */
  69. @PostMapping("/login")
  70. public R login(@RequestBody Map map, HttpSession session) {
  71. //log.info(map.toString());
  72. //获取手机号
  73. String phone = map.get("phone").toString();
  74. //获取验证码
  75. String code = map.get("code").toString();
  76. //从Session中获取保存的验证码
  77. Object codeInSession = session.getAttribute(phone);
  78. //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
  79. if (codeInSession != null && codeInSession.equals(code)) {
  80. //如果能够比对成功,说明登录成功
  81. LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
  82. queryWrapper.eq(User::getPhone, phone);
  83. //根据用户的手机号去用户表获取用户
  84. User user = userService.getOne(queryWrapper);
  85. if (user == null) {
  86. //判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册(通过客户端输入的手机号查不出来数据库中的数据,那么就说明为新用户)
  87. user = new User();
  88. user.setPhone(phone);
  89. user.setStatus(1); //可设置也可不设置,因为数据库我们设置了默认值
  90. //注册新用户
  91. userService.save(user);
  92. }
  93. //这一行容易漏。。保存用户登录状态
  94. session.setAttribute("user", user.getId()); //这里保存一下登录移动端成功的用户id信息,等会下面用户添加地址的时候,可以把这个id也保存到用户地址薄的数据库当中去(要不然谁知道这个地址是哪个用户的啊,谁登录的肯定就是谁添加的地址啊,所以先保存一下)
  95. return new R(1, user);
  96. }
  97. return new R(0, "ERROR");
  98. }
  99. }

随机生成验证码工具类:

  1. package com.Bivin.reggie.utils;
  2. import java.util.Random;
  3. /**
  4. * 随机生成验证码工具类
  5. */
  6. public class ValidateCodeUtils {
  7. /**
  8. * 随机生成验证码
  9. * @param length 长度为4位或者6位
  10. * @return
  11. */
  12. public static Integer generateValidateCode(int length){
  13. Integer code =null;
  14. if(length == 4){
  15. code = new Random().nextInt(9999);//生成随机数,最大为9999
  16. if(code < 1000){
  17. code = code + 1000;//保证随机数为4位数字
  18. }
  19. }else if(length == 6){
  20. code = new Random().nextInt(999999);//生成随机数,最大为999999
  21. if(code < 100000){
  22. code = code + 100000;//保证随机数为6位数字
  23. }
  24. }else{
  25. throw new RuntimeException("只能生成4位或6位数字验证码");
  26. }
  27. return code;
  28. }
  29. /**
  30. * 随机生成指定长度字符串验证码
  31. * @param length 长度
  32. * @return
  33. */
  34. public static String generateValidateCode4String(int length){
  35. Random rdm = new Random();
  36. String hash1 = Integer.toHexString(rdm.nextInt());
  37. String capstr = hash1.substring(0, length);
  38. return capstr;
  39. }
  40. }

二、导入用户地址簿相关功能代码

#

2.1、需求分析

be218b0d1279433a8e7a5244d0083d60.png

2.2、数据模型

注:后面打勾的说明这些数据都要添加,不能为null,要不然会报错

85176ff5079743d9aa3b2fed7c9086f7.png

2.3、导入功能代码

也就是我们前面说过的,如果出现一个数据库,我们想要操作该数据库的话(如上面的address_book数据库,当我们用户添加信息的时候就要用到这个数据库),因此就需要先把这个数据库对应的实体类、表现层、业务层、数据层骨架先搭建出来。

d702f5929d6d4265855700ba8adbabf2.png

2.4、代码开发

2.4.1、添加收货功能

0133a38904f545cabfff5128fd3ea48b.png

首先要知道,客户端填完收货地址后,点击保存地址按钮,会携带着这些数据向后端发送一个POST请求,请求路径 :/addressBook 数据:json格式

我们后端只需要接收到该客户端发送的请求路径和请求数据参数即可(后端的实体类addressBook就可以拿到客户端发送请求的全部数据)

  1. @RestController
  2. @Slf4j
  3. @RequestMapping("addressBook")
  4. public class AddressBookController {
  5. @Autowired
  6. private AddressBookService addressBookService;
  7. /**
  8. * 添加收货地址功能
  9. */
  10. @PostMapping
  11. public R save(@RequestBody AddressBook addressBook, HttpServletRequest request){
  12. log.info("接收到了客户端传递的参数数据:"+addressBook);
  13. // 1、首先我们把移动端客户手机登录成功时储存在session域当中的用户id拿出来。
  14. Object user = request.getSession().getAttribute("user");
  15. // 2、拿到用户id后,set到addressBook属性当中去(此时addressBook实体类属性当中既有了客户添加的收货地址数据,又有了该用户的id)
  16. // 这样做的目的就是我们把收货地址信息添加到数据库了,最起码要知道对应的是哪个用户啊,这他妈要不然只有地址信息不知道是哪个用户那还玩个毛线
  17. addressBook.setUserId((Long) user);
  18. // 3、直接调用保存功能,把封装在实体类addressBook属性中的数据保存到数据库当中去。
  19. addressBookService.save(addressBook);
  20. return new R(1,addressBook);
  21. }

#

66364c592e0d4fae86712a9b911e49e2.png

d0eb4cb304fc4ab4a6bc49249e2c0bbb.png

2.4.2、查询移动端登录的用户对应的收货地址功能

  1. /**
  2. * 查询该移动端登录用户所有的收货地址 (我们知道收货地址数据库中我们刚才已经把登录用户的id也保存进去了)
  3. *
  4. * 因此我们这里还是通过移动端登录时保存在session域中的用户id,然后查询一下收货地址数据库中所对应的收货地址即可、
  5. *
  6. * 思路:和我们美团上的一样啊,我们比如自己的手机号登录了之后,我们这个号还能选择多个收货地址呢,比如你写个你学校的收货地址,还能再写个你对象的地址
  7. * 我们每个号都对应很多个收货地址呢 太正常了。
  8. */
  9. @GetMapping(value = "/list")
  10. public R List(HttpServletRequest request){
  11. // 1、获取移动端登录成功的用户的id
  12. Long user = (Long) request.getSession().getAttribute("user");
  13. // 2、 通过上面的id对收货地址数据库中进行条件查询
  14. LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
  15. queryWrapper.eq(AddressBook::getUserId,user); // 拼接这个sql语句:select * from address_book where user_id = ? (?对应的是:user 用户名id)
  16. // 调用收货地址数据库中的查询功能,把和用户名id相关联的收货地址全部查询出来
  17. List<AddressBook> list = addressBookService.list(queryWrapper);
  18. // 3、把查询出来的该登录用户id对应的收货地址数据响应给前端页面,供前端页面展示
  19. return new R(1,list);
  20. }

#

26e701fe00f24f519fdfd5b4c4ec0445.png

#

2.4.3、设为默认地址功能

分析:

如果客户端想要把下面的王女士的地址设置为默认地址的话,只需要把王女士对应在数据库中的is_default字段设置为1即可 (此时为0,为1的时候就设为默认地址了)

9629828dc55344c48c61731729525289.png

d12cf882af574f4a9ec4e4d31329fc1c.png

当用户想把王女士地址设定为默认地址时,向后台发送的请求如下所示:

28cde0d85a824fdb87d4d666ec0f6ea1.png

e6c38a4bb3b44cafa23dc601d41b9ba7.png

代码实现:

  1. /**
  2. * 设置默认地址功能
  3. *
  4. * 实现思路: 我们只需要接收到客户端想要设定默认地址的id即可,然后把该id对应的is_default字段设定为1即可
  5. *
  6. * 注意:客户端传递的该id是json数据,因此我们用实体类接收即可、
  7. */
  8. @PutMapping(value = "/default")
  9. public R set_default(@RequestBody AddressBook addressBook){
  10. // 1、获取客户端传递的id
  11. Long id = addressBook.getId();
  12. // 2、通过该id让对应在数据库中的王女士的数据查询出来
  13. AddressBook data = addressBookService.getById(id);
  14. // 3、查询出来王女士的地址数据之后,把isDefault字段设定为1
  15. data.setIsDefault(1);
  16. // 4、调用一下修改功能,把isDefault字段设定为1的数据在数据库中修改一下,让数据库中也为1
  17. addressBookService.updateById(data);
  18. return new R(1,addressBook); // 然后把修改过isDefault字段的数据响应给前端,让前端展示页面即可
  19. }

最终前端拿到我们响应给他的修改过is_default字段的地址数据后,就可以在页面上做一些处理了:

8ad78d8c267b45af973133da43ec1f66.png

三、菜品展示

4c0361b0f0c2486a93ec7f2352c4aae8.png

3.1、需求分析

6671684ef2d747cd88c23279b45b8d28.png

我们还要知道:移动端位于下面的位置的时候,其实是向后台发送了两个请求:

5d4abfb0747f41f9856d550931a447f2.png

第一个请求(这个请求我们后端已经处理过了,并且把查询出来的菜品分类和套餐分类数据已经响应给前端页面了,之所以页面上没展示就是因为第二个请求后台没有处理):

2677a1af241f428c81904e0befea40b3.png

b297d9ca2d7949a080c72ccb80f18f9d.png

第二个请求:

9bad1ee20d9247e3b200468aa1029362.png

我们这个移动端页面之所以报404异常,就是因为向购物车发送的那个请求服务端没有接收该请求,因此我们可以先把购物车的请求在后端先写出来,先返回一个null即可,那么这个页面就不会报404异常了,因为两个请求都走的通了,并且也可以把第一个请求获取到的菜品分类和套餐分类数据展示在页面上:

8ebdb889d34a441786428ffc6da40659.png

最终:我们后端把第二个请求写通之后,移动端效果如下所示:

dff5e4b674f94c1e8588d0a92168fbbe.png

注:上面我们现在只是完成了菜品分类和套餐分类数据在移动端的展示。(右边的菜品分类或者套餐分类对应的相对应的菜我们先不处理,一点一点的分析慢慢处理)

到了上面我们知道我们已经把菜品分类和套餐分类数据展示在移动端页面上了,就是上面的红框起来的地方,接下来我们还需要一步一步的实现其他的功能接下来实现的功能就是:

我们知道我们在后台当中每个套餐分类或者菜品分类当中对应的都有相应的菜品和菜品对应的口味,比如我们川菜分类中会有一部分川菜类的菜,然后这些川菜类的菜也都是有口味的,因此我们肯定要把这些移动端选择的套餐分类或者菜品分类所关联的菜和该菜对应的口味在后端查询出来然后响应给前端,然后让前端展示在移动端页面上供客户选择啊。

再次分析:

c2b0cc0b998a455996b70d58b360591b.png

0d2598ae3e7d467380cf6832d7deef2b.png

最终目的:我们后端的总体代码就是把这些关联的菜品和菜品对应的口味查询出来响应给前端页面。

代码实现:

  1. /**
  2. * 客户端发送的GET请求格式如川菜分类:http://localhost:8080/dish/list?categoryId=1397844303408574465&status=1
  3. *
  4. * 我们最终的目的就是: 查询这个川菜套餐中所含有的所有菜品和这些菜品的口味
  5. *
  6. * 注: 我们这里因为需要操作三张数据库表,因此普通的实体类属性封装不了那么多的数据,因此我们就还用DTO实体类,
  7. * DishDto实体类当中继承了Dish实体类,并且有封装口味数据的属性,因此该DTO实体类属性可以封装客户端传递过来
  8. * 的套餐关联的所有菜品数据和菜品数据对应的口味数据。
  9. * */
  10. @GetMapping(value = "/list")
  11. public R list(DishDto dishDto){ // 客户端传递的川菜分类id可以封装在这个DTO实体类属性当中
  12. // 1、获取到该川菜分类id
  13. Long id = dishDto.getCategoryId();
  14. // 2、通过该川菜分类id,查询出来对应的菜品数据库中关联的所有菜品数据
  15. LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
  16. queryWrapper.eq(Dish::getCategoryId,id); // 拼接sql: select * from dish = category_id = id;
  17. // 调用查询功能即可把川菜分类id关联的所有菜品数据查询出来
  18. List<Dish> list = dishService.list(queryWrapper);
  19. // 3、遍历list集合,把每一个关联的菜品数据都遍历出来。 (因为菜品数据中id和菜品口味的dish_id相关联,我们需要拿出来,然后调用口味数据库把口味拿出来)
  20. List<DishDto> dtoList =list.stream().map((item) -> { // 遍历list集合,遍历出来的菜品数据对象就一个一个赋予给了item
  21. Long id1 = item.getId(); // 拿到菜品数据对象的id
  22. // log.info("Dwaddwa:"+id1);
  23. LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
  24. wrapper.eq(DishFlavor::getDishId,id1); // 拼接sql: select * from dish_flavor = dish_id = id1;
  25. // 调用查询功能就能把每个菜品数据所对应的N种口味数据查询出来了
  26. List<DishFlavor> list1 = dishFlavorService.list(wrapper);
  27. DishDto dto = new DishDto();
  28. // 4、把查询出来的这些口味数据封装到DTO实体类的属性当中去 (DTO实体类封装口味数据的属性也是集合的形式)
  29. dto.setFlavors(list1);
  30. // 5、并且把遍历出来的菜品数据对象也一个一个拷贝封装到DTO实体类属性当中
  31. BeanUtils.copyProperties(item,dto);
  32. /**
  33. * 通过上面的4、5步骤,我们就知道了DTO实体类当中通过遍历的方式已经一个一个的把川菜分类套餐所关联的菜品数据和菜品对应的口味数据
  34. * 封装到了DTO属性当中了。
  35. *
  36. * 然后我们把封装了数据的DTO对象封装到List集合种保存 (List<DishDto> dtoList =.....)
  37. * 最终将这个List集合响应给前端即可,前端页面就拿到该川菜分类套餐对应的所有菜品数据和菜品口味数据了。
  38. *
  39. */
  40. return dto;
  41. }).collect(Collectors.toList());
  42. return new R(1,dtoList); // 把该dtoList集合种的所有数据响应给前端即可
  43. }

ebc6a12987d94f01a21ee37f48332824.png

四、购物车

4.1、需求分析

93ed9486f54a48769c19d8b862fd4116.png

4.2、数据模型

226a99b595f04cd0b607cd3aa3ffa826.png

补:amount 字段表示金额

4.3、代码开发

首先我们知道我们现在要操作的是shopping_cart购物车数据库了,因此我们首先就要先把这个购物车数据库对应的实体类、数据层、业务层、表现层骨架搭出来。

思路分析:

注意:客户端每点击一次加入购物车,那么才会向后台发送那个add请求。

b204d7ae9e274300a26f08f26bc312aa.png

387f3538a129407fb06af24f6956dced.png

我们这里只演示了菜品加入购物车,套餐加入购物车我们不再演示(和菜品加入购物车的实现思路是一样的)

开拓视野:

我们要知道我们实际在美团买外卖的时候,我们加入购物车的该商品有可能是一模一样的两份或者更多份,那么我们后台总不能一份一份的把这些相同的商品都一条一条的添加到数据库当中吧,我们可以让这些重复添加到购物车数据库中的商品用number字段记录,也就是说如果用户买了两份一模一样的商品,那么我们就添加到数据库中一条该商品数据即可,然后把number字段为2,就说明这条商品客户端用户加入了两条。

实现代码如下所示:

  1. /**
  2. * 前端点击加入购物车按钮发送的POST请求: http://localhost:8080/shoppingCart/add 携带的请求数据为json格式数据
  3. *
  4. * 注: 使用request的目的: 就是我们知道移动端用户登录成功后会存入到session域当中该登录用户的id,
  5. * 我们这里就是通过request把session域中的用户名id拿出来,然后等会一起连同该用户名id
  6. * 保存到购物车数据库当中去,要不然我们哪能知道这个购物车中的菜品数据是哪个用户添加的呢
  7. */
  8. @PostMapping(value = "/add")
  9. public R add(@RequestBody ShoppingCart shoppingCart, HttpServletRequest request){
  10. // 1、先获取session域当中的登录移动端的用户名id
  11. Long id = (Long) request.getSession().getAttribute("user");
  12. // 2、查询当前客户端想要添加到购物车中的菜品数据是否已经添加过到购物车数据库当中了
  13. Long dishId = shoppingCart.getDishId(); // 把客户端传递的菜品id拿出来
  14. LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
  15. queryWrapper.eq(ShoppingCart::getDishId,dishId);
  16. queryWrapper.eq(ShoppingCart::getUserId,id);
  17. // 拼接的SQL: select * from shopping_cart where dish_id = dishId and user_id =id;
  18. // 也就是说查询一下购物车数据库当中是否已经存在了客户端添加的菜品数据,如果能查出来数据,那么说明购物车数据库当中肯定有了该菜品的数据了。
  19. ShoppingCart one = shoppingCartService.getOne(queryWrapper); // (因为有number字段的存在,那么相同的数据肯定就占用数据库那一条,所以用getOne即可)
  20. if (one !=null){
  21. /**
  22. * 注:如果one不为null的话,那么ShoppingCart one = shoppingCartService.getOne(queryWrapper);
  23. * 就已经把数据库中的那条菜品数据查询出来封装在了one对象属性中了。
  24. */
  25. // 3、不为null,那么就说明购物车数据库当中已经有了该菜品数据,那么我们就不需要再次添加该相同的商品到数据库当中了,我们只需要把数据库中有的那个相同的商品的
  26. // number字段+1即可
  27. // 我们知道上面我们已经把数据库中相同的那个菜品查询出来了,我们这里只需要把他的number+1然后修改到购物车数据库当中即可
  28. Integer number = one.getNumber(); // one对象当中已经查询出来了那条数据,因此这里可以直接利用one对象进行操作
  29. one.setNumber(number+1);
  30. // 调用修改功能把修改后的那条商品数据传递到数据库当中去
  31. shoppingCartService.updateById(one); // 把修改后的one对象传递过去
  32. }else {
  33. // 4、到这里为null,就说明购物车数据库当中没有移动端用户添加进来的数据,那么我们就把这个移动端想要加入购物车的
  34. // 的数据添加到数据库中保存即可
  35. shoppingCart.setNumber(1); // 因为第一次添加到数据库当中,那么数量就写1即可。
  36. shoppingCart.setUserId(id); // 把移动端登录的用户id也存入到数据库当中去,要不然不知道这个购物车是谁添加的。
  37. shoppingCartService.save(shoppingCart);
  38. }
  39. return new R(1,one);
  40. }

7822534e16a34bb992ee1d9f9792fc6c.png

bbfa3477f29647399dc042abbd6c83f4.png

五、查看购物车 & 清空购物车

  1. /**
  2. * * 查看购物车功能
  3. *
  4. * 客户端发送的GET请求: http://localhost:8080/category/list
  5. *
  6. * 思路:我们知道我们购物车当中有移动端登录的用户名字段(user_id字段),那么我们就用该用户名字段做条件进行查询购物车中的数据即可,
  7. * 毕竟我们每个用户对应的购物车都不一样,因此我们就用用户名进行查询购物车数据。
  8. *
  9. * 总的来说就是:移动端登录成功的用户,肯定查的就是这个登录成功的用户的购物车啊,因此我们就用该用户的id进行条件查询购物车,把数据库查出来不就得了。
  10. */
  11. @GetMapping(value = "/list")
  12. public R list(HttpServletRequest request){
  13. // 1、第一步:还是先获取移动端登录的用户id
  14. Long id = (Long) request.getSession().getAttribute("user");
  15. // 2、通过用户名id条件查询购物车数据库中的数据
  16. LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
  17. queryWrapper.eq(ShoppingCart::getUserId,id);
  18. List<ShoppingCart> list = shoppingCartService.list(queryWrapper);
  19. if (list!=null){
  20. return new R(1,list); // 把查询出来的该用户对应的购物车中的数据响应给前端即可、
  21. }
  22. return new R(0,"购物车中没有数据~"); // 把查询出来的该用户对应的购物车中的数据响应给前端即可、
  23. }

b117c08294b143d6b60290aa1a7d9f93.png

清空购物车:

思路:我们还是通过移动端登录成功后用户名id来进行清空购物车中的数据,毕竟用户登录成功后,这个购物车肯定就是这个用户的啊,然后他想清空那么就通过他的用户名id清空购物车中该用户id对应的数据不就可以了。

代码实现:

4b9514223e7544898e2f9bceed2b01c7.png

  1. /**
  2. * * 清空购物车功能
  3. *
  4. * 客户端发送的DELETE请求:http://localhost:8080/shoppingCart/clean
  5. */
  6. @DeleteMapping(value = "/clean")
  7. public R clean(HttpServletRequest request){
  8. // 1、获取该用户登录成功时存在session域中的用户名id
  9. Long id = (Long) request.getSession().getAttribute("user");
  10. // 2、拼接SQL语句,删除数据库中对应的数据即可。 SQL:delete * from shopping_cart where user_id =id; 删除购物车数据库中和用户名id一致的数据即可
  11. LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
  12. queryWrapper.eq(ShoppingCart::getUserId,id);
  13. shoppingCartService.remove(queryWrapper);
  14. return new R(1,"购物车清空成功");
  15. }

71e0a651f28e424a8df9169f26e060a1.png

3b74dd7642324d1ebfe820b2ea557c09.png

六、用户下单

6.1、需求分析

27d2b68b17d24d79950d63282e035852.png

6.2、数据模型

938aa21073e84610acc2c9309764cd13.png

总的来说:两张表:订单明细表是专门存放用户下单的菜品或者套餐数据的,
而订单表是专门存放用户下单的时间、下单地址、支付时间这些数据的。

这两张表有order_id这个键相关联,要不然第一张表中收货地址什么的看不到送的是什么菜品数据能行吗

c49d2be524434760ae02bd366bc02168.png

补: consignee: 收货人名字,order_time :下单时间, checkout_time : 支付完成时间 ,remark:备注

9bfd7c26a37a4ffaa6387df00b383c3b.png

代码实现:

15378b9b373f49469d3d13cff2f2e3cb.png

  1. /**
  2. * 总体思路就是: 把address_book数据库当中的设置为默认地址的用户信息查询出来响应给前端即可。
  3. * (注:is_default字段为1的用户就代表设定的默认地址)
  4. *
  5. */
  6. @GetMapping(value = "/default")
  7. public R default_g(){
  8. LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
  9. queryWrapper.eq(AddressBook::getIsDefault,1);
  10. AddressBook one = addressBookService.getOne(queryWrapper);
  11. return new R(1,one);
  12. }

4fcd049a096d442482e2f0218b0255f9.png

最终:客户端用户点击去结算按钮后,就会跳转到下面的页面上了,并且把设定为默认地址的用户信息展示了出来:

5fbb68dc913445f39d292cb2664d40c0.png

6.3、代码开发 —— 前期准备

同理我们知道,我们用到了两个数据库,一个是订单表,一个是订单明细表,因此我们需要把这两张表各对应的实体类、数据层、业务层、表现层骨架搭建出来。

31dfeec5dcd24676b371000c88627b16.png

我们知道客户端点击去支付按钮后,是会向后台发送一个POST请求的:

d3221bedb54d44fb90dd3f9ed5f6e533.png

6.4、代码开发

  1. /**
  2. * * 订单功能
  3. *
  4. * POST请求:http://localhost:8080/order/submit
  5. * 携带的json数据: addressBookId: "1574678301232926722"
  6. * payMethod: 1
  7. */
  8. @PostMapping(value = "/submit")
  9. @Transactional
  10. public R submit(@RequestBody Orders orders, HttpServletRequest request){
  11. /**
  12. * 1、首先我们要知道,移动端用户想要下单的商品数据就是我们刚才加入到购物车中的那些商品菜品数据,
  13. * 因此我们可以先把该移动端用户购物车中的商品查询出来,查询出来后我们把这些商品保存到订单明细表数据库当中即可。
  14. */
  15. Long id = (Long) request.getSession().getAttribute("user"); // 获取移动端登录的用户id
  16. // 通过id条件查询该用户id添加到购物车中的商品数据
  17. LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
  18. queryWrapper.eq(ShoppingCart::getUserId,id);
  19. List<ShoppingCart> list = shoppingCartService.list(queryWrapper); // 把该用户对应的购物车中的数据拿出来了。
  20. log.info("购物车中的商品数据(也是用户下单的商品数据):"+list);
  21. /**
  22. * 2、我们知道我们订单表orders数据库中是专门存放下单用户(也就是这个移动端登陆的用户)的id、订单号、手机号、收货地址、收货手机号等等这些东西的,
  23. * 我们要知道,用户的手机号是在user表中存放的,而收货地址、收货手机号等这些信息是在address_book表中存放的,因此我们可以调用这两个数据库
  24. * 通过登录成功时存放在session域中的用户id条件把这两个数据库中的对应的这些数据查询出来,等会set到订单表对应的实体类当中然后一起保存到订单表中去。
  25. */
  26. User user = userService.getById(id);
  27. AddressBook addressBook = addressBookService.getById(orders.getAddressBookId()); // 我们这个用客户端传递过来的数据查询即可
  28. log.info("dwadwa:"+user);
  29. log.info("dwadwa:"+addressBook);
  30. /**
  31. * 4、我们知道第三步中有一个专门记录用户下单的商品的总金额的,虽然前端帮我们算过总金额是多少了,但是我们肯定还是害怕啊,
  32. * 万一给我们算错了呢,那我们不是赔了吗,因此我们可以把第一步中用户下单的购物车中的那些数据一个一个遍历出来,然后一个一个的获取
  33. * 其商品金额,让其加在一起之后再set到orders实体类金额属性中保存到订单表中记录即可。
  34. */
  35. AtomicInteger amount = new AtomicInteger(0); // 我们用这个对象记录总金额 (和用int = 0,然后依次累加进来记录商品总金额的意义是一样的,不过这玩意很安全以后就这样用即可)
  36. for (ShoppingCart data : list) {
  37. BigDecimal amount1 = data.getAmount(); // 获取到每一个商品的价格
  38. Integer number = data.getNumber(); // 获取到每一个商品的数量
  39. amount.addAndGet(amount1.multiply(new BigDecimal(number)).intValue()); // 商品的价格 * 商品的数量。
  40. // addAndGet方法就是把这些价格+数量得到的钱数依次累加到上面的new AtomicInteger(0); 对象当中
  41. }
  42. // 上面依次累加完客户订单的商品总金额之后,就可以在第三步当中set到orders实体类金额属性当中了,最终就可以保存到订单表数据库中进行记录保存了。
  43. /**
  44. * 3、那么我们就可以向订单表orders数据库中添加数据了
  45. */
  46. long orderId = IdWorker.getId(); // 因为我们不是真正的项目,因此我们可以用IdWorker帮我们随机生成一个订单号
  47. log.info("订单号:"+orderId); // 1575383162295427073 充当订单号
  48. orders.setId(orderId); // set一个订单号到orders实体类属性中,等会保存到orders订单表数据库中去。
  49. orders.setOrderTime(LocalDateTime.now());
  50. orders.setCheckoutTime (LocalDateTime.now()) ;
  51. orders.setStatus(2) ;
  52. orders.setAmount (new BigDecimal(amount.get())); // 注: 这个是购物车商品数据的总金额属性
  53. orders.setNumber(String.valueOf(orderId));
  54. orders. setUserName(user.getName());
  55. orders.setUserId(id);
  56. orders.setAddress("1");
  57. orders.setUserName(user.getName()); // 把刚才上面查询出来的user表中name数据信息set到实体类orders实体类属性中去
  58. orders.setPhone(addressBook.getPhone()); // 同理把address_book数据库中的phone数据set到实体类orders属性中去
  59. /**
  60. * 5、第三步orders实体类属性当中set到所有的数据之后,这里就可以调用保存功能,把封装在实体类属性中的数据保存到orders订单表数据库当中了。
  61. */
  62. orderService.save(orders);
  63. /**
  64. * 6、我们还知道订单明细表是专门存放用户订单的商品的,也就是购物车中的那些数据的,因此我们可以把上面查询出来的用户购物车中的商品数据,
  65. * 保存添加到我们订单明细表中进行保存记录。 (第一步中已经查询出来了,直接调用保存即可)
  66. */
  67. /**
  68. *
  69. * 7、 订单成功之后,就可以把用户购物车中的数据清空了,毕竟人家都买了了,购物车里面的东西就没必要还有了。
  70. * (通过该用户id清空数据即可)
  71. */
  72. LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>();
  73. wrapper.eq(ShoppingCart::getUserId,id);
  74. shoppingCartService.remove(queryWrapper);
  75. return new R(1,"订单成功");
  76. }

e61aacacd3294f42b11808c1f8f03acc.png

发表评论

表情:
评论列表 (有 0 条评论,188人围观)

还没有评论,来说两句吧...

相关阅读

    相关 项目

    黑马-瑞吉外卖项目完成时间`2023-3-2` 。 1. 学习外卖平台后台管理和用户端的主要业务开发流程,springboot + mybatis plus开发核心 等技术

    相关 项目

    第三天 1. 新增员工需求分析 1、页面发送ajax请求,将新增员工页面中输入的数据以json的形式提交到服务端 2、服务端C

    相关 学习项目

    以当前热门的外卖点餐为业务基础,业务真实、实用、广泛。基于流行的Spring Boot、mybatis plus等技术框架进行开发。 第一天: 1. 设计产品原型