正在创建新的modelAttribute以执行控制器中的每个requestMapping方法

时间:2014-07-17 15:14:56

标签: spring-mvc

我的控制器中有以下方法。

@ModelAttribute("myAttribute")
public MyAttribute getMyAttribute() {
    return new MyAttribute();
}
@RequestMapping(method=RequestMethod.GET)
public String myHomePage(@ModelAttribute("myAttribute") MyAttribute myAttribute, Model model) {
    //some changes in model attribute
    model.addAttribute("myAttribute", myAttribute);
    returns ("myFirstPageView");
}
@RequestMapping(value = {"/mySecondPage" }, method = RequestMethod.POST)
public String mySecondPage(@ModelAttribute("myAttribute") MyAttribute myAttribute, Model model) {
    //some changes in model attribute
    model.addAttribute("myAttribute", myAttribute);
    returns ("mySecondPageView");
}

加载我的第一页后,点击一下按钮就可以通过该方法将用户带到第二页 @RequestMapping(value = {"/mySecondPage" }, method = RequestMethod.POST) 但问题是在执行第二个请求映射方法时会创建新的模型属性。

我需要第一个请求映射方法在模型中设置的值也保留在第二个方法中。

我知道这可以通过以下方法解决

MyAttribute myAttribute;    

    @ModelAttribute("myAttribute")
    public MyAttribute getMyAttribute() {
        if(myAttribute==null)
        {
            myAttribute=new MyAttribute();
        }
        return  myAttribute;    
    }

但我不应该使用类级变量。如果有办法在不使用类级别变量的情况下克服这个问题,请告诉我。

3 个答案:

答案 0 :(得分:0)

永远不要在spring控制器中使用类级变量:因为控制器是单例,变量将在每个会话中共享!

有一种简单的方法可以做你想要的事情:只需在会话中调整你的模型属性。但是要小心即使你能找到其他帖子说会话属性在你不再需要它时神奇地消失了它也是假的! 您必须通过SessionStatus.setComplete()手动删除会话属性。 (参考:Spring的PetClinic例子)

您可以通过以下方式修改控制器:

@SessionAttributes("myAttribute") // scopes myAttribute in session
public class myController {

    @RequestMapping(method=RequestMethod.GET)
    public String myHomePage(@ModelAttribute("myAttribute") MyAttribute myAttribute, Model model) {
        //some changes in model attribute
        model.addAttribute("myAttribute", myAttribute);
        returns ("myFirstPageView");
    }
    @RequestMapping(value = {"/mySecondPage" }, method = RequestMethod.POST)
    public String mySecondPage(@ModelAttribute("myAttribute") MyAttribute myAttribute, Model model, SessionStatus sessionStatus) {
        //some changes in model attribute
        model.addAttribute("myAttribute", myAttribute);
        sessionStatus.setComplete(); // if this is the last usage of myAttribute
        returns ("mySecondPageView");
    }
}

在上面的代码中,如果您连续调用myHomePage,则第一个调用之后的所有调用都将使用会话存储中的前一个myAttribute。如果您不希望这样,但总是在获取部分中有一个新的myAttribute,那么您应该拥有:

    @RequestMapping(method=RequestMethod.GET)
    public String myHomePage(Model model) {
        MyAttribute myAttribute = new MyAttribute(); // create a fresh myAttribute
        //some changes in model attribute
        model.addAttribute("myAttribute", myAttribute);
        returns ("myFirstPageView");
    }

作为参考,以下是使用SessionAttribute的完整控制器(来自PetClinic示例)

@Controller
@RequestMapping("/owners/{ownerId}/edit")
@SessionAttributes(types = Owner.class)
public class EditOwnerForm {

    private final Clinic clinic;


    @Autowired
    public EditOwnerForm(Clinic clinic) {
        this.clinic = clinic;
    }

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
        dataBinder.setDisallowedFields("id");
    }

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
        Owner owner = this.clinic.loadOwner(ownerId);
        model.addAttribute(owner);
        return "owners/form";
    }

    @RequestMapping(method = RequestMethod.PUT)
    public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {
        new OwnerValidator().validate(owner, result);
        if (result.hasErrors()) {
            return "owners/form";
        }
        else {
            this.clinic.storeOwner(owner);
            status.setComplete();
            return "redirect:/owners/" + owner.getId();
        }
    }

}

答案 1 :(得分:0)

这是因为在网址中使用http代替https。使用https,问题得以解决。

答案 2 :(得分:-1)

您可以将对象放入会话,然后使用@SessionAttribute来检索它,因为会话可以用于跨请求。