生活随笔
收集整理的這篇文章主要介紹了
Redis项目应用场景与实例汇总
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 一、背景
- 二、字符串的應用場景:封鎖一個IP地址
- 三、Hash的應用場景:存儲用戶信息
- 四、List的應用場景:隊列實現
- 五、Set的應用場景:自動去重
一、背景
- 本篇文章是將以前Redis實戰的系列文章進行匯總,針對Redis中常用的一些數據結構,進行實戰模擬。
stringshasheslistssetssorted sets
| 封鎖一個IP地址 | 存儲用戶信息 | 模擬消息隊列 | 自動排重 | 以某一個條件為權重,進行排序 |
1.1 開發環境
JDK 1.8SpringBoot 2.2.5JPASpring SecurityMysql 8.0Redis Server 3.2.1Redis Desktop ManagerSwagger2
1.2 項目配置
<
!--pom.xl--><!--Redis--><dependency
><groupId
>org.springframework.boot</groupId
><artifactId
>spring
-boot
-starter
-data
-redis</artifactId
></dependency
>
<
!-- application.yml
-->
server:port: 8000spring:freemarker:check-template-location: falseprofiles:active: dev
jackson:time-zone: GMT+8
data:redis:repositories:enabled: falsejpa:properties:hibernate:dialect: org.hibernate.dialect.MySQL5InnoDBDialect
open-in-view: trueredis:database: 0host: 127.0.0.1
port: 6379password:
@Configuration
@EnableCaching
@ConditionalOnClass(RedisOperations
.class)
@EnableConfigurationProperties(RedisProperties
.class)
public class RedisConfig extends CachingConfigurerSupport {@Beanpublic RedisCacheConfiguration
redisCacheConfiguration(){FastJsonRedisSerializer
<Object> fastJsonRedisSerializer
= new FastJsonRedisSerializer<>(Object
.class);RedisCacheConfiguration configuration
= RedisCacheConfiguration
.defaultCacheConfig();configuration
= configuration
.serializeValuesWith(RedisSerializationContext
.SerializationPair
.fromSerializer(fastJsonRedisSerializer
)).entryTtl(Duration
.ofHours(Constant
.CACHE_TIMEOUT_HOUR
));return configuration
;}@Beanpublic RedisTemplate
<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory
) {RedisTemplate
<Object, Object> template
= new RedisTemplate<>();template
.setConnectionFactory(redisConnectionFactory
);FastJsonRedisSerializer fastJsonRedisSerializer
= new FastJsonRedisSerializer(Object
.class);template
.setValueSerializer(fastJsonRedisSerializer
);template
.setHashValueSerializer(fastJsonRedisSerializer
);ParserConfig
.getGlobalInstance().setAutoTypeSupport(true);template
.setKeySerializer(new StringRedisSerializer());template
.setHashKeySerializer(new StringRedisSerializer());template
.afterPropertiesSet();return template
;}@Bean@Overridepublic KeyGenerator
keyGenerator() {return (target
, method
, params
) -> {Map
<String,Object> container
= new HashMap<>(3);Class
<?> targetClassClass
= target
.getClass();container
.put("class",targetClassClass
.toGenericString());container
.put("methodName",method
.getName());container
.put("package",targetClassClass
.getPackage());for (int i
= 0; i
< params
.length
; i
++) {container
.put(String
.valueOf(i
),params
[i
]);}String jsonString
= JSON
.toJSONString(container
);return DigestUtils
.sha256Hex(jsonString
);};}
- 增加RedisUtils工具類:實現對各種數據結構的封裝
@Component
@AllArgsConstructor
public class RedisUtils {private RedisTemplate
<Object, Object> redisTemplate
;public Object
hashGet(String key
, String item
) {return redisTemplate
.opsForHash().get(key
, item
);}public boolean hashSet(String key
, String item
, Object value
) {try {redisTemplate
.opsForHash().put(key
, item
, value
);return true;} catch (Exception e
) {e
.printStackTrace();return false;}}public boolean hashSet(String key
, String item
, Object value
, long time
) {try {redisTemplate
.opsForHash().put(key
, item
, value
);if (time
> 0) {expire(key
, time
);}return true;} catch (Exception e
) {e
.printStackTrace();return false;}}public long increment(String key
, long l
) {return redisTemplate
.opsForValue().increment(key
, l
);}public long increment(String key
, long l
, long time
) {long count
= redisTemplate
.opsForValue().increment(key
, l
);if (time
> 0) {expire(key
, time
);}return count
;}public long leftPush(String key
, Object value
) {return redisTemplate
.opsForList().leftPush(key
, value
);}public long leftPushAll(String key
, List
<Object> list
) {return redisTemplate
.opsForList().leftPushAll(key
, list
);}public long size(String key
) {return redisTemplate
.opsForList().size(key
);}public List
<Object> range(String key
, long start
, long end
) {return redisTemplate
.opsForList().range(key
, start
, end
);}public Object
rightPop(String key
) {return redisTemplate
.opsForList().rightPop(key
);}public Object
leftPop(String key
) {return redisTemplate
.opsForList().leftPop(key
);}public void deleteAll(String key
) {redisTemplate
.opsForList().trim(key
, 0, 0);redisTemplate
.opsForList().leftPop(key
);}public long setAdd(String key
, Object value
) {return redisTemplate
.opsForSet().add(key
,value
);}public long setAdd(String key
, List
<Object> list
) {return redisTemplate
.opsForSet().add(key
,list
);}public long setRemove(String key
, Object value
) {return redisTemplate
.opsForSet().remove(key
, value
);}public long setRemove(String key
, List
<Object> list
) {return redisTemplate
.opsForSet().remove(key
, list
);}public Set
<Object> setInter(String key1
, String key2
) {return redisTemplate
.opsForSet().intersect(key1
, key2
);}public Set
<Object> setInter(List
<Object> keys
) {return redisTemplate
.opsForSet().intersect(keys
);}public Set
<Object> setDifference(String key1
,String key2
){return redisTemplate
.opsForSet().difference(key1
,key2
);}public boolean expire(String key
, long time
) {try {if (time
> 0) {redisTemplate
.expire(key
, time
, TimeUnit
.SECONDS
);}} catch (Exception e
) {e
.printStackTrace();return false;}return true;}}
二、字符串的應用場景:封鎖一個IP地址
- 創建SpringBoot后臺服務程序,實現用戶登錄及JWT認證;
- 通過Redis緩存限制在1分鐘內同一IP請求登錄不能超過5次。
@Slf4j
@Service
@Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true, rollbackFor
= Exception
.class)
public class AuthServiceImpl implements AuthService {@Value("${wxMini.appId}")private String appId
;@Value("${wxMini.secret}")private String secret
;private final JwtTokenUtils jwtTokenUtils
;private final WxMiniApi wxMiniApi
;private final UserService userService
;private final JwtSecurityProperties properties
;private final RedisUtils redisUtils
;public AuthServiceImpl(JwtTokenUtils jwtTokenUtils
, WxMiniApi wxMiniApi
, UserService userService
, JwtSecurityProperties properties
, RedisUtils redisUtils
) {this.jwtTokenUtils
= jwtTokenUtils
;this.wxMiniApi
= wxMiniApi
;this.userService
= userService
;this.properties
= properties
;this.redisUtils
= redisUtils
;}@Override@Transactional(rollbackFor
= Exception
.class)public Result
<AuthUserDto> login(AuthUserDto authUserDto
, HttpServletRequest request
) {String ip
= NetworkUtils
.getIp(request
);String requestLoginIp
= "request_login_".concat(ip
);long loginCount
= redisUtils
.increment(requestLoginIp
, 1L
);if (loginCount
== 1) {redisUtils
.expire(requestLoginIp
, Constant
.REQUEST_LOGIN_LIMIT_TIME
);}if (loginCount
> Constant
.REQUEST_LOGIN_LIMIT_COUNT
) {log
.warn("IP:[".concat(ip
).concat("]已超出限定次數"));throw new RuntimeException("時間段內已超出限定次數,請不要頻繁登錄!");}......}
}
三、Hash的應用場景:存儲用戶信息
– 創建SpringBoot后臺服務程序,實現微信小程序登錄及JWT認證;
– 通過Redis緩存記錄該用戶最后一次登錄時間及登錄累計次數。
@Slf4j
@Service
@Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true, rollbackFor
= Exception
.class)
public class AuthServiceImpl implements AuthService {........String key
= authUserDto
.getUserInfo().getOpenId();redisUtils
.hashSet(key
, "id", authUserDto
.getUserInfo().getId());redisUtils
.hashSet(key
, "nickName", authUserDto
.getUserInfo().getNickName());redisUtils
.hashSet(key
, "getAvatarUrl", authUserDto
.getUserInfo().getAvatarUrl());redisUtils
.hashSet(key
, "lastLoginTime", Timestamp
.valueOf(LocalDateTime
.now()));Long loginCount
= 1L
;Object obj
= redisUtils
.hashGet(key
, "loginCount");if (obj
!= null
) {loginCount
+= Long
.valueOf(String
.valueOf(obj
));}redisUtils
.hashSet(key
, "loginCount", loginCount
);...}
四、List的應用場景:隊列實現
- 創建SpringBoot上傳文件WebApi服務接口;
- 通過Redis緩存隊列記錄最新10筆用戶上傳文件的信息。
@Slf4j
@AllArgsConstructor
@Service
@Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true, rollbackFor
= Exception
.class)
public class WxMiniCrmImpl implements WxMiniCrm {...@Override@Transactional(rollbackFor
= Exception
.class)public Result
<CrmIndex> uploadCrmIndex(String json
, String openId
, String realName
, MultipartFile multipartFile
) {try {JSONObject jsonObject
= JSONObject
.parseObject(json
);String createTime
= jsonObject
.getString("create");String employeeCode
= jsonObject
.getString("employeeCode");String customerCode
= jsonObject
.getString("customerCode");String customerName
= jsonObject
.getString("customerName");String type
= jsonObject
.getString("type");if (StringUtils
.isEmpty(createTime
) || StringUtils
.isEmpty(employeeCode
) || StringUtils
.isEmpty(customerCode
)|| StringUtils
.isEmpty(customerName
) || StringUtils
.isEmpty(type
)) {throw new RuntimeException("上傳信息中缺少關鍵資料");}UploadFile uploadFile
= uploadFileTool
.upload(openId
, realName
, multipartFile
);if (uploadFile
== null
) {throw new RuntimeException("上傳文件失敗!");}CrmIndex crmIndex
= new CrmIndex();DateTimeFormatter dateTimeFormatter
= DateTimeFormatter
.ofPattern("yyyy/MM/dd HH:mm");crmIndex
.setCreateTime(Timestamp
.valueOf(LocalDateTime
.parse(createTime
, dateTimeFormatter
)));crmIndex
.setEmployeeCode(employeeCode
);crmIndex
.setCustomerCode(customerCode
);crmIndex
.setCustomerName(customerName
);crmIndex
.setType(type
);crmIndex
.setJson(json
);crmIndex
.setOpenId(openId
);crmIndex
.setPath(uploadFile
.getPath());if (redisUtils
.size(Constant
.REDIS_UPLOAD_QUEUE_NAME
) >= Constant
.REDIS_UPLOAD_QUEUE_COUNT
) {log
.warn(Constant
.REDIS_UPLOAD_QUEUE_NAME
.concat("隊列已滿,移除最舊上傳信息:") + redisUtils
.rightPop(Constant
.REDIS_UPLOAD_QUEUE_NAME
));}log
.info(Constant
.REDIS_UPLOAD_QUEUE_NAME
.concat("隊列增加上傳信息:").concat(crmIndex
.toString()));redisUtils
.leftPush(Constant
.REDIS_UPLOAD_QUEUE_NAME
, crmIndex
);return new Result<CrmIndex>().ok(crmIndexRepository
.save(crmIndex
));} catch (JSONException ex
) {throw new RuntimeException("json轉換失敗:" + ex
.getMessage());}}...
}
文件上傳的原理與實現可參考該文章《SpringBoot實現微信小程序文件上傳的完整案例》
五、Set的應用場景:自動去重
- 創建SpringBoot添加客戶信息服務接口;
- 通過Redis集合緩存客戶信息,要求自動去重,不得重復記錄。
@Entity
@Getter
@Setter
@Table(name
= "customer")
public class Customer implements Serializable {@Id@GeneratedValue(strategy
= GenerationType
.IDENTITY
)@NotNull(groups
= Update
.class)private Long id
;@Column(name
= "open_id")private String openId
;@Column(name
= "customer_code")private String customerCode
;@Column(name
= "customer_name")private String customerName
;@Column(name
= "first_letter")private String firstLetter
;@Column(name
= "create_time")@CreationTimestampprivate Timestamp createTime
;@Column(name
= "update_time")@UpdateTimestampprivate Timestamp updateTime
;@Overridepublic String
toString() {return "Customer{" +"customerCode='" + customerCode
+ '\'' +", customerName='" + customerName
+ '\'' +'}';}
}
@ApiOperation(value
= "通過掃一掃功能上傳客戶信息")@PostMapping(value
= "/crmScan/{openId}")public ResponseEntity
crmScan(@RequestBody WxScanDto wxScanDto
, @PathVariable String openId
) {return ResponseEntity
.ok(wxMiniCrm
.wxScan(wxScanDto
, openId
));}
@Slf4j
@AllArgsConstructor
@Service
@Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true, rollbackFor
= Exception
.class)
public class WxMiniCrmImpl implements WxMiniCrm {private final UploadFileTool uploadFileTool
;private final CrmIndexRepository crmIndexRepository
;private final CustomerRepository customerRepository
;private final UserService userService
;private final RedisUtils redisUtils
;...@Override@Transactional(rollbackFor
= Exception
.class)public Result
<WxScanDto> wxScan(WxScanDto wxScanDto
, String openId
) {if (Constant
.SAVE_CUSTOMER_INFO
.equals(wxScanDto
.getScanType()) && wxScanDto
.getJsonObject() != null
) {try {Customer customer
= JSONObject
.parseObject(wxScanDto
.getJsonObject().toJSONString(), Customer
.class);Customer target
= customerRepository
.findByCustomerCodeAndOpenId(customer
.getCustomerCode(), openId
);if (target
!= null
) {BeanUtils
.copyProperties(customer
, target
, RepositoryUtil
.getNullPropertyNames(customer
));} else {target
= customer
;target
.setOpenId(openId
);}wxScanDto
.setReturnObject(customerRepository
.save(target
));redisUtils
.setAdd(openId
.concat("_customer"),customer
.toString());return new Result<WxScanDto>().ok(wxScanDto
);} catch (JSONException ex
) {throw new RuntimeException("json轉換失敗:" + ex
.getMessage());}}return new Result<WxScanDto>().error("無法處理掃一掃功能");}}
相同信息自動去重:通過swagger2進行接口測試,多次提交相同的客戶信息
- Redis Desktop Manager驗證數據
– 查看集合中的數據,實現自動去重
不同集合之間的交集與差集:用戶1通過接口添加4個客戶
–用戶2通過接口添加3個客戶
– 獲取用戶1與用戶2相同及不同的客戶信息
@SpringBootTest
@Slf4j
public class TestSet {@Testvoid test() {RedisUtils redisUtils
= SpringContextHolder
.getBean(RedisUtils
.class);Set
<Object> setInter
=redisUtils
.setInter("openId1_customer","openId2_customer");Iterator iterator
= setInter
.iterator();log
.info("openId1_customer與openId2_customer相同的客戶為:");while(iterator
.hasNext()){log
.info(iterator
.next().toString());}Set
<Object> setDiff
=redisUtils
.setDifference("openId1_customer","openId2_customer");iterator
= setDiff
.iterator();log
.info("openId1_customer與openId2_customer不同的客戶為:");while(iterator
.hasNext()){log
.warn(iterator
.next().toString());}Set
<Object> setDiff1
=redisUtils
.setDifference("openId2_customer","openId1_customer");iterator
= setDiff1
.iterator();log
.info("openId2_customer與openId1_customer不同的客戶為:");while(iterator
.hasNext()){log
.warn(iterator
.next().toString());}}
}
總結
以上是生活随笔為你收集整理的Redis项目应用场景与实例汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。