乐优商城项目---day18-购物车

1.搭建购物车服务

1.1.创建module

搭建购物车模块与之前的一样,依旧是加入引导类,编写配置文件,加入启动类

加入依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

加入配置文件

server:
  port: 8088
spring:
  application:
    name: cart-service
  redis:
    host: 192.168.56.101
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 10
  instance:
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 15

加入引导类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LeyouCartApplication {

    public static void main(String[] args) {
        SpringApplication.run(LeyouCartApplication.class, args);
    }
}

2.购物车功能分析

2.1.需求

需求描述:

  • 用户可以在登录状态下将商品添加到购物车

    • 放入数据库

    • mongodb

    • 放入redis(采用)

  • 用户可以在未登录状态下将商品添加到购物车

    • 放入localstorage

    • cookie

    • webSQL

  • 用户可以使用购物车一起结算下单

  • 用户可以查询自己的购物车

  • 用户可以在购物车中修改购买商品的数量。

  • 用户可以在购物车中删除商品。

  • 在购物车中展示商品优惠信息

  • 提示购物车商品价格变化

这幅图主要描述了两个功能:新增商品到购物车、查询购物车。

新增商品:

  • 判断是否登录

    • 是:则添加商品到后台Redis中

    • 否:则添加商品到本地的Localstorage

无论哪种新增,完成后都需要查询购物车列表:

  • 判断是否登录

    • 否:直接查询localstorage中数据并展示

    • 是:已登录,则需要先看本地是否有数据,

      • 有:需要提交到后台添加到redis,合并数据,而后查询

      • 否:直接去后台查询redis,而后返回

编写前端代码因为我个人的原因,JS没有代码校验,少写括号出现了

前端代码一定要写好:

	methods:{
			addCarts(){

			},
			incr(){
				this.num++;
			},desc(){
				if (this.num>1){
					this.num--;
				}
			}
		},

添加购物车的前端代码的编写:

	addCarts(){
				ly.http.get("/auth/verify").then(resp=>{
					//已经登录
				}).catch(()=>{
					//未登录
					let carts=ly.store.get("LY_CART")||[];
					let cart=carts.find(cart=>cart.skuId===this.sku.id);
					if (cart){
						//如果已经又商品,则在起基础上进行累计
						cart.num+=this.num;
					} else
					{
						//如果没有就进行新增
						cart={
							skuId:this.sku.id,
							image:this.sku.image,
							title:this.sku.titile,
							price:this.sku.price,
							ownSpec:this.sku.ownSpec
						}
						carts.push(cart);
					}
					ly.store.set("LY_CART",carts);
					window.location.href="http://www.leyou.com/cart.html";
				})
			},

完成测试:

JS代码段函数编写:

 created(){
            ly.verify().then(resp=>{

            }).catch(()=>{
               this.carts= ly.store.get("LY_CART")
            })
        },
        components: {
            shortcut: () => import("/js/pages/shortcut.js")
        }

加入购物车成功:

因为对前端的Vue的代码不熟悉,语法等不是很熟练,所以这一部分代码写起来比较吃力,不过大概的效果还是可以运行出来的,对购物车的增删改查操作,前端的标签进行值得渲染

decre(cart){
                if (cart.num>1){
                    cart.num--;
                    ly.verify().then(resp=>{

                    }).catch(()=>{
                        ly.store.set("LY_CART",this.carts);

                    })
                }
            },incr(cart){
                cart.num++;
                ly.verify().then(resp=>{

                }).catch(()=>{
                    ly.store.set("LY_CART",this.carts);
                })
            },deleteCart(index){
                ly.verify().then(resp=>{

                }).catch(()=>{
                    this.carts.splice(index,1);
                    ly.store.set("LY_CART",this.carts);
                })
            }

添加拦截器

@Component
@EnableConfigurationProperties(JwtProperties.class)
public class LoginInterpertor extends HandlerInterceptorAdapter {
    @Autowired
    private JwtProperties jwtProperties;
    private static final  ThreadLocal<UserInfo> THREAD_LOCAL=new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = CookieUtils.getCookieValue(request, jwtProperties.getCookieName());
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
        if (userInfo==null){
            return false;
        }
        THREAD_LOCAL.set(userInfo);
        return true;
    }
    public  static UserInfo get(){
        return THREAD_LOCAL.get();
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //删除线程池中得线程
        THREAD_LOCAL.remove();
    }
}
@Component
public class LeyouMVCConfiguatrion implements WebMvcConfigurer {

    @Autowired
    LoginInterpertor loginInterpertor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterpertor).addPathPatterns("/**");
    }
}

4.2.后台购物车设计

当用户登录时,我们需要把购物车数据保存到后台,可以选择保存在数据库。但是购物车是一个读写频率很高的数据。因此我们这里选择读写效率比较高的Redis作为购物车存储。

Redis有5种不同数据结构,这里选择哪一种比较合适呢?Map<String, List<String>>

  • 首先不同用户应该有独立的购物车,因此购物车应该以用户的作为key来存储,Value是用户的所有购物车信息。这样看来基本的k-v结构就可以了。

  • 但是,我们对购物车中的商品进行增、删、改操作,基本都需要根据商品id进行判断,为了方便后期处理,我们的购物车也应该是k-v结构,key是商品id,value才是这个商品的购物车信息。

综上所述,我们的购物车结构是一个双层Map:Map<String,Map<String,String>>

  • 第一层Map,Key是用户id

  • 第二层Map,Key是购物车中商品id,值是购物车数据

将购物车中得数据保存在Redis中

Controller:

@Controller
public class CartController {
    @Autowired
    private CartService cartService;

    @PostMapping
    public ResponseEntity<Void> addCart(@RequestBody Cart cart){
        this.cartService.addCart(cart);
        return ResponseEntity.ok(null);
    }
}

Service:

@Service
public class CartService {
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static final String PRY_KEY="leyou:cart:uid";


    public void addCart(Cart cart) {
        //获取用户信息
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        String key = cart.getSkuId().toString();
        Integer num = cart.getNum();
        //查询购物车中得商品记录
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(PRY_KEY + key);
        if (ops.hasKey(key)){
            //如果购物车中包含此商品
            String cartJson = ops.hasKey(key).toString();
            cart=  JsonUtils.parse(cartJson,Cart.class);
            cart.setNum(cart.getNum()+num);
            ops.put(key,cart);
        }
        else {
            //如果购物车中部包含此商品
            cart.setUserId(userInfo.getId());
            Sku sku = goodsClient.querBySkuId(cart.getSkuId());
            cart.setImage(StringUtils.isBlank(sku.getImages())?"":StringUtils.split(sku.getImages(),",")[0]);
            cart.setPrice(sku.getPrice());
            cart.setTitle(sku.getTitle());
            cart.setOwnSpec(sku.getOwnSpec());
        }
        ops.put(key,JsonUtils.serialize(cart));
    }
}

添加成功:则会个往Redis添加得时候可能会出现问题,一定要看清token又没有值,注意时拦截器得配置,其中得用户信息时从拦截器中获取得,如果拦截器配置部成功,token值为空,这个往redis中添加数据就一直就添加部进去,一定要注意token得值!!!

加入购物车成功:页面回显,关于购物车得查询

Controller:


    @GetMapping
    public ResponseEntity<List<Cart>> query(){
        List<Cart> cartList =this.cartService.query();
        if (CollectionUtils.isEmpty(cartList)){
            return ResponseEntity.badRequest().build();
        }
        return ResponseEntity.ok(cartList);
    }

Service:

/**
     * 查询购物车方法
     * @return
     */
    public List<Cart> query() {
        UserInfo user = LoginInterceptor.getLoginUser();
       if (!redisTemplate.hasKey(PRY_KEY+user.getId())){
           return null;
       }
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(PRY_KEY + user.getId());
        List<Object> objectList = ops.values();
        return  objectList.stream().map(cart->JsonUtils.parse(cart.toString(),Cart.class)).collect(Collectors.toList());
    }

修改购物车中得数量

Controller:

 @PutMapping
    public ResponseEntity<Void> updateCart(@RequestBody Cart cart){
        this.cartService.update(cart);
        return ResponseEntity.noContent().build();
    }

Serivce:

    public void update(Cart cart) {
        //获取用户信息
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //判断用户得购物车是否存在
        if(!redisTemplate.hasKey(PRY_KEY+userInfo))
        {
            return;
        }
        //获取购物车
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(PRY_KEY + userInfo);
        //获取Redios中得购物车
        Integer num = cart.getNum();
        String carString = ops.get(cart.getSkuId().toString()).toString();
        cart=JsonUtils.parse(carString,Cart.class);
        cart.setNum(num);
        //重新放入缓冲总
        ops.put(cart.getSkuId().toString(),JsonUtils.serialize(cart));
    }

Redis中得数量

今日总结:

1.nginx
    proxy_set_header Host $host;
2.zuul网关
  add-host-header: true
  sensitiveHeaders: # 设置敏感头信息为null

  skuId
  image
  skuTitle
  ownSpec
  price
  num
  
<input type="checkbox" value="java" v-model="language">
<input type="checkbox" value="php" v-model="language">
<input type="checkbox" value="ios" v-model="language">


1.jwt登陆校验接口

2.解决cookie写入问题
    Release SR2

3.首页用户名显示
    1.jwtUtils解析token
    2.刷新有效时间

4.zuul网关统一校验用户
    自定义过滤器继承ZuulFilter
    添加白名单

5.购物车,未登录状态购物车
    加入购物车 查询购物车 修改数量 删除购物车 勾选购物车
 

发布了143 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zgz102928/article/details/104623886