微服务秒杀项目整合网关+feign+redis分离热点商品分别下单示例
文章目錄
- 配置文件和通用文件
- 通用結(jié)果類(lèi)型:
- 返回碼:
- 統(tǒng)一異常處理:
- 網(wǎng)關(guān)
- feign服務(wù)
- redission配置
- controller
- service:熱點(diǎn)商品和普通商品分開(kāi)下單
- 消息隊(duì)列監(jiān)聽(tīng)訂單
思路:對(duì)于普通商品進(jìn)行正常下單(直接減去數(shù)據(jù)庫(kù)中的庫(kù)存然后生成訂單,對(duì)于熱點(diǎn)數(shù)據(jù)加一層redis緩存層,商品放在redis中,用分布式鎖加鎖,然后可以放入消息隊(duì)列中排隊(duì)下單,下單時(shí)先檢查Redis中庫(kù)存量是否足夠,成功了才減去數(shù)據(jù)庫(kù)庫(kù)存)
在這里還使用了feign用來(lái)遠(yuǎn)程調(diào)用服務(wù)和網(wǎng)關(guān)攔截請(qǐng)求。
下面是代碼:/
配置文件和通用文件
@Configuration public class RedisConfig {/**** 模板操作對(duì)象序列化設(shè)置* @param redissonConnectionFactory* @return*/@Bean("redisTemplate")public RedisTemplate getRedisTemplate(RedisConnectionFactory redissonConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(redissonConnectionFactory);redisTemplate.setValueSerializer(valueSerializer());redisTemplate.setKeySerializer(keySerializer());redisTemplate.setHashKeySerializer(keySerializer());redisTemplate.setHashValueSerializer(valueSerializer());return redisTemplate;}/***** 序列化設(shè)置* @return*/@Beanpublic StringRedisSerializer keySerializer() {return new StringRedisSerializer();}/***** 序列化設(shè)置* @return*/@Beanpublic RedisSerializer valueSerializer() {Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);return jackson2JsonRedisSerializer;} }通用結(jié)果類(lèi)型:
@ApiModel(description = "Result",value = "Result") public class Result<T> {@ApiModelProperty(value="執(zhí)行是否成功,true:成功,false:失敗",required = true)private boolean flag;//是否成功@ApiModelProperty(value="返回狀態(tài)碼,20000:成功,20001:失敗,20002:用戶(hù)名或密碼錯(cuò)誤,20003:權(quán)限不足,20004:遠(yuǎn)程調(diào)用失敗,20005:重復(fù)操作,20006:沒(méi)有對(duì)應(yīng)的數(shù)據(jù)",required = true)private Integer code;//返回碼@ApiModelProperty(value="提示信息",required = true)private String message;//返回消息@ApiModelProperty(value="邏輯數(shù)據(jù)",required = true)private T data;//返回?cái)?shù)據(jù)public Result(boolean flag, Integer code, String message, Object data) {this.flag = flag;this.code = code;this.message = message;this.data = (T) data;}public Result(boolean flag, Integer code, String message) {this.flag = flag;this.code = code;this.message = message;}public Result() {this.flag = true;this.code = StatusCode.OK;this.message = "操作成功!";}返回碼:
/*** 返回碼*/ public class StatusCode {public static final int OK = 20000;//成功public static final int ERROR = 20001;//失敗public static final int LOGINERROR = 20002;//用戶(hù)名或密碼錯(cuò)誤public static final int ACCESSERROR = 20003;//權(quán)限不足public static final int REMOTEERROR = 20004;//遠(yuǎn)程調(diào)用失敗public static final int REPERROR = 20005;//重復(fù)操作public static final int NOTFOUNDERROR = 20006;//沒(méi)有對(duì)應(yīng)的搶購(gòu)數(shù)據(jù)//庫(kù)存遞減狀態(tài)碼public static final int DECOUNT_1=1; //遞減成功public static final int DECOUNT_NUM=405;//庫(kù)存不足public static final int DECOUNT_HOT=205;//商品是熱賣(mài)商品public static final int DECOUNT_OK=200;//庫(kù)存遞減成功public static final int ORDER_QUEUE=202;//搶購(gòu)商品正在排隊(duì)public static final int ORDER_OK=200;//搶單成功//令牌無(wú)效public static final int TOKEN_ERROR=401; }統(tǒng)一異常處理:
@ControllerAdvice //所有請(qǐng)求路徑,都將被該類(lèi)處理->過(guò)濾器/(攔截器) public class BaseExceptionHandler {private static Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);/**** 異常處理* 當(dāng)前請(qǐng)求發(fā)生了指定異常,則執(zhí)行該方法處理異常*/@ExceptionHandler(Exception.class)@ResponseBodypublic Result error(Exception ex){StringWriter stringWriter = new StringWriter();PrintWriter writer = new PrintWriter(stringWriter);ex.printStackTrace(writer);ex.printStackTrace();logger.error(stringWriter.toString());return new Result(false, StatusCode.ERROR,ex.getMessage(),stringWriter.toString());} }網(wǎng)關(guān)
server:port: 8001 spring:application:name: gateway-webcloud:nacos:config:file-extension: yamlserver-addr: nacos-server:8848discovery:#Nacos的注冊(cè)地址server-addr: nacos-server:8848gateway:routes:#商品- id: goods_routeuri: lb://seckill-goodspredicates:- Path=/api/skuAct/**,/api/activity/**,/api/brand/**,/api/category/**,/api/seckillTime/**,/api/sku/**filters:- StripPrefix=1#訂單- id: order_routeuri: lb://seckill-orderpredicates:- Path=/api/order/**filters:- StripPrefix=1#搜索- id: search_routeuri: lb://seckill-searchpredicates:- Path=/api/search/**filters:- StripPrefix=1#用戶(hù)- id: user_routeuri: lb://seckill-userpredicates:- Path=/api/user/**filters:- StripPrefix=1#管理員- id: manager_routeuri: lb://seckill-managerpredicates:- Path=/api/admin/**filters:- StripPrefix=1#靜態(tài)頁(yè)- id: page_routeuri: lb://seckill-pagepredicates:- Path=/api/page/**filters:- StripPrefix=1網(wǎng)關(guān)攔截設(shè)置:
@Component public class AuthorizeFilter implements GlobalFilter,Ordered {//令牌頭名字private static final String AUTHORIZE_TOKEN = "Authorization";private static final String ADMINAUTHORIZE_TOKEN = "Admin-Token-Itheima";/**** 過(guò)濾攔截* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//獲取request和responseServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//獲取用戶(hù)請(qǐng)求的地址String path = request.getURI().getPath();// /api/user/login放行///api/order/add 測(cè)試放行if(path.equals("/api/user/login") || path.equals("/api/admin/login") || path.equals("/api/search") || path.equals("/api/activity/times")){//放行return chain.filter(exchange);}HttpMethod method = request.getMethod();System.out.println(method.name());// /sku/xxx GET方式允許通過(guò)if(path.startsWith("/api/sku/") && request.getMethod().name().equalsIgnoreCase("GET")){//放行return chain.filter(exchange);}//獲取用戶(hù)請(qǐng)求頭中的令牌String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN); //獲取請(qǐng)求頭中第1個(gè)Authorization參數(shù)//如果請(qǐng)求頭中沒(méi)有令牌,則有可能用的是參數(shù)傳入的if(StringUtils.isEmpty(token)){token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);//獲取請(qǐng)求參數(shù)中第1個(gè)Authorization}//如果請(qǐng)求頭和參數(shù)中都沒(méi)有令牌,則直接拒絕用戶(hù)訪(fǎng)問(wèn)各大微服務(wù)if(StringUtils.isEmpty(token)){//從Cookie中獲取令牌數(shù)據(jù)HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);HttpCookie adminCookie = request.getCookies().getFirst(ADMINAUTHORIZE_TOKEN);if(cookie==null && adminCookie==null){//狀態(tài)嗎 401response.setStatusCode(HttpStatus.UNAUTHORIZED);//結(jié)束當(dāng)前請(qǐng)求return response.setComplete();}//獲取令牌if(cookie!=null){token = cookie.getValue();}else{token = adminCookie.getValue();}//將令牌封裝到請(qǐng)求頭中request.mutate().header(AUTHORIZE_TOKEN,"bearer "+token);}return chain.filter(exchange);}/**** 排序* @return*/@Overridepublic int getOrder() {return 0;}@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();// cookie跨域config.setAllowCredentials(Boolean.TRUE); //允許Cookie跨域config.addAllowedMethod("*"); //所有提交方法都允許跨域config.addAllowedOrigin("*"); //所有的域名都允許跨域config.addAllowedHeader("*");//跨域解析器UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config); //所有請(qǐng)求路徑都支持跨域return new CorsWebFilter(source);} }feign服務(wù)
下面是庫(kù)存的接口:
@FeignClient(value = "seckill-goods") public interface SkuFeign {/***** 庫(kù)存遞減*/@PutMapping(value = "/sku/dcount/{id}/{count}")Result<Sku> dcount(@PathVariable(value = "id")String id,@PathVariable(value = "count")Integer count);/**** 熱點(diǎn)商品隔離*/@PostMapping(value = "/sku/hot/isolation")Result hotIsolation(@RequestParam List<String> ids);/***** 分頁(yè)查詢(xún)-查詢(xún)總數(shù)量*/@GetMapping(value = "/sku/count")Integer count();/***** 分頁(yè)查詢(xún)集合列表*/@GetMapping(value = "/sku/list/{page}/{size}")List<Sku> list(@PathVariable(value = "page")Integer page,@PathVariable(value = "size")Integer size);/**** 根據(jù)ID查詢(xún)Sku數(shù)據(jù)* @param id* @return*/@GetMapping("/sku/{id}")Result<Sku> findById(@PathVariable String id);/**** 商品數(shù)據(jù)歸0*/@GetMapping(value = "/sku/zero/{id}")Result zero(@PathVariable(value = "id") String id); }消息通知的接口:
@FeignClient(value = "seckill-message") public interface MessageFeign {/***** 發(fā)送消息*/@GetMapping(value = "/message/{userid}")String send(@PathVariable(value = "userid")String userid,@RequestParam(value = "msg") String msg) throws IOException; }redission配置
多個(gè)用戶(hù)實(shí)現(xiàn)加鎖操作,只允許有一個(gè)用戶(hù)可以獲取到對(duì)應(yīng)鎖
@Component public class RedissonDistributedLocker implements DistributedLocker {@Autowiredprivate RedissonClient redissonClient;/**** 加鎖,會(huì)一直循環(huán)加鎖,直到拿到鎖* @param lockkey* @return*/@Overridepublic RLock lock(String lockkey) {RLock lock = redissonClient.getLock(lockkey);lock.lock();return lock;}/**** 加鎖,在指定時(shí)間內(nèi)拿不到鎖就會(huì)放棄* @param lockkey* @return*/@Overridepublic RLock lock(String lockkey, long timeout) {RLock lock = redissonClient.getLock(lockkey);lock.lock(timeout,TimeUnit.SECONDS);return lock;}/**** 加鎖,在指定時(shí)間內(nèi)拿不到鎖就會(huì)放棄* @param lockkey* @return*/@Overridepublic RLock lock(String lockkey, long timeout, TimeUnit unit) {return null;}/**** 加鎖,在指定時(shí)間內(nèi)拿不到鎖就會(huì)放棄,如果拿到鎖,鎖最終有效時(shí)間為leasetime* @param lockkey* @return*/@Overridepublic boolean tryLock(String lockkey, long timeout, long leasetime, TimeUnit unit) {return false;}/***** 解鎖* @param lockkey*/@Overridepublic void unLock(String lockkey) {RLock lock = redissonClient.getLock(lockkey);lock.unlock();}/**** 解鎖* @param lock*/@Overridepublic void unLocke(RLock lock) {lock.unlock();} }controller
商品SkuController
@RestController @RequestMapping("/sku")public class SkuController {@Autowiredprivate SkuService skuService; /***** 庫(kù)存遞減*/@PutMapping(value = "/dcount/{id}/{count}")public Result<Sku> dcount(@PathVariable(value = "id")String id,@PathVariable(value = "count")Integer count){//1.調(diào)用業(yè)務(wù)層實(shí)現(xiàn)遞減int code = skuService.dcount(id, count);String message="";Sku sku = null;switch (code){case StatusCode.DECOUNT_OK:sku = skuService.findById(id);message="庫(kù)存遞減成功!";break;case StatusCode.DECOUNT_NUM:message="庫(kù)存不足!";break;case StatusCode.DECOUNT_HOT:message="商品是熱點(diǎn)商品!";break;default:}//3.根據(jù)狀態(tài)碼,響應(yīng)不同的提示信息return new Result<Sku>(true,code,message,sku);}/**** 熱點(diǎn)商品隔離*/@PostMapping(value = "/hot/isolation")public Result hotIsolation(@RequestParam List<String> ids){for (String id : ids) {skuService.hotIsolation(id);}return new Result(true,StatusCode.OK,"熱點(diǎn)數(shù)據(jù)隔離成功!");}訂單OrderController:
@RestController @RequestMapping("/order") //@CrossOrigin public class OrderController {@Autowiredprivate OrderService orderService;@Autowiredprivate IdWorker idWorker;/***** 添加訂單*/@PostMapping(value = "/add/{id}")public Result add(@PathVariable(value = "id") String id, @RequestHeader(value = "Authorization") String authorization) {String username = null;try {//解析令牌Map<String, Object> tokenMap = JwtTokenUtil.parseToken(authorization);username =tokenMap.get("username").toString();} catch (Exception e) {return new Result(false, StatusCode.TOKEN_ERROR, "令牌無(wú)效!");}//封裝OrderOrder order = new Order();order.setId("No"+idWorker.nextId());order.setSkuId(id);order.setCreateTime(new Date());order.setUpdateTime(order.getCreateTime());order.setUsername(username);order.setTotalNum(1);//添加訂單int code = orderService.add(order);switch (code) {case StatusCode.ORDER_OK:return new Result(true, StatusCode.ORDER_OK, order.getId());case StatusCode.DECOUNT_NUM:return new Result(false, StatusCode.DECOUNT_NUM, "庫(kù)存不足!");case StatusCode.ORDER_QUEUE:return new Result(true, StatusCode.ORDER_QUEUE, "排隊(duì)搶購(gòu)中!");default:return new Result(false, StatusCode.ERROR, "搶單發(fā)生異常!");}}/**** Order分頁(yè)條件搜索實(shí)現(xiàn)* @param page* @param size* @return*/@PostMapping(value = "/search/{page}/{size}")public Result<PageInfo> findPage(@RequestBody(required = false) OrderVo orderVo, @PathVariable int page, @PathVariable int size) {//調(diào)用OrderService實(shí)現(xiàn)分頁(yè)條件查詢(xún)OrderOrder order = new Order();BeanUtils.copyProperties(orderVo,order);PageInfo<Order> pageInfo = orderService.findPage(order, page, size);return new Result(true, StatusCode.OK, "查詢(xún)成功", pageInfo);}/**** 用戶(hù)訂單* @param page* @param size* @return*/@GetMapping(value = "/user/{page}/{size}")public Result<PageInfo> userOrders(@PathVariable int page,@PathVariable int size,@RequestParam(value = "type",defaultValue = "0")Integer type,@RequestHeader("Authorization")String authorization) {Map<String, Object> userMap = JwtTokenUtil.parseToken(authorization);//調(diào)用OrderService實(shí)現(xiàn)分頁(yè)條件查詢(xún)OrderOrder order = new Order();order.setUsername(userMap.get("username").toString());switch (type){case 1:order.setPayStatus("0");break;case 3:order.setPayStatus("1");break;}PageInfo<Order> pageInfo = orderService.findPage(order, page, size);return new Result(true, StatusCode.OK, "查詢(xún)成功", pageInfo);}}service:熱點(diǎn)商品和普通商品分開(kāi)下單
這里用了druid工具進(jìn)行熱點(diǎn)數(shù)據(jù)監(jiān)控:
@Component public class MonitorItemsAccess {@Value("${druidurl}")private String druidurl;@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate DruidDataSource dataSource;/******* 定義熱點(diǎn)數(shù)據(jù)標(biāo)準(zhǔn):* 1.某一件商品訪(fǎng)問(wèn)量>N* 2.最近N小時(shí)*/public List<String> loadData() throws Exception{//獲取連接對(duì)象//Connection connection = (AvaticaConnection) DriverManager.getConnection(druidurl);Connection connection =dataSource.getConnection();//StatementStatement statement = connection.createStatement();//執(zhí)行查詢(xún)ResultSet resultSet = statement.executeQuery(druidSQL());//解析結(jié)果集List<String> ids = new ArrayList<String>();while (resultSet.next()){String uri = resultSet.getString("uri");uri=uri.replace("/web/items/","").replace(".html","");ids.add(uri);}//關(guān)閉資源resultSet.close();statement.close();connection.close();return ids;}/**** SQL組裝* @return*/public String druidSQL(){//SQL語(yǔ)句String prefix="SELECT COUNT(*) AS \"viewCount\",uri FROM logsitems WHERE __time>=CURRENT_TIMESTAMP - INTERVAL '1' HOUR";//后部分String suffix=" GROUP BY uri HAVING viewCount>2";//SQL中間部分 AND uri NOT IN ('/web/items/S1235433012716498944.html')//SKU_S1235433012716498944String sql = "";//基于Redis中存的熱點(diǎn)商品的key來(lái)過(guò)濾排除要查詢(xún)的數(shù)據(jù)Set<String> keys = redisTemplate.keys("SKU_*");//所有以SKU_開(kāi)始的key全部查詢(xún)出來(lái)if(keys!=null && keys.size()>0){sql=" AND uri NOT IN (";for (String key : keys) {sql+="'/web/items/"+key.substring(4)+".html',";}sql=sql.substring(0,sql.length()-1);sql+=")";}return prefix+sql+suffix;} }然后用定時(shí)任務(wù)組件來(lái)執(zhí)行上面的監(jiān)控方法,設(shè)置每隔多久執(zhí)行一次,這里用的是elasticjob第三方工具,實(shí)際當(dāng)中可以用其他的定時(shí)任務(wù)框架
import com.dangdang.ddframe.job.api.ShardingContext; import com.dangdang.ddframe.job.api.simple.SimpleJob; import com.dangdang.elasticjob.lite.annotation.ElasticSimpleJob; import com.seckill.goods.feign.SkuFeign; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import java.util.List; @Component @ElasticSimpleJob(//這是elasticjob工具的定時(shí)任務(wù)注解cron = "1/5 * * * * ?",jobName = "monitortask",shardingTotalCount = 1 ) public class MonitorTask implements SimpleJob{@Autowiredprivate MonitorItemsAccess monitorItemsAccess;@Autowiredprivate SkuFeign skuFeign;/**** 執(zhí)行業(yè)務(wù)邏輯* @param shardingContext*/@SneakyThrows@Overridepublic void execute(ShardingContext shardingContext) {List<String> ids = monitorItemsAccess.loadData();for (String id : ids) {System.out.println("熱點(diǎn)商品ID:"+id);}//熱點(diǎn)數(shù)據(jù)隔離skuFeign.hotIsolation(ids);} }訂單Service
@Service public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate SkuFeign skuFeign;@Autowiredprivate IdWorker idWorker;@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate KafkaTemplate kafkaTemplate;@Autowiredprivate RedissonDistributedLocker redissonDistributedLocker;@Autowiredprivate MessageFeign messageFeign;/***** 熱點(diǎn)商品下單* @param orderMap* @return*/@Overridepublic void hotAdd(Map<String, String> orderMap) throws IOException {//消息封裝對(duì)象Map<String,Object> messageMap = new HashMap<String,Object>();String username = orderMap.get("username");String id = orderMap.get("id");//Redis中對(duì)應(yīng)的keyString key="SKU_"+id;String lockkey="LOCKSKU_"+id;String userKey="USER"+username+"ID"+id;//如果key在redis緩存,則表示商品信息在Redis中進(jìn)行操作boolean bo =true;// redissonDistributedLocker.tryLock(lockkey, 10, 10, TimeUnit.MINUTES);if(bo){if(redisTemplate.hasKey(key)){//獲取商品數(shù)量Integer num = Integer.parseInt(redisTemplate.boundHashOps(key).get("num").toString());if(num<=0){//商品售罄通知messageMap.put("code",20001);messageMap.put("message","商品已售罄");messageFeign.send(username,JSON.toJSONString(messageMap));return;}Result<Sku> skuResult =skuFeign.findById(id);Sku sku = skuResult.getData();//1.創(chuàng)建OrderOrder order = new Order();order.setTotalNum(1);order.setCreateTime(new Date());order.setUpdateTime(order.getCreateTime());order.setId("No"+idWorker.nextId());order.setOrderStatus("0");order.setPayStatus("0");order.setConsignStatus("0");order.setSkuId(id);order.setName(sku.getName());order.setPrice(sku.getSeckillPrice()*order.getTotalNum());orderMapper.insertSelective(order);//2.Redis中對(duì)應(yīng)的num遞減num--;if(num==0){skuFeign.zero(id);}//2.清理用戶(hù)排隊(duì)信息Map<String,Object> allMap = new HashMap<String,Object>();allMap.put(userKey,0);allMap.put("num",num);redisTemplate.boundHashOps(key).putAll(allMap);//3.記錄用戶(hù)購(gòu)買(mǎi)過(guò)該商品,24小時(shí)后過(guò)期redisTemplate.boundValueOps(userKey).set("");redisTemplate.expire(userKey,1,TimeUnit.MINUTES);//搶單成功通知messageMap.put("code",200);messageMap.put("message","搶單成功!");messageFeign.send(username,JSON.toJSONString(messageMap));}//釋放鎖//redissonDistributedLocker.unLock(lockkey);return;}//搶單失敗通知messageMap.put("code",20001);messageMap.put("message","搶單失敗!");messageFeign.send(username,JSON.toJSONString(messageMap));}/**** 添加訂單* @param order* @return*/@GlobalTransactional@Overridepublic int add(Order order) {String userKey="USER"+order.getUsername()+"ID"+order.getSkuId();//1.遞減庫(kù)存Result<Sku> dcount = skuFeign.dcount(order.getSkuId(), order.getTotalNum());//2.遞減成功->下單->記錄當(dāng)前用戶(hù)搶單的時(shí)間點(diǎn),24小時(shí)內(nèi)不能搶購(gòu)該商品if(dcount.getCode()== StatusCode.DECOUNT_OK){//int q=10/0;Sku sku = dcount.getData();//下單//order.setId("No"+idWorker.nextId());order.setOrderStatus("0");order.setPayStatus("0");order.setConsignStatus("0");order.setSkuId(sku.getId());order.setName(sku.getName());order.setPrice(sku.getSeckillPrice()*order.getTotalNum());orderMapper.insertSelective(order);//記錄當(dāng)前用戶(hù)搶單的時(shí)間點(diǎn),24小時(shí)內(nèi)不能搶購(gòu)該商品redisTemplate.boundValueOps(userKey).set("");redisTemplate.boundValueOps(userKey).expire(1, TimeUnit.MINUTES);return StatusCode.ORDER_OK;}else{//3.遞減失敗//405庫(kù)存不足if(dcount.getCode()==StatusCode.DECOUNT_NUM){return StatusCode.DECOUNT_NUM;}else if(dcount.getCode()==StatusCode.DECOUNT_HOT){//205商品熱點(diǎn)String key = "SKU_"+order.getSkuId();Long increment = redisTemplate.boundHashOps(key).increment(userKey, 1);if(increment==1){//執(zhí)行排隊(duì)Map<String,String> queueMap = new HashMap<String,String>();queueMap.put("username",order.getUsername());queueMap.put("id",order.getSkuId());kafkaTemplate.send("neworder", JSON.toJSONString(queueMap));}return StatusCode.ORDER_QUEUE;}//0return dcount.getCode();} }消息隊(duì)列監(jiān)聽(tīng)訂單
@Component public class RabbitOrderListener {@Autowiredprivate OrderService orderService;/**** 訂單消費(fèi)* @param message*/@RabbitListener(queues = PayOrderMchNotifyMQ.MQ_NAME)public void getMessage(String message) throws IOException {//下單信息Map<String,String> orderMap = JSON.parseObject(message,Map.class);//熱點(diǎn)商品下單orderService.hotAdd(orderMap);} }總結(jié)
以上是生活随笔為你收集整理的微服务秒杀项目整合网关+feign+redis分离热点商品分别下单示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql 共享锁和排他锁 意向锁 记录
- 下一篇: 类加载器源码、双亲委派、自定义类加载器详