package com.smallrig.srm.redis; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; /** * @version 1.0.0 * @aurhor chencl * @date 2020/4/28 0028 * @描述: redis缓存服务端接口 */ public interface RedisService { void setExpireTime(String key, long seconds); void setExpireDate(String key, Date date); Boolean exists(String key); void delete(String key); void delete(Listkeys); void put(String key, String value); void put(String key, String value, long seconds); Object get(String key); Long leftPush(String key, Object value); Long leftPush(String key, Object value, long seconds); Long rightPush(String key, Object value); Long rightPush(String key, Object value, long seconds); Object leftPop(String key); Object rightPop(String key); Long listLength(String key); List
package com.smallrig.srm.redis; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundHashOperations; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.TimeoutUtils; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.*; import java.util.concurrent.TimeUnit; /** * @version 1.0.0 * @aurhor chencl * @date 2020/4/28 0028 * @描述: redis缓存客户端实现 */ @Service @Slf4j public class RedisServiceImpl implements RedisService { @Autowired RedisTemplateobjectRedisTemplate; private static final long SHORT_SECONDS_TIME; private static final String LOCK_PREFIX = "redis:distributed:lock"; private static final int LOCK_EXPIRE = 6000; static { SHORT_SECONDS_TIME = TimeoutUtils.toSeconds(7L, TimeUnit.DAYS); } @Override public void setExpireTime(String key, long seconds) { if(seconds < 1L) { seconds = SHORT_SECONDS_TIME; } this.objectRedisTemplate.expire(key, seconds, TimeUnit.SECONDS); } @Override public void setExpireDate(String key, Date date) { if(date == null) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(5, 7); date = calendar.getTime(); } this.objectRedisTemplate.expireAt(key, date); } @Override public Boolean exists(String key) { return this.objectRedisTemplate.hasKey(key); } @Override public void delete(String key) { this.objectRedisTemplate.delete(key); } @Override public void delete(List keys) { this.objectRedisTemplate.delete(keys); } @Override public void put(String key, String value) { this.objectRedisTemplate.boundValueOps(key).set(value); } @Override public void put(String key, String value, long seconds) { Assert.hasText(key); this.objectRedisTemplate.boundValueOps(key).set(value); this.setExpireTime(key, seconds); } @Override public Object get(String key) { return this.objectRedisTemplate.boundValueOps(key).get(); } @Override public Long leftPush(String key, Object value) { Assert.hasText(key); return this.objectRedisTemplate.opsForList().leftPush(key, value); } @Override public Long leftPush(String key, Object value, long seconds) { Long resultLong = this.leftPush(key, value); this.setExpireTime(key, seconds); return resultLong; } @Override public Long rightPush(String key, Object value) { Assert.hasText(key); return this.objectRedisTemplate.opsForList().rightPush(key, value); } @Override public Long rightPush(String key, Object value, long seconds) { Long resultLong = this.rightPush(key, value); this.setExpireTime(key, seconds); return resultLong; } @Override public Object leftPop(String key) { return this.objectRedisTemplate.opsForList().leftPop(key); } @Override public Object rightPop(String key) { return this.objectRedisTemplate.opsForList().rightPop(key); } @Override public Long listLength(String key) { return this.objectRedisTemplate.opsForList().size(key); } @Override public List listRange(String key, int start, int end) { return this.objectRedisTemplate.opsForList().range(key, (long)start, (long)end); } @Override public void listRemove(String key, long i, Object value) { this.objectRedisTemplate.opsForList().remove(key, i, value); } @Override public String index(String key, long index) { return (String)this.objectRedisTemplate.opsForList().index(key, index); } @Override public void listSet(String key, long index, Object value) { this.objectRedisTemplate.opsForList().set(key, index, value); } @Override public void listTrim(String key, long start, int end) { this.objectRedisTemplate.opsForList().trim(key, start, (long)end); } @Override public void setAdd(String key, Object... values) { Assert.hasText(key); this.objectRedisTemplate.opsForSet().add(key, values); } @Override public void setAdd(String key, long seconds, Object... values) { this.setAdd(key, values); this.setExpireTime(key, seconds); } @Override public Boolean setContains(String key, Object value) { return this.objectRedisTemplate.opsForSet().isMember(key, value); } @Override public long setRemove(String key, Object... values) { return this.objectRedisTemplate.opsForSet().remove(key, values).longValue(); } @Override public Set setMembers(String key) { return this.objectRedisTemplate.opsForSet().members(key); } @Override public void hashPut(String key, String hkey, Object hvalue) { Assert.hasText(key); Assert.hasText(hkey); this.objectRedisTemplate.opsForHash().put(key, hkey, hvalue); } @Override public void hashPut(String key, String hkey, Object hvalue, long seconds) { this.hashPut(key, hkey, hvalue); this.setExpireTime(key, seconds); } @Override public Object hashGet(String key, String hkey) { Assert.hasText(key); Assert.hasText(hkey); return this.objectRedisTemplate.opsForHash().get(key, hkey); } @Override public long hashRemove(String key, Object... hkey) { Assert.hasText(key); return this.objectRedisTemplate.opsForHash().delete(key, hkey).longValue(); } @Override public Map hashEntries(String key) { Assert.hasText(key); BoundHashOperations ops = this.objectRedisTemplate.boundHashOps(key); return ops.entries(); } @Override public Set hashKeys(String key) { return this.objectRedisTemplate.opsForHash().keys(key); } @Override public Boolean hashHasKey(String key, String hashKey) { return this.objectRedisTemplate.opsForHash().hasKey(key, hashKey); } @Override public Long hashSize(String key) { return this.objectRedisTemplate.opsForHash().size(key); } @Override public void hashPutAll(String key, Map m) { this.objectRedisTemplate.opsForHash().putAll(key, m); } @Override public long getExpire(String key) { return this.objectRedisTemplate.getExpire(key).longValue(); } @Override public Set getKeys(String pattern) { return this.objectRedisTemplate.keys(pattern); } @Override public long increment(String key) { return this.objectRedisTemplate.boundValueOps(key).increment(1L).longValue(); } @Override public Boolean tryGetDistributedLock(String lockKey) { String lock = LOCK_PREFIX + lockKey; return (Boolean) this.objectRedisTemplate.execute((RedisCallback) connection -> { long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1; Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes()); if (acquire) { return true; } else { byte[] value = connection.get(lock.getBytes()); if (Objects.nonNull(value) && value.length > 0) { long expireTime = Long.parseLong(new String(value)); // 如果锁已经过期 if (expireTime < System.currentTimeMillis()) { // 重新加锁,防止死锁 byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes()); return Long.parseLong(new String(oldValue)) < System.currentTimeMillis(); } } } return false; }); } @Override public Boolean releaseDistributedLock(String lockKey) { String lock = LOCK_PREFIX + lockKey; return this.objectRedisTemplate.delete(lock); } }
分布式锁使用例子
String key="head_sync_fba_status"+headNo; Boolean b=redisService.tryGetDistributedLock(key); if(!b){ return ResponseBean.buildFail(50002,"请勿重复提交!"); } HeadFbaSeparateWarehouse warehouse=headFbaSeparateWarehouseMapper.queryByShipmentIdAndStatus(shipmentId,null); HeadFbaPlatformInformation platformInformation=headFbaPlatformInformationMapper.queryByPlanNo(warehouse.getPlanNo()); //获取公司地址id HeadFbaStartAddress headFbaStartAddress=headFbaStartAddressMapper.queryStartAddressById(platformInformation.getOriginConfigId()); //封装获取退货地址 Address shipFromAddress=headFbaPlatformInformationService.getShipFromAddress(headFbaStartAddress); AmazonInterConfig amazonInterConfig = headFbaPlatformInformationMapper.queryAmazonInterConfigByChannelId(platformInformation.getChannelId()); MapparameterMap = headFbaPlatformInformationService.queryAmazonInterConfigByChannelId(amazonInterConfig); //封装数据 UpdateInboundShipmentRequest request = headFbaPlatformInformationService.getUpdateInboundShipmentRequest(warehouse,shipFromAddress); if(request!=null){ parameterMap =headFbaPlatformInformationService.getUpdateInboundShipment(request, parameterMap, ShipmentStatusEnum.SHIPPED.getCode()); //签名 String url=amazonInterConfig.getSiteUrl()+ CommonConstant.CREATE_INBOUND_SHIPMENT_PLAN_URL; String str= HttpUtil.calculateStringToSignV2(parameterMap,amazonInterConfig.getSiteUrl()); if(org.apache.commons.lang3.StringUtils.isBlank(str)){ //更新同步状态为失败 getDao().updateFbaStatusByHeadNo(1,headNo); //释放锁 redisService.releaseDistributedLock(key); return ResponseBean.buildFail(50001,"拼接签名串失败"); } String signature = HttpUtil.sign(str, amazonInterConfig.getSecretKey()); if(org.apache.commons.lang3.StringUtils.isBlank(signature)){ //更新同步状态为失败 getDao().updateFbaStatusByHeadNo(1,headNo); log.error("更新亚马逊货件状态为SHIPPED:{}签名失败",shipmentId); //释放锁 redisService.releaseDistributedLock(key); return ResponseBean.buildFail(50002,"签名失败"); } parameterMap.put("Signature", HttpUtil.urlEncode(signature)); log.info("调用亚马逊提交货件信息请求参数:{}", parameterMap.toString()); String paramStr = HttpUtil.sortParams(new StringBuilder(), parameterMap); String xml = HttpUtil.doPost(url, paramStr); if(org.apache.commons.lang3.StringUtils.isBlank(xml)){ //更新同步状态为失败 getDao().updateFbaStatusByHeadNo(1,headNo); log.error("请求更新亚马逊货件状态为SHIPPED:{}接口失败",shipmentId); //释放锁 redisService.releaseDistributedLock(key); return ResponseBean.buildFail(50003,"请求更新亚马逊货件状态接口失败"); } if (xml.contains("UpdateInboundShipmentResponse")) { //更新同步状态为成功 getDao().updateFbaStatusByHeadNo(2,headNo); log.info("请求更新亚马逊货件状态为SHIPPED:{}接口成功",shipmentId); //释放锁 redisService.releaseDistributedLock(key); return ResponseBean.buildSuccess(); } else { //处理错误消息 if (xml.contains("ErrorResponse")) { //更新同步状态为失败 getDao().updateFbaStatusByHeadNo(1,headNo); log.error("解析亚马逊错误消息开始================================="); InputStream inputStream2 = new ByteArrayInputStream(xml.getBytes()); net.sf.json.JSONObject obj2 = JavaBeanXmlUtil.parseXML(inputStream2); String jsonObject = obj2.getJSONObject("Error").getString("Message"); log.error("解析亚马逊错误消息结束=================================,:{}", jsonObject); //释放锁 redisService.releaseDistributedLock(key); return ResponseBean.buildFail(50004,jsonObject); } } } return ResponseBean.buildFail(50005,"未知错误");