PrimeFaces 5.1 + 可编辑数据表 + 文件上传列
PrimeFaces 5.1 + editable dataTable + fileUpload column
我正在使用可编辑的 <p:dataTable>
,其中每个 <p:column>
包含一个 <p:cellEditor>
。我使用一个特定的 <p:column>
来表示用于存储文件名称(由用户上传)的模型项的 属性(我们称之为 chemin) ).对应的<p:cellEditor>
如下:
- 在
<f:facet>
中包含一个 <p:fileUpload>
和一个 <h:outputLink>
- out
<f:facet>
包含一个 <h:outputLink>
我想执行以下操作:当用户单击 <p:rowEditor>
(铅笔图标)时,(1) 显示 <p:fileUpload>
,(2) 然后用户选择并上传文件(3) 当用户验证更新(通过单击复选标记)时,该列显示 link 到新上传的文件,这意味着当前模型项目已相应更新:chemin 属性 将包含新上传文件的名称。
下面的代码正确实现了步骤 (1) 到 (2),但步骤 (3) 不起作用。
Version.xhtml
<h:form id="RUDForm" enctype="multipart/form-data">
<p:dataTable
id="versionDT"
var="version"
value="#{versionController.rechercherToutVersion()}"
editable="true"
paginator="true"
rows="3"
dir="rtl"
style="width: 100%"
emptyMessage="#{messages.listeVide}">
<p:ajax event="rowEdit" listener="#{versionController.updateVersion(version)}" update=":RUDForm:versionDT" />
...
<p:column headerText="#{messages.chemin}">
<p:cellEditor>
<f:facet name="output">
<h:outputLink
id = "versionCheminLink"
value="#{versionController.relativeUploadUrl(version.chemin)}"
target="_blank"
rendered = "#{version.chemin != null}"
>
<h:outputText styleClass="title-text" value="#{version.chemin}"/>
</h:outputLink>
</f:facet>
<f:facet name="input">
<p:panelGrid
id="uploadUpdatePG"
dir="rtl"
>
<p:row>
<p:column>
<p:fileUpload
id = "versionChemin"
fileUploadListener="#{versionController.fileUploadListenerUpdate}"
mode="advanced"
dragDropSupport="false"
update=":RUDForm:versionDT:uploadUpdatePG"
fileLimit="1"
label="#{messages.unChoix}"
uploadLabel="#{messages.upload}"
cancelLabel="#{messages.annuler}"
invalidSizeMessage = "#{messages.invalidSizeMessage}"
invalidFileMessage = "#{messages.invalidFileMessage}"
sizeLimit="1000000"
>
<f:attribute name="version" value="#{version}" />
</p:fileUpload>
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLink
id = "versionCheminLinkReminder"
value="#{versionController.relativeUploadUrl(version.chemin)}"
target="_blank"
rendered = "#{version.chemin != null}"
>
<h:outputText styleClass="title-text" value="#{version.chemin}"/>
</h:outputLink>
</p:column>
</p:row>
</p:panelGrid>
</f:facet>
</p:cellEditor>
<p:message for="versionChemin"/>
</p:column>
...
<p:column style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
VersionController.java
@ManagedBean
@ViewScoped
public class VersionController extends GenericPageController implements Serializable
{
...
@ManagedProperty(value="#{versionServiceImpl}")
private VersionService versionService;
public VersionService getVersionService() {
return versionService;
}
public void setVersionService(VersionService versionService) {
this.versionService = versionService;
}
private UploadedFile file;
public UploadedFile getFile() {
return file;
}
public void setFile(UploadedFile file) {
this.file = file;
}
...
public void updateVersion(Version version)
{
if (getVersionService().updateVersion(version))
{
addInfoByKey("msgUpdateOk");
}
else
{
addErrorByKey("msgUpdateKo");
}
}
...
public void fileUploadListenerUpdate(FileUploadEvent event)
{
setFile(event.getFile());
uploadVersionUpdate((Version)event.getComponent().getAttributes().get("version"));
}
public void uploadVersionUpdate(Version version)
{
if ((getFile() != null) && (getFile().getSize() != 0))
{
version.setChemin(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + addZeros(new Random().nextInt(10),3) + getFile().getFileName());
upload(getFile(),version.getChemin());
addInfoByKey("RUDForm:uploadUpdatePG","uploadOk");
}
else
{
addErrorByKey("RUDForm:uploadUpdatePG","uploadKo");
}
}
}
我的想法是使用 <p:fileUpload>
中的 <f:attribute>
将正在编辑的模型项传递给控制器。
上传成功后(在方法uploadVersionUpdate中,由fileUploadListener
调用)属性 chemin模型项目更新为实际上传文件的名称。
我希望当用户单击复选标记(以验证更新)时,该行将显示 chemin 的新值。
上面的代码不是这种情况。
看起来 <p:rowEditor>
忽略了 fileUploadListener
所做的更改。有没有办法强制行编辑考虑 fileUploadListener 所做的更改?
PS:文件上传正常(配置良好),行版也正常,除了 chemin 属性.
截图:
修改前:
注意旧的 chemin 值:blabla13blabla.pdf
单击版本(铅笔)图标并选择要上传的新文件后:
成功上传新文件后:
请注意 chemin 属性 已更新:blabla12blabla.pdf.
验证版本后:单击复选标记图标:
请注意 chemin 属性 显示旧值:blabla13blabla.pdf.
Solution Found Here !
填充 dataTable 值的方法每次都在调用一个服务(反过来调用一个查询数据库的存储库)。
解决方案是仅当提供 dataTable 的列表为空时才转到数据库,从而转换以下内容:
public List<Version> rechercherToutVersion()
{
return(getVersionService().rechercherToutVersion());
}
进入:
private List<Version> allVersions;
public List<Version> getAllVersions() {
return allVersions;
}
public void setAllVersions(List<Version> allVersions) {
this.allVersions = allVersions;
}
...
public List<Version> rechercherToutVersion()
{
if (getAllVersions() == null)
{
setAllVersions(getVersionService().rechercherToutVersion());
}
return(getAllVersions());
}
这解决了我的问题,但即使从数据库访问的角度来看该解决方案更有效,我也不得不修改我的 saveVersion 和 deleteVersion 方法。事实上,因为行不是每次都从数据库中获取,所以当我在 dataTable 中删除一行时,删除的行仍然显示,如果我添加一个新项目,该项目是dataTable 中未显示:我必须刷新页面才能看到修改。
这个新问题的解决方案是 "manually" 从 allVersions 属性 中删除或添加一个项目,或者每次都将其重置为 null 删除 或 保存 完成。删除示例:
public void deleteVersion(Version version)
{
if (getVersionService().deleteVersion(version))
{
setAllVersions(null);
addInfoByKey("msgDeleteOk");
}
else
{
addErrorByKey("msgDeleteKo");
}
}
最后让我最沮丧的是:为什么在原始代码版本中,更新对其他属性工作得很好,但特别是 属性 绑定到文件上传?
我正在使用可编辑的 <p:dataTable>
,其中每个 <p:column>
包含一个 <p:cellEditor>
。我使用一个特定的 <p:column>
来表示用于存储文件名称(由用户上传)的模型项的 属性(我们称之为 chemin) ).对应的<p:cellEditor>
如下:
- 在
<f:facet>
中包含一个<p:fileUpload>
和一个<h:outputLink>
- out
<f:facet>
包含一个<h:outputLink>
我想执行以下操作:当用户单击 <p:rowEditor>
(铅笔图标)时,(1) 显示 <p:fileUpload>
,(2) 然后用户选择并上传文件(3) 当用户验证更新(通过单击复选标记)时,该列显示 link 到新上传的文件,这意味着当前模型项目已相应更新:chemin 属性 将包含新上传文件的名称。
下面的代码正确实现了步骤 (1) 到 (2),但步骤 (3) 不起作用。
Version.xhtml
<h:form id="RUDForm" enctype="multipart/form-data">
<p:dataTable
id="versionDT"
var="version"
value="#{versionController.rechercherToutVersion()}"
editable="true"
paginator="true"
rows="3"
dir="rtl"
style="width: 100%"
emptyMessage="#{messages.listeVide}">
<p:ajax event="rowEdit" listener="#{versionController.updateVersion(version)}" update=":RUDForm:versionDT" />
...
<p:column headerText="#{messages.chemin}">
<p:cellEditor>
<f:facet name="output">
<h:outputLink
id = "versionCheminLink"
value="#{versionController.relativeUploadUrl(version.chemin)}"
target="_blank"
rendered = "#{version.chemin != null}"
>
<h:outputText styleClass="title-text" value="#{version.chemin}"/>
</h:outputLink>
</f:facet>
<f:facet name="input">
<p:panelGrid
id="uploadUpdatePG"
dir="rtl"
>
<p:row>
<p:column>
<p:fileUpload
id = "versionChemin"
fileUploadListener="#{versionController.fileUploadListenerUpdate}"
mode="advanced"
dragDropSupport="false"
update=":RUDForm:versionDT:uploadUpdatePG"
fileLimit="1"
label="#{messages.unChoix}"
uploadLabel="#{messages.upload}"
cancelLabel="#{messages.annuler}"
invalidSizeMessage = "#{messages.invalidSizeMessage}"
invalidFileMessage = "#{messages.invalidFileMessage}"
sizeLimit="1000000"
>
<f:attribute name="version" value="#{version}" />
</p:fileUpload>
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLink
id = "versionCheminLinkReminder"
value="#{versionController.relativeUploadUrl(version.chemin)}"
target="_blank"
rendered = "#{version.chemin != null}"
>
<h:outputText styleClass="title-text" value="#{version.chemin}"/>
</h:outputLink>
</p:column>
</p:row>
</p:panelGrid>
</f:facet>
</p:cellEditor>
<p:message for="versionChemin"/>
</p:column>
...
<p:column style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
VersionController.java
@ManagedBean
@ViewScoped
public class VersionController extends GenericPageController implements Serializable
{
...
@ManagedProperty(value="#{versionServiceImpl}")
private VersionService versionService;
public VersionService getVersionService() {
return versionService;
}
public void setVersionService(VersionService versionService) {
this.versionService = versionService;
}
private UploadedFile file;
public UploadedFile getFile() {
return file;
}
public void setFile(UploadedFile file) {
this.file = file;
}
...
public void updateVersion(Version version)
{
if (getVersionService().updateVersion(version))
{
addInfoByKey("msgUpdateOk");
}
else
{
addErrorByKey("msgUpdateKo");
}
}
...
public void fileUploadListenerUpdate(FileUploadEvent event)
{
setFile(event.getFile());
uploadVersionUpdate((Version)event.getComponent().getAttributes().get("version"));
}
public void uploadVersionUpdate(Version version)
{
if ((getFile() != null) && (getFile().getSize() != 0))
{
version.setChemin(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + addZeros(new Random().nextInt(10),3) + getFile().getFileName());
upload(getFile(),version.getChemin());
addInfoByKey("RUDForm:uploadUpdatePG","uploadOk");
}
else
{
addErrorByKey("RUDForm:uploadUpdatePG","uploadKo");
}
}
}
我的想法是使用 <p:fileUpload>
中的 <f:attribute>
将正在编辑的模型项传递给控制器。
上传成功后(在方法uploadVersionUpdate中,由fileUploadListener
调用)属性 chemin模型项目更新为实际上传文件的名称。
我希望当用户单击复选标记(以验证更新)时,该行将显示 chemin 的新值。 上面的代码不是这种情况。
看起来 <p:rowEditor>
忽略了 fileUploadListener
所做的更改。有没有办法强制行编辑考虑 fileUploadListener 所做的更改?
PS:文件上传正常(配置良好),行版也正常,除了 chemin 属性.
截图:
修改前:
单击版本(铅笔)图标并选择要上传的新文件后:
成功上传新文件后:
验证版本后:单击复选标记图标:
Solution Found Here !
填充 dataTable 值的方法每次都在调用一个服务(反过来调用一个查询数据库的存储库)。 解决方案是仅当提供 dataTable 的列表为空时才转到数据库,从而转换以下内容:
public List<Version> rechercherToutVersion()
{
return(getVersionService().rechercherToutVersion());
}
进入:
private List<Version> allVersions;
public List<Version> getAllVersions() {
return allVersions;
}
public void setAllVersions(List<Version> allVersions) {
this.allVersions = allVersions;
}
...
public List<Version> rechercherToutVersion()
{
if (getAllVersions() == null)
{
setAllVersions(getVersionService().rechercherToutVersion());
}
return(getAllVersions());
}
这解决了我的问题,但即使从数据库访问的角度来看该解决方案更有效,我也不得不修改我的 saveVersion 和 deleteVersion 方法。事实上,因为行不是每次都从数据库中获取,所以当我在 dataTable 中删除一行时,删除的行仍然显示,如果我添加一个新项目,该项目是dataTable 中未显示:我必须刷新页面才能看到修改。
这个新问题的解决方案是 "manually" 从 allVersions 属性 中删除或添加一个项目,或者每次都将其重置为 null 删除 或 保存 完成。删除示例:
public void deleteVersion(Version version)
{
if (getVersionService().deleteVersion(version))
{
setAllVersions(null);
addInfoByKey("msgDeleteOk");
}
else
{
addErrorByKey("msgDeleteKo");
}
}
最后让我最沮丧的是:为什么在原始代码版本中,更新对其他属性工作得很好,但特别是 属性 绑定到文件上传?