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.购物车服务 -谷粒商城的主要内容,如果未能解决你的问题,请参考以下文章
*Leetcode 426 & 剑指 Offer 36. 二叉搜索树与双向链表
*Leetcode 426 & 剑指 Offer 36. 二叉搜索树与双向链表