动态页面的eXist-db URL映射

时间:2018-10-24 11:54:09

标签: exist-db

我的eXist-db应用程序中有许多动态页面,到目前为止,这些页面已经通过硬编码输入进行了测试。现在,我必须冒险进入最不适应的域:eXist-db中的URL映射/重写。

这是基本方案。当用户想要在我的网站上查看中世纪文档时,他们可以搜索列表并单击链接,也可以直接输入URL。无论如何,该网址将是:

www.foo.com/doc/MS609-0020

/ doc /表示您正在查看文档,而MS609-0020实际上是文档的名称(反映了XML文件,即MS609-0020.xml)。

所有此类文档将通过位于以下位置的通用页面输出:

/db/apps/deheresi/document.html

document.html包含一些模板,这些模板需要来自请求的文档名称MS609-0020.xml才能知道要处理的内容。我已将此全局可用变量命名为$currentdoc。使用此变量,不同的模板将获得组装document.html所需的数据。

然后将HTML发送到www.foo.com/doc/MS609-0020下的浏览器

如果找不到文档名称,则将用户定向到“找不到文档页面”。

如您所见,我的解释是基本的-反映了我仍然使用eXist和XQuery进行培训的事实。

我已经阅读了Siegel / Retter的eXist书中的各章,但是如何在模块中完成重新映射,以及如何与必需的parameters一起传递...无论我受到多少黑客攻击,对于我来说都不是一件好事通过这个。

对于从伪代码和指令到某些摘要的任何指导,我将深表感谢。一旦我知道如何处理这个请求,然后作为实践我就会将其汇总。

非常感谢。

注意:我要补充一点,这将是一个公共站点,不需要查看文档的权限。

NB 2:一旦符合条件,我将悬赏这个问题。

下面是Siegel / Retter的书中的图表。

Diagram from Siegel/Retter

1 个答案:

答案 0 :(得分:1)

此答案仅涵盖基本的URL重写,并假定eXist应用程序是使用我称之为“基本” eXist应用程序体系结构构建的:

  • 该应用程序(我们称为“ my-app”)存储在/db/apps/my-app中。
  • 未对EXIST_HOME/tools/jetty/etc中的Jetty配置文件,EXIST_HOME/webapp/WEB-INF/web.xml中的XQuery servlet配置文件或在webapp/WEB-INF/controller-config.xml处eXist的URL重写的基本配置进行修改。
  • 这意味着可以在http://localhost:8080/exist/apps/my-app上访问该应用程序。 (如果目标是通过http://my-server/之类的URL为该应用程序提供服务,并将其路由到http://localhost:8080/exist/apps/my-app处的eXist,则最好由反向代理服务器处理,这超出了“基本”范围eXist应用架构。)
  • 我们将通过eXist的URL重写工具(即写入controller.xql文件)而非RESTXQ来处理URL重写。

基于这些假设,我们可以创建完全自定义的URL,使我们可以采用以下URL:

  • http://localhost:8080/exist/apps/my-app/doc.xq?filename=my-document.xml

并通过以下方式提供相同的资源:

  • http://localhost:8080/exist/apps/my-app/doc/my-document

要完成此操作,我们需要在您应用的根集合中创建一个名为controller.xql的新XQuery主模块(必须完全称为它,我们将其称为应用的“控制器”)。 :/db/apps/my-app/controller.xql。这是一个特殊的模块,当请求到达/apps URL空间中的路径(例如http://localhost:8080/exist/apps/...)时,eXist首先寻找该模块。通常,一个应用程序只有一个控制器,而eXist支持多个控制器。 eXist会查看目标集合,然后从最深的分支一直到根/db/apps集合,再向上查看集合树。

控制器的目的是获取有关请求的信息(所请求的路径以及有关应用程序上下文的其他信息),并返回一种特殊的指令,该指令告诉eXist如何路由请求。有关请求的关键信息通过一系列外部变量(您不必为您定义eXist集且您可以引用的变量)向您的查询公开,包括,最重要的是, $exist:path-请求URL中位于包含控制器的集合路径之后的部分。因此,在上面的URL中,$exist:path等于/doc/my-document

现在,让我们创建一条指令,该指令采用此路径并将请求转发(与filename参数一起使用到您的实际端点:

xquery version "3.1";

declare variable $exist:path external;
declare variable $exist:resource external;
declare variable $exist:controller external;
declare variable $exist:prefix external;
declare variable $exist:root external;

if (starts-with($exist:path, "/doc/")) then
    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
        <forward url="{$exist:controller}/doc.xq">
            <add-parameter name="filename" value="{$exist:resource}.xml"/>
        </forward>
    </dispatch>

else
    <ignore xmlns="http://exist.sourceforge.net/NS/exist"/>

在第一段代码(序言)中,此控制器显式声明eXist提供给控制器的变量。在查询的主要部分,条件表达式处理两种情况:

  1. 如果请求的路径以/doc/开头,那么我们希望通过doc.xq处理请求-/db/apps/my-app/doc.xq中应用程序中的XQuery模块。除了键入完整路径之外,我们可以将/db/apps/my-app替换为$exist:controller-这是找到活动控制器的集合的数据库路径。我们也知道doc.xq需要一个filename参数,因此我们从$exist:resource变量中显式构造该变量,该变量始终为我们提供最后斜杠后的请求网址部分-例如, my-document在上面的示例网址中。从控制器将请求转发到的查询的角度(例如doc.xq),它认为控制器已直接接收到请求,并且可以通过request:get-parameter()函数访问请求参数。例如,doc.xq可以仅包含:

    xquery version "3.1";
    
    let $doc := request:get-parameter("filename", ())
    return
        <p>Who's looking for {$filename}?</p>
    

    对上述URL的请求将返回<p>Who's looking for my-document.xml?</p>

  2. 对于其他任何请求,我们将在不执行任何转发或其他URL操作的情况下让它们通过。

如果您使用的是eXist的HTML模板功能,则可能会将请求转发到模板(document.html),而不是查询(doc.xq)。在这种情况下,该指令变得更复杂了

    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
        <forward url="{$exist:controller}/document.html"/>
        <view>
            <forward url="{$exist:controller}/modules/view.xql">
                <add-parameter name="filename" value="{$exist:resource}.xml"/>
            </forward>
        </view>
    </dispatch>

在这里,我们将请求转发到document.html,但是结果通过eXist的模板处理程序模块传递,该模块通常存储在应用程序的modules/view.xql文件中。 (请注意,<add-parameter>指令已移至第二个<forward>指令。)

eXist文档的URL页面上描述了其他外部变量(即$exist:root$exist:prefix)和其他类型的指令(即<redirect>和其他子元素)重写http://exist-db.org/exist/apps/doc/urlrewrite。尽管该页面当前警告它已过时,但我认为它仍然是一个很好的资源。

eXist的URL重写功能的强项是您可以使用XQuery的完整表达能力来确定应用程序如何路由和接收URL。缺点是,控制器可能会变成一连串的条件条件,难以维护。只要尝试使控制器逻辑尽可能简单即可。学习外部变量也可能需要一些时间。我建议充分利用日志记录(通过util:logconsole:log函数来输出外部变量的值以及有关请求的其他信息,可以通过request:get-url()和其他request:get-*个函数)查看每个请求的处理情况,直到您掌握了它。您可能还会发现,在可用源代码的其他应用程序中调查控制器文件,并在此处提出更多问题会很有帮助!