Spring MVC中的Http Session

Ser*_*ase 1 java spring spring-mvc

我正在使用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);
}

}
Run Code Online (Sandbox Code Playgroud)

sti*_*vlo 7

永远不要将状态放在Controller中,就像在Servlet中一样,它对每个人都是全局的,并且必须同步对它的访问.一般来说,一个好的规则是不要把任何可变的东西作为Controller的字段.您甚至不应该将业务逻辑放在Controller中,您应该从服务层调用Objects,使用强大的服务完成所有工作.

要解决您的问题,您可以定义一个名为的接口QuestSession,它将充当用户会话状态的代理.如果你实施边界检查会更好.(我猜索引和分数不能为负数,例如).

public interface QuestSession {
     public int getIndex();
     public void setIndex(int index);
     public int getScore();      
     public void setScore(int score);
}
Run Code Online (Sandbox Code Playgroud)

接下来,您只需将此界面传递到您需要的位置,例如:

public ModelAndView showQuestionForm2(
    @ModelAttribute("questionForm") QuestionForm questionForm, 
    BindingResult result, QuestSession session) {
Run Code Online (Sandbox Code Playgroud)

要使其工作,您需要创建QuestSessionImpl并添加XML配置.

<bean id="questSessionImpl" class="package.QuestSessionImpl" scope="session">
    <aop:scoped-proxy />
</bean>
Run Code Online (Sandbox Code Playgroud)

AOP:范围的代理,是面向方面的编程位,做进行代理类的魔法使每个环节会跟不同的对象.您甚至可以@Autowired在Controller字段上使用,每个会话仍将接收不同的Object.

我不知道如何用注释来表达它,如果有人在读这个就知道了,请指教.

一句警告.即使会话访问也不是线程安全的.当然,它比单个字段的全局共享访问危险性小,但用户仍然可以打开两个浏览器选项卡或窗口来创建竞争条件.您开始感受到AJAX的所有痛苦,因为许多异步请求可以组合在一起.即使您没有使用AJAX,也可能需要添加适当的同步.