【问题标题】:Alternative for profile document配置文件的替代方案
【发布时间】:2017-05-23 05:07:50
【问题描述】:

我正在关注article,它告诉我们如何存储全局参数,以及配置文件如何为经典的 Notes 应用程序工作。我按照文章的步骤并根据必要的全局参数实现了类,但是当我调用 javascript 对象的方法时,会发生以下错误。我有点困惑,因为在应用程序的其他地方调用相同的方法可以正常工作。下面是 javascript 对象的代码,作为文章中的示例实现。

脚本解释器错误,line=12,col=21:[TypeError] 在“java.util.HashMap [Dynamic Java Wrapper, java.util.HashMap]”类型的对象上调用方法“getDbRH()”时出错

var dbFotoConfig = { 

getDbFoto : function ( ) { 

    var cache = this. getCacheObject ( ) ; 

    var result = cache.get( "DbFoto" ) ; 

    if (result == null ) {

        // Here is where you would do @DBSomething or worse
        var visao:NotesView=database.getView("Configuracoes")
        var doc:NotesDocument=visao.getFirstDocument();
        if (doc!=null)
        {

            result=  [doc.getItemValueString("servidor_foto"),doc.getItemValueString("base_foto"),doc.getItemValueString("visao_foto")]
            cache.put("DbFoto",result)
             sessionScope.put ( "dbFotoConfig" ,cache )
        }
        else
        {

        cache.put("DbFoto",null)
         sessionScope.put ( "dbFotoConfig" ,null )
        }           

    } 

    return result ; 
} , 


    /* Here would be much more of these functions */ 


    /* Utility functions for cache management */ 

/* Retrieves the configuration object from a cache store. 
   There are many ways to do that */ 
getCacheObject : function ( ) { 
    // Consider carefully where to cache. Typical places 
    // are sessions or applications 
    var curCache = sessionScope. get ( "dbFotoConfig" ) ; 
    if (curCache == null ) { 
        curCache = new java. util. HashMap ( ) ; 
        sessionScope. put ( "dbFotoConfig" ,curCache ) ; 
    } 

    return curCache ;     
} , 

/* Resets the cache */ 
reset : function ( ) { 
    var curCache = new java. util. HashMap ( ) ; 
    sessionScope. put ( "dbFotoConfig" ,curCache ) ; 
} 
}
var dbRHConfig = {

getDbRH : function ( ) { 

var cache = this. getCacheObject ( ) ;

var result = cache. get ( "DbRH" ) ;

if (result == null ) {

    // Here is where you would do @DBSomething or worse
    var visao:NotesView=database.getView("Configuracoes")
    var doc:NotesDocument=visao.getFirstDocument();
    if (doc!=null)
    {

        result=[doc.getItemValueString("servidor_RH"),doc.getItemValueString("base_RH"),doc.getItemValueString("visao_RH")]
        cache.put("DbRH",result)
         sessionScope.put ( "dbRHConfig" ,cache )
    }
    else
    {

        cache.put("DbRH",null)
     sessionScope.put ( "dbRHConfig" ,null )
    }


} 

return result ; 
} , 


/* Here would be much more of these functions */ 


/* Utility functions for cache management */ 

/* Retrieves the configuration object from a cache store. 
There are many ways to do that */ 
getCacheObject : function ( ) { 
// Consider carefully where to cache. Typical places 
// are sessions or applications 
var curCache = sessionScope. get ( "dbRHConfig" ) ; 
if (curCache == null ) { 
    curCache = new java. util. HashMap ( ) ; 
    sessionScope. put ( "dbRHConfig" ,curCache ) ; 
} 

return curCache ;     
} , 

/* Resets the cache */ 
reset : function ( ) { 
var curCache = new java. util. HashMap ( ) ; 
sessionScope. put ( "dbRHConfig" ,curCache ) ; 
} 
}

【问题讨论】:

    标签: javascript xpages profile


    【解决方案1】:

    我的首选选项是创建一个普通文档,保存它,然后调用setUniversalID() 使用session.evaluate("@Password(\"whateverYouWant\")") 将其更改为自定义内容。 @Password 将值散列为 32 个字符的十六进制字符串(即有效的 UNID)。这使您可以使用Database.getDocumentByUnid() 轻松检索文档(普通文档,因此避免了配置文件文档的缓存问题),这是访问文档的最快方法之一。如果您想避免每次都计算它,可以将“UNID”存储在 applicationScope 变量中。

    【讨论】:

    • 但那会怎样呢?创建文档时调用函数 setUniversalID() 使用作为参数 session.evaluate("@Password(\"whateverYouWant\"))。会是这样吗?访问文档使用 Database.getDocumentByUnid()。一个问题,做您建议将 UNID 存储在会话变量中,对吗?要存储,我将不得不使用公式 session.evaluate ("@Password (\"whateverYouWant \")"),对吗?它总是会带来相同的值吗?论据?
    • 如何确定您的哈希值不会与另一个已经存在的文档冲突?
    【解决方案2】:

    请,请,不要那样做。忘掉 SSJS 并尽可能多地使用 XPages:IBM Domino 风格的 JSF 框架实现。

    首先,您需要确定您希望配置保留多长时间,以及它是否对每个用户都相同。

    如果每次使用都相同,那么您可以做的最好的事情是将其存储在 application scoped bean 中。应用程序范围与每个用户共享,实例化一次并持续整个应用程序的生命周期。

    会话范围 bean 保留在当前用户中,并且只有当前用户可见。

    托管 bean 的生命是由框架管理的。该框架负责在应用程序中的任何位置引用它时对其进行实例化。它由您在 XPage 应用程序的 faces-config.xml 文档中配置时决定的变量名称分发。

    <managed-bean>
        <managed-bean-name>app</managed-bean-name>
        <managed-bean-class>demo.bean.ApplicationBean
        </managed-bean-class>
        <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>
    

    ma​​naged-bean-name 声明了你的 bean 可用的变量名。 ma​​naged-bean-scope 表示 bean 的寿命。

    现在你需要做的是在 demo.bean 包下创建一个名为 ApplicationBean 的 Java 类(这就是上面示例中的内容,你可以将它命名为您喜欢的任何名称)。 从您命名变量的方式来看,在我看来,您需要更多的应用程序范围 bean,而不是会话 bean。因此,为了便于交流,我编写了一个示例,说明您在上面发布的代码中应用程序 bean 的样子

    package demo.bean;
    
    import java.io.Serializable;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.faces.FacesException;
    
    import lotus.domino.Document;
    import lotus.domino.NotesException;
    import lotus.domino.View;
    
    import com.ibm.xsp.model.domino.DominoUtils;
    
    public class ApplicationBean implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        // Just a way to do it without repeating the same lines over and over
        private static final String[] CONFIG_FIELD_PREFIXES = { "servidor", "base", "visao" };
    
        private Map<String, String> dbFoto;
        private Map<String, String> dbRh;
    
        public Map<String, String> getDbFoto() {
            if (dbFoto == null) {
                loadConfig();
            }
    
            return dbFoto;
        }
    
        public Map<String, String> getDbRh() {
            if (dbRh == null) {
                loadConfig();
            }
    
            return dbRh;
        }
    
        private void loadConfig() {
            dbFoto = new HashMap<String, String>();
            dbRh = new HashMap<String, String>();
    
            try {
                View vw = DominoUtils.getCurrentDatabase().getView("Configuracoes");
                Document doc = vw.getFirstDocument();
    
                if (doc != null) {
                    for (String fieldName : CONFIG_FIELD_PREFIXES) {
                        dbFoto.put(fieldName, doc.getItemValueString(fieldName + "_foto"));
                        dbRh.put(fieldName, doc.getItemValueString(fieldName + "_RH"));
                    }
                }
            } catch (NotesException e) {
                throw new FacesException(e.getMessage(), e);
            }
        }
    
        public void reset() {
            dbFoto = null;
            dbRh = null;
        }
    
    }
    

    那里有几个概念。希望我不会用太多的东西淹没你。但简单解释一下:首先,bean 大部分时间都在延迟加载中工作,这意味着您不会在创建它们时预加载数据,而是让类在外部源调用其方法时填充。第一次调用该方法时,它会加载并缓存数据(您不必担心它的持久性,因为请记住,这是由框架保证的,其生命周期在faces-config.xml 中确定)。第二次调用该方法时,它将提供缓存数据(您在类开头声明的 Map 对象中看到的内容)。考虑到您从同一个地方加载 2 个数据库配置的事实,一次加载两个数据库配置而不是在不同时间延迟加载它们的成本更低 - 这就是我编写私有方法 loadConfig 的原因。

    现在发生的情况是配置存储在地图中,并且由于 EL 表达式,您可以以简洁的方式从此类地图中读取数据。 如果您使用以下代码创建 XPage,您将看到页面上的所有内容都活跃起来:

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    
        <xp:text value="#{app.dbFoto.servidore} #{app.dbFoto.base} #{app.dbFoto.visao}" />
    
        <xp:text value="#{app.dbHr.servidore} #{app.dbHr.base} #{app.dbHr.visao}" />
    
        <xp:button id="button1" value="reset">
            <xp:eventHandler event="onclick" submit="true"
                refreshMode="complete" action="#{app.reset}" />
        </xp:button>
    
    </xp:view>
    

    app 是我们的 bean 名称 dbFoto / dbHr 是我们对 Map&lt;String, String&gt; getDbFoto( / Map&lt;String, String&gt; getDbHr( 的调用(get 被删除并且第一个字母小写,这是要遵守的约定),每个名称都是访问地图值的键。

    我还提供了一个帮助方法来清除配置以备不时之需:reset()。它只是取消了 2 个变量,因此在第一次再次询问时会再次获取这些变量。

    【讨论】:

    • 非常感谢!我会努力实现的。