1.引入maven依赖包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- springboot - Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.池化
package com.dd.common;
import com.dd.util.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.util.Hashing;
import redis.clients.util.Sharded;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ckl on 2018/8/31.
*/
@Slf4j
public class RedisShardedPool {
private static ShardedJedisPool pool;
private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total","20")); //最大连接数
private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle","20"));//在jedispool中最大的idle状态(空闲的)的jedis实例的个数
private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle","20"));//在jedispool中最小的idle状态(空闲的)的jedis实例的个数
private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow","true"));//在borrow一个jedis实例的时候,是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。
private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return","true"));//在return一个jedis实例的时候,是否要进行验证操作,如果赋值true。则放回jedispool的jedis实例肯定是可以用的。
private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));
private static void initPool(){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);//连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。
//127.0.0.1:6379
JedisShardInfo jedis1 = new JedisShardInfo(redis1Ip,redis1Port,1000*2);
jedis1.setPassword("123456"); //设置redis 6379密码
//127.0.0.1:6380
JedisShardInfo jedis2 = new JedisShardInfo(redis2Ip,redis2Port,1000*2);
jedis2.setPassword("123456");//设置redis 6380密码
List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);
jedisShardInfoList.add(jedis1);
jedisShardInfoList.add(jedis2);
/**
* public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards) {
this(poolConfig, shards, Hashing.MURMUR_HASH);
}
public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
Hashing algo) {
this(poolConfig, shards, algo, null);
}
public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
Pattern keyTagPattern) {
this(poolConfig, shards, Hashing.MURMUR_HASH, keyTagPattern);
}
public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards,
Hashing algo, Pattern keyTagPattern) {
super(poolConfig, new ShardedJedisFactory(shards, algo, keyTagPattern));
}
* final GenericObjectPoolConfig poolConfig:pool的一些设置(maxTotal、maxIdle、minIdle)
* List<JedisShardInfo> shards:为Redis实例的IP、端口以及超时时间等信息
* Hashing algo:根据Key计算hash值,从而决定具体存入那个Redis实例
* Pattern keyTagPattern:Key标签模式,默认是取{}中内容去计算对应Hash值,
* 当key='{key1_0}_0_0'时,**此时将根据’key1_0'来计算对应hash值,而不是根据{key1_0}_0_0来计算hash值**,
* 从而决定将存入到哪个Redis实例中,如果需要将数据进行排序,将要利用这个构造函数,因为只有将需要排序的数据
* 存入同一个Redis实例中,排序才是准确的。
*/
//一致性Hash分片算法 基于一个圆圈~~
pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
}
static{
initPool();
}
/**
* 获取ShardedJedis实例
* @return
*/
public static ShardedJedis getJedis(){
return pool.getResource();
}
/**
* 关闭ShardedJedis实例,pool回收
* @param jedis
*/
public static void returnBrokenResource(ShardedJedis jedis){
pool.returnBrokenResource(jedis); //3.0被弃用
// jedis.close();
}
/**
* 关闭ShardedJedis实例,pool回收
* @param jedis
*/
public static void returnResource(ShardedJedis jedis){
pool.returnResource(jedis);
}
}
##配置文件
redis1.ip=127.0.0.1
redis1.port=6379
redis2.ip=127.0.0.1
redis2.port=6380
#最大连接数
redis.max.total=20
#最大空闲数
redis.max.idle=10
#最小空闲数
redis.min.idle=0
#从jedis连接池获取连接时,校验并返回可用的连接
redis.test.borrow=true
#把连接放回jedis连接池时,校验并返回可用的连接
redis.test.return=false
#redis config end
#closeOrderTaskTime start
close.order.task.time.hour=2
#毫秒数
lock.timeout=5000
#closeOrderTaskTime end
3.RedisShardedPool工具
package com.dd.util;
import com.dd.common.RedisShardedPool;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.ShardedJedis;
/**
* Sharded Redis工具类
* Created by ckl on 2018/8/31.
*/
@Slf4j
public class RedisShardedPoolUtil {
/**
* 设置key的有效期,单位是秒
* @param key
* @param exTime
* @return
*/
public static Long expire(String key,int exTime){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.expire(key,exTime);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 设置key value exTime的单位是秒
* @param key
* @param value
* @param exTime
* @return
*/
public static String setEx(String key,String value,int exTime){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setex(key,exTime,value);
} catch (Exception e) {
log.error("setex key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 获取
* @param key
* @return
*/
public static String get(String key){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.get(key);
} catch (Exception e) {
log.error("get key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 设置值
* @param key
* @param value
* @return
*/
public static String set(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.set(key,value);
} catch (Exception e) {
log.error("set key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 获取旧的value,设置新的value;可用于锁操作
* @param key
* @param value
* @return
*/
public static String getSet(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.getSet(key,value);
} catch (Exception e) {
log.error("getset key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 删除key
* @param key
* @return
*/
public static Long del(String key){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.del(key);
} catch (Exception e) {
log.error("del key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
/**
* 当且仅当key不存在,将key的值设置为value,并且返回1;
* 若是给定的key已经存在,则setnx不做任何动作,返回0。
* 可用于锁操作
* @param key
* @param value
* @return
*/
public static Long setnx(String key,String value){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setnx(key,value);
} catch (Exception e) {
log.error("setnx key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
}
4.Cookie工具
package com.dd.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Cookie 工具类
* Created by ckl on 2018/8/31.
*/
@Slf4j
public class CookieUtil {
//顶级域
private final static String COOKIE_DOMAIN = "dandiandenglu.com";
private final static String COOKIE_NAME = "login_token";
/**
* 获取cookie
* @param request
* @return
*/
public static String readLoginToken(HttpServletRequest request){
Cookie[] cks = request.getCookies();
if(cks != null){
for (Cookie ck : cks){
log.info("read cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
if(StringUtils.equals(ck.getName(), COOKIE_NAME)){
log.info("return cookieName:{},cookieValue:{}",ck.getName(), ck.getValue());
return ck.getValue();
}
}
}
return null;
}
//X:domain=".dandiandenglu.com"
//a:A.dandiandenglu.com cookie:domain=A.dandiandenglu.com;path="/"
//b:B.dandiandenglu.com cookie:domain=B.dandiandenglu.com;path="/"
//c:A.dandiandenglu.com/aa/cc cookie:domain=A.dandiandenglu.com;path="/aa/cc"
//d:A.dandiandenglu.com/bb/dd cookie:domain=A.dandiandenglu.com;path="/aa/bb"
//e:A.dandiandenglu.com/aa cookie:domain=A.dandiandenglu.com;path="/aa"
//原理就是设置获取.dandiandenglu.com顶级域的cookie
/**
* 存储cookie
* @param response
*/
public static void writeLoginToken(HttpServletResponse response, String token){
Cookie ck = new Cookie(COOKIE_NAME, token);
//设置域名 .dandiandenglu.com
ck.setDomain(COOKIE_DOMAIN);
//代表设置在根目录
ck.setPath("/");
/**
* 在支持HttpOnly cookies的浏览器中(IE6+,FF3.0+),如果在Cookie中设置了"HttpOnly"属性,
* 那么通过JavaScript脚本将无法读取到Cookie信息,这样能有效的防止XSS攻击,让网站应用更加安全。
*/
ck.setHttpOnly(true);
//单位是秒。
//如果这个maxage不设置的话,cookie就不会写入硬盘,而是写在内存。只在当前页面有效。
ck.setMaxAge( 60 * 60 * 24 * 365);
log.info("write cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
response.addCookie(ck);
}
/**
* 删除cookie
* @param request
* @param response
*/
public static void delLoginToken(HttpServletRequest request,HttpServletResponse response){
Cookie[] cks = request.getCookies();
if(cks != null){
for(Cookie ck : cks){
if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
ck.setDomain(COOKIE_DOMAIN);
ck.setPath("/");
ck.setMaxAge(0);//设置成0,代表删除此cookie。
log.info("del cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
response.addCookie(ck);
return;
}
}
}
}
}
5.Controller
package com.dd.controller;
import com.dd.common.ResponseData;
import com.dd.model.User;
import com.dd.service.UserService;
import com.dd.util.Const;
import com.dd.util.CookieUtil;
import com.dd.util.JsonUtil;
import com.dd.util.RedisShardedPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Created by ckl on 2018/8/31.
*/
@Slf4j
@RestController
public class LoginController {
@Autowired
private UserService userService;
@RequestMapping("login")
@ResponseBody
public ResponseData<User> login(String username,
String password,
HttpSession session,
HttpServletResponse httpServletResponse){
ResponseData<User> response = userService.login(username,password);
//登录成功
if(response.isSuccess()){
// User user = response.getData();
// session.setAttribute("ckl",response.getData());
//设置cookie值 token为:session.getId()
CookieUtil.writeLoginToken(httpServletResponse,session.getId());
//保存token到redis
RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()), Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
}
return response;
}
@RequestMapping("info")
@ResponseBody
public ResponseData<User> getInfo(HttpSession session,
HttpServletRequest request){
User user = (User) session.getAttribute("ckl");
String sessionId = CookieUtil.readLoginToken(request);
log.info("sessionId {}",sessionId);
return ResponseData.createBySuccess(user);
}
}