html5的web存储
localstorage 没有时间限制,只能保存字符串。可以在网页之间传输信息。
购物车的流程。
首先,我们在商品详情页点击加入购物车,把sku信息保存在localstorge中,当页面跳转到购物车页面的时候,我们判断有没有登陆 ,没有登陆的话,我们保存在本地的购物车,也是localstoreage中,如果登录u了,我们把数据提交到后台处理。
本地购物车也要判断是否登陆,如果登陆,要进行和后台的合并。
后台添加的逻辑
我们把skuId和num发送到后台,后台会将我们的购物车添加到redis中
public void addCart(Cart cart) { //凡事走到这里的,都是登录过的 //用户名我们在token中已经解析过了 UserInfo userInfo = LoginInterceptor.getUserInfo(); String key = KEY_PREFIX + userInfo.getId(); //通过key获取redis中的数据 BoundHashOperations<String, Object, Object> cartsData = redisTemplate.boundHashOps(key); Long skuId = cart.getSkuId(); Integer num = cart.getNum(); Boolean boo = cartsData.hasKey(skuId.toString()); //如果购物车中存在此商品 if (boo) { //修改购物车中商品的数量 //1.首先从redis中得到该商品 String json = cartsData.get(skuId.toString()).toString(); //将得到的数据解析成对象 Cart redisCart = JsonUtils.parse(json, Cart.class); //修改对象中商品的数量 redisCart.setNum(redisCart.getNum() + num); } else { //根据skuid查询商品的详细信息 ResponseEntity<Sku> skuResp = this.goodsClient.querySkuBySkuId(skuId); if (!skuResp.hasBody()) { logger.error("没有查到相关sku的信息:{}" + skuId); throw new RuntimeException(); } //将信息和数量封装在cart中 Sku skuBody = skuResp.getBody(); cart.setImage(StringUtils.isBlank(skuBody.getImages()) ? "" : StringUtils.split(skuBody.getImages(), ",")[0]); cart.setOwnSpec(skuBody.getOwnSpec()); cart.setPrice(skuBody.getPrice()); cart.setTitle(skuBody.getTitle()); cart.setUserId(userInfo.getId()); } //将此商品添加到redis中 cartsData.put(skuId.toString(), JsonUtils.serialize(cart)); }
查询购物车
/** * 查询购物车 * * @return */ public List<Cart> queryCart() { UserInfo userInfo = LoginInterceptor.getUserInfo(); Long userId = userInfo.getId(); String key = KEY_PREFIX + userId; if (!this.redisTemplate.hasKey(key)) { return null; } BoundHashOperations<String, Object, Object> cartData = this.redisTemplate.boundHashOps(key); List<Object> values = cartData.values(); if (CollectionUtils.isEmpty(values)) { return null; } List<Cart> carts = new ArrayList<>(); for (Object value : values) { Cart c = JsonUtils.parse(value.toString(), Cart.class); carts.add(c); } return carts; }
这边逐一将字符串进行系列化,因为我们的stringrestemplate保存到全是字符串的形式。
更新商品的信息,对商品的数量进行修改
public void updateCart(Long skuId, Integer num) { //得到用户的信息 UserInfo userInfo = LoginInterceptor.getUserInfo(); Long userId = userInfo.getId(); String key = KEY_PREFIX + userId; //根据key查询到数据 if (this.redisTemplate.hasKey(key)) { BoundHashOperations<String, Object, Object> cartData = this.redisTemplate.boundHashOps(key); String json = cartData.get(skuId.toString()).toString(); Cart redisCart = JsonUtils.parse(json, Cart.class); redisCart.setNum(num); cartData.put(skuId.toString(), JsonUtils.serialize(redisCart)); } else { logger.error("您所修改的商品不存在"); }
删除购物车中商品的信息
* 删除购物车 * @param skuId */ public void daleteCart(Long skuId) { //首先得到登陆用户的信息 UserInfo userInfo = LoginInterceptor.getUserInfo(); Long userId = userInfo.getId(); String key = KEY_PREFIX + userId; Boolean boo = this.redisTemplate.hasKey(key); if (boo) { BoundHashOperations<String, Object, Object> cartData = this.redisTemplate.boundHashOps(key); cartData.delete(skuId.toString()); } }
购物车我们实现的功能
未登陆状态,数据保存在localstrage中
登陆后,未登陆的数据保存到后台,然后查询数据,查询到的数据就是本地加登陆状态的数据。
在购物车微服务,我们也要校验用户有没有登陆,并拿到用的id,我们采用springmvc的过滤器来做这个判断。
过滤器的实现思路,首先用一个类继承HandlerInterceptorAdapter类,选择要实现的方法,哪个拦截器,前置后置,最终。
然后将这个拦截器添加到springmvc中
public class LoginInterceptor extends HandlerInterceptorAdapter { private JwtProperties jwtProperties; //一个线程域,存放登陆的对象 private static final ThreadLocal<UserInfo> t_user = new ThreadLocal<>(); public LoginInterceptor(JwtProperties jwtProperties) { this.jwtProperties = jwtProperties; } //获取登陆用户的方法 public static UserInfo getUserInfo() { return t_user.get(); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { //首先拿到令牌 String token = CookieUtils.getCookieValue(request, jwtProperties.getCookieName()); //判断令牌是否是空 if (StringUtils.isBlank(token)) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; } //令牌不为空,解析得到用户的信息 UserInfo userInfo = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey()); t_user.set(userInfo); return true; } catch (Exception e) { //抛出异常,证明未登陆,401 response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { t_user.remove(); } }
@Configuration @EnableConfigurationProperties(JwtProperties.class) public class MvcConfig implements WebMvcConfigurer { //把配置文件注入 @Autowired private JwtProperties jwtProperties; //将拦截器注入 @Bean public LoginInterceptor loginInterceptor() { return new LoginInterceptor(jwtProperties); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor()).addPathPatterns("/**"); }