首先為什麼使用redis。
因為分布式有不同伺服器的緣故,如果你安照一般方式儲存session,那麼你的session會儲存在某一台伺服器上,如果你的下一個請求並不是訪問這台伺服器,那麼會發生讀取不到session的情況
redis儲存的實現方案:
第一種 是使用容器拓展來實現,一般都是通過容器外掛程式來實現,例如基於Tomcat的tomcat-redis-session-manager,基於Jetty的jetty-session-redis等等。好處是對項目來說是透明的,無需更改代碼,但是目前還不支援Tomcat8。個人覺得由於過於依賴容器,,一旦更換容器或者容器升級,那又得重新來過。而且代碼並不在項目中,對於開發人員的維護也是個麻煩。
第二種 是自訂會話管理的工具類,這樣的話靈活性很大,可以根據自身需求來實現,但是需要額外的開發時間
第三種是使用架構的會話管理工具,例如spring-session,shiro等,可以理解是替換了servlet那一套會話管理,不依賴容器,不用改動代碼。如果採用spring-session的話,使用的是spring-data-redis那一套串連池,prefect,不過前提是你得用spring架構。至於shiro,那是一個十分成熟,強大易用的安全架構,學習成本比spring-session來的要多一些。
下面我們介紹一下第二種方式的實現
要注意的是為什麼前端用ajax的方式登入,因為把類比的session資訊用存到redis後,需要在本地存入userId和token來作為使用者的標識,通過這個標識去redis裡驗證該使用者是否登入,從而擷取redis中的使用者登入資訊,但是分布式中多個系統對應多個domain,所以login模組產生的userId和token要想每個系統都用,必須每個系統都產生自己的cookie資訊,java端無法為每個系統產生一份cookie所以只能在前端用iframe的方式為每個系統產生一份cookie
下面是詳細代碼
redis的配置:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.7.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- redis緩衝部分 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="maxWaitMillis" value="${redis.maxWaitMillis}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig" /> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory" /> </bean> <!--載入redis --> <bean id="redisService" class="com.maigangle.b2b.common.redis.RedisSpringServiceImpl"> <!-- 控制redis開關 --> <property name="isUse" value="true"></property> </bean></beans>
RedisSpringServiceImpl.java
package com.maigangle.b2b.common.redis;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.RedisConnectionFailureException;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import com.alibaba.fastjson.JSON;import com.maigangle.b2b.common.exception.CommonException;/** * redis介面實現 * * @author * @since * @version 1.0 * */public class RedisSpringServiceImpl implements RedisSpringService { private static String redisCode = "utf-8"; private boolean isUse; // redis開關 private byte[] getBytes(String str) { try { return str.getBytes(redisCode); } catch (UnsupportedEncodingException e) { return str.getBytes(); } } public boolean isUse() { return isUse; } public void setIsUse(boolean isUse) { this.isUse = isUse; } @Autowired private RedisTemplate<String, String> redisTemplate; public void pub(String channel, String param) { if (!isUse) return; redisTemplate.convertAndSend(channel, param); } /** * @param key */ public Long del(final String... keys) { if (!isUse) return null; try { long re = redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { long result = 0; for (int i = 0; i < keys.length; i++) { result = connection.del(keys[i].getBytes()); result++; } return result; } }); return re; } catch (Exception e) { return null; } } /** * @param key * @param value * @param liveTime */ public void set(final byte[] key, final byte[] value, final long liveTime) { if (!isUse) return; try { redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.set(key, value); if (liveTime > 0) { connection.expire(key, liveTime); } return 1L; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); } } /** * @param key * @param value * @param liveTime */ public void set(String key, String value, long liveTime) { this.set(getBytes(key), getBytes(value), liveTime); } /** * @param key * @param liveTime */ public boolean expire(String key, long liveTime) { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.expire(key.getBytes(), liveTime); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @param key * @param value */ public void set(String key, String value) { this.set(key, value, 0L); } /** * @param key * @param value */ public void set(byte[] key, byte[] value) { this.set(key, value, 0L); } /** * @param key * @param value */ public void set(String key, byte[] value) { this.set(getBytes(key), value, 0L); } /** * */ @Override public void setOjb(String key, Object value, long time) { this.set(getBytes(key), getBytes(JSON.toJSONString(value)), time); } /** * @param key * @return */ public String get(final String key) { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection connection) throws DataAccessException { try { byte[] bytes = connection.get(getBytes(key)); if (bytes == null || bytes.length == 0) { return null; } return new String(bytes, redisCode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (Exception e1) { e1.printStackTrace(); return null; } return ""; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } public byte[] get4byte(final String key) { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<byte[]>() { public byte[] doInRedis(RedisConnection connection) throws DataAccessException { try { return connection.get(getBytes(key)); } catch (Exception e1) { e1.printStackTrace(); return null; } } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } @Override public <T> T getObj(String key, Class<T> elementType) { String jsonString = this.get(key); T obj; obj = JSON.parseObject(jsonString, elementType); if (obj == null) { try { obj = elementType.newInstance();// 防止null 指標異常 } catch (InstantiationException | IllegalAccessException e) { throw new CommonException("get redis error:", e); } } return obj; } /** * @param pattern * @return */ public void Setkeys(String pattern) { if (!isUse) return; try { redisTemplate.keys(pattern); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); } } /** * @param key * @return */ public boolean exists(final String key) { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.exists(getBytes(key)); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @return */ // public String flushDB() { // if(!isUse) return null; // return redisTemplate.execute(new RedisCallback<String>() { // public String doInRedis(RedisConnection connection) throws // DataAccessException { // connection.flushDb(); // return "ok"; // } // }); // } public boolean flushDB() { if (!isUse) return false; try { return redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return true; } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return false; } } /** * @return */ public long dbSize() { if (!isUse) return 0; try { return redisTemplate.execute(new RedisCallback<Long>() { public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return 0; } } /** * @return */ public String ping() { if (!isUse) return null; try { return redisTemplate.execute(new RedisCallback<String>() { public String doInRedis(RedisConnection connection) throws DataAccessException { return connection.ping(); } }); } catch (Exception e) { closeSwitch(e); e.printStackTrace(); return null; } } private void closeSwitch(Exception e) { if (e instanceof RedisConnectionFailureException) { this.isUse = false; } } /** * submit check token * * @param token * @return */ public boolean checkToken(String token) { if (StringUtils.isBlank(token)) { return false; } Object tk = this.get(token); if (tk != null) { this.del(token); return true; } return false; } @Override public void setHm(String key, Map<String, String> map, long liveTime) { if (!isUse) return; final Map<byte[], byte[]> hashes = new LinkedHashMap<byte[], byte[]>(map.size()); for (Map.Entry<String, String> entry : map.entrySet()) { hashes.put(getBytes(entry.getKey()), getBytes(entry.getValue())); } redisTemplate.execute(new RedisCallback<Object>() { public Object doInRedis(RedisConnection connection) { connection.hMSet(getBytes(key), hashes); if (liveTime > 0) { connection.expire(getBytes(key), liveTime); } return null; } }, true); } @Override public Map<String, String> getHm(String key) { final byte[] rawKey = getBytes(key); Map<byte[], byte[]> entries = redisTemplate.execute(new RedisCallback<Map<byte[], byte[]>>() { public Map<byte[], byte[]> doInRedis(RedisConnection connection) { return connection.hGetAll(rawKey); } }, true); Map<String, String> map = new LinkedHashMap<String, String>(entries.size()); for (Map.Entry<byte[], byte[]> entry : entries.entrySet()) { try { map.put(new String(entry.getKey(), redisCode), new String(entry.getValue(), redisCode)); } catch (UnsupportedEncodingException e) { return new HashMap<String, String>(); } } return map; } @Override public void setList(String key, List<String> list, long liveTime) { if (!isUse) return; final List<byte[]> listes = new ArrayList<byte[]>(list.size()); for (String value : list) { listes.add(getBytes(value)); } redisTemplate.execute(new RedisCallback<Object>() {