Redis---用Hash存储与读取List,记录网站访问量(二)

news/2024/5/11 1:30:58/文章来源:https://blog.csdn.net/lanhezhong/article/details/84070690

一、问题:

java对象经过序列化后可存储到Redis中。同样,一个List也可以经过序列化后存储到Redis中。

现在有一个需求,记录某个网站不同ip的访问次数,或者是记录每个接口的访问次数,那么最终存储的数据就有可能是这样子:

123.1.2.1 : 10次

123.1.2.2 : 50次

220.121.205.9 : 17次   ..................

/login : 1000次

/resetPassword : 100次

/data/findData : 50001次  ....................

1、当然可以以字符串+ip为key存储次数,不过麻烦的是当你要取出数据的时候必须知道ip才能取出ip对应的次数。想查看某一天所有ip的访问次数时就比较麻烦。虽然也可以通过key like进行模糊查询,单用like查询终归不大好;

2、把每个ip及次数组装成一个对象,放到List中,然后再放到Redis中。这样一次性读取所有数据方便了,但是读取单个数据或者修改单个数据就麻烦了。需要一次性取出所有数据,然后找到要修改的那一条,修改完成后又整个存回去。这样效率是非常低的。

3、使用Redis的Hash功能,可以很方便的解决这个问题。下面介绍着重介绍这个方法-------------->>>>>>>>>>

二、Redis用Hash存储List

如果只是单纯的存储次数,Jedis中有一个hincrBy方法非常合适,该方法为Hash的某个域递增一个值并返回结果;

首先创建一个model类,包含key和value;

RedisHashObject.java

package com.lan.LanUtil.utils;import java.io.Serializable;public class RedisHashObject implements Serializable{private static final long serialVersionUID = 6478533647755905534L;private String field;private Object value;public RedisHashObject(String field, Object obj) {this.field = field;this.value = obj;}//get set方法略
}

然后编写一个RedisUtil,这个类功能比较全,先关心hashIncrease方法和getHashLongList方法。

RedisUtil.java

package com.lan.LanUtil.utils;import java.util.ArrayList;
import java.util.List;
import java.util.Set;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;public class RedisUtil {private static String redisUrl = "127.0.0.1";private static int redisPort = 6379;private static String redisPassword = null;private static int database = 1;// 可选0-15private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);private static volatile JedisPool jedisPool = null;private RedisUtil() {}/*** 服务器整个应用关闭后(不是单个方法结束后),可考虑调用此方法销毁连接池* @author LAN* @date 2018年11月14日*/public static void destroy() {if(jedisPool==null) return;if(!jedisPool.isClosed()) jedisPool.close();jedisPool.destroy();}private static Jedis getConnection() {if (jedisPool == null) {synchronized (RedisUtil.class) {// 线程安全if (jedisPool == null) {logger.debug("=================创建jedisPool Start=================");JedisPoolConfig config = new JedisPoolConfig();config.setMaxTotal(200);//最大连接数, 默认8个config.setMaxIdle(8);//最大空闲连接数, 默认8个config.setMaxWaitMillis(1000 * 100);//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1config.setTestOnBorrow(true);jedisPool = new JedisPool(config, redisUrl, redisPort, 100000, redisPassword, database);logger.debug("=================创建jedisPool End=================");}}}return jedisPool.getResource();}/*** * @author LAN* @date 2018年11月14日* @param key     存储的键* @param o       存储的java对象* @param expire  设置过期时间,单位:秒,小于0时为永不过期*/public static void set(String key, Object o, int expire) {Jedis jedis = null;try {jedis = getConnection();if(o==null) {jedis.del(key.getBytes());return;}byte[] data = KryoSerializeUtil.serialize(o);if(expire>0) {jedis.setex(key.getBytes(), expire, data);}else {jedis.set(key.getBytes(), data);}}finally {if(jedis!=null) jedis.close();//新版本的close方法,如果是从JedisPool中取出的,则会放回到连接池中,并不会销毁。}}public static void set(String key, Object o) {set(key, o, -1);}public static <T> T get(String key, Class<T> clazz) {Jedis jedis = null;try {jedis = getConnection();byte[] data = jedis.get(key.getBytes());if(data==null || data.length==0){return null;}T t = (T) KryoSerializeUtil.unserialize(data, clazz);return t;}finally {if(jedis!=null) jedis.close();//新版本的close方法,如果是从JedisPool中取出的,则会放回到连接池中,并不会销毁。}}/*** 存:setHashObject("UserTimesHash", "1001", new Integer(10));* 取:getHashObject("UserTimesHash", "1001", Integer.class);* 批量取全部:getHashList("UserTimesHash");* * 用hash存入值,方便批量查询* expire=-1表示永不失效* @author LAN* @date 2018年9月17日* @param key* @param field* @param o* @param expire*/public static void setHashObject(String key, String field, Object o, int expire) {Jedis jedis = null;try {jedis = getConnection();if(o==null) {jedis.hdel(key.getBytes(), field.getBytes());return;}byte[] data = KryoSerializeUtil.serialize(o);jedis.hset(key.getBytes(), field.getBytes(), data);if(expire!=-1){jedis.expire(key.getBytes(), expire);}}finally {if(jedis!=null) jedis.close();}}private static <T> T getHashObject(byte[] key, byte[] field, Class<T> clazz){Jedis jedis = null;try {jedis = getConnection();byte[] data = jedis.hget(key, field);if(data==null || data.length==0){return null;}T t = KryoSerializeUtil.unserialize(data, clazz);return t;} finally {if(jedis!=null) jedis.close();}}/*** 存:setHashObject("UserTimesHash", "1001", new Integer(10));* 取:getHashObject("UserTimesHash", "1001", Integer.class);* 批量取全部:getHashList("UserTimesHash");* @author LAN* @date 2018年9月17日* @param key* @param field* @param clazz* @return*/public static <T> T getHashObject(String key, String field, Class<T> clazz) {return getHashObject(key.getBytes(), field.getBytes(), clazz);}/*** 存:setHashObject("UserTimesHash", "1001", new Integer(10));* 取:getHashObject("UserTimesHash", "1001", Integer.class);* 批量取全部:getHashList("UserTimesHash");* @author LAN* @date 2018年9月17日* @param key* @param clazz* @return*/public static <T> List<RedisHashObject> getHashList(String key, Class<T> clazz) {Jedis jedis = null;try {jedis = getConnection();Set<byte[]> hkeys = jedis.hkeys(key.getBytes());if(hkeys==null || hkeys.size()==0){return null;}List<RedisHashObject> list = new ArrayList<>(); for(byte[] field:hkeys){T obj = getHashObject(key.getBytes(), field, clazz);list.add(new RedisHashObject(new String(field), obj));}return list;} finally {if(jedis!=null) jedis.close();}}/*** 获取hashIncrease方法某个key下设置的所有值* @author LAN* @date 2018年11月13日* @param key* @return*/public static <T> List<RedisHashObject> getHashLongList(String key) {Jedis jedis = null;try {jedis = getConnection();Set<byte[]> hkeys = jedis.hkeys(key.getBytes());if(hkeys==null || hkeys.size()==0){return null;}List<RedisHashObject> list = new ArrayList<>(); for(byte[] field:hkeys){Long value = jedis.hincrBy(key, new String(field), 0l);list.add(new RedisHashObject(new String(field), value));}return list;} finally {if(jedis!=null) jedis.close();}}/*** 为Redis的Hash某个key中的某个域field递增某个值* @author LAN* @date 2018年11月13日* @param key* @param field* @param increase* @param expire*/public static Long hashIncrease(String key, String field, Long increase, int expire) {Jedis jedis = null;try {jedis = getConnection();Long n = jedis.hincrBy(key, field, increase);if(expire!=-1){jedis.expire(key, expire);}return n;} finally {if(jedis!=null) jedis.close();}}
}

RedisUtil可以通过hashIncrease把单个值递增,通过getHashLongList把所有值拿出来;

写一个测试类

TestRedis.java

package com.lan.LanUtil;import java.util.List;import com.lan.LanUtil.utils.RedisHashObject;
import com.lan.LanUtil.utils.RedisUtil;public class TestRedis {public static void main(String[] args) {//模拟设置访问量RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.1", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.2", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.1", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.5", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.2", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.1", 1l, -1);RedisUtil.hashIncrease("visitTimes-20181115", "192.168.1.1", 1l, -1);//获取所有ip访问量List<RedisHashObject> list = RedisUtil.getHashLongList("visitTimes-20181115");for(RedisHashObject rho:list) {System.out.println(rho.getField()+" : "+rho.getValue());}RedisUtil.destroy();}
}

运行结果:

再运行一次,结果:

        这就很好的解决了Redis记录并展示ip访问量的问题,同样道理也可以用于记录接口的访问量。这种功能只需写一个拦截器来进行记录即可。假如需要对展示的数据进行分页查看也是可以的,只需修改RedisUtil中的getHashLongList方法,对field进行排序后取分页的某一段数据。缺点是不能按照访问量进行排序,若要按照访问量进行排序只能在内存中对所有数据进行sort后再分页展示;

三、结语

用Jedis的lset方法本身是可以存储List数据,但并不大适用于本文的记录访问量问题,因为lset只能根据index下标存储,不能根据字符索引进行存储。用Hash功能就可以很好解决这个问题。

此外,假如需要存储的信息不是次数,而是某个复杂的java对象,好比如session对象,只需用RedisUtil中的setHashObject、getHashObject即可,而获取某个key下的所有域及对象只需用getHashList方法即可。详细逻辑,看RedisUtil中的代码。

 

author:蓝何忠

email:lanhezhong@163.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_806798.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

游戏开发网站

Microsoft官方开发网站 http://msdn.microsoft.com/directx/ Microsoft官方讨论区 Newsgroups DirectXAV DirectXDev Groups.Google nVidia官方开发网站 http://developer.nvidia.com/ Cg官方开发网站 http://developer.nvidia.com/view.asp?PAGEcg_main CgShader…

PS网页设计教程IV——如何在Photoshop中创建一个专业博客网站布局

向Talk-Mania网站致敬。一年前&#xff0c;在该网站上看过许多不错的网页设计教程。一年后&#xff0c;再回头想看看有没有什么新的教程的时候&#xff0c;蓦然发现该网站已经打不开了。也许是关闭了&#xff0c;也许是改了网站名了。幸好&#xff0c;去年本人还是下载保存了几…

40款不容错过的个人摄影设计作品集网站

日期&#xff1a;2012-11-7 来源&#xff1a;GBin1.com 如果你不仅仅是网站设计师同时也是摄影师爱好者的话&#xff0c;那么拍摄高水准的摄影作品绝对可以为你的工作带来更大的帮助&#xff01;你可以将这些照片处理后放到你设计的网站上&#xff0c;绝对是件了不起的作品。当…

给大家分享个 网站头像上传的 插件

给大家分享个 网站头像上传的 插件&#xff0c;可以实现头像的修改&#xff0c; 下载链接&#xff1a;http://download.csdn.net/detail/abc456456456456/6621241 转载于:https://www.cnblogs.com/lechao/p/3655648.html

网站类百度百科词条如何创建?

常见的网站推广方式是利用论坛、贴吧、博客、问答网站进行外链推广&#xff0c;这些方法花费时间长&#xff0c;总归是没有百科营销好&#xff0c;百度百科词条代表着客观性、专业性和权威性&#xff0c;词条不仅仅有助于网站的推广&#xff0c;也有助于对搜索引擎的优化。下面…

怎么投稿各大媒体网站?有哪些媒体网站?

互联网时代&#xff0c;软文无处不在&#xff0c;广告已经悄悄地渗透进了我们生活里&#xff0c;不论你打开什么媒体平台或是网站上的内容&#xff0c;都在影响着我们的心智甚至是行为。区别在于有的稿件内容引不起用户兴趣所以根本起不到什么效果&#xff0c;甚至有的稿件都没…

VS2012 未能将网站***配置为使用ASP.NET。为了使此网站正确运行,您必须将它手动配置为使用ASP.NET 4.5。

之前下载VS2012的时候我记得我自己配置好了这方面的信息&#xff0c;但是这次敲击牛腩新闻发布系统的时候新建Web项目时报出错误&#xff0c;如下图&#xff1a;单击确定之后还报出了如下错误&#xff1a;我担心在我敲好牛腩新闻发布系统之后会影响成果的发布&#xff0c;所以在…

CSS--例子:鲜花销售网站

排版分析CSS代码HTML代码效果展示主界面效果 end 排版分析 CSS代码 body{background-color:#ffd8d9;margin:1px 0px 0px 0px;padding:0px;text-align:center;font-size:12px;font-family:Arial, Helvetica, sans-serif; } #container{position:relative;margin:0px auto 0px a…

百度搜索时,使用‘-csdn’屏蔽掉CSDN网站的博客和内容

有些小伙伴在搜索相关技术问题的时候&#xff0c;想屏蔽掉CSDN网站的博客和资源&#xff1b; 可以在使用百度搜索时&#xff0c;关键词后面加上-csdn&#xff0c;即可手动屏蔽掉CSDN的搜索结果&#xff0c;例如一般搜索&#xff1a; 加上-csdn后&#xff1a; 参考链接1&…

写了100多篇原创文章,我常用的在线工具网站推荐给大家!

原文链接&#xff1a;http://www.macrozheng.com/#/reference/my_web_tools 不知不觉写博客已经一年多了&#xff0c;累计写了100多篇原创文章&#xff0c;今天给大家分享下我经常使用的在线工具网站&#xff0c;希望对大家有所帮助&#xff01; Markdown Nice 支持自定义样式…

response 返回图片_ReactPHP 爬虫实战:下载整个网站的图片

什么是网页抓取?你是否曾经需要从一个没有提供 API 的站点获取信息? 我们可以通过网页抓取&#xff0c;然后从目标网站的 HTML 中获得我们想要的信息&#xff0c;进而解决这个问题。 当然&#xff0c;我们也可以手动提取这些信息, 但手动操作很乏味。 所以, 通过爬虫来自动化…

语文网站第十九周推荐博客

新叶子的博客  真正的幸福&#xff0c;在于对平淡生活的热爱!用真心交知心朋友与月有关的成语 相信你的孩子是最棒的 艾岚的博客  春来了&#xff0c;看花去&#xff1b;秋来了&#xff0c;扫落叶&#xff01; [情感天地]春风相送[班务日志]我与我的猴儿们&#xff08;5月…

接口做的好怎么形容_电商网站平台怎么做?

关于电商网站平台的开发问题&#xff0c;之前敖游已经分享了很多篇相关文章。电商网站平台怎么做&#xff1f;平台开发需要准备哪些资料&#xff1f;…… 这次我准备做一个总结性的发布。让准备做电商的朋友&#xff0c;看了这篇文章基本上可以找到想要的解决方法。一、个人可以…

绕过CDN查找网站真实IP方法

查找网站 源IP方法&#xff1a; 如果遇到需要绕过CDN&#xff0c;查找网站真实IP地址时&#xff0c;可以采用如下方法&#xff1a; 假设主站服务和邮件服务在同一台服务器&#xff1a; 1.在网站用QQ邮箱注册账号&#xff1b; 2.收取注册验证邮件&#xff1b; 3.查看邮件-->显…

ubuntu 自适应分辨率_Web—响应式网站和自适应网站区别

"做网页设计的时候总是混淆响应式设计和自适应设计&#xff0c;开始我以为这俩都是指根据屏幕大小自动进行适配。所以和前端小哥哥沟通时候&#xff0c;前端小哥哥蒙圈了&#xff0c;跟我强度这俩不是一个东西~~~~今天从设计角度和开发角度介绍下这俩的区别"“开篇”…

推荐:一款超强、超简单的在线免费照片特效网站

网址是&#xff1a;http://www.photofunia.com/只需先在此网站主页上列出的74个预设特效中选择一个喜欢的&#xff0c;然后再上传一张照片图片&#xff0c;等待20秒&#xff0c;OK&#xff0c;特效完成了。这是我得到的两个特效&#xff1a;

高清视频录播服务器网站,高清录播服务器——DDA RSS3000

高清录播服务器——DDA RSS3000DDA RSS3000完全采用H.323协议研制&#xff0c;具有超强处理能力&#xff0c;可支CIF、4CIF、720P、1080P等高清画面以及H.239双视频流的录制&#xff0c;并可同时录制多个会场的画面。DDA RSS3000具有超强的兼容性&#xff0c;可以配合所有标准H…

linux 启动一个网站_想体验各种各样的Linux发行版?这里在在线版的,免费的哟...

Linux 和 Unix 存在着各种各样的发行版本&#xff0c;有的界面美观&#xff0c;有的功能强大&#xff0c;想要尝试不同的 Linux 和 Unix 操作系统&#xff0c;你可能会烦于进行本地安装。不急&#xff0c;今天&#xff0c;我们来介绍一个强大的服务&#xff0c;DistroTest 。Di…

HTML5+CSS3 效果网站集合

1、jquery插件库 HTML5制作3D樱花漫天飞舞 http://www.jq22.com/jquery-info3547 2、17素材网 http://www.17sucai.com/pins/tag/532.html 3、jquery之家 http://www.htmleaf.com/html5/ 心怀梦想,勿忘初心转载于:https://www.cnblogs.com/sxz2008/p/6497828.html

在etherscan.io网站校验智能合约源码

有图有真相&#xff0c;https://etherscan.io/address/0x95b0bf320f6e51ef3439aa673a7ca7b5b03746fd#code 第一步&#xff1a;打开校验合约源码的网址&#xff1a;https://etherscan.io/verifyContract2 第二步&#xff1a;检查网页是否正常&#xff0c;这一步对国内的同学们…