生活随笔
收集整理的這篇文章主要介紹了
                                
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项目应用场景与实例汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。