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