谷粒商城-购物车

目录

商城业务-购物车-环境搭建

商城业务-购物车-数据模型分析

商城业务-购物车-VO编写

商城业务-购物车-ThreadLocal用户身份鉴别

商城业务-购物车-页面环境搭建

商城业务-购物车-添加购物车

商城业务-购物车-添加购物车细节

商城业务-购物车-RedirectAttribute

商城业务-购物车-获取&合并购物车

商城业务-购物车-选中购物项

商城业务-购物车-改变购物项数量

商城业务-购物车-删除购物项


商城业务-购物车-环境搭建

1.使用spring的初始化向导创建购物车服务

谷粒商城-购物车_第1张图片

谷粒商城-购物车_第2张图片

2.域名配置

谷粒商城-购物车_第3张图片

3. 导入common服务,进行配置

谷粒商城-购物车_第4张图片

谷粒商城-购物车_第5张图片

开启服务注册并排除数据库自动配置

谷粒商城-购物车_第6张图片3. Nginx动态分离配置

①上传静态资源

谷粒商城-购物车_第7张图片

谷粒商城-购物车_第8张图片

②复制html至templates,修改静态资源访问路径

 

 

③ 配置网关

谷粒商城-购物车_第9张图片

④前端页面跳转

谷粒商城-购物车_第10张图片

商城业务-购物车-数据模型分析

谷粒商城-购物车_第11张图片

购物车功能 

谷粒商城-购物车_第12张图片

购物项详情对象

谷粒商城-购物车_第13张图片整个购物车是一个数组 

谷粒商城-购物车_第14张图片

将购物车中的购物项存为list类型的话,修改起来太麻烦要从头到尾遍历。可以使用hash来存储购物车中的购物项

谷粒商城-购物车_第15张图片

商城业务-购物车-VO编写

购物项的Vo编写

谷粒商城-购物车_第16张图片

编写购车Vo 

谷粒商城-购物车_第17张图片

商城业务-购物车-ThreadLocal用户身份鉴别

1.将购物车数据存储至Redis中,因此,需要导入Spring整合Redis的依赖以及Redis的配置。项目上线之后,应该有一个专门的Redis负责存储购物车的数据不应该使用缓存的Redis



    org.springframework.boot
    spring-boot-starter-data-redis
#配置redis的ip地址
spring.redis.host=192.168.56.22

2.编写服务层

谷粒商城-购物车_第18张图片

3.判断用户是否登录则通过判断Session中是否有用户的数据,因此,导入SpringSession的依赖



    org.springframework.session
    spring-session-data-redis

配置Session 

@EnableRedisHttpSession
@Configuration
public class GulimallSessionConfig {
    /**
     * 子域问题共享解决
     */
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setDomainName("gulimall.com");
        cookieSerializer.setCookieName("GULIMALLSESSION");
        return cookieSerializer;
    }

    /**
     * 使用json序列化方式来序列化对象数据到redis中
     */
    @Bean
    public RedisSerializer springSessionDefaultRedisSerializer() {
       return new GenericJackson2JsonRedisSerializer();
    }
} 
  

4. cookie中的user-key说明

第一次访问京东,会给你的cookie中设置user-key标识你的身份,有效期为一个月,浏览器会保存你的user-key,以后访问都会带上

谷粒商城-购物车_第19张图片

5.编写To与常量

谷粒商城-购物车_第20张图片

谷粒商城-购物车_第21张图片6.编写拦截器 

拦截器逻辑:业务执行之前,判断是否登录,若登录则封装用户信息,将标识位设置为true,postHandler就不再设置作用域和有效时间,否则为其创建一个user-key

注意细节:整合SpringSession之后,Session获取数据都是从Redis中获取的

使用ThreadLocal,解决线程共享数据问题,方便同一线程共享UserInfoTo 

谷粒商城-购物车_第22张图片

 编写拦截器实现类

谷粒商城-购物车_第23张图片

过期时间为1一个月,编写一个月的时间常量 

谷粒商城-购物车_第24张图片

配置拦截器,否则拦截器不生效 

谷粒商城-购物车_第25张图片

Debug测试UserInfoTo中是否有数据 

商城业务-购物车-页面环境搭建

点击我的购物车跳转到商品列表页

将商品详情页的立即预约修改为加入购物车 

谷粒商城-购物车_第26张图片

 

谷粒商城-购物车_第27张图片

跳转至购物车列表页 ,跳转商品详情页先写死保证能跳转即可

谷粒商城-购物车_第28张图片

商城业务-购物车-添加购物车

编写添加商品进入购物车的请求方法,需要知道商品的SkuId和数量

谷粒商城-购物车_第29张图片

为加入购物车绑定单击事件,url改为#避免跳转并且设置id

谷粒商城-购物车_第30张图片

为文本框设置id

谷粒商城-购物车_第31张图片

为超链接自定义属性,用于存储skuId

编写单击事件 ,$(this)指当前实例,return false : 禁止默认行为

谷粒商城-购物车_第32张图片

修改加入购物车的成功页面的显示 

①默认图片的显示

②商品详情页跳转以及标题显示

谷粒商城-购物车_第33张图片

③商品数量显示

 购物车前缀 

谷粒商城-购物车_第34张图片

boundHashOps()方法:所有的增删改查操作只针对这个key

将其抽取成方法 

选中->右击->Refactor->Extract Method 

谷粒商城-购物车_第35张图片

远程调用product查询sku详情

谷粒商城-购物车_第36张图片

谷粒商城-购物车_第37张图片

远程调用product服务查询销售属性

①编写product服务中的查询销售属性AsString的接口

②编写远程服务调用接口   

谷粒商城-购物车_第38张图片配置线程池提高查询效率

@Configuration
public class MyThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties threadPoolConfigProperties){
       return new ThreadPoolExecutor(threadPoolConfigProperties.getCoreThreadSize(),
                threadPoolConfigProperties.getMaxThreadSize(),
                threadPoolConfigProperties.getKeepAliveTime(), TimeUnit.SECONDS,new LinkedBlockingQueue<>(100000),
                Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
    }
}
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
    private Integer coreThreadSize;
    private Integer maxThreadSize;
    private Integer keepAliveTime;
}
#线程池配置
gulimall.thread.core-thread-size=20
gulimall.thread.max-thread-size=200
gulimall.thread.keep-alive-time=10

使用异步编排 

①编写vo,属性从SkuInfoEntity中copy

谷粒商城-购物车_第39张图片

②异步编排

谷粒商城-购物车_第40张图片出现问题:

解决方案:

将th:else改为th:if 

商城业务-购物车-添加购物车细节

上面的操作是针对添加新商品进购物车,若购物车里已存在此商品则是一个数量的叠加

谷粒商城-购物车_第41张图片

@Slf4j
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor executor;

    private final String CART_PREFIX = "gulimall:cart:";


    @Override
    public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations cartOpts = getCartOpts();
        String item = (String) cartOpts.get(skuId.toString());
        // redis中无此商品,需要往购物车中添加新商品
        if (StringUtils.isEmpty(item)){
            CartItem cartItem = new CartItem();
            CompletableFuture getSkuInfoTask = CompletableFuture.runAsync(() -> {
                // 1. 远程服务调用获取sku的信息
                R r = productFeignService.info(skuId);
                SkuInfoVo skuInfo = r.getData("skuInfo", new TypeReference() {
                });
                cartItem.setSkuId(skuId);
                cartItem.setTitle(skuInfo.getSkuTitle());
                cartItem.setPrice(skuInfo.getPrice());
                cartItem.setDefaultImg(skuInfo.getSkuDefaultImg());
                cartItem.setCheck(true);
                cartItem.setCount(num);
            }, executor);
            CompletableFuture getSaleAttrsAsStringTask = CompletableFuture.runAsync(()->{
                // 2. 获取销售属性
                List saleAtrrs = productFeignService.getSaleAttrAsString(skuId);
                cartItem.setSkuAttr(saleAtrrs);
            },executor);

            // 阻塞等待各个任务执行完成
            CompletableFuture.allOf(getSkuInfoTask,getSaleAttrsAsStringTask).get();

            // 3. 存储cartItem至Redis中
            // 为了方便Redis序列化将pojo变成json字符串否则使用jdk的序列化器
            String s = JSON.toJSONString(cartItem);
            cartOpts.put(skuId.toString(),s);
            return cartItem;
        }else {
            // 购物车中有此商品只需要数量的叠加
            CartItem cartItem = JSON.parseObject(item, CartItem.class);
            cartItem.setCount(cartItem.getCount()+num);
            String s = JSON.toJSONString(cartItem);
            cartOpts.put(skuId.toString(),s);
            return cartItem;
        }

    }

    private BoundHashOperations getCartOpts() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String cartKey = "";
        // 判断是否登录
        if (userInfoTo.getUserId()!=null){
            cartKey = CART_PREFIX + userInfoTo.getUserId();
        }else {
            cartKey = CART_PREFIX + userInfoTo.getUserKey();
        }
        BoundHashOperations boundHashOperations = stringRedisTemplate.boundHashOps(cartKey);
        return boundHashOperations;
    }
}

商城业务-购物车-RedirectAttribute

为了避免用户一直刷新页面,重复提交数据,通过重定向的方式获取购物车内容

RedirectAttributes的addFlashAttribut()方法:将对象存储在Session中且只能使用一次,再次刷新就没有了

RedirectAttributes的addAttribut()方法:将对象拼接在url中

谷粒商城-购物车_第42张图片

谷粒商城-购物车_第43张图片前端页面修改,进行简单的逻辑判断 

谷粒商城-购物车_第44张图片

商城业务-购物车-获取&合并购物车

购物车列表展示逻辑:首先判断是否登录,没有登录则展示临时购物车,若登录则展示合并后的购物车,将临时购物车合并后并清空

1.编写获取购物车的方法

谷粒商城-购物车_第45张图片

2. 编写删除购物车的方法

谷粒商城-购物车_第46张图片

3. 合并购物车,合并完之后要删除临时购物车

谷粒商城-购物车_第47张图片

前端页面编写 

1.登录回显

谷粒商城-购物车_第48张图片

2. 逻辑判断

3. 购物车中商品遍历

4. 是否选中

5.图片展示

6.标题展示

7. 销售属性展示

8.格式化商品单价展示

9.商品数量展示

谷粒商城-购物车_第49张图片

10. 商品总价显示

11.购物车总价显示

谷粒商城-购物车_第50张图片12. 优惠价格显示

效果如下图所示,对区域1和区域2进行优化

谷粒商城-购物车_第51张图片

 区域1优化:

 区域2优化:

谷粒商城-购物车_第52张图片

商城业务-购物车-选中购物项

为input框设置class方便后续绑定单击事件修改选中状态,自定义属性保存skuId

谷粒商城-购物车_第53张图片

单击事件编写 ,prop会返回true或false

谷粒商城-购物车_第54张图片

编写Controller处理请求 

谷粒商城-购物车_第55张图片

谷粒商城-购物车_第56张图片

商城业务-购物车-改变购物项数量

为父标签自定义属性存储skuId,为加减操作设置相同的class,为数量设置class

谷粒商城-购物车_第57张图片

编写加减的单击事件

谷粒商城-购物车_第58张图片编写Controller

谷粒商城-购物车_第59张图片

商城业务-购物车-删除购物项

为图中的删除按钮设置class,绑定单击事件临时保存skuId

谷粒商城-购物车_第60张图片

谷粒商城-购物车_第61张图片为确认删除按钮编写删除函数  

谷粒商城-购物车_第62张图片

编写Controller   

谷粒商城-购物车_第63张图片

谷粒商城-购物车_第64张图片  

你可能感兴趣的:(尚硅谷谷粒商城,购物车,谷粒商城高级篇,谷粒商城笔记)