作为Grails应用程序功能的一部分,是否允许编辑GSP(包括布局)?

作为Grails应用程序功能的一部分,是否允许编辑GSP(包括布局)?,grails,content-management-system,gsp,Grails,Content Management System,Gsp,我正在一个Grails站点上工作,尽管它需要包含大量类似CMS的功能,但由于各种原因,还没有作为实际CMS安装的一部分进行构建。我需要允许用户做的一件事是编辑HTML布局——在Grails应用程序中,HTML布局在GSP文件中——以及不同页面的其他通常静态元素,这些元素既不会绑定到任何特定的域对象,也不会形成处理域对象的CRUD页面的任何部分 我知道这两种情况,而且可以从应用程序中的某个地方写入正在运行的应用程序中的实际文件。我还知道,如果我这样做的话,可能需要非常小心,以确保用户不会太严重地破

我正在一个Grails站点上工作,尽管它需要包含大量类似CMS的功能,但由于各种原因,还没有作为实际CMS安装的一部分进行构建。我需要允许用户做的一件事是编辑HTML布局——在Grails应用程序中,HTML布局在GSP文件中——以及不同页面的其他通常静态元素,这些元素既不会绑定到任何特定的域对象,也不会形成处理域对象的CRUD页面的任何部分


我知道这两种情况,而且可以从应用程序中的某个地方写入正在运行的应用程序中的实际文件。我还知道,如果我这样做的话,可能需要非常小心,以确保用户不会太严重地破坏页面的整个布局和内容,我准备处理这个问题。但允许用户编辑用于创建Grails页面的布局和其他GSP文件吗?如果是这样,我该怎么做呢?

一种简单的方法是将HTML块作为域对象存储在数据库中。然后,您的视图可以自动拉入html。可以创建一个简单的界面,允许用户编辑html。关于这方面的更多讨论,请参见另一种可能的选择,即使用

,而不是将类似cms的功能集成到Grails应用程序中,虽然可能,但我看到了不同的方法

一种方法是将CMS放在一边,并确保其能够:

  • 在转换过程后读取gsp,通常是自动或计划的作业

  • 生成Grails应用程序使用的gsp文件。在这种情况下,如您所述,可以替代视图位置

为了避免我所描述的方法出现严重的UI问题或CMS限制,您不会使用布局。CMS供应商提供导入/导出GSP文件的模块,如果不是,则由您自己编写该层


希望有帮助,祝你好运。

版面也是gsp视图,根据定义,它负责处理动态视图内容

但是,直接编辑gsp文件并在运行时编译它们并不是一个好的做法

相反,您可以定义一个域类,其中自定义内容被持久化并从预定义的gsp布局加载

具体而言,您可以定义类似以下域类的内容来保存自定义web元素:

class Module {
    Integer positionLeft
    Integer positionTop
    Integer width
    Integer height
    String  className   //CSS class
    String  border      
    String  borderColor 
    Integer borderSize  
    Integer seq
    String  content
    String  type
    static  hasMany = [components: Component]        //inner elements within a module
    Module  parentModule                    //support nested module structure to ensure flexibility
    User    owner
}

class Component {
    String title
    String content
    String methodName
    String url
    String type     //I-image,A-attachment,L-external link,T-text,G-graph report,D-data table,R RSS FEED...
    String font
    String fontFamily
    String fontBold
    String fontUnderline
    String color    
    String textAlign
    String source      //uri -- enables ajax call to some method to get dynamic data
    Integer seq
}
通过客户端javascript,该应用程序可以方便地使用户通过拖动、调整大小、从一些菜单中选择不同的元素类型以及提交给执行这些元素CRUD操作的后端控制器来生成定制视图

然后在布局中,逐个渲染这些自定义元素:

<%@ page import="com.app.Module" %>
<g:each in="${Module.findAllByOwnerAndParentModuleIsNull(session.user,[fetch:[components:'join']]).collect {[
            id:it.id,
            posLeft:it.posLeft,
            posTop:it. posTop,
            width:it.width,
            height:it.height,
            className:it.className,
            border:it.border,
            borderColor:it.borderColor,
            borderSize:it.borderSize,
            seq:it.seq,
            content:it.content,
            type:it.type,
            components:it.components,
            innerModules:Module.findAllByParentModule(it)
        ]}}" var="module" status="i">
    <div class="${module.className?module.className:''}" style="position: absolute; left: ${module.posLeft}px; top: ${module.posTop}px; width: ${module.width}px; height: ${module.height}px; border: ${module.borderColor} ${module.borderSize?(module.borderSize+'px'):''} ${module.border};">
        <g:each in="${module.innerModules}" var="inner">  
             <div class="${inner.className?inner.className:''}"  style="position: absolute; left: ${inner.posLeft-module.posLeft}px; top: ${inner.posTop-module.posTop}px; width: ${inner.width}px; height: ${inner.height}px; border: blue 1px solid;">
                  <g:render template="/home/module" model="[
                      module: inner
                  ]"/>
            </div>
        </g:each> 
        <g:render template="/home/module" model="[
             module: module
        ]"/>
    </div>
</g:each>


通过这种方式,每个用户都可以管理其个性化布局。

如果您将模板/布局存储在数据库中(正如上面一些人所建议的),您可以 使用GroovyPagesTemplateEngine渲染它:

package com.mycompany

import groovy.text.Template;
import org.codehaus.groovy.grails.web.pages.GroovyPagesTemplateEngine 

class TemplatingService {
  GroovyPagesTemplateEngine groovyPagesTemplateEngine

  def render(String templateString, Map model) {
    ByteArrayInputStream bais = new ByteArrayInputStream(templateString.getBytes());
    Template template = groovyPagesTemplateEngine.createTemplate(bais)

    try {
      def writer = new StringWriter()
      template.make(model).writeTo(writer)
      return writer.toString()
    } catch (Exception e) {
      // handle exception
      return ""    // or "[an error occurred]" or rethrow the exception
    }
  }
}
现在,当你能够做到这一点时,请务必考虑其中的含义。您可以在gsp中执行的任何内容都可以在此上下文中执行。比如写入、删除文件、执行命令等

我从未想过如何利用SecurityManager来限制模板中可以执行的操作,因此我的解决方案是不允许用户将模板输入数据库。如果我想要一个新模板,我会在检查了它的安全性后,自己把它放在那里


您还可以通过缓存
createTemplate()
的结果来提高性能,以避免每次重新编译它。

在Grails下呈现GSP文件的正确方法是使用Grails的GSP bean。使用此功能,您可以访问所有标记库功能。以下是my Grails插件中处理GSP文件的一个片段:

GroovyPagesTemplateEngine gsp = (GroovyPagesTemplateEngine)appCtx.getBean(GROOVY_PAGES_TEMPLATE_ENGINE);
Template template = gsp.createTemplate(new ByteArrayResource(bufferStr.getBytes(encoding)), false);
Writable w = template.make();
StringWriter sw = new StringWriter();
w.writeTo(new PrintWriter(sw));