如何以编程方式禁用 JSF 组件
How to disable JSF components programmatically
我们有一个带有 <rich:tab>
的 JSF 应用程序,它根据存储在数据库中的某些配置显示字段,因此组件未在 .xhtml 页面中定义,但必须以编程方式生成,如本例所示:
在面板中生成组件:
<rich:tab id="someTab" header="#{msg['someHeader']}" immediate="true">
<rich:messages/>
<h:panelGrid id="generatedComponentsContainer"/>
</rich:tab>
组件生成示例(为简单起见进行了简化):
FacesContext ctx = FacesContext.getCurrentInstance();
UIPanel panel = (UIPanel) ctx.getViewRoot().findComponent("someForm:generatedComponentsContainer");
text = (UIInput) ctx.getApplication().createComponent(ctx, "javax.faces.Input", "javax.faces.component.UIInput");
text.getAttributes().put("label", someLabel);
panel.getChildren().add(text);
根据某些情况,这些组件必须显示为禁用状态,因此如果需要,我使用以下代码禁用它们中的每一个:
if (!showEnabled) { text.getAttributes().put("disabled", "true"); }
此方法适用于 UIInput
和 HtmlInputTextarea
但不适用于 UICalendar
,抛出 IllegalArgumentException (argument type mismatch)
.
如何禁用日历?
我也一直想知道这段代码是否只是在客户端禁用了该组件,而在服务器端启用了它。这可能是一种安全威胁,因为有人可以通过 Javascript 启用组件并将表单提交到服务器。我不确定这是否可能,如果我错了请指教。
经过进一步研究,我注意到有一些 类 扩展了我们在项目中使用的那些。那些 类 有一个 getter/setter 的 disabled 属性,它也禁用服务器端的组件。我测试了这个以编程方式禁用组件并在浏览页面时删除禁用属性以允许编辑和提交。提交表单时,值在请求中设置但在服务器端被忽略。 Bean 值保持不变。
我们用过的类:
HtmlInputTextarea
而不是 UIInput
HtmlInputText
而不是 UIInput
我们已经在使用 UICalendar
,这符合目的
代码示例:
HtmlInputText text = (HtmlInputText) ctx.getApplication().createComponent(
ctx, HtmlInputText.COMPONENT_TYPE, "javax.faces.component.html.HtmlInputText");
if (!showEnabled) { text.setDisabled(true); }
调试 HtmlInputText
的内容时,您可以看到一个 ComponentStateHelper
对象(名为 stateHelper
),它存储组件的禁用状态(以及其他数据)。它的超级接口是 StateHolder
:
public interface StateHolder
This interface is implemented by classes that need to save their state
between requests.
我知道组件的服务器端状态存储在这个对象中,但我不确定它是只存储在这里还是存储在更多点,甚至我对其用途的解释是否正确。来自专家的反馈将非常有用。
我们有一个带有 <rich:tab>
的 JSF 应用程序,它根据存储在数据库中的某些配置显示字段,因此组件未在 .xhtml 页面中定义,但必须以编程方式生成,如本例所示:
在面板中生成组件:
<rich:tab id="someTab" header="#{msg['someHeader']}" immediate="true">
<rich:messages/>
<h:panelGrid id="generatedComponentsContainer"/>
</rich:tab>
组件生成示例(为简单起见进行了简化):
FacesContext ctx = FacesContext.getCurrentInstance();
UIPanel panel = (UIPanel) ctx.getViewRoot().findComponent("someForm:generatedComponentsContainer");
text = (UIInput) ctx.getApplication().createComponent(ctx, "javax.faces.Input", "javax.faces.component.UIInput");
text.getAttributes().put("label", someLabel);
panel.getChildren().add(text);
根据某些情况,这些组件必须显示为禁用状态,因此如果需要,我使用以下代码禁用它们中的每一个:
if (!showEnabled) { text.getAttributes().put("disabled", "true"); }
此方法适用于 UIInput
和 HtmlInputTextarea
但不适用于 UICalendar
,抛出 IllegalArgumentException (argument type mismatch)
.
如何禁用日历?
我也一直想知道这段代码是否只是在客户端禁用了该组件,而在服务器端启用了它。这可能是一种安全威胁,因为有人可以通过 Javascript 启用组件并将表单提交到服务器。我不确定这是否可能,如果我错了请指教。
经过进一步研究,我注意到有一些 类 扩展了我们在项目中使用的那些。那些 类 有一个 getter/setter 的 disabled 属性,它也禁用服务器端的组件。我测试了这个以编程方式禁用组件并在浏览页面时删除禁用属性以允许编辑和提交。提交表单时,值在请求中设置但在服务器端被忽略。 Bean 值保持不变。
我们用过的类:
HtmlInputTextarea
而不是 UIInput
HtmlInputText
而不是 UIInput
我们已经在使用 UICalendar
,这符合目的
代码示例:
HtmlInputText text = (HtmlInputText) ctx.getApplication().createComponent(
ctx, HtmlInputText.COMPONENT_TYPE, "javax.faces.component.html.HtmlInputText");
if (!showEnabled) { text.setDisabled(true); }
调试 HtmlInputText
的内容时,您可以看到一个 ComponentStateHelper
对象(名为 stateHelper
),它存储组件的禁用状态(以及其他数据)。它的超级接口是 StateHolder
:
public interface StateHolder
This interface is implemented by classes that need to save their state between requests.
我知道组件的服务器端状态存储在这个对象中,但我不确定它是只存储在这里还是存储在更多点,甚至我对其用途的解释是否正确。来自专家的反馈将非常有用。