为什么在post / postback之后调用@PostConstruct方法?

时间:2013-12-03 20:25:43

标签: spring jsf

我使用request scoped方法@postconstruct关注init() Spring bean:

@Component
@Scope("request")
public class editUserBB {

        Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
        private UserDto user;

        @Autowired
        private IUserService userService;

        @PostConstruct
        public void init() throws IOException {
            String id_string = params.get("id");
            Long id = Long.parseLong(id_string);
            user = userService.getUserById(id);
        }

        public String save(){
            // save to database
            return "user?faces-redirect=true&id=" + (long)user.getId();
        }

}

userEdit.xhtmlh:formcommandButton

<h:commandButton value="Save" action="#{editUserBB.save()}" />

但是,在单击保存按钮后,再次调用init()方法取消对UserDto对象所做的所有更改,然后才能将其保存到数据库。那么我做错了什么?

我刚测试过,init()方法在 save()之前被称为,我也不明白。

1 个答案:

答案 0 :(得分:3)

这不是init()方法的错误。这只是将bean放在请求范围而不是视图范围内的错误。

只要一个HTTP请求 - 响应周期,请求范围的bean就会存在。打开包含表单的页面计为一个HTTP请求。当关联的HTTP响应完成将结果发送到客户端(包括所有关联的请求范围bean)时,HTTP请求将被吞噬。提交表单计为另一个HTTP请求,从而创建一个全新的请求范围bean实例。如果您探索/调试实例的哈希码(和构造函数),您会注意到它实际上是两个物理上完全不同的实例。因此绝对没有办法init()“覆盖”旧的价值观。旧的价值观并不存在。

JSF通过引入视图范围解决了请求范围bean的这种尴尬行为。由于某种原因,你可能在Spring的一个替换JSF bean管理工具之前听过/读过它。 Spring bean管理工具没有视图范围的原生概念,你需要自己创建一个。

如果您打算坚持使用Spring bean管理工具,那么最好的办法是保留请求参数,该参数负责正确初始化数据以及表单提交。您可以使用<f:param>

<h:commandButton value="Save" action="#{editUserBB.save()}">
    <f:param name="id" value="#{param.id}" />
</h:commandButton>

另见:


对具体问题

无关,应避免在实例构建/初始化期间调用FacesContext。这是糟糕的设计。在这种特殊情况下,将获取请求参数映射的那一行移到init()方法内。此外,JSF bean管理工具有@ManagedProperty风格的标准解决方案,而Spring没有。