Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中一个servlet的多个会话_Java_Session - Fatal编程技术网

Java中一个servlet的多个会话

Java中一个servlet的多个会话,java,session,Java,Session,我有一个servlet负责多个站点,因此我希望为不同的站点提供不同的会话,即使是同一个用户 Java中是否支持此功能,或者我是否需要为属性名添加前缀?我想前缀不是个好主意 /Br约翰内斯我想你在找类似的东西。它将管理单个servlet应用程序的单个会话。对于用户和web应用程序的组合,该会话是唯一的。当然,您可以在同一个Tomcat实例上的多个web应用程序中部署servlet,但您将无法仅根据URL参数将HTTP请求路由到不同的web应用程序,除非您在第二个servlet中计算URL参数并将浏

我有一个servlet负责多个站点,因此我希望为不同的站点提供不同的会话,即使是同一个用户

Java中是否支持此功能,或者我是否需要为属性名添加前缀?我想前缀不是个好主意


/Br约翰内斯

我想你在找类似的东西。它将管理单个servlet应用程序的单个会话。

对于用户和web应用程序的组合,该会话是唯一的。当然,您可以在同一个Tomcat实例上的多个web应用程序中部署servlet,但您将无法仅根据URL参数将HTTP请求路由到不同的web应用程序,除非您在第二个servlet中计算URL参数并将浏览器重定向到特定web应用程序的新URL

不同的servlet容器或J2EE应用程序服务器可能有不同的选项来将请求路由到特定的web应用程序,但作为开箱即用的工具,Tomcat只能基于主机名或基本目录委派请求,例如:

  • 。。。或委托给app1
  • 。。。或委托给app2,依此类推

这不能仅基于URL参数在servlet容器中完成;你得自己做。但是,管理“单独”会话的最简单方法不是处理servlet中的属性前缀,而是通过过滤器:

  • 为HttpSession编写一个简单的包装器类。使其持有属性地图,并通过所述地图支持所有属性/值方法;将所有其他方法委托给正在包装的实际会话。重写
    invalidate()
    方法以删除会话包装,而不是终止整个“真实”会话
  • 编写一个servlet过滤器;将其映射到拦截所有适用的URL
  • 在实际会话中维护会话包装器的集合作为属性
  • 在筛选器的
    doFilter()
    方法中,通过将原始请求包装到HttpServletRequestWrapper(其getSession()方法被覆盖)中,从集合中提取适当的会话包装器,并将其注入到正在传递链的请求中
  • 您的servlet/jsp/etc。。。将享受“单独”课程

  • 请注意,会话的“lastAccessedTime”与此方法共享。如果需要将这些内容分开,则必须编写自己的代码来维护此设置并使会话包装过期。

    我最近也遇到了这个问题,我同意CHSSLY76的建议来解决它。我想我应该在这里发布我的结果,以提供一个参考实现。它还没有经过广泛的测试,所以如果你发现任何弱点,请告诉我

    我假设对servlet的每个请求都包含一个名为uiid的参数,该参数表示用户ID。每次单击打开新窗口的链接时,请求者都必须跟踪发送新ID的情况。在我的例子中,这已经足够了,但是可以在这里随意使用任何其他(可能更安全的)方法。此外,我使用Tomcat 7或8。在使用不同的servlet容器时,您可能需要扩展其他类,但是API不应该改变太多

    在下文中,创建的会话称为子会话,原始容器管理的会话是父会话。该实现由以下五个类组成:

    SingleSessionManager跟踪所有子会话的创建、分发和清理。它通过充当servlet过滤器来实现这一点,该过滤器将servlet请求替换为返回相应子会话的包装器。调度器会定期检查过期的子会话…是的,它是一个单例。对不起,我还是喜欢

    package session;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.ScheduledFuture;
    import java.util.concurrent.TimeUnit;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    /**
     * A singleton class that manages multiple sessions on top of a regular container managed session.
     * See web.xml for information on how to enable this.
     *
     */
    public class SingleSessionManager implements Filter {
    
        /**
         * The default session timeout in seconds to be used if no explicit timeout is provided.
         */
        public static final int DEFAULT_TIMEOUT = 900;
    
        /**
         * The default interval for session validation checks in seconds to be used if no explicit
         * timeout is provided.
         */
        public static final int DEFAULT_SESSION_INVALIDATION_CHECK = 15;
    
        private static SingleSessionManager instance;
    
        private ScheduledExecutorService scheduler;
        protected int timeout;
        protected long sessionInvalidationCheck;
    
        private Map<SubSessionKey, HttpSessionWrapper> sessions = new ConcurrentHashMap<SubSessionKey, HttpSessionWrapper>();
    
        public SingleSessionManager() {
            sessionInvalidationCheck = DEFAULT_SESSION_INVALIDATION_CHECK;
            timeout = DEFAULT_TIMEOUT;
        }
    
        public static SingleSessionManager getInstance() {
            if (instance == null) {
                instance = new SingleSessionManager();
            }
            return instance;
        }
    
        @Override
        public void destroy() {
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper((HttpServletRequest) request);
            chain.doFilter(wrapper,  response);
        }
    
        @Override
        public void init(FilterConfig cfg) throws ServletException {
            String timeout = cfg.getInitParameter("sessionTimeout");
            if (timeout != null && !timeout.trim().equals("")) {
                getInstance().timeout = Integer.parseInt(timeout) * 60;
            }
    
            String sessionInvalidationCheck = cfg.getInitParameter("sessionInvalidationCheck");
            if (sessionInvalidationCheck != null && !sessionInvalidationCheck.trim().equals("")) {
                getInstance().sessionInvalidationCheck = Long.parseLong(sessionInvalidationCheck);
            }
    
            getInstance().startSessionExpirationScheduler();
        }
    
        /**
         * Create a new session ID.
         * 
         * @return A new unique session ID.
         */
        public String generateSessionId() {
            return UUID.randomUUID().toString();
        }
    
        protected void startSessionExpirationScheduler() {
            if (scheduler == null) {
                scheduler = Executors.newScheduledThreadPool(1);
                final Runnable sessionInvalidator = new Runnable() {
                    public void run() {
                        SingleSessionManager.getInstance().destroyExpiredSessions();
                    }
                };
                final ScheduledFuture<?> sessionInvalidatorHandle =
                        scheduler.scheduleAtFixedRate(sessionInvalidator
                                , this.sessionInvalidationCheck
                                , this.sessionInvalidationCheck
                                , TimeUnit.SECONDS);
            }
        }
    
        /**
         * Get the timeout after which a session will be invalidated.
         * 
         * @return The timeout of a session in seconds.
         */
        public int getSessionTimeout() {
            return timeout;
        }
    
        /**
         * Retrieve a session.
         * 
         * @param uiid
         *            The user id this session is to be associated with.
         * @param create
         *            If <code>true</code> and no session exists for the given user id, a new session is
         *            created and associated with the given user id. If <code>false</code> and no
         *            session exists for the given user id, no new session will be created and this
         *            method will return <code>null</code>.
         * @param originalSession
         *            The original backing session created and managed by the servlet container.
         * @return The session associated with the given user id if this session exists and/or create is
         *         set to <code>true</code>, <code>null</code> otherwise.
         */
        public HttpSession getSession(String uiid, boolean create, HttpSession originalSession) {
            if (uiid != null) {
                SubSessionKey key = new SubSessionKey(originalSession.getId(), uiid);
                if (!sessions.containsKey(key) && create) {
                    HttpSessionWrapper sw = new HttpSessionWrapper(uiid, originalSession);
                    sessions.put(key, sw);
                }
                HttpSessionWrapper session = sessions.get(key);
                session.setLastAccessedTime(System.currentTimeMillis());
                return session;
            }
            return null;
        }
    
        public HttpSessionWrapper removeSession(SubSessionKey key) {
            return sessions.remove(key);
        }
    
        /**
         * Destroy a session, freeing all it's resources.
         * 
         * @param session
         *            The session to be destroyed.
         */
        public void destroySession(HttpSessionWrapper session) {
            String uiid = ((HttpSessionWrapper)session).getUiid();
            SubSessionKey key = new SubSessionKey(session.getOriginalSession().getId(), uiid);
            HttpSessionWrapper w = getInstance().removeSession(key);
            if (w != null) {
                System.out.println("Session " + w.getId() + " with uiid " + uiid + " was destroyed.");
            } else {
                System.out.println("uiid " + uiid + " does not have a session.");
            }
        }
    
        /**
         * Destroy all session that are expired at the time of this method call.
         */
        public void destroyExpiredSessions() {
            List<HttpSessionWrapper> markedForDelete = new ArrayList<HttpSessionWrapper>();
            long time = System.currentTimeMillis() / 1000;
            for (HttpSessionWrapper session : sessions.values()) {
                if (time - (session.getLastAccessedTime() / 1000) >= session.getMaxInactiveInterval()) {
                    markedForDelete.add(session);
                }
            }
            for (HttpSessionWrapper session : markedForDelete) {
                destroySession(session);
            }
        }
    
        /**
         * Remove all subsessions that were created from a given parent session.
         * 
         * @param originalSession
         *            All subsessions created with this session as their parent session will be
         *            invalidated.
         */
        public void clearAllSessions(HttpSession originalSession) {
            Iterator<HttpSessionWrapper> it = sessions.values().iterator();
            while (it.hasNext()) {
                HttpSessionWrapper w = it.next();
                if (w.getOriginalSession().getId().equals(originalSession.getId())) {
                    destroySession(w);
                }
            }
        }
    
        public void setSessionTimeout(int timeout) {
            this.timeout = timeout;
        }
    
    }
    
    子会话由子会话键标识。这些关键对象取决于uiid和父会话的ID

    package session;
    
    /**
     * Key object for identifying a subsession.
     *
     */
    public class SubSessionKey {
    
        private String sessionId;
        private String uiid;
    
        /**
         * Create a new instance of {@link SubSessionKey}.
         * 
         * @param sessionId
         *            The session id of the parent session.
         * @param uiid
         *            The users's id this session is associated with.
         */
        public SubSessionKey(String sessionId, String uiid) {
            super();
            this.sessionId = sessionId;
            this.uiid = uiid;
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode());
            result = prime * result + ((uiid == null) ? 0 : uiid.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            SubSessionKey other = (SubSessionKey) obj;
            if (sessionId == null) {
                if (other.sessionId != null)
                    return false;
            } else if (!sessionId.equals(other.sessionId))
                return false;
            if (uiid == null) {
                if (other.uiid != null)
                    return false;
            } else if (!uiid.equals(other.uiid))
                return false;
            return true;
        }
    
        @Override
        public String toString() {
            return "SubSessionKey [sessionId=" + sessionId + ", uiid=" + uiid + "]";
        }
    
    }
    
    package session;
    
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * Session listener that listens for the destruction of a container managed session and takes care
     * of destroying all it's subsessions.
     * <p>
     * Normally this listener won't have much to do since subsessions usually have a shorter lifetime
     * than their parent session and therefore will timeout long before this method is called. This
     * listener will only be important in case of an explicit invalidation of a parent session.
     * </p>
     *
     */
    public class SessionInvalidator implements HttpSessionListener {
    
        @Override
        public void sessionCreated(HttpSessionEvent arg0) {
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent arg0) {
            SingleSessionManager.getInstance().clearAllSessions(arg0.getSession());
        }
    
    }
    
    HttpServletRequestWrapper包装HttpServletRequest对象。除了
    getSession
    方法之外,所有方法都会重定向到包装请求,该方法将根据此请求参数中的用户ID返回
    HttpSessionWrapper

    package session;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    /**
     * Wrapper class that wraps a {@link HttpServletRequest} object. All methods are redirected to the
     * wrapped request except for the <code>getSession</code> which will return an
     * {@link HttpSessionWrapper} depending on the user id in this request's parameters.
     *
     */
    public class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {
    
        private HttpServletRequest req;
    
        public HttpServletRequestWrapper(HttpServletRequest req) {
            super(req);
            this.req = req;
        }
    
        @Override
        public HttpSession getSession() {
            return getSession(true);
        }
    
        @Override
        public HttpSession getSession(boolean create) {
            String[] uiid = getParameterMap().get("uiid");
            if (uiid != null && uiid.length >= 1) {
                return SingleSessionManager.getInstance().getSession(uiid[0], create, req.getSession(create));
            }
            return req.getSession(create);
        }
    }
    
    HttpSessionWrapper表示一个子会话

    package session;
    
    import java.util.Collections;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionContext;
    
    /**
     * Implementation of a HttpSession. Each instance of this class is created around a container
     * managed parent session with it's lifetime linked to it's parent's.
     *
     */
    @SuppressWarnings("deprecation")
    public class HttpSessionWrapper implements HttpSession {
    
        private Map<String, Object> attributes;
        private Map<String, Object> values;
        private long creationTime;
        private String id;
        private String uiid;
        private boolean isNew;
        private long lastAccessedTime;
        private HttpSession originalSession;
    
        public HttpSessionWrapper(String uiid, HttpSession originalSession) {
            creationTime = System.currentTimeMillis();
            lastAccessedTime = creationTime;
            id = SingleSessionManager.getInstance().generateSessionId();
            isNew = true;
            attributes = new HashMap<String, Object>();
            Enumeration<String> names = originalSession.getAttributeNames();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                attributes.put(name, originalSession.getAttribute(name));
            }
            values = new HashMap<String, Object>();
            for (String name : originalSession.getValueNames()) {
                values.put(name, originalSession.getValue(name));
            }
            this.uiid = uiid;
            this.originalSession = originalSession;
        }
    
        public String getUiid() {
            return uiid;
        }
    
        public void setNew(boolean b) {
            isNew = b;
        }
    
        public void setLastAccessedTime(long time) {
            lastAccessedTime = time;
        }
    
        @Override
        public Object getAttribute(String arg0) {
            return attributes.get(arg0);
        }
    
        @Override
        public Enumeration<String> getAttributeNames() {
            return Collections.enumeration(attributes.keySet());
        }
    
        @Override
        public long getCreationTime() {
            return creationTime;
        }
    
        @Override
        public String getId() {
            return id;
        }
    
        @Override
        public long getLastAccessedTime() {
            return lastAccessedTime;
        }
    
        @Override
        public int getMaxInactiveInterval() {
            return SingleSessionManager.getInstance().getSessionTimeout();
        }
    
        @Override
        public ServletContext getServletContext() {
            return originalSession.getServletContext();
        }
    
        @Override
        public HttpSessionContext getSessionContext() {
            return new HttpSessionContext() {
    
                @Override
                public Enumeration<String> getIds() {
                    return Collections.enumeration(new HashSet<String>());
                }
    
                @Override
                public HttpSession getSession(String arg0) {
                    return null;
                }
    
            };
        }
    
        @Override
        public Object getValue(String arg0) {
            return values.get(arg0);
        }
    
        @Override
        public String[] getValueNames() {
            return values.keySet().toArray(new String[values.size()]);
        }
    
        @Override
        public void invalidate() {
            SingleSessionManager.getInstance().destroySession(this);
        }
    
        @Override
        public boolean isNew() {
            return isNew;
        }
    
        @Override
        public void putValue(String arg0, Object arg1) {
            values.put(arg0, arg1);
        }
    
        @Override
        public void removeAttribute(String arg0) {
            attributes.remove(arg0);
        }
    
        @Override
        public void removeValue(String arg0) {
            values.remove(arg0);
        }
    
        @Override
        public void setAttribute(String arg0, Object arg1) {
            attributes.put(arg0, arg1);
        }
    
        @Override
        public void setMaxInactiveInterval(int arg0) {
            SingleSessionManager.getInstance().setSessionTimeout(arg0);
        }
    
        public HttpSession getOriginalSession() {
            return originalSession;
        }
    
    }
    
    通过在web.xml中添加以下内容来启用所有功能

    
    单会话过滤器
    de.supportgis.sgjWeb.session.SingleSessionManager
    会话超时
    1.
    会话验证检查
    15
    单会话过滤器
    YourServlet
    session.SessionInvalidator
    40
    
    以下是针对用户3792852回复的错误修复

    public HttpSession getSession(String uiid, boolean create, HttpSession originalSession)
    {
        if (uiid != null && originalSession != null)
        {
            SubSessionKey key = new SubSessionKey(originalSession.getId(), uiid);
            synchronized (sessions)
            {
                HttpSessionWrapper session = sessions.get(key);
                if (session == null && create)
                {
                    session = new HttpSessionWrapper(uiid, originalSession);
                    sessions.put(key, session);
                }
                if (session != null)
                {
                    session.setLastAccessedTime(System.currentTimeMillis());
                }
                return session;
            }
        }
        return null;
    }
    

    我可以手动设置路径来帮助解决这个问题吗?请定义“多个站点”这个词是的,我同意,我的定义不好:)。同一个servlet将根据不同的url参数显示不同的html页面。对于不同的url参数,我希望有不同的会话,即使是同一个用户。同一个servlet将根据不同的url参数显示不同的html页面。对于不同的url参数,我希望有不同的会话,即使它是相同的user@Johannes当前位置你是如何处理那种情况的。我现在的处境和你两年前的处境一样(我在下面给出了一些错误修复