因为给手机app写接口,接口采用的hprose方式,故无法使用容器自带session。
现在想重写session,当用户没有登录的时候,别的接口都不给调用直接返回自定义错误,小马哥说,一言不合就抛异常,抛了异常后面的代码就不执行了。
可是无法满足返回自定义错误信息的需求。
于是使用redis重写了session,并且使用匿名内部类实现了filter的效果。
现在将代码分享出来给大家。
首先是重写session的。 如果你只想知道怎么搞过滤器那么往后看。
@Service("pubSessionServiceImpl")
public class PubSessionServiceImpl implements PubSessionService,InitializingBean
{
/*
*用于存储所有类型Session类型的失效时间
*/
public static List<ServiceSession> sessionTypeExpiraTiontimelist = new ArrayList<ServiceSession>();
@Autowired
private RedisCacheService<PubSession> redisCacheService;
@Autowired
private RedisCacheService<String> sessionIdCacheService;
@Autowired
private RedisCacheService<HashSet<String>> pubsessionIdSetService;
@Autowired
private ServiceSessionDao serviceSessionDao;
/**
* 注册session
*
* @param PubSession pubSession
* @param int sessionType
*/
@Override
public void recordSession(PubSession pubSession, int sessionType)
{
pubSession.setAttribute("sessionType", sessionType);
pubSession.setAttribute("lastOperationTime", new Date().getTime());
HashSet<String> pubsessionIdSet = new HashSet<String>();
if ((!CheckUtils.isNullOrEmpty(pubsessionIdSetService.get(EConstant.PUBSESSIONIDSET)))
&& pubsessionIdSetService.get(EConstant.PUBSESSIONIDSET).size() > 0)
{
pubsessionIdSet = pubsessionIdSetService.get(EConstant.PUBSESSIONIDSET);
}
pubsessionIdSet.add(pubSession.getSessionId());
pubsessionIdSetService.put(EConstant.PUBSESSIONIDSET, pubsessionIdSet);
redisCacheService.put("pmsservice:pubsession:" + pubSession.getSessionId(), pubSession);
}
/**
* 获取session
*
* @param String sessionId
* @return PubSession
*/
@Override
public PubSession getPubSession(String sessionId)
{
PubSession pubSession = redisCacheService.get("pmsservice:pubsession:" + sessionId);
if(!CheckUtils.isNullOrEmpty(pubSession)){
pubSession.setAttribute("lastOperationTime", new Date().getTime());
redisCacheService.put("pmsservice:pubsession:" + pubSession.getSessionId(), pubSession);
}
return pubSession;
}
/**
* 更新session
*
* @param PubSession pubSession
*/
@Override
public void updatePubSession(PubSession pubSession)
{
pubSession.setAttribute("lastOpoeratorTime", new Date().getTime());
redisCacheService.put("pmsservice:pubsession:" + pubSession.getSessionId(), pubSession);
}
/**
* 销毁session
*
* @param String sessionId
*/
@Override
public void destroySession(String sessionId)
{
HashSet<String> pubsessionIdSet = pubsessionIdSetService.get(EConstant.PUBSESSIONIDSET);
pubsessionIdSet.remove(sessionId);
pubsessionIdSetService.put(EConstant.PUBSESSIONIDSET, pubsessionIdSet);
redisCacheService.remove("pmsservice:pubsession:" + sessionId);
}
@Override
public void afterPropertiesSet()
throws Exception
{
this.init(new ServiceSession());
}
public void init(ServiceSession serviceSession)
{
sessionTypeExpiraTiontimelist = serviceSessionDao.findForList(serviceSession);
}
}
其中有一个redisCacheservice 也给大家共享出来。 这个写的不是太好,大家见笑了
@Service("redisCacheServiceImpl")
public class RedisCacheServiceImpl<E> implements RedisCacheService<E>
{
/**
* redisTemplate
*/
@Resource(name = "jedisTemplate")
private RedisTemplate<String, E> redisTemplate;
@Resource(name = "stringRedisTemplate")
private RedisTemplate<String, String> strRedisTemplate;
@Override
public void put(String key, E obj)
{
ValueOperations<String, E> valueOper = redisTemplate.opsForValue();
valueOper.set(key, obj);
}
@Override
public E get(String key)
{
ValueOperations<String, E> valueOper = redisTemplate.opsForValue();
return valueOper.get(key);
}
@Override
public List<E> getList(String key)
{
ListOperations<String, E> valueOper = redisTemplate.opsForList();
return valueOper.range(key, 0, -1);
}
@Override
public Long remove(final String key)
{
if (!exists(key))
{
return 0l;
}
return redisTemplate.execute(new RedisCallback<Long>()
{
@Override
public Long doInRedis(RedisConnection connection)
throws DataAccessException
{
long result = 0;
result = connection.del(key.getBytes());
return result;
}
});
}
@Override
public boolean exists(final String key)
{
return redisTemplate.execute(new RedisCallback<Boolean>()
{
public Boolean doInRedis(RedisConnection connection)
throws DataAccessException
{
return connection.exists(key.getBytes());
}
});
}
@Override
public void addSet(String key, E[] objs)
{
ListOperations<String, E> list = redisTemplate.opsForList();
for(E obj : objs)
{
list.leftPush(key, obj);
}
}
@SuppressWarnings("unchecked")
@Override
public void addSet(String key, Set<E> list)
{
this.addSet(key, (E[])list.toArray());
}
@SuppressWarnings("unchecked")
@Override
public void addSet(String key, List<E> objSet)
{
this.addSet(key, (E[])objSet.toArray());
}
@Override
public boolean addStr(final String key, final String value)
{
boolean result = strRedisTemplate.execute(new RedisCallback<Boolean>()
{
public Boolean doInRedis(RedisConnection connection)
throws DataAccessException
{
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = serializer.serialize(value);
return connection.setNX(keys, values);
}
});
return result;
}
@Override
public boolean updateStr(final String key, final String value)
{
if (!this.exists(key))
{
return this.addStr(key, value);
}
return strRedisTemplate.execute(new RedisCallback<Boolean>()
{
public Boolean doInRedis(RedisConnection connection)
throws DataAccessException
{
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = serializer.serialize(value);
connection.set(keys, values);
return true;
}
});
}
@Override
public String getStr(final String key)
{
String result = strRedisTemplate.execute(new RedisCallback<String>()
{
public String doInRedis(RedisConnection connection)
throws DataAccessException
{
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = connection.get(keys);
if (values == null)
{
return null;
}
String value = serializer.deserialize(values);
return value;
}
});
return result == null ? EConstant.EMPTY : result;
}
/**
* 获取 RedisSerializer
*
* @return RedisSerializer
*/
private RedisSerializer<String> getRedisSerializer()
{
return strRedisTemplate.getStringSerializer();
}
@Override
public Long removeFuzzy(final String key)
{
return redisTemplate.execute(new RedisCallback<Long>()
{
@Override
public Long doInRedis(RedisConnection connection)
throws DataAccessException
{
long result = 0;
Set<byte[]> keys = connection.keys(key.getBytes());
for(byte[] keySet : keys){
result += connection.del(keySet);
}
return result;
}
});
}
@Override
public Set<E> getSet(String key)
{
// TODO Auto-generated method stub
return null;
}
}
我这里有一个用户是否绑定房间的判断,和ssoid(有的叫token或者sessionId)是否能查到对应的用户。
来判断是否往下执行业务方法,如果没登录ssoid查询到的session里面的user为null,直接返回错误。
用以下的类来接收用户信息和错误信息。
/**
* 用户基础数据校验结果
*
* @author wanglei
* @version [版本号, 2016年10月20日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
class UserCheckInfo
{
/**
* 检查结果
*/
private boolean checkResult;
/**
* 错误信息
*/
private String resultMsg;
/**
* 用户中心的用户
*/
private UCenterUser centerUser;
public UserCheckInfo(boolean checkResult, String resultMsg, UCenterUser centerUser)
{
this.checkResult = checkResult;
this.resultMsg = resultMsg;
this.centerUser = centerUser;
}
public boolean isCheckResult()
{
return checkResult;
}
public String getResultMsg()
{
return resultMsg;
}
public UCenterUser getCenterUser()
{
return centerUser;
}
}
用以下方法来做检查
/**
* 获取usercheck信息 主要是检查是否绑定了房间和是否登陆
*
* @param ssoId ssoId
* @param isCheckBindUnit 是否检查绑定房间, true检查 false不检查
* @return 如果ssoId在用户中心验证m欸有登陆用户,则返回错误,如果isCheckBindUnit=true 并且没有绑定房间会返回false 其他情况返回true
*/
private UserCheckInfo getUserCheckInfo(String ssoId, boolean isCheckBindUnit)
{
UCenterUser centerUser = this.getUserInfo(ssoId);
if (!CheckUtils.isNullOrEmpty(centerUser))
{
if (isCheckBindUnit && CheckUtils.isNullOrEmpty(centerUser.getSysBindingUnit()))
{
return new UserCheckInfo(false, this.getErrorJson("该用户没有绑定默认房间"), centerUser);
}
}
else
{
return new UserCheckInfo(false, this.getErrorJson("ssoid验证失败"), null);
}
return new UserCheckInfo(true, null, centerUser);
}
interface WYServiceFun
{
String service(Map<String, Object> paramMap, UCenterUser centerUser, String ssoId);
}<span style="white-space:pre"> </span>
然后是充当filter的方法,这个方法没有使用到usercheckinfo的错误信息我一会修复下。
/**
* 执行业务方法,如果验证出了问题,出了异常 直接返回code 300
*
* @param paramMap 参数map
* @param isCheckBindUnit 是否检查绑定房间
* @param serviceFun WYServiceFun实现类,里面只有一个服务接口
* @return 直接返回此数据即可
*/
private String exeService(Map<String, Object> paramMap, boolean isCheckBindUnit, WYServiceFun serviceFun)
{
String ssoId = StringUtil.toString(paramMap.get("sso_sid"));
// 获取用户信息
UserCheckInfo checkInfo = this.getUserCheckInfo(ssoId, false);
try
{
if (checkInfo.isCheckResult())
{
return serviceFun.service(paramMap, checkInfo.getCenterUser(), ssoId);
}
}
catch (Exception e)
{
e.getStackTrace();
LOG.error(null, e);
return getReturnClientJson(EConstant.ERROR_CODE, new HashMap<String, Object>());
}
return getReturnClientJson(EConstant.ERROR_CODE, new HashMap<String, Object>());
}
如果用户没有登录exeService方法可以直接返回错误。
有没有感觉像是在写js的回调方法。
/**
* 发送验证码
* @param paramMap sso_sid phone 房主的手机号 identity 绑定类型
* @return state 300代表输入的手机号没有查询到他底下有相关的房间 200代表验证码发送成功
*/
public String sendVCode(Map<String, Object> paramMap)
{
return exeService(paramMap, false, new WYServiceFun()
{
public String service(Map<String, Object> paramMap, UCenterUser centerUser, String ssoId)
{
PubSession pubSession = pubSessionService.getPubSession(ssoId);
List<Map<String, Object>> unitInfoList = getUserUnitInfoList(paramMap,null);
// 如果这个手机号没有找到
if (unitInfoList.isEmpty())
{
return getReturnClientJson(EConstant.ERROR_CODE, (Map<String, Object>)MapUtils.getMapFromArgs(new Object[]{"data","notFindUnit"}));
}
pubSession.setAttribute("unitInfoList", unitInfoList);
// 还没写完,将就着看吧,写着代码突然想写博客的
return getReturnClientJson(EConstant.SUCCESS_CODE, list2Map(unitInfoList));
}
});
}