用spring-data-redis实现类似twitter的网站(转)
封装了一下redis的客户端,使得使用起来更方便。
优点是把客户端连接放到一个连接池里,从而提高性能。还有就是可以不同的客户端之间实现切换,而不用改一行代码(Spring惯用的一个手法)。
本文写作时最新版是1.3,
目前支持下面4种java客户端,可以自由切换而不用改代码。
2. twitter简介
twitter如果没用过的话,可以理解成类似于国内的新浪微博。因为微博的访问量和使用人数极大,用传统的关系型数据库支撑不了,所以有了用redis这种非关系型数据库的架构设计。
本文我们将用spring-data-redis来实现一个类似twitter的网站。
3. 环境
本人亲测通过环境
jdk 1.6.0_45 64bit
gradle 1.7
tomcat 7.0.35
redis 2.8.11 win64
jedis 2.5.1
spring 3.2.9
spring-data-redis 1.3.0
4. 先动手操作
4.1 首先git clone以下项目
https://github.com/spring-projects/spring-data-keyvalue-examples/tree/master/retwisj
4.2 本人做了一些修改,一些3pp改成本文写作时最新的版本
build.gradle
- compile "redis.clients:jedis:2.5.1"
gradle.properties
- springVersion = 3.2.9.RELEASE
- springRedisVersion = 1.3.0.RELEASE
4.3 编译
- gradle build
4.4 将retwisj.war放入tomcat的webapp目录下,启动tomcat
4.5 访问http://localhost:8080/retwisj
花几分钟上去玩一下,熟悉一下功能。
好了,我们已经做好了一个微博网站了。玩好了我们简单分析一下代码实现。
5. 实现分析
5.1 表结构设计
5.1.1 用户(User)
用以前的关系型数据库设计是这样的
| Key | Username | Password |
| 1 | springrod | interface21 |
| 2 | costinl | this is fun |
而用redis的则变成了这样
| Key | Type | Value |
| uid:1 | hash | {name: springrod, pass: interface21} |
| uid:2 | hash | {name: costinl, pass: secret} |
将用户的名字和密码作为一个hash存入
对应的redis原生命令是
- HMSET user:1 name springrod pass interface21
uid是自增长的,可以用redis的INCR来实现,这是一个原子操作
- INCR global:uid
| Key | Type | Value |
| global:uid | string | 2 |
我们要保存username和uid的对应关系,比如一个user登录时,我们要得到他的uid。可以创建一个倒转的key来实现此功能。user:[name]:uid
还创建了一个users用来保存所有uid的list
| Key | Type | Value |
| user:springrod:uid | string | 1 |
| user:costinl:uid | string | 2 |
| users | list | {1, 2} |
5.1.2 微博(Post)
同样的,用global:pid来记录自增长的post id
| Key | Type | Value |
| global:pid | string | 2 |
将微博的内容、时间和作者作为一个hash存入
| Key | Type | Value |
| pid:1 | hash | {content: Hello World, time: 1301931414757, uid: 1} |
| pid:2 | hash | {content: Working on some cool stuff, time: 1301931414897, uid: 1} |
| pid:3 | hash | {content: Checking out RetwisJ, time: 1301931454897, uid: 2} |
某个用户的所有微博
| Key | Type | Value |
| uid:1:posts | list | {1, 2} |
| uid:2:posts | list | {3} |
所有微博列表(Timeline)
| Key | Type | Value |
| timeline | list | {1, 2, 3} |
5.1.3 关系(粉丝(Follower),关注(Following))
比如user2关注了user1,则user2是user1的粉丝,
user3也关注了user1,
则user1被user2,user3所关注
| Key | Type | Value |
| uid:1:followers | set | {2,3} |
| uid:2:following | set | {1} |
| uid:3:following | set | {1} |
新浪微博上姚晨的粉丝有7000万,光记录她一个人的粉丝就要7000万条记录。
如果用传统的关系型数据库实现,压力很大。
5.2 安全验证
我们不用session来跟踪用户,而用cookie。
每当用户登录后,为他生成一个随机数(令牌),发给该用户,让他作为cookie保存,这个cookie用来验证用户的身份。
同样的存储一个倒转的key,可以根据cookie来得到uid
| Key | Type | Value |
| uid:2:auth | string | {fea5e81ac8ca77622bed1c2132a021f9} |
| auth:fea5e81ac8ca77622bed1c2132a021f9 | string | {2} |
5.3 包的结构
| org.springframework.data.redis.sample.retwisj.web | web层 |
| org.springframework.data.redis.sample.retwisj.redis | 持久层 |
| org.springframework.data.redis.sample.retwisj | 领域层 |
5.4 使用redisTemplate
applicationContext-redis.xml
- <beans>
- <context:property-placeholder location="classpath:redis.properties"/>
- <!-- Redis client 这里就是不改代码实现不同客户端切换的地方了,我们用jedis-->
- <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
- p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"/>
- <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"
- p:connection-factory-ref="connectionFactory"/>
- <context:annotation-config />
- <context:component-scan base-package="org.springframework.data.redis.samples"/>
- </beans>
5.5 web层
采用spring MVC和JSP
5.5.1 Controller层
RetwisController
5.5.2 CookieInterceptor
对于用户验证,采用cookie的方式,写了一个Spring MVC的拦截器
- public class CookieInterceptor extends HandlerInterceptorAdapter
并在retwisj-servlet.xml里配置
- <mvc:interceptors>
- <bean class="org.springframework.data.redis.samples.retwisj.web.CookieInterceptor" />
- </mvc:interceptors>
执行效果就是在客户端保存了一个叫"retwisauth"的cookie,保存了用户的令牌。
5.5.3 i18
CookieLocaleResolver把语言作为cookie存在客户端
- <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>
执行效果就是在客户端保存了一个叫"org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE"的cookie,保存了语言。
LocaleChangeInterceptor可以用来变更语言
- <mvc:interceptors>
- <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
- </mvc:interceptors>
这样就可以通过http://localhost:8080/retwisj/?lang=cn来变更语言
5.6 持久层
RetwisRepository
如下代码示例了如何用intersect来找出2个用户相同的粉丝
- private RedisSet<String> following(String uid) {
- return new DefaultRedisSet<String>(KeyUtils.following(uid), template);
- }
- public List<String> commonFollowers(String uid, String targetUid) {
- RedisSet<String> tempSet = following(uid).intersectAndStore(following(targetUid),
- KeyUtils.commonFollowers(uid, targetUid));
- tempSet.expire(5, TimeUnit.SECONDS);
- return covertUidsToNames(tempSet.getKey());
- }
如下代码示例了用RedisAtomicLong实现自增长的id,BoundHashOperations来存储用户的用户名和密码
- public String addUser(String name, String password) {
- String uid = String.valueOf(userIdCounter.incrementAndGet());
- // save user as hash
- // uid -> user
- BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid));
- userOps.put("name", name);
- userOps.put("pass", password);
- valueOps.set(KeyUtils.user(name), uid);
- users.addFirst(name);
- return addAuth(name);
- }
用spring-data-redis实现类似twitter的网站(转)的更多相关文章
- spring mvc Spring Data Redis RedisTemplate [转]
http://maven.springframework.org/release/org/springframework/data/spring-data-redis/(spring-data包下载) ...
- Spring Data Redis简介以及项目Demo,RedisTemplate和 Serializer详解
一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...
- spring data redis 理解
前言 Spring Data Redis project,应用了Spring概念来开发使用键值形式的数据存储的解决方案.我们(官方)提供了一个 "template" ,这是一个高级 ...
- Spring Data Redis 让 NoSQL 快如闪电(2)
[编者按]本文作者为 Xinyu Liu,文章的第一部分重点概述了 Redis 方方面面的特性.在第二部分,将介绍详细的用例.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 把 Redis ...
- Spring Data Redis学习
本文是从为知笔记上复制过来的,懒得调整格式了,为知笔记版本是带格式的,内容也比这里全.点这里 为知笔记版本 Spring Data Redis 学习 Version 1.8.4.Release 前言 ...
- Redis(八):spring data redis 理解
前言 Spring Data Redis project,应用了Spring概念来开发使用键值形式的数据存储的解决方案.我们(官方)提供了一个 "template" ,这是一个高级 ...
- 使用Spring Data Redis操作Redis(集群版)
说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...
- Spring Data Redis整体介绍 (一)
为什么使用Spring Data Redis 首先Spring Data Redis 是Spring 框架提供的用于操作Redis的客户端. Spring框架是一个全栈Java程序框架,通过DI.AO ...
- spring data redis RedisTemplate操作redis相关用法
http://blog.mkfree.com/posts/515835d1975a30cc561dc35d spring-data-redis API:http://docs.spring.io/sp ...
- Spring Data Redis—Pub/Sub(附Web项目源码)
一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...
随机推荐
- stm32基础入门
1.开发工具,初学者建议MDK,后期ivr 2.寄存器开发or库 版本开发:先寄存器开发,后期两者结合: 3.软件仿真or开发板,先软件仿真,后期两者结合: 建立工程: 1.包含三部分:start.u ...
- Android 中 关闭部分 Activity 的方法总结
每一个activity都有自己的生命周期,被打开了最终就要被关闭. 四种结束当前的activity方法 但如果已经启动了四个Activity:A,B,C和D, 在D Activity里,想再启动一个A ...
- 四级流水线的8bit加法器
以流水线实现8bit 加法器. //date : 2013/8/23 //designer :pengxiaoen //function : module pipeline ( clock ,rese ...
- Verilog中的标点
在Verilog中有时候会误用的上引号 1,define 中的 `define INITIAL 0 这个单引号用的是键盘左上角的那个单引号,其实就是一个小撇. 2,4'd0 这个 用的是才是叫真正的 ...
- Spring Boot 探索系列 - 自动化配置篇
26. Logging Prev Part IV. Spring Boot features Next 26. Logging Spring Boot uses Commons Logging f ...
- php启用gzip压缩
GZIP(GNU-ZIP)是一种压缩技术.经过GZIP压缩后页面大小可以变为原来的30%甚至更小.这样用户浏览的时候就会感觉很爽很愉快! 要实现GZIP压缩页面需要浏览器和服务器共同支持,实际上就是服 ...
- Derby的下载安装和使用,(和JAVA中使用Derby)
首先是Java环境变量要配置: 1.打开我的电脑--属性--高级--环境变量 2.新建系统变量JAVA_HOME 和CLASSPATH 变量名:JAVA_HOME 变量值:C:\Program Fil ...
- CocoaPods on Xcode 6 and Yosemite
老子今天又给环境跪了..... cocoapods 在升级完新系统以后无法工作 解决cocoapods 在 mac 10.10下报错 错误例如以下. /System/Library/Framework ...
- linux 内核代码精简
#为了提高性能,文件系统一般都是以 relatime形式挂载进来的,见:/etc/fstab #更新一下mtime,这样,编译过程中用到的文件的atime都会被更新 find . -exec touc ...
- SICP中sqrt(开方)的实现(附C#实现)
#lang racket (define (square x) (* x x)) (define (sqrt-iter guess x) (if (good-enough? guess x) gues ...