直接開門見山,針對一個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.csdn.net/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>
就這麼多,我要肥家了,告辭各位!