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)
永远不要将状态放在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,也可能需要添加适当的同步.
| 归档时间: |
|
| 查看次数: |
3600 次 |
| 最近记录: |