Memcache+Tomcat9集群实现session共享(非jar式配置, 手动编写Memcache客户端)
Windows上两个tomcat, 虚拟机中ip为192.168.0.30的centos上一个(测试用三台就够了, 为了测试看见端口所以没有使用nginx转发请求)
开始
1.windows上开启两个tomcat端口分别为:8888和9999
2.使用ssh文件传输工具将项目放到centos的tomcat中
3.使用putty链接上centos后进入tomcat的bin目录执行./startup.sh后使用wget http://192.168.0.30测试是否启动成功如下图 1-1
1-1
4.使用浏览器访问项目登(输入用户名密码登录, 涉及到cookie跨域) 图 1-2
1-2
登录成功 图1-3
1-3
切换到9999端口的项目, 如果直接跳转到和上图1-3一样的页面取的是memcache的缓存如下图1-4
1-4
再试另外一个8888端口的tomcat(这个项目被放到ROOT目录了所以我直接127.0.0.1:8888)也是成功的图1-5
1-5
8888端口的tomcat对应的控制台
关闭9999端口的tomcat然后重启过滤器中拦截到了该请求在Memcache中存在共享的user实例直接跳转到首页
如果拦截到了请求然后发现Memcache中存在user实例那么久转发到对应的页面比如我访问8888的时候点击了'日拒转单'页面然后我再去访问9999的时候发现memcache中有user实例那么久根据拦截到的路径转到'日拒转单' 页面而不会转发到其它页面; 如下图a和b
a
b
最后退出后不同的端口时都应该看到都是登录页面(因为退出时memcache中的user被删除, 过滤器中在接到请求后发现memcache中对应请求的user实例没有了直接跳到登录页)
登录代码:
package yingyue.web.controller; import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import yingyue.utils.MemCacheUtil;
import yingyue.web.form.User;
/**
*
* @author YingYue
* @date 2016-1-1 下午4:13:09
* @file LoginController.java
*
* 步骤:
* 1.获取浏览器的自定义的cookie
* 1.1如果该cookie不存在这add
* 1.2存在则set更新; set等效于(add和replace)即: 存在则replace不存在则add, 这一步思考一直使用replace的, 我还比较钟情set的;
*
* cookie的四个属性
* max-age 指定Ccookie的生存周期(以秒为单位)!默认情况下,Cookie的值只在浏览器的会话期间存在,当用户退出浏览器这些值就消失了!
* path 指定与Cookie关联在一起的网页.默认情况下,cookie会和创建它的网页以及与这个网页处于同一个目录下的网页和处于该目录下的子目录关联。
* domain 设置访问域 举个例子:位于order.example.com的服务器要读取catalog.example.com设置的cookie.这里就要引入domain属性,假定由位于catalog.example.com的页面创 的cookie把自己的path属性设置为"/",把domain属性设置为".example.com",那么所有位于"catalog.example.com"的网页和所有位于"orders.example.com"的网页以及所有位于example.com域的其他服务器上得网页都能够访问这个cookie.如果没有设置cookie的domain值,该属性的默认值就是创建cookie的网页所在的 服务器的主机名。 注意:不能将一个cookie的域设置成服务器所在的域之外的域.
* seure 指定在网络上如何传输cookie的值
* secure值为true时,在http中是无效的;在https中才有效。
*/
@WebServlet(urlPatterns={"/login/LoginController.yingyue", "/login/LoginServlet"})
public class LoginController extends HttpServlet {
private static final long serialVersionUID = -8517127272218599956L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); /* 模拟数据库用户;*/
Map<String, String> items = new HashMap<String, String>();
items.put("zhoujianxu", "000000");
items.put("盈月", "000000");
items.put("test", "123456");
items.put("admin", "123456");
items.put("yingyue", "123456");
items.put("zuobiexitianyuncai", "000000"); /* 验证登录;*/
String userName = request.getParameter("userName"),
password = request.getParameter("password"); /* 验证开始*/
if (userName != null && !"".equals(userName)) {
if (password == null || "".equals(password)) {
request.setAttribute("tips", "密码不能为空!");
} else {
// 验证用户名密码是否正确;
if (items.containsKey(userName) && password.equalsIgnoreCase(items.get(userName))) {
/** 写入Memcache缓存;*/
User user = new User(userName, password, "15001027805", userName.concat("@163.com")); /**
* 如果不同用户使用同一个浏览器登录成功后都要为该用户重新 '创建' 一个key相同value值不同的cookie是多么的不合理啊,
* 解决办法:
* 当key不存在时则创建一个带有该key的cookie
* 当key存在时则更新key对应的value
*
* 如下:
*/
// 1.设置 key 为 'MEMCACHE_AND_BROWSER_KEY' value值为 '登录用户名+部门名称'的cookie 并Response到请求的客户端浏览器 '响应响应头信息'
String memcacheAndBrowserKey = "MEMCACHE_AND_BROWSER_KEY";
String memcacheAndBrowserForeignKey = userName.concat("IT");
Cookie[] cookies = request.getCookies();
if (cookies.length > 0 && cookies != null) {
for (Cookie cookie : cookies) {
boolean b = isContainsKeyCookies(memcacheAndBrowserKey, cookies);
if (!b) { Cookie newCookie = new Cookie(memcacheAndBrowserKey, memcacheAndBrowserForeignKey);
newCookie.setMaxAge(7 * 24 * 60 * 60);
newCookie.setPath("/");
response.addCookie(newCookie);
System.out.println("[登录时key名为MEMCACHE_AND_BROWSER_KEY的cookie不存在执行添加操作]\r\n 详情--> key名称为 " +
cookie.getName() + "的value值为 " + cookie.getValue() +
"的cookie已经响应到浏览器 '响应头信息' 中请看Set-Cookie");
break; } else {// 更新cookie的key对应的value; if (memcacheAndBrowserKey.equals(cookie.getName())) {
cookie.setValue(memcacheAndBrowserForeignKey);// 设置新的memcacheAndBrowserForeignKey
cookie.setPath("/");
cookie.setMaxAge(7 * 24 * 60 * 60);// 设置为1周
response.addCookie(cookie);// 更新key为'MEMCACHE_AND_BROWSER_KEY'的cookie的value值;
System.out.println("[登录时key名为MEMCACHE_AND_BROWSER_KEY的cookie存在执行更新操作]\r\n 详情--> key名称为 " +
cookie.getName() + "的value值为 " + cookie.getValue() +
"的cookie已经响应到浏览器 '响应头信息' 中请看Set-Cookie");
break;
} }
} // 2.将 'MEMCACHE_AND_BROWSER_KEY' 的value
Date expiry = new Date(7 * 24 * 60 * 60 * 1000);// 设置存到memcache中数据的失效时间, 这里设置为1周与cookie失效时间保持相同;
boolean b = MemCacheUtil.getInstance().set(memcacheAndBrowserForeignKey, user, expiry);
if (b) {
System.out.println("登录成功");
} } else {
System.out.println("cookie为空!");
}
request.setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/index.jsp").forward(request, response);
return;
} else {
if (!items.containsKey(userName)) {
request.setAttribute("tips", "用户不存在!");
} else {
request.setAttribute("tips", "用户名或密码错误!");
}
}
}
} else {
request.setAttribute("tips", "用户名不能为空!");
}
request.getRequestDispatcher("/index.jsp").forward(request, response);
} private boolean isContainsKeyCookies(String key, Cookie[] cookies) {
boolean b = false;
for (Cookie cookie : cookies) {
if (key.equals(cookie.getName())) {
b = true;
break;
}
}
return b;
} }
过滤器代码:
package yingyue.web.controller; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import yingyue.utils.MemCacheUtil;
import yingyue.web.form.User; /*
* @WebFilter(filterName = "AuthenticateFilter",
* urlPatterns = {"/login/LoginController", "/login/LoginServlet"})
* 或使用下面这种过滤我自定义的 '.yingyue' 的后缀
*/
@WebFilter(filterName="AuthenticateFilter", urlPatterns={"*.yingyue", "*.love", "*.^o^", "/index.jsp"})
public class AuthenticateFilter implements Filter { private FilterConfig config;
private List<String> releases = new ArrayList<String>(); @Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
releases.add("/login/LoginController.yingyue");
} @Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException { // 获取ServletContext 对象,用于记录日志
ServletContext context = this.config.getServletContext(); HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.setCharacterEncoding("UTF-8"); String path = request.getServletPath();
String methodValue = request.getParameter("method"); if(releases.contains(path)){
chain.doFilter(request, response);
return;
}
if (methodValue != null && !"".equals(methodValue)) {
path = path + "?method=" + request.getParameter("method");
}
System.out.println("已拦截到请求: ".concat(path)); /* 1.从请求中获取和Memcache关联的key*/
String memcacheAndBrowserForeignKey = "";
String memcacheAndBrowserKey = "MEMCACHE_AND_BROWSER_KEY";
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
if (memcacheAndBrowserKey.equals(cookie.getName())) {
memcacheAndBrowserForeignKey = cookie.getValue();
break;
}
}
} else {
context.log("cookie为空!");
} // 2.根据上述获取的key获取Memcache中的user对象
User loginUser = null;
if (memcacheAndBrowserForeignKey != null && !"".equals(memcacheAndBrowserForeignKey)) {
loginUser = (User) MemCacheUtil.getInstance().get(memcacheAndBrowserForeignKey);
}
if(loginUser != null){
request.setAttribute("user", loginUser);// 每次过滤后都将user对象放到request中, 以便每个页面取值;
if ("/index.jsp".equals(path)) {
System.out.println("直接跳转到首页");
request.getRequestDispatcher("/WEB-INF/index.jsp").forward(request, response);
}
chain.doFilter(request, response);
System.out.println("Memcache中存在该user用户放行该请求链接: " + path);
return;
} System.out.println("登录用户为空跳转到登录页");
request.getRequestDispatcher("/index.jsp").forward(request, response);
} @Override
public void destroy() {
this.config = null;
}
}
退出代码:
package yingyue.web.controller; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import yingyue.utils.MemCacheUtil;
import yingyue.web.form.User;
/**
* @author YingYue
* @date 2016-1-1 下午10:42:05
* @file LogoutController.java
*/
@WebServlet(urlPatterns={"/logout/LogoutController.yingyue", "/logout/LogoutServlet"})
public class LogoutController extends HttpServlet {
private static final long serialVersionUID = 7799109727234048708L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); /* 1.从请求中获取和Memcache关联的key, 退出清空客户端的key, 强制退出则根据key清空memcache的user实例*/
String memcacheAndBrowserForeignKey = "";
String memcacheAndBrowserKey = "MEMCACHE_AND_BROWSER_KEY";
Cookie[] cookies = request.getCookies();
if (cookies.length > 0 && cookies != null) {
for (Cookie cookie : cookies) {
if (memcacheAndBrowserKey.equals(cookie.getName())) {
memcacheAndBrowserForeignKey = cookie.getValue();
cookie.setMaxAge(0);// 设置为0表示删除cookie
System.out.println("[退出时删除key名为MEMCACHE_AND_BROWSER_KEY的cookie]\r\n 详情--> key名称为 " +
memcacheAndBrowserKey + "value值为 " + memcacheAndBrowserForeignKey +
"的cookie已经从浏览器 '响应头信息' 中删除请看Set-Cookie");
break;
}
}
} else {
System.out.println("退出请求cookie为空!");
} // 根据上述获取的key获取Memcache中的user对象
User loginUser = (User) MemCacheUtil.getInstance().get(memcacheAndBrowserForeignKey);
System.out.println(loginUser != null?"退出前登录用户信息" + loginUser:"");
boolean delete = MemCacheUtil.getInstance().delete(memcacheAndBrowserForeignKey);
if (delete) {
System.out.println("[退出]Memcache中key为 " + memcacheAndBrowserForeignKey + " 的 'user实例' 已被删除");
System.out.println(loginUser != null?"退出后登录用户信息" + (User) MemCacheUtil.
getInstance().get(memcacheAndBrowserForeignKey):"");
} response.sendRedirect(request.getContextPath());
}
}
其它相关跳转(servlet就是讨厌)
package yingyue.web.controller; import java.io.IOException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns={"/skip/SkipController.yingyue", "/skip/SkipController.action", "/skip/SkipServlet"})
public class SkipController extends HttpServlet { private static final long serialVersionUID = 9078198285369158430L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doPost(request, response);
} public synchronized void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { request.setCharacterEncoding("UTF-8");
String method = request.getParameter("method"); if ("1".equalsIgnoreCase(method)) {
request.getRequestDispatcher("/WEB-INF/pages/1.jsp").forward(request, response);
} else if ("2".equalsIgnoreCase(method)) {
request.getRequestDispatcher("/WEB-INF/pages/2.jsp").forward(request, response);
} else if ("3".equalsIgnoreCase(method)) {
request.getRequestDispatcher("/WEB-INF/pages/3.jsp").forward(request, response);
} else if ("4".equalsIgnoreCase(method)) {
request.getRequestDispatcher("/WEB-INF/pages/4.jsp").forward(request, response);
} else if ("imageslist".equalsIgnoreCase(method)) {
request.getRequestDispatcher("/WEB-INF/pages/images_list.jsp").forward(request, response);
} } }
还有一种通过jar包和配置tomcat的context.xml方式实现自动共享session, 类似于Redis 那种自动配置;
最后配上nginx 就完美了~^o^~
Memcache+Tomcat9集群实现session共享(非jar式配置, 手动编写Memcache客户端)的更多相关文章
- Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享
Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 ============================= 蕃薯耀 2017年11月27日 http: ...
- 集群中Session共享解决方案分析
一.为什么要Session共享 Session存储在服务器的内存中,比如Java中,Session存放在JVM的中,Session也可以持久化到file,MySQL,redis等,SessionID存 ...
- 集群间Session共享问题解决方案
两个基本概念的生命周期 session: 当新客户端发现一个HTTP请求时服务端会创建一个session.并分配一个sessionID作为服务端来客户端的识别,session对象会保存在服务端.此时s ...
- Tomcat集群的session共享
配置Tomcat的session共享可以有三种解决方案: 第一种是以负载均衡服务器本身提供的session共享策略,每种服务器的配置是不一样的并且nginx本身是没有的. 第二种是利用web容器本身的 ...
- CAS 集群部署session共享配置
背景 前段时间,项目计划搞独立的登录鉴权中心,由于单独开发一套稳定的登录.鉴权代码,工作量大,最终的方案是对开源鉴权中心CAS(Central Authentication Service)作适配修改 ...
- 关于 tomcat 集群中 session 共享的三种方法
前两种均需要使用 memcached 或redis 存储 session ,最后一种使用 terracotta 服务器共享. 建议使用 redis,不仅仅因为它可以将缓存的内容持久化,还因为它支持的单 ...
- Java集群之session共享解决方案
随着互联网的日益壮大,网站的pv和uv成线性或者指数倍的增加.单服务器单数据库早已经不能满足实际需求.比如像盛大,淘宝这样的大型网络公司,更是如此. 集群,也就是让一组计算机服务器协同工作,达 ...
- tomcat集群及session共享
一般来说,java web app主要用作两个领域: 1.api.api一般是无状态的,所以无需考虑session共享的问题 2.传统web应用和网站,如crm,oa,erp,b2c,bbs等.尤其b ...
- 基于tomcat集群做session共享
前端代理服务器nginx:192.168.223.136 tomcat服务器:采用的一台多实例192.168.223.146:8081,192.168.223.146:8082(如何构建多实例tomc ...
随机推荐
- 手机app(功能)测试重点
在手机客户端进行查看的测试重点:1.“点击加载更多”的分页处理技术,是否有重复的数据,数据显示是否完整,到达最后一页后是否还有数据进行显示2.数据的排序方式2.界面跳转是否正确3.出现异常情况是否有提 ...
- 支持多浏览器的镜像反转css效果
今天接到一个需求,通过一张图片得到其镜像对称的图片.本来说是后台处理的,但这样除了技术上难实现之外,还带来了资源消耗的问题,相当于每张图都要存储一个副本了. 只记得以前用过css的滤镜可以实现这个,但 ...
- Table of Contents - Servlet & JSP
Servlet Servlet API Overview Java Web 访问资源的路径问题 getParameter 与 request.getAttribute 的区别 转发与重定向的区别 中文 ...
- C# 短信猫(SMS cat) 操作源码开发经验
我曾经开发的某项目需要使用短信猫模块,要求使用C#编程操作.能独立使用的动态链接库之一就是网上流传的sms.dll,但它的功能较少,不能满足需求,鉴于一时找不到合适的完整代码,我深入研究了短信协议,借 ...
- CS对于dll文件的引用
1.对于.net或者com型的组件,直接添加引用即可. 2.对于标准的dll文件,利用DLLImport这个函数即可,如果要使用函数的别名,那么应该加入EntryPoint. 示例:一般可以封装成一个 ...
- Shanghai InfoSys .NET engineer telephone interview
Collect the answers,interested friends from research. 1,Interface and Abstract difference? 2,Generic ...
- 在远程系统上开发 SharePoint 应用程序
适用范围: apps for SharePoint | Office 365 | SharePoint Foundation 2013 | SharePoint Server 2013 使用远程安装的 ...
- mysql数据库用户和权限管理记录
一.MySQL用户的基本说明: 1.1 用户的基本结构MySQL的用户:用户名@主机 ■用户名:16个字符以内■主机:可以是主机名.IP地址.网络地址等主机名:www.111cn.net,localh ...
- C# WinForm动态调用远程Web服务
本文转自:http://blog.csdn.net/muyangjun/article/details/7930871 1.添加服务引用 2.在弹出的添加服务引用对话框地址栏中输入WebService ...
- HIV T2
甲学者将HIV病毒的遗传物质彻底水解后得到A.B.C三种化合物,乙学者将组成T2噬菌体的遗传物质彻底水解后得到了A.B.D三种化合物.你认为C.D两种化合物分别指的是 A.尿嘧啶.胸腺嘧啶 B.胸腺嘧 ...