Атрибут Область и время жизни сеанса в сервлете моего веб-приложения приводят меня в замешательство при использовании более двух вкладок одного браузера. - PullRequest
3 голосов
/ 13 мая 2011

Я делал простой веб-проект (вы можете увидеть код ниже).Насколько я знаю, атрибуты сеанса связаны с одним сеансом.Когда я открыл две вкладки одного и того же браузера и запустил, введите URL-адрес, создается только один идентификатор сеанса, но работают два разных объекта с одним и тем же атрибутом сеанса (т. Е. Я не хочу запускать два опроса одновременно. Но, когда я изменил вопрос на одной из вкладок, это не влияет на атрибуты сеанса другой вкладки).Можете ли вы объяснить мне, почему это произошло так?Как я могу изменить свой код, чтобы сделать переменные сеанса общими, чтобы при изменении одного из атрибутов сеанса на одной из вкладок я хотел, чтобы переменные сеанса другой вкладки были затронуты?

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.quizServlet;

import QuizApp.Quiz;
import java.io.IOException;
import java.io.PrintWriter;
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;

/**
 *
 * @author Mati
 */
@WebServlet(name = "QuizServlet", urlPatterns = {"/Quiz"})
public class QuizServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
        } catch (Exception ex) {
            out.write("<font style='color:red'><b>" + ex.getMessage() + "</b></font>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            if (request.getSession().getAttribute("QuizzObject") == null) {
                Quiz quiz = new Quiz();
                quiz.addQuestion(new int[]{1, 2, 3, 4});
                quiz.addQuestion(new int[]{1, 1, 2, 3, 5, 8});
                quiz.addQuestion(new int[]{0, 5, 10, 15, 20, 25});
                request.getSession().setAttribute("QuizzObject", quiz);
            }
            if (request.getSession().getAttribute("questionsLeft") == null) {
                request.getSession().setAttribute("questionsLeft", true);
            }
                        Quiz qq = (Quiz) request.getSession().getAttribute("QuizzObject");
                        qq.reset();

            StringBuilder SB = new StringBuilder();

            SB.append("<form name='myform' method='post'>");
            SB.append("<h3>Have fun with NumberQuiz!</h3>");
            SB.append("<p><input type='submit' name='btnNext' value='Start quiz' /></p>");
            SB.append("</form>");
            out.print(SB.toString());

        } catch (Exception ex) {
            out.write("<font style='color:red'><b>" + ex.getMessage() + "</b></font>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        PrintWriter out = response.getWriter();

        try {

            StringBuilder SB = new StringBuilder();
            String msg="";
            SB.append("<html><head></head><body>");
            Quiz qq = (Quiz) request.getSession().getAttribute("QuizzObject");
            SB.append(request.getSession().getId());
            boolean questionsLeft = (Boolean) request.getSession().getAttribute("questionsLeft");
            if (questionsLeft) {
                qq.addAttempts();
                if (request.getParameter("txtAnswer") != null) {
                    if (qq.isCorrect(Integer.parseInt(request.getParameter("txtAnswer")))) {
                        qq.scoreAnswer();
                    } else {
                        msg="<p><font style='color:red'>Wrong Answer .. Try Again</font></p>";
                    }
                }
                if (qq.getCurrentQuestion() == null) {
                    request.getSession().setAttribute("questionsLeft", false);
                    SB.append("Congratulations, you have completed the quiz!");
                    SB.append("<br>Your final score is:" + qq.getScore());
                    SB.append("<br>Total attempts:" + qq.getAttempt());
                    qq.reset();
                    request.getSession().setAttribute("questionsLeft",null);
                } else {
                    SB.append("<form name='myform' method='post'>");
                    //SB.append("<h3>Have fun with NumberQuiz!</h3>");
                    SB.append("<p>Your current score is " + qq.getScore() + ".</p>");
                    SB.append("<p>Guess the next number in the sequence!</p>");
                    SB.append("<p>" + qq.getCurrentQuestion().toString().replaceAll("\\?", "<font style='color:red'><b>?</b></font>") + "</p>");
                    SB.append("<p>Your answer:<input type='text' id='txtAnswer' name='txtAnswer' value='' /></p>");
                    SB.append("<p><input type='submit' name='btnNext' value='Next' onclick='return validate()' />");
                    SB.append("<input type='Reset' name='btnStart' value='Restart!' onclick=\"document.location.href='/QuizzWeb/Quiz';return false;\" /></p>");
                    SB.append(msg);
                    SB.append("</form>");
                    SB.append("<script type='text/javascript'>function validate(){if(document.getElementById('txtAnswer').value==''){alert('You should write an answer');return false;}return true;}</script>");
                }
                SB.append("</body></html>");
                out.print(SB.toString());
            }

        } catch (Exception ex) {
            out.print("<font style='color:red'><b>" + ex.getMessage() + "</b></font>");
        } finally {
            out.close();
        }

    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Ответы [ 2 ]

7 голосов
/ 13 мая 2011

Я думаю, что у вас может быть несколько запутанных понятий, надеюсь, это объяснение будет иметь смысл и поможет вам разобраться.

Сеанс живет на вашем сервере приложений.После создания он передается в ваш браузер с помощью файла cookie (часто называемого JSESSIONID).Когда ваш браузер передает этот файл cookie веб-серверу как часть запроса, сервер может извлечь сеанс и связанные с ним объекты (должны быть сериализуемыми, см. Другие вопросы SO), которые уже были присоединены к этому сеансу (при условии, что этот сеанс не истек)).

Поскольку эти переменные сеанса живут только на сервере, они используются сервером для построения ответа, данного клиенту.Но чтобы получить ответ, ваш клиент должен сделать запрос.Вы сделали запрос и изменили состояние первой вкладки, но поскольку вторая вкладка не сделала собственный запрос, ее состояние не обновилось.(Поскольку эти вкладки находятся в одном и том же браузере, они совместно используют файл cookie сеанса и извлекают один и тот же сеанс для выполнения своих запросов).С некоторыми дополнительными возможностями вы можете использовать некоторые технологии на стороне клиента, такие как AJAX, для периодического выполнения небольших запросов о состоянии сеанса и обновления отображения окон вашего браузера.(Вы можете различать такие запросы, вызывая их для вызова другого ресурса или разных типов принятия запроса).

Теперь с дизайном вашего кода ... Я не смотрел на него слишком подробно, но вы, возможно, захотите проработать свой поток немного больше.Кажется, GET всегда сбрасывает ваш тест и сообщение продолжает его?(Мне это немного странно, но я не могу понять, почему ... Я бы порекомендовал почитать REST и дизайн, созданный на основе этого. JAX-RS и Jersey довольно милы:)).

Редактировать: Вот гораздо более простой сервлет, с которым вы можете играть.Поместите его в войну и откройте 2 вкладки, одну только для самого сервлета, а другую, добавив строку запроса? CheckOnly = true.Поиграйте с обновлением каждой вкладки независимо и посмотрите, что происходит с графом.

package test.servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Counting servlet counts the number of requests to it.
 * @author Charlie Huggard-Lee
 */
@SuppressWarnings("nls")
public class CountingServlet extends HttpServlet {

/**
 * The serialVersionUID.
 */
private static final long serialVersionUID = 4279853716717632192L;

/**
 * {@inheritDoc}
 */
@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
    final HttpSession session = req.getSession();
    AtomicInteger counter = (AtomicInteger) session.getAttribute("Count");
    if (counter == null) {
        counter = new AtomicInteger();
        session.setAttribute("Count", counter);
    }

    final boolean checkOnly = Boolean.parseBoolean(req.getParameter("checkOnly"));

    final int thisCount;
    if (checkOnly) {
        thisCount = counter.get();
    } else {
        thisCount = counter.getAndIncrement() + 1;
    }

    resp.setStatus(200);
    resp.setHeader("Content-Type", "text/plain"); //$NON-NLS-1$ //$NON-NLS-2$
    resp.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
    final PrintWriter writer = resp.getWriter();

    if (session.isNew()) {
        writer.append("Hey new user!\n");
    } else {
        writer.append("Welcome Back!\n");
    }
    writer.append("Session ID: ");
    writer.append(session.getId());
    writer.append("\n");
    if (checkOnly) {
        writer.append("(checking) ");
    }
    writer.append("Count: ");
    writer.append(Integer.toString(thisCount));
    }
}
0 голосов
/ 13 мая 2011

Когда сессия установлена, сервер отправляет куки в ваш браузер. Один и тот же файл cookie отправляется обратно каждый раз, когда URL соответствует области действия файла cookie, который (в большинстве случаев) определяется атрибутами cookie домена и пути. Так что не имеет значения, если у вас есть 2, 10 или 50 открытых вкладок в вашем браузере. Пока есть совпадение между URL-адресом, к которому вы обращаетесь, и областью cookie вашего сеанса, вы получите тот же сеанс. Что касается браузера, такого сеанса не существует, поэтому не думайте, что ваш браузер знает об этом. Он просто отправляет куки. Вот и все.

И не существует "двух разных объектов одного и того же атрибута сеанса". Сеанс гарантирует, что для данного имени существует только одна запись. Вы просто перезаписываете его каждый раз, когда делаете запрос из другой вкладки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...