Day425&426.购物车服务 -谷粒商城

Posted 阿昌喜欢吃黄桃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day425&426.购物车服务 -谷粒商城相关的知识,希望对你有一定的参考价值。

购物车服务

一、环境搭建

  • springboot初始化

  • 新增本地域名cart.achangmall.com

  • 修改对应pom配置,与此次服务间版本对应
    • 引入公共依赖
    • 修改springboot版本
    • 修改springcloud版本

  • 将提供的静态资源导入nginx服务,做到动静分离

  • 修改页面对应的资源地址,修改只选nginx的静态地址,如:

  • 主启动类com.achang.achangmall.cart.AchangmallCartApplication
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableFeignClients
@EnableDiscoveryClient
public class AchangmallCartApplication 
    public static void main(String[] args) 
        SpringApplication.run(AchangmallCartApplication.class, args);
    

  • 配置文件achangmall-cart/src/main/resources/application.yaml
spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    nacos:
      discovery:
        server-addr: localhost:8848
  thymeleaf:
    cache: false
  redis:
    host: 192.168.109.101
    port: 6379
  application:
    name: achangmall-cart

server:
  port: 30000
  • 网关配置路由映射achangmall-gateway/src/main/resources/application.yml
        - id: cart_route
          uri: lb://achangmall-cart
          predicates:
            - Host=cart.achangmall.com
  • 启动服务测试,访问:http://cart.achangmall.com/


二、业务

  • com.achang.achangmall.cart.vo.CartVo
/**
 * 购物车1级
 */
public class CartVo 

    /**
     * 购物车子项信息
     */
    List<CartItemVo> items;

    /**
     * 商品数量
     */
    private Integer countNum;

    /**
     * 商品类型数量
     */
    private Integer countType;

    /**
     * 商品总价
     */
    private BigDecimal totalAmount;

    /**
     * 减免价格
     */
    private BigDecimal reduce = new BigDecimal("0.00");;

    public List<CartItemVo> getItems() 
        return items;
    

    public void setItems(List<CartItemVo> items) 
        this.items = items;
    

    public Integer getCountNum() 
        int count = 0;
        if (items != null && items.size() > 0) 
            for (CartItemVo item : items) 
                count += item.getCount();
            
        
        return count;
    

    public Integer getCountType() 
        int count = 0;
        if (items != null && items.size() > 0) 
            for (CartItemVo item : items) 
                count += 1;
            
        
        return count;
    

    public BigDecimal getTotalAmount() 
        BigDecimal amount = new BigDecimal("0");
        // 计算购物项总价
        if (!CollectionUtils.isEmpty(items)) 
            for (CartItemVo cartItem : items) 
                if (cartItem.getCheck()) 
                    amount = amount.add(cartItem.getTotalPrice());
                
            
        
        // 计算优惠后的价格
        return amount.subtract(getReduce());
    

    public BigDecimal getReduce() 
        return reduce;
    

    public void setReduce(BigDecimal reduce) 
        this.reduce = reduce;
    

  • com.achang.achangmall.cart.vo.CartItemVo
/**
 * 购物车2级--购物项
 */
public class CartItemVo 

    private Long skuId;

    private Boolean check = true;

    private String title;

    private String image;

    /**
     * 商品套餐属性
     */
    private List<String> skuAttrValues;

    private BigDecimal price;

    private Integer count;

    private BigDecimal totalPrice;

    public Long getSkuId() 
        return skuId;
    

    public void setSkuId(Long skuId) 
        this.skuId = skuId;
    

    public Boolean getCheck() 
        return check;
    

    public void setCheck(Boolean check) 
        this.check = check;
    

    public String getTitle() 
        return title;
    

    public void setTitle(String title) 
        this.title = title;
    

    public String getImage() 
        return image;
    

    public void setImage(String image) 
        this.image = image;
    

    public List<String> getSkuAttrValues() 
        return skuAttrValues;
    

    public void setSkuAttrValues(List<String> skuAttrValues) 
        this.skuAttrValues = skuAttrValues;
    

    public BigDecimal getPrice() 
        return price;
    

    public void setPrice(BigDecimal price) 
        this.price = price;
    

    public Integer getCount() 
        return count;
    

    public void setCount(Integer count) 
        this.count = count;
    

    /**
     * 计算当前购物项总价
     * @return
     */
    public BigDecimal getTotalPrice() 
        return this.price.multiply(new BigDecimal("" + this.count));
    

    public void setTotalPrice(BigDecimal totalPrice) 
        this.totalPrice = totalPrice;
    

  • com.achang.achangmall.cart.vo.SkuInfoVo
@Data
public class SkuInfoVo 

    private Long skuId;
    /**
     * spuId
     */
    private Long spuId;
    /**
     * sku名称
     */
    private String skuName;
    /**
     * sku介绍描述
     */
    private String skuDesc;
    /**
     * 所属分类id
     */
    private Long catalogId;
    /**
     * 品牌id
     */
    private Long brandId;
    /**
     * 默认图片
     */
    private String skuDefaultImg;
    /**
     * 标题
     */
    private String skuTitle;
    /**
     * 副标题
     */
    private String skuSubtitle;
    /**
     * 价格
     */
    private BigDecimal price;
    /**
     * 销量
     */
    private Long saleCount;

  • 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 整合springsession -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
  • com.achang.achangmall.cart.config.AchangmallSessionConfig
@Configuration
@EnableRedisHttpSession
public class AchangmallSessionConfig 
    @Bean
    public CookieSerializer cookieSerializer() 
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        //放大作用域
        cookieSerializer.setDomainName("achangmall.com");
        cookieSerializer.setCookieName("ACHANGSESSION");
        return cookieSerializer;
    

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() 
        //使用json存储redis,而不是默认的序列化存储
        return new GenericJackson2JsonRedisSerializer();
    

  • com.achang.achangmall.cart.config.MyThreadConfig
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig 
    @Bean
    public ThreadPoolExecutor executor(ThreadPoolConfigProperties pool) 
        return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    

  • com.achang.achangmall.cart.config.ThreadPoolConfigProperties
@ConfigurationProperties(prefix = "achangmall.thread")
@Data
public class ThreadPoolConfigProperties 
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;

  • com.achang.achangmall.cart.exception.RuntimeExceptionHandler
@ControllerAdvice
public class RuntimeExceptionHandler 
    /**
     * 全局统一异常处理
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public R handler(RuntimeException exception) 
        return R.error(exception.getMessage());
    
    @ExceptionHandler(CartExceptionHandler.class)
    public R userHandler(CartExceptionHandler exception) 
        return R.error("购物车无此商品");
    

  • com.achang.achangmall.cart.exception.CartExceptionHandler
public class CartExceptionHandler extends RuntimeException 
  • com.achang.achangmall.cart.feign.ProductFeignService
@FeignClient("achangmall-product")
public interface ProductFeignService 
    /**
     * 根据skuId查询sku信息
     */
    @RequestMapping("/product/skuinfo/info/skuId")
    R getInfo(@PathVariable("skuId") Long skuId);

    /**
     * 根据skuId查询pms_sku_sale_attr_value表中的信息
     */
    @GetMapping(value = "/product/skusaleattrvalue/stringList/skuId")
    List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId);

    /**
     * 根据skuId查询当前商品的最新价格
     */
    @GetMapping(value = "/product/skuinfo/skuId/price")
    BigDecimal getPrice(@PathVariable("skuId") Long skuId);

  • com.achang.achangmall.cart.intercept.CartIntercept
@Data
public class UserInfoTo 
    private Long userId;
    private String userKey;//一定存在
    /**
     * 是否临时用户
     */
    private Boolean tempUser = false;

  • 拦截器com.achang.achangmall.cart.intercept.CartIntercept
@Component
public class CartIntercept implements HandlerInterceptor 

    public static ThreadLocal<UserInfoTo> toThreadLocal = new ThreadLocal<>();

    //在目标方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception 
        UserInfoTo userInfoTo = new UserInfoTo();

        HttpSession session = request.getSession();
        MemberResponseVo memberResponseVo = (MemberResponseVo) session.getAttribute(LOGIN_USER);
        if (memberResponseVo != null) 
            //用户登录了
            userInfoTo.setUserId(memberResponseVo.getId());
        
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) 
            for (Cookie cookie : cookies) 
                //user-key
                String name = cookie.getName();
                if (name.equals(TEMP_USER_COOKIE_NAME)) 
                    userInfoTo.setUserKey(cookie.getValue());
                    //标记为已是临时用户
                    userInfoTo.setTempUser(true);
                
            
        
        //如果没有临时用户一定分配一个临时用户
        if (StringUtils.isEmpty(userInfoTo.getUserKey())) 
            String uuid = UUID.randomUUID().toString();
            userInfoTo.setUserKey(uuid);
        

        //目标方法执行之前
        toThreadLocal.set(userInfoTo);
        return true;
    


    //业务执行之后,分配临时用户来浏览器保存
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception 
        //获取当前用户的值
        UserInfoTo userInfoTo = toThreadLocal.get();

        //如果没有临时用户一定保存一个临时用户
        if (!userInfoTo.getTempUser()) 
            //创建一个cookie
            Cookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
            //扩大作用域
            cookie.setDomain("achangmall.com");
            //设置过期时间
            cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);
            response.addCookie(cookie);
        
        toThreadLocal.remove();
    

  • com.achang.achangmall.cart.to.UserInfoTo
@Data
public class UserInfoTo 
    private Long userId;
    private String userKey;//一定存在
    /**
     * 是否临时用户
     */
    private Boolean tempUser = false;

  • com.achang.common.constant.CartConstant
public class CartConstant 
    public final static String TEMP_USER_COOKIE_NAME = "user-key";
    public final static int TEMP_USER_COOKIE_TIMEOUT = 60*60*24*30;
    public final static String CART_PREFIX = "achangmall:cart:";

  • com.achang.achangmall.cart.intercept.AchangmallWebConfig配置拦截器,让其生效
@Configuration
public class AchangmallWebConfig implements WebMvcConfigurer 
    @Override
    public void addInterceptors(InterceptorRegistry registry) 
        registry.addInterceptor(

以上是关于Day425&426.购物车服务 -谷粒商城的主要内容,如果未能解决你的问题,请参考以下文章

JDK 19 / Java 19 正式发布,虚拟线程来了!

熊猫将多行作为一列,添加特定列

*Leetcode 426 & 剑指 Offer 36. 二叉搜索树与双向链表

*Leetcode 426 & 剑指 Offer 36. 二叉搜索树与双向链表

web day25 web day24 小项目练习图书商城, 购物车模块,订单模块,支付(易宝支付)

红色小恐龙团队--冲刺DAY3