Reading out all actions in a Grails-Controller

2019-02-09 20:28发布

I need to read out all available actions from any controller in my web-app. The reason for this is an authorization system where I need to give users a list of allowed actions.

E.g.: User xyz has the authorization for executing the actions show, list, search. User admin has the authorization for executing the actions edit, delete etc.

I need to read out all actions from a controller. Does anyone has an idea?

4条回答
闹够了就滚
2楼-- · 2019-02-09 21:12

To print out a list of all the methods with action names:

   grailsApplication.controllerClasses.each {
               it.getURIs().each {uri ->
                 println  "${it.logicalPropertyName}.${it.getMethodActionName(uri)}"
               }
   }
查看更多
小情绪 Triste *
3楼-- · 2019-02-09 21:26

Here's an example that works with Grails 2, i.e it will capture actions defined as either methods or closures

import org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
import java.lang.reflect.Method
import grails.web.Action

// keys are logical controller names, values are list of action names  
// that belong to that controller
def controllerActionNames = [:]

grailsApplication.controllerClasses.each { DefaultGrailsControllerClass controller ->

    Class controllerClass = controller.clazz

    // skip controllers in plugins
    if (controllerClass.name.startsWith('com.mycompany')) {
        String logicalControllerName = controller.logicalPropertyName

        // get the actions defined as methods (Grails 2)
        controllerClass.methods.each { Method method ->

            if (method.getAnnotation(Action)) {
                def actions = controllerActionNames[logicalControllerName] ?: []
                actions << method.name

                controllerActionNames[logicalControllerName] = actions
            }
        }
    }
}
查看更多
老娘就宠你
4楼-- · 2019-02-09 21:29

Grails does not support a straightforward way to do this. However, I was able to put together a puzzle from available grails methods and have come to this solution:

def actions = new HashSet<String>()
def controllerClass = grailsApplication.getArtefactInfo(ControllerArtefactHandler.TYPE)
                         .getGrailsClassByLogicalPropertyName(controllerName)
for (String uri : controllerClass.uris ) {
    actions.add(controllerClass.getMethodActionName(uri) )
}

Variables grailsApplication and controllerName are injected by grails. As controller itself does not have necessary methods, this code retrieves its controllerClass (see GrailsControllerClass), which has what we need: property uris and method getMethodActionName

查看更多
家丑人穷心不美
5楼-- · 2019-02-09 21:30

This will create a List of Maps (the 'data' variable) with controller information. Each element in the List is a Map with keys 'controller', corresponding to the URL name of the controller (e.g. BookController -> 'book'), controllerName corresponding to the class name ('BookController'), and 'actions' corresponding to a List of action names for that controller:

import org.springframework.beans.BeanWrapper
import org.springframework.beans.PropertyAccessorFactory

def data = []
for (controller in grailsApplication.controllerClasses) {
    def controllerInfo = [:]
    controllerInfo.controller = controller.logicalPropertyName
    controllerInfo.controllerName = controller.fullName
    List actions = []
    BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(controller.newInstance())
    for (pd in beanWrapper.propertyDescriptors) {
        String closureClassName = controller.getPropertyOrStaticPropertyOrFieldValue(pd.name, Closure)?.class?.name
        if (closureClassName) actions << pd.name
    }
    controllerInfo.actions = actions.sort()
    data << controllerInfo
}
查看更多
登录 后发表回答