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. 二叉搜索树与双向链表