Http сессия в Spring MVC - PullRequest
       2

Http сессия в Spring MVC

1 голос
/ 31 октября 2011

Я создаю очень простое приложение для викторины, используя Spring MVC.Работает нормально.Но прямо сейчас, если пользователь задает третий вопрос и поступает другой запрос от другого браузера (другого пользователя), он передает четвертый вопрос новому пользователю.Я не хочу, чтобы это случилось.Каждый новый запрос должен начинать тест с первого вопроса.Как мне добиться этого, не имея формы входа для каждого пользователя, и при этом идентифицировать каждый новый запрос от другого браузера как другого пользователя?Я знаю, что это может быть достигнуто с помощью сессий.

Может кто-нибудь объяснить, как это сделать?

package dmv2.spring.controller;

import java.util.List;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import dmv2.form.QuestionForm;
import dmv2.model.Exam;
import dmv2.model.Question;

@Controller
@SessionAttributes
@RequestMapping("/Exam")
public class ExamController
{
private List<Question> questions = (new Exam()).getQuestions();
private int            index     = 0;
private int            score     = 0;

@RequestMapping(method = RequestMethod.GET)
public ModelAndView showQuestionForm()
{
    Question q = questions.get(index);
    return new ModelAndView("exam", "questionForm", new QuestionForm()).addObject("q", q);
}

@RequestMapping(method = RequestMethod.POST)
public ModelAndView showQuestionForm2(@ModelAttribute("questionForm") QuestionForm questionForm, BindingResult result)
{
    Question q = questions.get(index);
    if(q.getAnswer().getRightChoiceIndex() == Integer.parseInt(questionForm.getChoice()))
        score = score + 1;
    index = index + 1;
    if(index < questions.size())
    {
        q = questions.get(index);
    }
    else
        return new ModelAndView("result").addObject("score", score);
    return new ModelAndView("exam", "questionForm", new QuestionForm()).addObject("q", q);
}

}

1 Ответ

7 голосов
/ 31 октября 2011

Никогда не помещайте состояние в контроллер, как в сервлете, он будет глобальным для всех, и доступ к нему должен быть синхронизирован.В общем, это хорошее правило, чтобы просто не помещать ничего изменяемого в поле контроллера.Вы даже не должны помещать бизнес-логику в контроллер, вы должны вызывать Objects из сервисного уровня, выполняющего всю работу с мощными сервисами.

Чтобы решить вашу проблему, вы можете определить интерфейс под названием QuestSession, которыйбудет действовать как прокси для пользовательского разговорного состояния.Лучше, если вы реализуете пограничные проверки.(Я думаю, индекс и оценка не могут быть отрицательными, например).

public interface QuestSession {
     public int getIndex();
     public void setIndex(int index);
     public int getScore();      
     public void setScore(int score);
}

Затем вы просто передаете этот интерфейс туда, где он вам нужен, например:

public ModelAndView showQuestionForm2(
    @ModelAttribute("questionForm") QuestionForm questionForm, 
    BindingResult result, QuestSession session) {

Чтобы сделатьэто работает, вы должны создать QuestSessionImpl и добавить в свою конфигурацию XML.

<bean id="questSessionImpl" class="package.QuestSessionImpl" scope="session">
    <aop:scoped-proxy />
</bean>

aop: scoped-proxy , это бит аспектно-ориентированного программирования, который выполняетмагия прокси вашего класса, чтобы каждая сессия разговаривала с другим объектом.Вы даже можете использовать @Autowired в поле «Контроллер», и каждый сеанс будет по-прежнему получать разные объекты.

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

Слово предупреждения.Даже доступ к сеансу не является потокобезопасным.Конечно, это менее опасно, чем глобальный общий доступ к одному полю, но все же возможно, что пользователь открывает две вкладки браузера или окна, создающие условия гонки.Вы начинаете чувствовать всю боль от этого с AJAX, так как многие асинхронные запросы могут объединяться.Даже если вы не используете AJAX, вы можете добавить правильную синхронизацию.

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