内容:给手机充值
创建数据库表phone_fare
CREATE TABLE `phone_fare` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`phone` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '手机号码',
`fare` decimal(10,2) DEFAULT NULL COMMENT '充值金额',
`is_active` tinyint(4) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
PRIMARY KEY (`id`),
KEY `idx_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8 COMMENT='手机充值记录';
逆向工程生成entity, mapper, mapper.xml
使用hibernate时,在save方法时,报了:org.hibernate.validator.constraints.NotBlank’ validating type 'java.math.BigDecimal,因为@NotBlank是针对String的 。 解决方法是将实体类的注解换成 @NotNull,就行了
SortedSetService
@Service
public class SortedSetService {
private static final Logger log= LoggerFactory.getLogger(SortedSetService.class);
@Autowired
private PhoneFareMapper fareMapper;
@Autowired
private RedisTemplate redisTemplate;
//TODO:新增 手机话费充值记录
@Transactional(rollbackFor = Exception.class)
public Integer addRecord(PhoneFare fare) throws Exception{
log.info("----sorted set话费充值记录新增:{} ",fare);
fare.setId(null);
//先插db
int res = fareMapper.insertSelective(fare);
if(res > 0){
//再插Cache
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
//往sortedSet添加一条充值记录,手机号为value,充值金额为score
zSetOperations.add(Constant.RedisSortedSetKey2, fare.getPhone(), fare.getFare().doubleValue());
}
return fare.getId();
}
//TODO:获取充值排行榜-正序
public List<PhoneFare> getSortFares(){
List<PhoneFare> list = Lists.newLinkedList();
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
Long total = zSetOperations.size(Constant.RedisSortedSetKey2);
//得到了排好序的、带分数的成员
Set<ZSetOperations.TypedTuple<String>> set = zSetOperations.rangeWithScores(Constant.RedisSortedSetKey2, 0L, total);
set.forEach(tuple->{
list.add(new PhoneFare(tuple.getValue(), BigDecimal.valueOf(tuple.getScore())));
});
return list;
}
//TODO:获取充值排行榜-倒序
public List<PhoneFare> getSortFaresV2(){
List<PhoneFare> list = Lists.newLinkedList();
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
Long total = zSetOperations.size(Constant.RedisSortedSetKey2);
//得到了排好序的、带分数的成员
Set<ZSetOperations.TypedTuple<String>> set = zSetOperations.reverseRangeWithScores(Constant.RedisSortedSetKey2, 0L, total);
set.forEach(tuple->{
list.add(new PhoneFare(tuple.getValue(), BigDecimal.valueOf(tuple.getScore())));
});
return list;
}
//TODO:获取指定手机号的充值金额
public Double getFareByPhone(final String phone) {
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
return zSetOperations.score(Constant.RedisSortedSetKey2, phone);
}
}
SortedSetController
@RestController
@RequestMapping("sorted/set")
public class SortedSetController extends AbstractController {
@Autowired
private SortedSetService sortedSetService;
//充值
@RequestMapping(value = "put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public BaseResponse put(@RequestBody @Validated PhoneFare fare, BindingResult result){
String checkRes= ValidatorUtil.checkResult(result);
if (StrUtil.isNotBlank(checkRes)){
return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
}
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
response.setData(sortedSetService.addRecord(fare));
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
//获取排行榜
@RequestMapping(value = "rank",method = RequestMethod.GET)
public BaseResponse get(@RequestParam String phone){
BaseResponse response=new BaseResponse(StatusCode.Success);
Map<String,Object> resMap=Maps.newHashMap();
try {
resMap.put("RankINfo-正序", sortedSetService.getSortFares());
resMap.put("RankINfo-倒序", sortedSetService.getSortFaresV2());
resMap.put("PhoneFare-获取具体的充值金额", sortedSetService.getFareByPhone(phone));
}catch (Exception e) {
response = new BaseResponse(StatusCode.Fail.getCode(), e.getMessage());
}
response.setData(resMap);
return response;
}
}
上述代码的问题:对于同一个手机进行充值的话,不是采取的叠加的形式,而是用最新的覆盖之前的,修改业务逻辑
升级内容:一个手机可以充多次值!
在新增之前,先判断SortSet集合中是否存在响应的元素,如果存在,使用incrementScore方法,否则才使用add方法
//TODO:新增 手机话费充值记录
@Transactional(rollbackFor = Exception.class)
public Integer addRecord(PhoneFare fare) throws Exception{
log.info("----sorted set话费充值记录新增:{} ",fare);
fare.setId(null);
//先插db
int res = fareMapper.insertSelective(fare);
if(res > 0){
//再插Cache
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
//TODO:插入cache之前,需要判断一下cache里面是否有该手机号的充值记录,如果有,则叠加;如果没有,则直接插入(第一次)
Double curFare = zSetOperations.score(Constant.RedisSortedSetKey2, fare.getPhone());
if(curFare != null){
//fare.getFare().doubleValue()由包装类转换为基本数据类型
zSetOperations.incrementScore(Constant.RedisSortedSetKey2, fare.getPhone(), fare.getFare().doubleValue());
}else{
//往sortedSet添加一条充值记录,手机号为value,充值金额为score
zSetOperations.add(Constant.RedisSortedSetKey2, fare.getPhone(), fare.getFare().doubleValue());
}
}
return fare.getId();
}
扩展
游戏充值排行榜、积分排行榜、充币排行榜、比赛得分排行榜、点赞(评论)-微博热搜排行榜......