package com.alatus.mall.seckill.app; import com.alatus.common.utils.R; import com.alatus.mall.seckill.service.SecKillService; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class SeckillController { @Autowired private SecKillService secKillService; /** * 获取当前时间可以参与秒杀的商品信息 * @return */ @GetMapping("/getCurrentSeckillSkus") public R getCurrentSeckillSkus() { List
secKillSkuRedisToList = secKillService.getCurrentSeckillSkus(); return R.ok().put("data",secKillSkuRedisToList); } } package com.alatus.mall.seckill.app; import com.alatus.common.utils.R; import com.alatus.mall.seckill.service.SecKillService; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class SeckillController { @Autowired private SecKillService secKillService; /** * 获取当前时间可以参与秒杀的商品信息 * @return */ @GetMapping("/getCurrentSeckillSkus") public R getCurrentSeckillSkus() { ListsecKillSkuRedisToList = secKillService.getCurrentSeckillSkus(); return R.ok().put("data",secKillSkuRedisToList); } }
package com.alatus.mall.seckill.scheduled; import com.alatus.mall.seckill.service.SecKillService; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * 秒杀商品的定时上架 * 每天晚上凌晨4点,上架最新三天秒杀商品 * 重复上架无需处理 */ @Service @Slf4j public class SecKillSkuScheduled { @Autowired private SecKillService secKillService; @Autowired private RedissonClient redissonClient; private final String upload_lock = "seckill:upload:lock"; @Scheduled(cron = "0 0 4 * * ?") // TODO 幂等性处理 // @Scheduled(cron = "*/3 * * * * ?") public void uploadSecKillSkuLatest3Days() { log.info("上架秒杀的商品信息..."); RLock rLock = redissonClient.getLock(upload_lock); rLock.lock(30, TimeUnit.SECONDS); try{ secKillService.uploadSecKillSkuLatest3Days(); }finally { rLock.unlock(); } } }
package com.alatus.mall.seckill.scheduled; import com.alatus.mall.seckill.service.SecKillService; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * 秒杀商品的定时上架 * 每天晚上凌晨4点,上架最新三天秒杀商品 * 重复上架无需处理 */ @Service @Slf4j public class SecKillSkuScheduled { @Autowired private SecKillService secKillService; @Autowired private RedissonClient redissonClient; private final String upload_lock = "seckill:upload:lock"; @Scheduled(cron = "0 0 4 * * ?") // TODO 幂等性处理 // @Scheduled(cron = "*/3 * * * * ?") public void uploadSecKillSkuLatest3Days() { log.info("上架秒杀的商品信息..."); RLock rLock = redissonClient.getLock(upload_lock); rLock.lock(30, TimeUnit.SECONDS); try{ secKillService.uploadSecKillSkuLatest3Days(); }finally { rLock.unlock(); } } }
server: port: 88 spring: redis: port: 6379 host: 192.168.56.10 cloud: gateway: routes: # 前端项目都带API前缀 - id: product_route uri: lb://Mall-product predicates: - Path=/api/product/** filters: - RewritePath=/api/(?
/?.*),/$\{segment} - id: coupon_route uri: lb://Mall-coupon predicates: - Path=/api/coupon/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: ware_route uri: lb://Mall-ware predicates: - Path=/api/ware/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: member_route uri: lb://Mall-member predicates: - Path=/api/member/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: third_party_route uri: lb://Mall-third-party predicates: - Path=/api/thirdparty/** filters: - RewritePath=/api/thirdparty/(? /?.*), /$\{segment} - id: admin_route uri: lb://Mall-admin predicates: - Path=/api/** filters: - RewritePath=/api/(? /?.*), /Mall-admin/$\{segment} - id: alatusmall_host_route uri: lb://Mall-product predicates: - Host=alatusmall.com,item.alatusmall.com - id: alatusmall_search_route uri: lb://Mall-search predicates: - Host=search.alatusmall.com - id: alatusmall_auth_route uri: lb://Mall-auth-server predicates: - Host=auth.alatusmall.com - id: alatusmall_cart_route uri: lb://Mall-cart predicates: - Host=cart.alatusmall.com - id: alatusmall_order_route uri: lb://Mall-order predicates: - Host=order.alatusmall.com - id: alatusmall_member_route uri: lb://Mall-member predicates: - Host=member.alatusmall.com - id: alatusmall_seckill_route uri: lb://Mall-seckill predicates: - Host=seckill.alatusmall.com
server: port: 88 spring: redis: port: 6379 host: 192.168.56.10 cloud: gateway: routes: # 前端项目都带API前缀 - id: product_route uri: lb://Mall-product predicates: - Path=/api/product/** filters: - RewritePath=/api/(?/?.*),/$\{segment} - id: coupon_route uri: lb://Mall-coupon predicates: - Path=/api/coupon/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: ware_route uri: lb://Mall-ware predicates: - Path=/api/ware/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: member_route uri: lb://Mall-member predicates: - Path=/api/member/** filters: - RewritePath=/api/(? /?.*),/$\{segment} - id: third_party_route uri: lb://Mall-third-party predicates: - Path=/api/thirdparty/** filters: - RewritePath=/api/thirdparty/(? /?.*), /$\{segment} - id: admin_route uri: lb://Mall-admin predicates: - Path=/api/** filters: - RewritePath=/api/(? /?.*), /Mall-admin/$\{segment} - id: alatusmall_host_route uri: lb://Mall-product predicates: - Host=alatusmall.com,item.alatusmall.com - id: alatusmall_search_route uri: lb://Mall-search predicates: - Host=search.alatusmall.com - id: alatusmall_auth_route uri: lb://Mall-auth-server predicates: - Host=auth.alatusmall.com - id: alatusmall_cart_route uri: lb://Mall-cart predicates: - Host=cart.alatusmall.com - id: alatusmall_order_route uri: lb://Mall-order predicates: - Host=order.alatusmall.com - id: alatusmall_member_route uri: lb://Mall-member predicates: - Host=member.alatusmall.com - id: alatusmall_seckill_route uri: lb://Mall-seckill predicates: - Host=seckill.alatusmall.com
package com.alatus.mall.seckill.service; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import java.util.List; public interface SecKillService { void uploadSecKillSkuLatest3Days(); List
getCurrentSeckillSkus(); }
package com.alatus.mall.seckill.service; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import java.util.List; public interface SecKillService { void uploadSecKillSkuLatest3Days(); ListgetCurrentSeckillSkus(); }
package com.alatus.mall.seckill.service.impl; import com.alatus.common.utils.R; import com.alatus.mall.seckill.constant.SecKillConstants; import com.alatus.mall.seckill.feign.CouponFeignService; import com.alatus.mall.seckill.feign.ProductFeignService; import com.alatus.mall.seckill.service.SecKillService; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import com.alatus.mall.seckill.vo.SeckillSessionEntityVo; import com.alatus.mall.seckill.vo.SkuInfoVo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.redisson.api.RSemaphore; import org.redisson.api.RedissonClient; import org.springframework.beans.BeanUtils; 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.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Service public class SecKillServiceImpl implements SecKillService { @Autowired private CouponFeignService couponFeignService; @Autowired private ProductFeignService productFeignService; @Autowired private StringRedisTemplate redisTemplate; @Autowired private RedissonClient redissonClient; @Override public void uploadSecKillSkuLatest3Days() { // 扫描需要参与秒杀的活动 R daySession = couponFeignService.Latest3DaySession(); if(daySession.getCode() == 0){ List
seckillSessionVos = daySession.getData(new TypeReference >() {}); // 缓存活动信息 saveSessionInfos(seckillSessionVos); // 缓存活动关联的商品信息 saveSkuInfos(seckillSessionVos); } } // 返回当前事件可以参与的秒杀商品信息 @Override public List
getCurrentSeckillSkus() { // 确定当前时间属于哪个秒杀场次 long time = new Date().getTime(); Set keys = redisTemplate.keys(SecKillConstants.SESSION_CACHE_PREFIX + "*"); List secKillSkuRedisToList = new ArrayList<>(); for (String key : keys) { String replace = key.replace(SecKillConstants.SESSION_CACHE_PREFIX, ""); String[] tempString = replace.split(":"); String timeString = tempString[1]; String[] timeSplit = timeString.split("-"); Long start = Long.parseLong(timeSplit[0]); Long end = Long.parseLong(timeSplit[1]); if(time >= start && time <= end){ // 获取当前场次的商品信息 List range = redisTemplate.opsForList().range(key, 0, -1); BoundHashOperations operations = redisTemplate.boundHashOps(SecKillConstants.SKU_CACHE_PREFIX); List
package com.alatus.mall.seckill.service.impl; import com.alatus.common.utils.R; import com.alatus.mall.seckill.constant.SecKillConstants; import com.alatus.mall.seckill.feign.CouponFeignService; import com.alatus.mall.seckill.feign.ProductFeignService; import com.alatus.mall.seckill.service.SecKillService; import com.alatus.mall.seckill.to.SecKillSkuRedisTo; import com.alatus.mall.seckill.vo.SeckillSessionEntityVo; import com.alatus.mall.seckill.vo.SkuInfoVo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.redisson.api.RSemaphore; import org.redisson.api.RedissonClient; import org.springframework.beans.BeanUtils; 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.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Service public class SecKillServiceImpl implements SecKillService { @Autowired private CouponFeignService couponFeignService; @Autowired private ProductFeignService productFeignService; @Autowired private StringRedisTemplate redisTemplate; @Autowired private RedissonClient redissonClient; @Override public void uploadSecKillSkuLatest3Days() { // 扫描需要参与秒杀的活动 R daySession = couponFeignService.Latest3DaySession(); if(daySession.getCode() == 0){ ListseckillSessionVos = daySession.getData(new TypeReference >() {}); // 缓存活动信息 saveSessionInfos(seckillSessionVos); // 缓存活动关联的商品信息 saveSkuInfos(seckillSessionVos); } } // 返回当前事件可以参与的秒杀商品信息 @Override public List
getCurrentSeckillSkus() { // 确定当前时间属于哪个秒杀场次 long time = new Date().getTime(); Set keys = redisTemplate.keys(SecKillConstants.SESSION_CACHE_PREFIX + "*"); List secKillSkuRedisToList = new ArrayList<>(); for (String key : keys) { String replace = key.replace(SecKillConstants.SESSION_CACHE_PREFIX, ""); String[] tempString = replace.split(":"); String timeString = tempString[1]; String[] timeSplit = timeString.split("-"); Long start = Long.parseLong(timeSplit[0]); Long end = Long.parseLong(timeSplit[1]); if(time >= start && time <= end){ // 获取当前场次的商品信息 List range = redisTemplate.opsForList().range(key, 0, -1); BoundHashOperations operations = redisTemplate.boundHashOps(SecKillConstants.SKU_CACHE_PREFIX); List
package com.alatus.mall.seckill.vo; import lombok.Data; import java.math.BigDecimal; @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; }
package com.alatus.mall.seckill.vo; import lombok.Data; import java.math.BigDecimal; @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; }