背景

    最近学习了redis相关的一些知识,想着如何写一个小项目运用一下所学知识,偶然的一个机会想到了session。
    传统的session是存储在每个项目所在服务器的本地的,这样会面临俩个问题:1.当同一个项目搭建了集群时候,多台机器的session无法共享。2.session数量太多时候影响服务器性能,影响项目正常运行。
    这时候redis就派上用场了,只要所有服务都将session存储到一个redis服务器中,设置session自动过期时间,就可以很好的解决这些问题了。
    我在这里写了一个基于redis的session验证系统,他会在你访问服务时验证你是否登陆。

基本思路

    其实思路很简单,就是写一个传统的filter或者springmvc中的Interceptor(拦截器),当收到请求时经过这个拦截器,它会查询redis是否有相应的session,如果有则放行,如果没有则拒绝访问。
    redis中有五种数据类型,但是我这里为了演示的简单起见就用了最基础的String类型。
    默认cookie为:peerless=xxx
    默认redis中的k-v对是:peerless.xxx - session的存储时间

代码实现

1.编写interceptor
package edu.hnu.tomato.peerlessacquaintance.interceptor;

import java.io.PrintWriter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import edu.hnu.tomato.peerlessacquaintance.pojo.ReturnData;



public class AcquaintanceInterceptor implements HandlerInterceptor {
	private static final String cookieName="peerless";
	//注入redis操作string的对象
	@Autowired
	private StringRedisTemplate redisTemplate;

	public AcquaintanceInterceptor(){}

	//构造器,用于传入你想自定义的cookiname
	public AcquaintanceInterceptor(String cookieName){
		this.cookieName=cookieName;
	}

	//拦截器的的拦截方法
	@Override
	public boolean preHandle(final HttpServletRequest request,
			final HttpServletResponse response, final Object handler) throws Exception {
		//获取这次请求的所有cookie
		Cookie[] cookies=request.getCookies();
		//遍历找到制定cookie
		for (Cookie cookie : cookies) {
			if (cookie.getName().equals(this.cookieName)) {
				//redis查找对于cookie
				//如果查到了则放行
				String cookieMessage=redisTemplate.opsForValue().get(cookieName+"."+cookie.getValue());
				if (cookieMessage==null) {
					break;
				}
				return true;
			}
		}
		//如果没有查到则拒绝请求
		response.setContentType("text/xml;charset=utf-8");
		//返回401 拒绝请求
		response.setStatus(401);
		PrintWriter pw = response.getWriter();
		pw.write(“用户没有登陆”);
		return false;
	}

	@Override
	public void postHandle(final HttpServletRequest request,
			final HttpServletResponse response, final Object handler,
			final ModelAndView modelAndView) throws Exception {
		
		
	}

	@Override
	public void afterCompletion(final HttpServletRequest request,
			final HttpServletResponse response, final Object handler, final Exception ex)
			throws Exception {
		
	}

}
2.注册interceptor
package edu.hnu.tomato.peerlessacquaintance.config;


import edu.hnu.tomato.peerlessacquaintance.interceptor.AcquaintanceInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;


@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

	//这里注册一定要是容器里的那个interceotor 而不是自己new一个放进去
    @Autowired
    public AcquaintanceInterceptor interceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加拦截器
        registry.addInterceptor(interceptor)
                //添加需要拦截的路径
                .addPathPatterns("/**/*");
    }
}

完成这俩步,编写controller以后就可以测试看效果了,注意我这里默认的redis中的key是peerless.xxx value是存储这个session的时间。

总结

以上内容提供了利用redis存储session的基本思路,希望可以起到一个抛砖引玉的作用,大家可以在这个基础上自己进行发挥,比如把它写成一个starter,每个项目只需要引入依赖就可以自动配置等等,这里就不做具体的展开了