【问题标题】:How to access controller dynamic properties within a base controller's constructor in Grails?如何在 Grails 的基本控制器的构造函数中访问控制器动态属性?
【发布时间】:2010-06-15 22:35:21
【问题描述】:

基本上,我希望能够将在过滤器中创建的对象分配给每个控制器扩展的基本控制器中的成员。有什么可能的方法吗?

这是我尝试过的方法,但还没有成功。

我想要实现的是让我的所有控制器都扩展一个基本控制器。基本控制器的构造函数将用于为其成员分配值,这些值是从 session 映射中提取的。下面的例子。

文件 grails-app/controllers/HomeController.groovy:

class HomeController extends BaseController {
    def index = {
        render username
    }
}

文件 grails-app/controllers/BaseController.groovy:

abstract class BaseController {
    public String username

    public BaseController() {
        username = session.username
    }
}

运行应用程序时,显示的输出为:

2010-06-15 18:17:16,671 [main] ERROR [localhost].[/webapp]  - Exception sending context initialized event to listener instance of class org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
    ...
Caused by: java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
    ...
Caused by: java.lang.reflect.InvocationTargetException
    ...
Caused by: org.codehaus.groovy.grails.exceptions.NewInstanceCreationException: Could not create a new instance of class [com.my.package.controller.HomeController]!
    ...
Caused by: groovy.lang.MissingPropertyException: No such property: session for class: com.my.package.controller.HomeController
    at com.my.package.controller.BaseController.<init>(BaseController.groovy:16)
    at com.my.package.controller.HomeController.<init>(HomeController.groovy)
    ...
2010-06-15 18:17:16,687 [main] ERROR core.StandardContext  - Error listenerStart
2010-06-15 18:17:16,687 [main] ERROR core.StandardContext  - Context [/webapp] startup failed due to previous errors

应用程序将无法运行。

这只是一个示例,因为在我的情况下,我不想将用户名分配给字符串值,而是从 session 映射中提取的一些对象。从 session 映射中提取的对象正在过滤器中设置。

我看到的替代方法是能够在过滤器的执行中访问控制器的实例。这可能吗?

请帮忙!非常感谢!

【问题讨论】:

    标签: model-view-controller groovy grails grails-controller


    【解决方案1】:

    您通常不能在 Grails 工件的构造函数中做很多事情。不过,您可以为此使用拦截器:

    abstract class BaseController {
       protected String username
    
       def beforeInterceptor = {
          username = session.username
       }
    }
    

    这在http://grails.org/doc/latest/ 的第 6.1.5 节中有描述

    【讨论】:

    • 感谢您的回答!问题是当一个具体的控制器(HomeController)自己定义一个 beforeInterceptor 时,BaseController 的 beforeInterceptor 不会被调用。尝试通过具体控制器编译使用“super.beforeInterceptor()”调用它,但在运行时抛出:org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.StackOverflowError at java.lang.Thread.run(Thread. java:619) 引起:com.my.package.controller.HomeController$_closure1.doCall(HomeController.groovy) 处的 java.lang.StackOverflowError ... 有什么办法可以解决这个问题吗?谢谢!
    • 由于是闭包,super.beforeInterceptor() 不能工作。但是你可以让拦截器委托给一个可以被覆盖的真实方法: def beforeInterceptor = { prepareCall() } protected void prepareCall() { username = session.username }
    【解决方案2】:

    您可以使用请求范围的服务...

    【讨论】:

      【解决方案3】:

      作为一项规则,我会告诫不要将状态直接放在控制器中;一般来说,控制器(无论框架如何)通常都是无状态的。我会坚持使用标准的 webapp 状态构造,例如请求和会话来存储和传输数据。

      对于您的具体情况,我会执行以下操作之一:

      • 如果是轻量级数据(基元),我会将它们存储在会话中,然后根据需要访问它们:
        例如渲染 session.username

      • 如果是动态或数据库驱动的数据,我会创建一个服务并根据需要提取数据: 例如homeService.getUser().用户名

      • 作为上述与 Burt 讨论的变体,您也可以使用过滤器来填充请求或会话值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-29
        • 2010-11-03
        • 1970-01-01
        • 1970-01-01
        • 2017-05-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多