奇怪的行为:Spring Session Attributes vs ModelAttribute

时间:2015-06-22 18:52:19

标签: spring spring-mvc httpsession

我在JBoss 7.2上托管的Spring MVC 4.0.6遇到了一个非常奇怪的问题。更新现有用户时,提交的信息有时会转移到POST RequestMapping控制器方法(下面的validateUpdate方法)。

UserController.java

@Controller
@RequestMapping(value = "/security/user")
@SessionAttributes(value = {"userForm", "user"})
public class UserController {

    private final String CREATE_VIEW = "user/createOrUpdate";
    private final String READ_VIEW = "user/readOrDelete";
    private final String UPDATE_VIEW = CREATE_VIEW;
    private final String DELETE_VIEW = READ_VIEW;    

    @Autowired
    private LocationService locationService;

    @Autowired
    private SecurityService securityService;

    @Autowired
    private UserValidator userValidator;

    @InitBinder("userForm")
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(userValidator);
        binder.setDisallowedFields("strId");
    }

    @ModelAttribute("regions")
    public List<Region> populateRegions() {

        Locale locale = LocaleContextHolder.getLocale();
        List<Region> regions = this.locationService.lstRegions(locale.getLanguage());

        return regions;
    }

    @RequestMapping(value = "/update/{intUserId}", method = RequestMethod.GET)
    public String updateUser(@PathVariable Integer intUserId, Model model) {

        User user = this.securityService.findUserByPk(intUserId);

        if (user != null) {
            UserForm userForm = new UserForm();
            userForm.setUser(user);

            model.addAttribute(userForm);
        }

        return UPDATE_VIEW;
    }

    @RequestMapping(value = "/update/validate",  method = RequestMethod.POST)
    public String validateUpdate(@Valid @ModelAttribute("userForm") UserForm userForm,
                                BindingResult result,
                                Model model,
                                RedirectAttributes redirectAttributes,
                                SessionStatus status) {

        return this.performCreateOrUpdateOperation(userForm, result, model, redirectAttributes, status);
    }

    private String performCreateOrUpdateOperation(
        UserForm userForm, 
        BindingResult result,
        Model model,
        SessionStatus status) {

        if(result.hasErrors()) {
            return UPDATE_VIEW;
        } else {

            User user = userForm.getUser();

            this.securityService.validateCreateOrUpdateUser(result, user);

            if (result.hasErrors() == false) {

                if (userForm.isNew()) {
                    this.securityService.addUser(user);
                } else {
                    this.securityService.updateUser(user);
                }

                model.addAttribute(user);

                status.setComplete();

                return "user/success";

            } else {
                return UPDATE_VIEW;
            }
        }
    }
}

表单Bean

public class UserForm {

    private String strUserIdToSearch = "";

    private String strId = "0";
    private String strUserId = "";
    private String strFirstName = "";
    private String strLastName = "";
    private String strEmail = "";

    private String strRegionId = "0";
    private boolean booArchived = false;

    public User getUser() {

        User user = new User();

        user.setIntId(Integer.valueOf(this.strId));
        user.setStrUserId(this.strUserId);
        user.setStrFirstName(this.strFirstName);
        user.setStrLastName(this.strLastName);
        user.setStrEmail(this.strEmail);

        Region region = new Region(Integer.valueOf(this.strRegionId));
        user.setRegion(region);

        user.setBooArchived(this.booArchived);

        return user;
    }

    public void setUser(User user) {

        this.strUserIdToSearch = user.getStrUserId();

        this.strId = String.valueOf(user.getIntId());
        this.strUserId = user.getStrUserId();
        this.strFirstName = user.getStrFirstName();
        this.strLastName = user.getStrLastName();
        this.strEmail = user.getStrEmail();

        this.strRegionId = String.valueOf(user.getRegion().getIntId());
        this.booArchived = user.getBooArchived();
    }

    ...getters and setters...
}

JSP(为清晰起见,删除了样式) crudMethod是一个JSP标签返回&#34;创建&#34;,&#34;读&#34;,&#34;更新&#34;或&#34;删除&#34;取决于$ {requestScope [&#39; javax.servlet.forward.request_uri&#39;]}

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

    <spring:url var="userFormAction" value="/rest/security/user/${crudMethod}/validate" />    

<form:form id="userForm" modelAttribute="userForm" action="${userFormAction}" method="POST">

<form:hidden path="strId" />
<form:hidden path="strUserId" id="strUserId" />
<form:hidden path="strLastName" id="strLastName" />
<form:hidden path="strFirstName" id="strFirstName" />
<form:hidden path="strEmail" id="strEmail" />

<form:select id="strRegionId" path="strRegionId">
    <form:option value="0" label="${strSelectRegionLabel}" />
    <form:options items="${regions}" itemValue="intId" itemLabel="${strRegionLabel}" />
</form:select>

</form:form>

因此,当我提交表单时,例如,将区域更改为列表中的另一个ID(让我们说从1到6)。有时它有效,有时不行。通过&#34;工作&#34;,我的意思是我点击成功页面,然后我回去再次看到用户。有时它会保持在1,有时它会变为6.

我找到了一个模式/解决方法,可以一直重现问题:

  1. 加载更新表单(UserController&gt; updateUser)
  2. 将区域从1更改为6
  3. 单击“保存”。表单提交,因此正在调用UserController.validateUser方法。
  4. 获得了成功页面。在该成功页面上,我获得了用户的读取操作的链接。点击该链接,我意识到该区域没有改变(主要问题)。在阅读页面上有一个更新用户的链接。
  5. 重新执行我在步骤#2中所做的完全相同的更改。
  6. 单击“保存”。表单提交,我获得了成功页面视图。
  7. 再次点击阅读超链接,现在我看到更改有效。
  8. 问题是:为什么?我错过了什么吗?

    注意:它与业务层无关。我测试了它,它很稳定。这肯定与我使用Spring MVC Framework有关。

    浏览器是IE11。

    感谢您的帮助。

    *更新2015-06-29 *

    经过几次搜索后,我发现:

    • 当它不起作用时,请求Content-Length标头值为0.
    • 当它起作用时,有一个值(例如:146)。
    • 请求邮件正文总是正确的,如下所示:

      strId = THE_ID&安培; strUserId = THE_USERID&安培; strLastName = THE_LASTNAME&安培; strFirstName = THE_FIRSTNAME&安培; strEmail = THE_EMAILADDRESS&安培; strRegionId = THE_REGIONID&安培; booArchived =假

      请注意&#34; THE_REGIONID&#34;每次都很好。

    相关资源

1 个答案:

答案 0 :(得分:1)

Path.Combine

我认为表单中的 id :select 是罪魁祸首。它与 UserForm 中的属性名称不匹配,即&#34; strRegionId &#34;。因此它不会绑定。将ID值更改为 strRegionId