diff --git a/ly-auth/ly-auth-service/src/main/resources/application.yaml b/ly-auth/ly-auth-service/src/main/resources/application.yaml
index 133cd33..8e4e2ef 100644
--- a/ly-auth/ly-auth-service/src/main/resources/application.yaml
+++ b/ly-auth/ly-auth-service/src/main/resources/application.yaml
@@ -19,5 +19,5 @@ ly:
secret: leyou@Login(Auth}*^31)&lollipop% # 登录校验的密钥
pubKeyPath: G:/test/rsa.pub # 公钥地址
priKeyPath: G:/test/rsa.pri # 私钥地址
- expire: 30 # 过期时间,单位分钟
+ expire: 1800 # 过期时间,单位秒
cookieName: LY_TOKEN
\ No newline at end of file
diff --git a/ly-cart/pom.xml b/ly-cart/pom.xml
new file mode 100644
index 0000000..7b236e3
--- /dev/null
+++ b/ly-cart/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ leyou
+ cn.lollipop
+ 1.0.0-SNAPSHOT
+
+ 4.0.0
+
+ ly-cart
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ cn.lollipop
+ ly-auth-common
+ ${leyou-latest.version}
+
+
+ cn.lollipop
+ ly-common
+ ${leyou-latest.version}
+
+
+
\ No newline at end of file
diff --git a/ly-cart/src/main/java/cn/lollipop/CartApplication.java b/ly-cart/src/main/java/cn/lollipop/CartApplication.java
new file mode 100644
index 0000000..532a2de
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/CartApplication.java
@@ -0,0 +1,18 @@
+package cn.lollipop;
+
+import cn.lollipop.cart.config.JwtProperties;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableEurekaClient
+@EnableFeignClients
+@EnableConfigurationProperties(JwtProperties.class)
+public class CartApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(CartApplication.class, args);
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/config/JwtProperties.java b/ly-cart/src/main/java/cn/lollipop/cart/config/JwtProperties.java
new file mode 100644
index 0000000..8a95bee
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/config/JwtProperties.java
@@ -0,0 +1,25 @@
+package cn.lollipop.cart.config;
+
+import cn.lollipop.auth.utils.RsaUtils;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import javax.annotation.PostConstruct;
+import java.security.PublicKey;
+
+@Data
+@Slf4j
+@ConfigurationProperties(prefix = "ly.jwt")
+public class JwtProperties {
+ private String pubKeyPath;
+ private String cookieName;
+
+ private PublicKey publicKey;
+
+ // 实例化完成后进行公钥的读取
+ @PostConstruct
+ public void init() throws Exception {
+ publicKey = RsaUtils.getPublicKey(pubKeyPath);
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/config/MvcConfig.java b/ly-cart/src/main/java/cn/lollipop/cart/config/MvcConfig.java
new file mode 100644
index 0000000..5b0e1ff
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/config/MvcConfig.java
@@ -0,0 +1,22 @@
+package cn.lollipop.cart.config;
+
+import cn.lollipop.cart.interceptor.UserInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+ private final UserInterceptor userInterceptor;
+
+ @Autowired
+ public MvcConfig(UserInterceptor userInterceptor) {
+ this.userInterceptor = userInterceptor;
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(userInterceptor).addPathPatterns("/**");
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/interceptor/UserInterceptor.java b/ly-cart/src/main/java/cn/lollipop/cart/interceptor/UserInterceptor.java
new file mode 100644
index 0000000..5d50f1d
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/interceptor/UserInterceptor.java
@@ -0,0 +1,47 @@
+package cn.lollipop.cart.interceptor;
+
+import cn.lollipop.auth.pojo.UserInfo;
+import cn.lollipop.auth.utils.JwtUtils;
+import cn.lollipop.cart.config.JwtProperties;
+import cn.lollipop.cart.utils.ThreadLocalUtils;
+import cn.lollipop.common.ExceptionConstant;
+import cn.lollipop.common.exception.LyException;
+import cn.lollipop.common.util.CookieUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class UserInterceptor implements HandlerInterceptor {
+ private final JwtProperties prop;
+
+ @Autowired
+ public UserInterceptor(JwtProperties prop) {
+ this.prop = prop;
+ }
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ // 获取Cookie中的token
+ String token = CookieUtils.getCookieValue(request, prop.getCookieName());
+ try {
+ // 解析token
+ UserInfo user = JwtUtils.getInfoFromToken(token, prop.getPublicKey());
+ ThreadLocalUtils.set(user);
+ return true;
+ } catch (Exception e) {
+ log.error("[购物车服务],用户认证失败!");
+ throw new LyException(ExceptionConstant.UNAUTHORIZED);
+ }
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ ThreadLocalUtils.remove();
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/pojo/Cart.java b/ly-cart/src/main/java/cn/lollipop/cart/pojo/Cart.java
new file mode 100644
index 0000000..093790d
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/pojo/Cart.java
@@ -0,0 +1,15 @@
+package cn.lollipop.cart.pojo;
+
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString
+public class Cart {
+ private Long skuId;// 商品id
+ private String title;// 标题
+ private String image;// 图片
+ private Long price;// 加入购物车时的价格
+ private Integer num;// 购买数量
+ private String ownSpec;// 商品规格参数
+}
\ No newline at end of file
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/service/CartService.java b/ly-cart/src/main/java/cn/lollipop/cart/service/CartService.java
new file mode 100644
index 0000000..b217cf1
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/service/CartService.java
@@ -0,0 +1,61 @@
+package cn.lollipop.cart.service;
+
+import cn.lollipop.auth.pojo.UserInfo;
+import cn.lollipop.cart.pojo.Cart;
+import cn.lollipop.cart.utils.ThreadLocalUtils;
+import cn.lollipop.common.ExceptionConstant;
+import cn.lollipop.common.exception.LyException;
+import cn.lollipop.common.util.JsonUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundHashOperations;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class CartService {
+ private final StringRedisTemplate redisTemplate;
+
+ private static final String KEY_PREFIX = "cart:user:id:";
+
+ @Autowired
+ public CartService(StringRedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ public void addCart(Cart cart) {
+ // 获取当前登录用户
+ UserInfo user = ThreadLocalUtils.get();
+ // key
+ String key = KEY_PREFIX + user.getId();
+ // hashKey
+ String hashKey = String.valueOf(cart.getSkuId());
+ int num = cart.getNum();
+
+ BoundHashOperations operations = redisTemplate.boundHashOps(key);
+ // 判断当前购物车商品是否存在
+ if (operations.hasKey(hashKey)) {
+ // 修改数量
+ String json = operations.get(hashKey).toString();
+ cart = JsonUtils.parse(json, Cart.class);
+ cart.setNum(num + cart.getNum());
+ }
+ operations.put(hashKey, JsonUtils.serialize(cart));
+ }
+
+ public List queryCartList() {
+ // 获取当前登录用户
+ UserInfo user = ThreadLocalUtils.get();
+ // key
+ String key = KEY_PREFIX + user.getId();
+ if (!redisTemplate.hasKey(key)) {
+ throw new LyException(ExceptionConstant.CART_NOT_FOUND);
+ }
+
+ BoundHashOperations operations = redisTemplate.boundHashOps(key);
+ return operations.values().stream()
+ .map(o -> JsonUtils.parse(o.toString(), Cart.class)).collect(Collectors.toList());
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/utils/ThreadLocalUtils.java b/ly-cart/src/main/java/cn/lollipop/cart/utils/ThreadLocalUtils.java
new file mode 100644
index 0000000..26a10e9
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/utils/ThreadLocalUtils.java
@@ -0,0 +1,22 @@
+package cn.lollipop.cart.utils;
+
+import cn.lollipop.auth.pojo.UserInfo;
+
+public class ThreadLocalUtils {
+ private static final ThreadLocal threadLocal = new ThreadLocal<>();
+
+ private ThreadLocalUtils() {
+ }
+
+ public static void set(UserInfo user) {
+ threadLocal.set(user);
+ }
+
+ public static void remove() {
+ threadLocal.remove();
+ }
+
+ public static UserInfo get() {
+ return threadLocal.get();
+ }
+}
diff --git a/ly-cart/src/main/java/cn/lollipop/cart/web/CartController.java b/ly-cart/src/main/java/cn/lollipop/cart/web/CartController.java
new file mode 100644
index 0000000..35d0f0a
--- /dev/null
+++ b/ly-cart/src/main/java/cn/lollipop/cart/web/CartController.java
@@ -0,0 +1,45 @@
+package cn.lollipop.cart.web;
+
+import cn.lollipop.cart.pojo.Cart;
+import cn.lollipop.cart.service.CartService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class CartController {
+ private final CartService cartService;
+
+ @Autowired
+ public CartController(CartService cartService) {
+ this.cartService = cartService;
+ }
+
+ /**
+ * 新增购物车
+ *
+ * @param cart
+ * @return
+ */
+ @PostMapping
+ public ResponseEntity addCart(@RequestBody Cart cart) {
+ cartService.addCart(cart);
+ return ResponseEntity.status(HttpStatus.CREATED).build();
+ }
+
+ /**
+ * 查询购物车
+ *
+ * @return
+ */
+ @GetMapping("list")
+ public ResponseEntity> queryCartList() {
+ return ResponseEntity.ok(cartService.queryCartList());
+ }
+}
diff --git a/ly-cart/src/main/resources/application.yaml b/ly-cart/src/main/resources/application.yaml
new file mode 100644
index 0000000..1c9aaa3
--- /dev/null
+++ b/ly-cart/src/main/resources/application.yaml
@@ -0,0 +1,19 @@
+server:
+ port: 8088
+spring:
+ application:
+ name: cart-service
+ redis:
+ host: 192.168.161.101
+eureka:
+ client:
+ service-url:
+ defaultZone: http://127.0.0.1:8761/eureka
+ registry-fetch-interval-seconds: 10
+ instance:
+ prefer-ip-address: true
+ ip-address: 127.0.0.1
+ly:
+ jwt:
+ pubKeyPath: G:/test/rsa.pub # 公钥地址
+ cookieName: LY_TOKEN # cookie的名称
\ No newline at end of file
diff --git a/ly-common/src/main/java/cn/lollipop/common/ExceptionConstant.java b/ly-common/src/main/java/cn/lollipop/common/ExceptionConstant.java
index 9d3ae78..ffb2cc3 100644
--- a/ly-common/src/main/java/cn/lollipop/common/ExceptionConstant.java
+++ b/ly-common/src/main/java/cn/lollipop/common/ExceptionConstant.java
@@ -30,7 +30,8 @@ public enum ExceptionConstant {
GOODS_DETAIL_NOT_FOUND(404, "商品详细信息不存在!"),
GOODS_STOCK_NOT_FOUND(404, "商品库存信息不存在!"),
CREATE_TOKEN_ERROR(500, "用户凭证创建失败!"),
- UNAUTHORIZED(403, "未授权用户");
+ UNAUTHORIZED(403, "未授权用户"),
+ CART_NOT_FOUND(404, "购物车为空");
private int code;
private String msg;
diff --git a/ly-common/target/classes/cn/lollipop/common/ExceptionConstant.class b/ly-common/target/classes/cn/lollipop/common/ExceptionConstant.class
index 33e5127..d978868 100644
Binary files a/ly-common/target/classes/cn/lollipop/common/ExceptionConstant.class and b/ly-common/target/classes/cn/lollipop/common/ExceptionConstant.class differ
diff --git a/ly-gateway/src/main/resources/application.yml b/ly-gateway/src/main/resources/application.yml
index d321a2c..8cc6645 100644
--- a/ly-gateway/src/main/resources/application.yml
+++ b/ly-gateway/src/main/resources/application.yml
@@ -14,6 +14,7 @@ zuul:
search-service: /search/** # 搜索微服务
user-service: /user/** # 用户微服务
auth-service: /auth/** # 授权中心微服务
+ cart-service: /cart/** # 购物车微服务
upload-service: # 文件上传微服务
path: /upload/**
serviceId: upload-service
diff --git a/ly-gateway/target/classes/application.yml b/ly-gateway/target/classes/application.yml
index d321a2c..8cc6645 100644
--- a/ly-gateway/target/classes/application.yml
+++ b/ly-gateway/target/classes/application.yml
@@ -14,6 +14,7 @@ zuul:
search-service: /search/** # 搜索微服务
user-service: /user/** # 用户微服务
auth-service: /auth/** # 授权中心微服务
+ cart-service: /cart/** # 购物车微服务
upload-service: # 文件上传微服务
path: /upload/**
serviceId: upload-service
diff --git a/ly-item/ly-item-service/src/main/java/cn/lollipop/item/service/GoodsService.java b/ly-item/ly-item-service/src/main/java/cn/lollipop/item/service/GoodsService.java
index 0bdc6e5..17d755a 100644
--- a/ly-item/ly-item-service/src/main/java/cn/lollipop/item/service/GoodsService.java
+++ b/ly-item/ly-item-service/src/main/java/cn/lollipop/item/service/GoodsService.java
@@ -123,21 +123,11 @@ public SpuDetail querySpuDetailById(Long id) {
public List querySkuListBySpuId(Long id) {
Sku sku = new Sku();
sku.setSpuId(id);
- List skus = skuMapper.select(sku);
- if (skus == null) {
- throw new LyException(ExceptionConstant.GOODS_SKU_NOT_FOUND);
- }
-
+ List list = skuMapper.select(sku);
// 库存查询
- List ids = skus.stream().map(Sku::getId).collect(Collectors.toList());
- List stockList = stockMapper.selectByIdList(ids);
- if (stockList == null) {
- throw new LyException(ExceptionConstant.GOODS_STOCK_NOT_FOUND);
- }
-
- Map stockMap = stockList.stream().collect(Collectors.toMap(Stock::getSkuId, Stock::getStock));
- skus.forEach(s -> s.setStock(stockMap.get(s.getId())));
- return skus;
+ List ids = list.stream().map(Sku::getId).collect(Collectors.toList());
+ loadStockInSku(ids, list);
+ return list;
}
@Transactional
@@ -210,4 +200,24 @@ public Spu querySpuById(Long id) {
spu.setSpuDetail(querySpuDetailById(id));
return spu;
}
+
+ public List querySkuListByIds(List ids) {
+ List list = skuMapper.selectByIdList(ids);
+ if (list == null) {
+ throw new LyException(ExceptionConstant.GOODS_SKU_NOT_FOUND);
+ }
+
+ loadStockInSku(ids, list);
+ return list;
+ }
+
+ private void loadStockInSku(List ids, List skuList) {
+ List stockList = stockMapper.selectByIdList(ids);
+ if (stockList == null) {
+ throw new LyException(ExceptionConstant.GOODS_STOCK_NOT_FOUND);
+ }
+
+ Map stockMap = stockList.stream().collect(Collectors.toMap(Stock::getSkuId, Stock::getStock));
+ skuList.forEach(s -> s.setStock(stockMap.get(s.getId())));
+ }
}
diff --git a/ly-item/ly-item-service/src/main/java/cn/lollipop/item/web/GoodsController.java b/ly-item/ly-item-service/src/main/java/cn/lollipop/item/web/GoodsController.java
index d2b4dc7..0848446 100644
--- a/ly-item/ly-item-service/src/main/java/cn/lollipop/item/web/GoodsController.java
+++ b/ly-item/ly-item-service/src/main/java/cn/lollipop/item/web/GoodsController.java
@@ -82,6 +82,17 @@ public ResponseEntity> querySkuListBySpuId(Long id) {
return ResponseEntity.ok(goodsService.querySkuListBySpuId(id));
}
+ /**
+ * 批量查询sku信息
+ *
+ * @param ids skuId集合
+ * @return
+ */
+ @GetMapping("sku/list/ids")
+ public ResponseEntity> querySkuListByIds(@RequestParam("ids") List ids) {
+ return ResponseEntity.ok(goodsService.querySkuListByIds(ids));
+ }
+
/**
* 根据id查询spu信息
*
diff --git a/ly-item/ly-item-service/target/classes/cn/lollipop/item/service/GoodsService.class b/ly-item/ly-item-service/target/classes/cn/lollipop/item/service/GoodsService.class
index 115c32a..b4680f4 100644
Binary files a/ly-item/ly-item-service/target/classes/cn/lollipop/item/service/GoodsService.class and b/ly-item/ly-item-service/target/classes/cn/lollipop/item/service/GoodsService.class differ
diff --git a/ly-item/ly-item-service/target/classes/cn/lollipop/item/web/GoodsController.class b/ly-item/ly-item-service/target/classes/cn/lollipop/item/web/GoodsController.class
index c2c6553..717a1ce 100644
Binary files a/ly-item/ly-item-service/target/classes/cn/lollipop/item/web/GoodsController.class and b/ly-item/ly-item-service/target/classes/cn/lollipop/item/web/GoodsController.class differ
diff --git a/ly-page/src/main/resources/templates/item.html b/ly-page/src/main/resources/templates/item.html
index 62f7a30..c0ba725 100644
--- a/ly-page/src/main/resources/templates/item.html
+++ b/ly-page/src/main/resources/templates/item.html
@@ -675,7 +675,7 @@ 猜你喜欢
ownSpec: JSON.stringify(this.ownSpec)
}).then(() => {
// 跳转到购物车列表页
- window.location.href = "http://www.lyshop.com/cart.html";
+ window.location.href = "/cart.html";
}).catch(() => {
alert("添加购物车失败,请重试!");
})
@@ -701,7 +701,7 @@ 猜你喜欢
// 未登录
ly.store.set("carts", carts);
// 跳转到购物车列表页
- window.location.href = "http://www.lyshop.com/cart.html";
+ window.location.href = "/cart.html";
})
},
locked(id, i) {
diff --git a/pom.xml b/pom.xml
index 1988ce8..6b2d069 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
ly-upload
ly-user
ly-auth
+ ly-cart
pom