将初始化参数从 JSF 视图传递到后台的托管 bean

Pass initialization argument from JSF view to managed bean in background

我是 JSF 的新手,正在努力将数据传递给我的支持 bean。我有一个 bean 应该读取数据并将其保存到一个特定的 table。此 table 有两列 "Property" 和 "Val"。 class 的简化版本如下所示:

@ManagedBean
@SessionScoped
 public class GlobalProperties implements Serializable {

    // private void setKey(param);
    // private String getKey();      
    // some more attributes and getters / setters
    private String property; // + getter/setter    

    private void saveProperty() throws SQLException {
        try {
            dbHandler = dbConnection.connect();
            ps = dbHandler.prepareStatement("UPDATE TABLEXXX SET VAL = '" + getValue() + "' WHERE PROPERTYKEY = '" + getProperty() + "'");
            ps.executeQuery();
            } catch (SQLException ex) {
            Logger.getLogger(GlobalProperties.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
            if (dbHandler != null) {
                dbHandler.close();
            }
        }        
    }

    private void readProperty() throws SQLException {
        try {
            dbHandler = dbConnection.connect();
            ps = dbHandler.prepareStatement("SELECT VAL FROM TABLEXXX WHERE PROPERTYKEY = '" + getProperty() + "'");
            rs = ps.executeQuery();
            while (rs.next()) {
                setValue("VAL");
            }
        } catch (SQLException ex) {
            Logger.getLogger(GlobalProperties.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (dbHandler != null) {
                dbHandler.close();
            }
        }    
    }        
}

此 class 已在多个页面上使用。在每个使用它的页面上,它需要为 属性 属性填充不同的值,因为我必须从 table 读取不同的键。在 JSF 端有一个文本输入,它显示值并在用户单击保存按钮时设置它。

每当创建此 class 的实例时,我都需要向 class 传递有关它必须读取的键的信息。但是我无法在 JSF 端找到合适的机制来实现这一点,因为它非常重要,用户不能更改该值。

我最后一次尝试是像这样使用 "preRenderView"-事件:

  <f:metadata>
        <f:event type="preRenderView" listener="#{globalProperties.setKey('SYSTEM_NAME')}" />
    </f:metadata>

这样对吗?

在后台的 ManagedBean 中设置 属性 的最佳做法是什么,无需任何用户操作并且以安全的方式,以便它不能被用户操纵?

谢谢大家。

<f:event type="preRenderView"> 在每次请求时被调用。这对于请求作用域 bean 可能没问题,但对于 view/session 作用域 bean 则不必要。另见 What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

另一方面,虽然 preRenderView 方法可行,但 JSF 视图应该是声明式的。模型(这个特定视角中的支持 bean)实际上应该根据视图执行初始化,而不是相反。所以当你对此有疑问时,你的直觉是正确的。

JSF 对此没有专门的方法。最接近的声明方法是在 <f:metadata> ("define a metadata attribute on the view").

中使用 <f:attribute>
<f:metadata>
    <f:attribute name="key" value="SYSTEM_NAME" />
</f:metadata>

UIViewRoot#getAttributes() 在 a.o @PostConstruct:

String key = (String) context.getViewRoot().getAttributes().get("key");

或者当你碰巧使用 OmniFaces:

String key = Faces.getMetadataAttribute("key");

OmniFaces 展示应用程序也使用这种方法来声明文档和源代码的路径(参见示例 /push/socket.xhtml source of <o:socket> showcase)。

另一种方法是通过视图 ID 在应用程序范围内映射键,并改为依赖视图 ID。

Map<String, String> keysByViewId = new HashMap<>();
keysByViewId.put("/foo.xhtml", "SYSTEM_NAME");

String key = keysByViewId.get(context.getViewRoot().getViewId());