【畅购商城】购物车模块之添加购物车

一时失言乱红尘 2024-03-31 09:08 238阅读 0赞

购物车数据2种形态:

登录态:保存到服务器端的redis中

没登录:保存在浏览器端 localStorage 中

搭建购物车服务:8095

步骤一:创建changgou4-service-cart 项目

步骤二:修改pom.xml文件,添加坐标

  1. <dependencies>
  2. <!--自定义项目-->
  3. <dependency>
  4. <groupId>com.czxy.changgou</groupId>
  5. <artifactId>changgou4-common-auth</artifactId>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.czxy.changgou</groupId>
  9. <artifactId>changgou4-pojo</artifactId>
  10. </dependency>
  11. <!--web起步依赖-->
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-web</artifactId>
  15. </dependency>
  16. <!--redis-->
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-data-redis</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>redis.clients</groupId>
  23. <artifactId>jedis</artifactId>
  24. </dependency>
  25. <!-- nacos 客户端 -->
  26. <dependency>
  27. <groupId>com.alibaba.nacos</groupId>
  28. <artifactId>nacos-client</artifactId>
  29. </dependency>
  30. <!-- nacos 服务发现 -->
  31. <dependency>
  32. <groupId>com.alibaba.cloud</groupId>
  33. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  34. </dependency>
  35. <!-- openfeign 远程调用 -->
  36. <dependency>
  37. <groupId>org.springframework.cloud</groupId>
  38. <artifactId>spring-cloud-starter-openfeign</artifactId>
  39. </dependency>
  40. <!--swagger2-->
  41. <dependency>
  42. <groupId>io.springfox</groupId>
  43. <artifactId>springfox-swagger2</artifactId>
  44. </dependency>
  45. <dependency>
  46. <groupId>io.springfox</groupId>
  47. <artifactId>springfox-swagger-ui</artifactId>
  48. </dependency>
  49. <!--fastjson-->
  50. <dependency>
  51. <groupId>com.alibaba</groupId>
  52. <artifactId>fastjson</artifactId>
  53. </dependency>
  54. </dependencies>

步骤三:创建yml文件,

  1. #端口号
  2. server:
  3. port: 8095
  4. spring:
  5. application:
  6. name: cart-service
  7. redis:
  8. host: 127.0.0.1
  9. cloud:
  10. nacos:
  11. discovery:
  12. server-addr: 127.0.0.1:8848 #nacos服务地址
  13. #自定义内容
  14. sc:
  15. jwt:
  16. secret: sc@Login(Auth}*^31)&czxy% # 登录校验的密钥
  17. pubKeyPath: D:/rsa/rsa.pub # 公钥地址
  18. priKeyPath: D:/rsa/rsa.pri # 私钥地址
  19. expire: 360 # 过期时间,单位分钟

步骤四:拷贝JWT配合类 + Swagger + Redis

ba3ccda668cc4bb3ac8859cefbe26ca4.png

步骤五:启动类

  1. package com.czxy.changgou4;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.openfeign.EnableFeignClients;
  6. /**
  7. * @author 桐叔
  8. * @email liangtong@itcast.cn
  9. */
  10. @SpringBootApplication
  11. @EnableDiscoveryClient
  12. @EnableFeignClients
  13. public class CGCartServiceApplication {
  14. public static void main(String[] args) {
  15. SpringApplication.run(CGCartServiceApplication.class, args);
  16. }
  17. }

添加到购物车

整体分析

1ea5e1c9da25439c97d34c17a7df5307.png

#

接口

  1. POST http://localhost:10010/cart-service/carts
  2. {
  3. "skuid": 2600242,
  4. "count": 5,
  5. "checked": true
  6. }

#

后端实现:JavaBean

eb6e2c1c50cf4e028e47d8a0938ed03e.png

购物车列表项对象:CartItem (某一件商品的购买情况:商品、购买数量 等)

  1. package com.czxy.changgou4.cart;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import lombok.Data;
  4. /**
  5. * @author 桐叔
  6. * @email liangtong@itcast.cn
  7. */
  8. @Data
  9. public class CartItem {
  10. private Integer skuid;
  11. private Integer spuid;
  12. @JsonProperty("goods_name")
  13. private String goodsName;
  14. private Double price;
  15. private Integer count;//购买数量
  16. private Boolean checked;
  17. private String midlogo;
  18. @JsonProperty("spec_info")
  19. private String specInfo;
  20. }

购物车对象:Cart

  1. package com.czxy.changgou4.cart;
  2. import lombok.Data;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. /**
  6. * @author 桐叔
  7. * @email liangtong@itcast.cn
  8. */
  9. @Data
  10. public class Cart {
  11. private Map<Integer , CartItem > data = new HashMap<>();
  12. private Double total;
  13. public Double getTotal() {
  14. double sum = 0.0;
  15. for (CartItem cartItem : data.values()) {
  16. //只统计勾选的价格
  17. if(cartItem.getChecked()){
  18. sum += ( cartItem.getPrice() * cartItem.getCount());
  19. }
  20. }
  21. return sum;
  22. }
  23. public void addCart(CartItem cartItem) {
  24. CartItem temp = data.get(cartItem.getSkuid());
  25. if(temp == null) {
  26. data.put( cartItem.getSkuid() , cartItem);
  27. } else {
  28. temp.setCount( cartItem.getCount() + temp.getCount() );
  29. }
  30. }
  31. public void updateCart(Integer skuid, Integer count , Boolean checked) {
  32. CartItem temp = data.get(skuid);
  33. if(temp != null) {
  34. temp.setCount( count );
  35. temp.setChecked(checked);
  36. }
  37. }
  38. public void deleteCart(Integer skuid) {
  39. data.remove( skuid );
  40. }
  41. }

aba77d89974c4c82977d13e47c8046c7.png

购物车专门定制的对象

CartCategory

  1. package com.czxy.changgou4.vo;
  2. import com.fasterxml.jackson.annotation.JsonInclude;
  3. import com.fasterxml.jackson.annotation.JsonProperty;
  4. import lombok.Data;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. /**
  8. * @author 桐叔
  9. * @email liangtong@itcast.cn
  10. */
  11. @Data
  12. public class CartCategory {
  13. private Integer id;
  14. @JsonProperty("cat_name")
  15. private String catName;
  16. @JsonProperty("parent_id")
  17. private Integer parentId;
  18. @JsonProperty("is_parent")
  19. private Boolean isParent;
  20. //当前分类具有的所有孩子
  21. @JsonInclude(JsonInclude.Include.NON_EMPTY)
  22. private List<CartCategory> children = new ArrayList<>();
  23. }

CartSpecificationOption

  1. package com.czxy.changgou4.vo;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import lombok.Data;
  4. /**
  5. * @author 桐叔
  6. * @email liangtong@itcast.cn
  7. */
  8. @Data
  9. public class CartSpecificationOption {
  10. private Integer id;
  11. @JsonProperty("spec_id")
  12. private Integer specId; //外键,规格ID
  13. private CartSpecification specification; //外键对应对象
  14. @JsonProperty("option_name")
  15. private String optionName; //选项名称
  16. }

CartSpecification

  1. package com.czxy.changgou4.vo;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import lombok.Data;
  4. import java.util.List;
  5. /**
  6. * @author 桐叔
  7. * @email liangtong@itcast.cn
  8. */
  9. @Data
  10. public class CartSpecification {
  11. private Integer id;
  12. @JsonProperty("spec_name")
  13. private String specName; //规格名称
  14. private Integer categoryId; //分类外键
  15. private CartCategory category; //分类外键对应对象
  16. private List<CartSpecificationOption> options; //一个规格,具有多个规格选项
  17. }

CartOneSkuResult

  1. package com.czxy.changgou4.vo;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import lombok.Data;
  4. import java.util.Date;
  5. import java.util.List;
  6. import java.util.Map;
  7. /**
  8. * @author 桐叔
  9. * @email liangtong@itcast.cn
  10. */
  11. @Data
  12. public class CartOneSkuResult {
  13. private Integer skuid;
  14. private Integer spuid;
  15. @JsonProperty("goods_name")
  16. private String goodsName;
  17. private Double price;
  18. @JsonProperty("on_sale_date")
  19. private Date onSaleDate;
  20. @JsonProperty("comment_count")
  21. private Integer commentCount;
  22. @JsonProperty("comment_level")
  23. private Integer commentLevel;
  24. @JsonProperty("cat1_info")
  25. private CartCategory cat1Info;
  26. @JsonProperty("cat2_info")
  27. private CartCategory cat2Info;
  28. @JsonProperty("cat3_info")
  29. private CartCategory cat3Info;
  30. private Map<String, String> logo;
  31. private List<Map> photos;
  32. private String description;
  33. private String aftersale;
  34. private Integer stock;
  35. @JsonProperty("spec_list")
  36. private List<CartSpecification> specList;
  37. // id_list:'规格ID:选项ID|规格ID:选项ID|...',
  38. // id_txt:'规格名称:选项名称|规格名称:选项名称|...'
  39. @JsonProperty("spec_info")
  40. private Map<String, String> specInfo;
  41. @JsonProperty("sku_list")
  42. private List<Map<String, String>> skuList;
  43. }

#

后端实现

4a9eb0eae8ec433c8686ad5a884fdfcc.png

步骤一:创建CartVo,用于封装请求参数

  1. package com.czxy.changgou4.vo;
  2. import lombok.Data;
  3. /**
  4. * @author 桐叔
  5. * @email liangtong@itcast.cn
  6. */
  7. @Data
  8. public class CartVo {
  9. private Integer skuid ; //"SKUID",
  10. private Integer count; //"购买数量"
  11. private Boolean checked; //"是否选中"
  12. }

步骤二:创建SkuClient,用于查询详情

  1. package com.czxy.changgou4.feign;
  2. import com.czxy.changgou4.vo.BaseResult;
  3. import com.czxy.changgou4.vo.OneSkuResult;
  4. import org.springframework.cloud.openfeign.FeignClient;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. /**
  8. * @author 桐叔
  9. * @email liangtong@itcast.cn
  10. */
  11. @FeignClient(value="web-service",path = "/sku")
  12. public interface SkuClient {
  13. @GetMapping("/goods/{skuid}")
  14. public BaseResult<OneSkuResult> findSkuById(@PathVariable("skuid") Integer skuid);
  15. }

步骤三:创建CartService接口,用于完成添加业务逻辑

  1. package com.czxy.changgou4.service;
  2. import com.czxy.changgou4.pojo.User;
  3. import com.czxy.changgou4.vo.CartVo;
  4. /**
  5. * @author 桐叔
  6. * @email liangtong@itcast.cn
  7. */
  8. public interface CartService {
  9. /**
  10. * 给指定用户添加商品
  11. * @param user
  12. * @param cartVo
  13. */
  14. public void addCart(User user , CartVo cartVo);
  15. }

步骤四:创建CartService实现类

  1. package com.czxy.changgou4.service.impl;
  2. import com.alibaba.fastjson.JSON;
  3. import com.czxy.changgou4.cart.Cart;
  4. import com.czxy.changgou4.cart.CartItem;
  5. import com.czxy.changgou4.feign.SkuClient;
  6. import com.czxy.changgou4.pojo.User;
  7. import com.czxy.changgou4.service.CartService;
  8. import com.czxy.changgou4.vo.BaseResult;
  9. import com.czxy.changgou4.vo.CartOneSkuResult;
  10. import com.czxy.changgou4.vo.CartVo;
  11. import com.czxy.changgou4.vo.OneSkuResult;
  12. import org.springframework.data.redis.core.StringRedisTemplate;
  13. import org.springframework.stereotype.Service;
  14. import org.springframework.transaction.annotation.Transactional;
  15. import javax.annotation.Resource;
  16. /**
  17. * @author 桐叔
  18. * @email liangtong@itcast.cn
  19. */
  20. @Service
  21. @Transactional
  22. public class CartServiceImpl implements CartService {
  23. @Resource
  24. private StringRedisTemplate stringRedisTemplate;
  25. @Resource
  26. private SkuClient skuClient;
  27. @Override
  28. public void addCart(User user, CartVo cartVo) {
  29. //1 获得购物车
  30. Cart cart;
  31. String key = "cart" + user.getId();
  32. String cartStr = stringRedisTemplate.opsForValue().get(key);
  33. // 处理是否有购物车,没有创建,有转换(jsonStr --> java对象 )
  34. if(cartStr != null){
  35. //如果有,将json字符串转换购物车对象
  36. cart = JSON.parseObject( cartStr , Cart.class);
  37. } else {
  38. //如果没有创建一个
  39. cart = new Cart();
  40. }
  41. //2 保存商品
  42. // 2.1 确定购物买商品
  43. BaseResult<CartOneSkuResult> entity = skuClient.findSkuById(cartVo.getSkuid());
  44. CartOneSkuResult oneSkuResult = entity.getData();
  45. // * 将OneSkuResult 转换成 CartItem
  46. CartItem cartItem = new CartItem();
  47. cartItem.setSkuid( oneSkuResult.getSkuid() );
  48. cartItem.setSpuid( oneSkuResult.getSpuid() );
  49. cartItem.setGoodsName( oneSkuResult.getGoodsName() );
  50. cartItem.setPrice( oneSkuResult.getPrice() );
  51. cartItem.setCount( cartVo.getCount() ); //购买数量,用户传递的
  52. cartItem.setChecked(true);
  53. cartItem.setMidlogo( oneSkuResult.getLogo().get("biglogo"));
  54. cartItem.setSpecInfo( JSON.toJSONString( oneSkuResult.getSpecInfo() ) ); //将对象转换json字符串
  55. // 2.2 添加到购物车
  56. cart.addCart( cartItem );
  57. System.out.println(JSON.toJSONString(cart) );
  58. //3 保存购物车
  59. stringRedisTemplate.opsForValue().set( key , JSON.toJSONString(cart) );
  60. }
  61. }

步骤五:创建CartController

  1. package com.czxy.changgou4.controller;
  2. import com.czxy.changgou4.config.JwtProperties;
  3. import com.czxy.changgou4.pojo.User;
  4. import com.czxy.changgou4.service.CartService;
  5. import com.czxy.changgou4.utils.JwtUtils;
  6. import com.czxy.changgou4.vo.BaseResult;
  7. import com.czxy.changgou4.vo.CartVo;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RequestBody;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import javax.annotation.Resource;
  13. import javax.servlet.http.HttpServletRequest;
  14. /**
  15. * @author 桐叔
  16. * @email liangtong@itcast.cn
  17. */
  18. @RestController
  19. @RequestMapping("/carts")
  20. public class CartController {
  21. @Resource
  22. private CartService cartService;
  23. @Resource
  24. private HttpServletRequest request;
  25. @Resource
  26. private JwtProperties jwtProperties;
  27. @PostMapping
  28. public BaseResult addCart(@RequestBody CartVo cartVo){
  29. //1 获得用户信息
  30. // 1.1 获得token
  31. String token = request.getHeader("Authorization");
  32. // 1.2 解析token
  33. User loginUser = null;
  34. try {
  35. loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
  36. } catch (Exception e) {
  37. return BaseResult.error("token失效或未登录");
  38. }
  39. //2 添加操作
  40. cartService.addCart( loginUser , cartVo );
  41. //3 提示
  42. return BaseResult.ok("添加成功");
  43. }
  44. }

步骤六:测试

9d788201cadd464fa2973445792030d3.png

#

前端实现:购买数量

步骤一:修改Goods.vue ,为文本框添加键盘事件,用于校验输入的数据

67e58ffd732c42e7aff9ce2feab0f6f7.png

  1. <input type="text" name="amount" v-model="buyCount" @keyup.prevent="updateCount($event)" value="1" class="amount"/>

步骤二:修改Goods.vue ,完成updateCount函数

a392153c33c64ad59a561aa035e683af.png

  1. updateCount : function(e){
  2. // e.target.value 获得用户输入的数据
  3. //使用正则处理数字
  4. if( /^\d+$/.test(e.target.value) ){
  5. //如果是数字,小于1,默认为1
  6. if( e.target.value < 1) {
  7. this.buyCount = 1;
  8. }
  9. } else {
  10. //默认为1
  11. this.buyCount = 1;
  12. }
  13. },

步骤三:检查+和-已完成功能

58bd3f6e959b44cd8467e72a7ebdae44.png

前端实现

步骤一:修改 api.js ,完成“添加到购物车”方法

1420c12785d04540b0a9ed2e006941f2.png

  1. //添加到购物车
  2. addToCart : ( params ) => {
  3. return axios.post("/cart-service/carts", params )
  4. },

步骤二:修改Goods.vue,给“加入购物车”绑定点击事件 addToCartFn

bd81d0ea41c840a3ad66e92ac224dbec.png

  1. <input type="submit" value="" class="add_btn" @click.prevent="addToCartFn" />

步骤三:修改Goods.vue,完成addToCartFn功能

未登录:保存到sessionStorage

登录:保存到redis

待完善功能:用户登录时,将sessionStorage保存的商品信息合并到redis中

  1. async addToCartFn(){
  2. //获得登录标识
  3. let token = sessionStorage.getItem("token");
  4. if(token != null){
  5. //登录:发送ajax进行添加
  6. let newGoods = {
  7. skuid: this.$route.query.id,
  8. count:this.buyCount
  9. };
  10. //登录状态下的添加商品到购物车操作
  11. let {data} = await this.$request.addToCart(newGoods)
  12. if(data.code == 20000){
  13. //location.href = "flow1"
  14. this.$router.push('flow1')
  15. } else {
  16. alert(data.data.errmsg);
  17. }
  18. return;
  19. }
  20. //未登录:在浏览器保存
  21. //1 准备添加物品数据
  22. var newGoods = {
  23. skuid: this.goodsInfo.skuid,
  24. goods_name:this.goodsInfo.goods_name,
  25. price:this.goodsInfo.price,
  26. count:this.buyCount,
  27. checked:true,
  28. midlogo:this.goodsInfo.logo.smlogo,
  29. spec_info: JSON.stringify(this.goodsInfo.spec_info)
  30. };
  31. //2 维护数据:本地已经存储信息 和 新添加信息 合并
  32. var cartStr = localStorage.getItem("cart");
  33. var cart;
  34. if(cartStr == null) {
  35. // 2.1 第一次添加,直接已数组方式添加
  36. cart = [newGoods];
  37. } else {
  38. //判断是否存在(将字符串转换数组、依次遍历)
  39. cart = JSON.parse(cartStr);
  40. //是否为新物品,默认为新的
  41. let isNew = true;
  42. cart.forEach( g => {
  43. //已有数据的id 和 新物品id 是否一样
  44. if(g.skuid == newGoods.skuid){
  45. //不是新物品
  46. isNew = false;
  47. // 2.3 已有,重复,先获得对应,修改数量
  48. g.count += parseInt(newGoods.count);
  49. }
  50. });
  51. if(isNew == true){
  52. // 2.2 已有,不重复,先获得数组,后追加
  53. cart.push(newGoods);
  54. }
  55. }
  56. //3 存放到浏览器
  57. var cartStr = JSON.stringify(cart);
  58. localStorage.setItem("cart" , cartStr );
  59. //4 跳转页面
  60. location.href = "flow1"
  61. }

步骤四:编写flow1页面

64b7efe44a634ca58dc2db28bce56593.png

  1. <template>
  2. <div>
  3. 购物车
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. }
  9. </script>
  10. <style>
  11. </style>

发表评论

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

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

相关阅读