我使用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.xhtml
与h:form
和commandButton
:
<h:commandButton value="Save" action="#{editUserBB.save()}" />
但是,在单击保存按钮后,再次调用init()
方法取消对UserDto
对象所做的所有更改,然后才能将其保存到数据库。那么我做错了什么?
我刚测试过,init()
方法在 save()
之前被称为,我也不明白。
答案 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没有。