直接开门见山,针对一个Tomcat容器里不同工程Session无法共享问题,参考很多地方博客(会一一标注出处),搭建一个小Demo。
问题来源:项目比较老的代码,有三个不同项目,菜单切换的时候访问到了不同项目下的请求,比如菜单1请求地址http://host:port/projectA/.......... 菜单2请求地址:http://host:port/projectB/..........这些菜单都请求了相同的host port,系统首先肯定登陆进来的,假设请求的都jsp(事实上,这个项目也的确是这样),每个项目请求到的jsp中都包含了这样一句<jsp:include page="/pub/UserInfo.jsp" flush="true"/> ,UserInfo.jsp里嵌套了部分js代码,将session中用户信息取出来;可是当不同工程切换的时候,session一会有,切换工程一会有没有了,项目比较复杂,session不宜于管理,排错真的不好找;另一种思路,session中信息替换为存到redis里,但是鉴于项目工程,所以打消了念头。
废话不多说直接进入正题了:
Step1.
新建两个简单的web工程SessionA以及SessionB(结构很简单,不多解释了.....代码会贴在step2)
Step2.
SessionA中SessionServlet代码:
package com.lvbinbin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionServlet extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = -5130555166003468048L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
service(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// System.out.println("方法执行..."+req.getParameter("name"));
// req.getSession().setAttribute("name", req.getParameter("name"));
// PrintWriter pw = resp.getWriter();
// pw.println("success done!"+req.getSession().getAttribute("name"));
System.out.println("doService方法执行..."+req.getParameter("name"));
req.getSession().setAttribute("name", req.getParameter("name"));
ServletContext ctx1=req.getSession().getServletContext();
ctx1.setAttribute("session", req.getSession());
PrintWriter pw = resp.getWriter();
pw.println("success done!"+((HttpSession)req.getServletContext().getAttribute("session")).getAttribute("name"));
}
}
SessionA中web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SessionProjectA</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>servletA</servlet-name>
<servlet-class>com.lvbinbin.servlet.SessionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletA</servlet-name>
<url-pattern>/sessionA</url-pattern>
</servlet-mapping>
</web-app>
SessionA中index.jsp文件
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
Project: SessionProjectA <br>
<form action="sessionA">
姓名:<input type="text" name="name"/><br/>
<input type="submit" value="点击保存信息(lvbinbin)进入session"/>
</form>
</body>
</html>
SessionA就是这样简单,补充说明几句无关紧要的,ServletContext配置我会在Step3说明一下我的看法,随意看看:
Tomcat6是不支持@WebServlet注解的,从Tomcat7开始支持Servlet3.0特性,Servlet3.0有很多新特性(感兴趣的可以自行百度,因为我就知道这么几个注解特性)
========================================华丽的分割线 SessionB==========================
SessionB的SessionServlet代码
package com.lvbinbin.servletB;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionServlet extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = -5130555166003468048L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
service(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext ctx1 = req.getServletContext();
ServletContext ctxA = ctx1.getContext("/SessionA");
System.out.println("servletContext==null?"+(ctxA==null));
HttpSession session=(HttpSession) ctxA.getAttribute("session");
System.out.println("session==null?"+(session==null));
System.out.println("session得到数据:"+session.getAttribute("name"));
req.getRequestDispatcher("index.jsp").forward(req, resp);
}
}
SessionB的web.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SessionProjectA</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>servletB</servlet-name>
<servlet-class>com.lvbinbin.servletB.SessionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletB</servlet-name>
<url-pattern>/sessionB</url-pattern>
</servlet-mapping>
</web-app>
SessionB的index.jsp文件
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>SessionB</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
Project:SessionProjectB.<br>
<%
ServletContext ctx=application.getContext("/SessionA");
request.getSession().setAttribute("name", ((HttpSession)ctx.getAttribute("session")).getAttribute("name"));
%>
<h3>${sessionScope.name}</h3>
</body>
</html>
代码部分就这么多了
Step3.Tomcat的配置以及补充说明
Eclipse里的server文件夹如下:
重点!把项目部署到Tomcat里,server.xml这样配置!
<Context docBase="SessionA" path="/SessionA" reloadable="true" source="org.eclipse.jst.jee.server:SessionA" crossContext="true"/>
<Context docBase="SessionB" path="/SessionB" reloadable="true" source="org.eclipse.jst.jee.server:SessionB" crossContext="true"/>
其中crossContext必须配置。参考地址( https://blog.youkuaiyun.com/jayyanzi/article/details/46561509 ),更详细的原因有人这么说:crosscontext="true"表示配置的不同context共享一个session 我菜,先人云亦云吧。
Step4.启动Tomcat:
浏览器访问SessionA: http://localhost:8080/SessionA/
点击进入按钮
可知,Session中已经存了name值。
访问SessionB: http://localhost:8080/SessionB/sessionB
控制台打印:
emmmmm 这样应该对Session共享有一种思路了,ServletContext保存Session.我还要尝试WebLogic...因为项目就是Weblogic部署的
总结下本文的Demo,可能有价值的地方:
1.通过SessionB项目的request请求得到另外一个项目的ServletContext,进而得到Session对象
ServletContext ctx1 = req.getServletContext();
ServletContext ctxA = ctx1.getContext("/SessionA");
HttpSession session=(HttpSession) ctxA.getAttribute("session");
2.SessionB项目的index.jsp页面,我们可以利用application内置对象得到ServletContext,然后把session中的对象存到新的Session中,这样就可以只在UserInfo.jsp里改动一小部分代码,实现原有功能
<%
ServletContext ctx=application.getContext("/SessionA");
request.getSession().setAttribute("name", ((HttpSession)ctx.getAttribute("session")).getAttribute("name"));
%>
3.server.xml文件的配置属性,其中source属性应该是Eclipse生成的,各位小心点,别产生不必要的错误
<Context docBase="SessionA" path="/SessionA" reloadable="true" source="org.eclipse.jst.jee.server:SessionA" crossContext="true"/>
<Context docBase="SessionB" path="/SessionB" reloadable="true" source="org.eclipse.jst.jee.server:SessionB" crossContext="true"/></Host>
就这么多,我要肥家了,告辞各位!