消息队列 网页浏览量记录 ssm 使用redis 和scheduled定时任务实现

需求

如果访问网站中某些页面,例如某某用户发布的商品页面。。。需要统计浏览量,那么更新数据库就显得蛋疼,所以我想到一种方式,使用redis+spring自带的scheduled定时任务来实现。

思路

使用redis的pub/sub 消息队列来统计一段时间内的网站浏览量。

使用scheduled定时任务 每隔一段时间批量更新数据库中的浏览量。

实现

开始之前请确保引入了正确的pom配置。。。

第一个是消息队列的实现。。消息队列是什么可以百度

redis配置文件:(配置文件中所引用的类需要自己实现,我会标出)

<!-- 配置JedisPoolConfig实例 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxTotal" value="${redis.maxActive}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
<!-- 配置JedisConnectionFactory -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}" />
        <property name="port" value="${redis.port}" />
        <!-- <property name="password" value="${redis.pass}" /> -->
        <property name="database" value="${redis.dbIndex}" />
        <property name="poolConfig" ref="poolConfig" />
    </bean>
    <!-- 配置RedisTemplate 这里不适用RedisTemplate 我们不存对象不需要序列化操作,有需要的可以自行寻找解决办法-->
    <!-- <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
        <property name="connectionFactory" ref="jedisConnectionFactory" /> </bean> -->
    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
    </bean>
    <!-- 配置RedisCacheManager -->
    <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="stringRedisTemplate" />
        <property name="defaultExpiration" value="${redis.expiration}" />
    </bean>
    <bean id="redisUtils" class="com.creator.redis.RedisUtils">
        <property name="redisTemplate" ref="stringRedisTemplate" />
    </bean>
# Redis settings  
redis.host=127.0.0.1
redis.port=6379
#redis.pass=password
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

RedisMessageReceiver  用来处理订阅之后 收到的消息 ,其中的RedisUtils工具类会在文末给大家。。只是用来操作redis数据库用的,没有逻辑,主要的逻辑都注释了,先试试做吧。

@Component
public class RedisMessageReceiver {
	
	@Autowired
	private RedisUtils redisUtils;
	/**接收消息的方法*/  
    public void receiveMessage(String message){  
   
        // 输出发布的信息
        System.out.println("有用户浏览一次 prodId为 : " + message+" 的页面");
        //如果缓存中没有 浏览数据 则创建哈希表
        if(redisUtils.hmget("prodGlance").isEmpty()){
            //创建新的哈希表 用来储存 页面访问量数据
            Map<String, String> newMap = new HashMap<String, String>();
            //往map里边添加此次访问增加的访问量
            newMap.put(message, "1");
            redisUtils.hmset("prodGlance", newMap);
        }else{ // 如果缓存中存在map 则寻找对应键值 加一
                //如果 map中没有这个页面的访问数据缓存 则添加此页面Id
                if(redisUtils.hget("prodGlance", message) == null){
                    redisUtils.hset("prodGlance", message, "1");
                }else { // 如果找到 则直接+1
                    redisUtils.hincr("prodGlance", message, 1);
	        }
        }
        
    } 
}

最后是SubscriberConfig 用来注册订阅信息,以及处理收到消息的方法

@Configuration
public class SubscriberConfig {
	@Bean
	RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
			MessageListenerAdapter listenerAdapter) {

		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		// 订阅了一个叫prodId 的通道
		container.addMessageListener(listenerAdapter, new PatternTopic("prodId"));
		// 这个container 可以添加多个 messageListener
		return container;
	}

	@Bean
	MessageListenerAdapter listenerAdapter(RedisMessageReceiver receiver) {
		// 这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
		return new MessageListenerAdapter(receiver, "receiveMessage");
	}

}

现在我们写一个controller接收请求

@Controller
public class PublisherController {

	@Autowired
	private PublisherService publisherService;

	@RequestMapping(value = "pub",method=RequestMethod.GET)
	public String pubMsg(@Param(value="id") String id) {
		publisherService.pubMsg(id);
		return "index";
	}
}

再来一个Service处理逻辑

@Service("publisherService")
public class PublisherServiceImp implements PublisherService {
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	public void pubMsg(String id) {
		stringRedisTemplate.convertAndSend("prodId", id);
		System.out.println("Publisher sendes Topic... ");
	}

}

最后看一下效果~~

使用PostMan访问。


redis已经记下了浏览数量,接下来我们用定时任务来更新数据库 ,这边比较简单了。简单贴配置文件和代码。

之前一直使用的是@Scheduled注解来做的定时任务,今天不知道怎么了跑不起来,现在使用配置文件写一个。

配置文件中加入命名空间

xmlns:task="http://www.springframework.org/schema/task"xmlns:task="http:/    
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd 

配置定时任务,红字是实现类 method是方法,cron是时间间隔,我们设为10秒一次,比较快查看效果

<!-- 配置定时任务 -->
	<task:annotation-driven />

	<bean id="Task" class="com.creator.redis.SaveRedisToMysql"/>
	<task:scheduler id="task" pool-size="3" />
	<task:scheduled-tasks scheduler="task">

		<task:scheduled ref="Task" method="save" cron="10 * * * * ?" />

	</task:scheduled-tasks>

现在是定时任务实现类,同样 其中的RedisUtils类会在文末给出

public class SaveRedisToMysql {
	@Autowired
	private RedisUtils redisUtils;
	@Autowired
	private ProductionMapper productionDao;

	public void save() {
		// 如果缓存中有页面访问量数据 则进行操作
		Map<Object, Object> glanceMap = redisUtils.hmget("prodGlance");
		if (!glanceMap.isEmpty()) {
			Iterator keys = glanceMap.entrySet().iterator();
			while (keys.hasNext()) {
				// 获取键值
				Map.Entry entry = (Map.Entry) keys.next();
				Object prodId = entry.getKey();
				Object glance = entry.getValue();
				// 更新至数据库
				int oldGlance = productionDao.selectByPrimaryKey(Integer.parseInt(prodId.toString())).getGlance();
				productionDao.updateByPrimaryKeySelective(
						new Production(Integer.parseInt(prodId.toString()), Integer.parseInt(glance.toString())+oldGlance));
				// 重置缓存中的键值
				redisUtils.hset("prodGlance", prodId.toString(), "0");
			}
		}
		System.out.println("成功保存redis数据到数据库");
	}}

现在看最终成果~~~

希望对你们有帮助。。

现在把RedisUtils贴出来。。

算了。。太长了,留下邮箱我发给大家

猜你喜欢

转载自blog.csdn.net/qq_33683097/article/details/80698694
今日推荐