使用Grails域查找方法重复代码

时间:2014-12-03 12:45:59

标签: grails dry findby

初始问题

如果你有不同的方法,基本上只有一行不同,有没有办法通过创建一个方法使其干燥。

示例:

def showA( ) {
   def instance

    try {
        instance = A.findById( params.id )
    } catch ( Exception e ) {
        def message = "Error while retrieving details for the given id ${ params.id }, $e"
        log.error message
        responseAsJson( 400, "Invalid id", message )
        return false
    }

    return checkAndRender(instance,  params.id);
}

def showB( ) {

       def instance

        try {
            instance = B.findByBId( params.BId )
        } catch ( Exception e ) {
            def message = "Error while retrieving details for the given id ${ params.id }, $e"
            log.error message
            responseAsJson( 400, "Invalid id", message )
            return false
        }

        return checkAndRender(instance,  params.id);
    }

那么,是否有办法制作一个方法并简单地作为参数传递:

  • 域类
  • 要搜索的ID

或者改为传递SQL语句会更好吗?

更新

基于@dmahapatro评论,我想出了以下内容:

def showA( ) {
        def clos = {id -> A.findByAId( id ) }
        return findAndShow(clos, params.AId, params )
    }

def showB( ) {
        def clos = {id -> B.findByBId( id ) }
        return findAndShow(clos, params.BId, params )
    }

 def findAndShow(Closure closure, def id, def p)
    {
        def instance
        try {
            instance = closure(id)
        }
        catch ( Exception e ) {
            def message = "Error while retrieving instance details for the given id ${ id }, $e"
            log.error message
            responseAsJson( 400, "Invalid Id", message )
            return false
        }

        return checkAndRender(instance,  id);
    }

只剩下的问题是:

  • 如何进一步清理/使其更清洁。
  • 如何绕过警告:

      

    [ApiController]中的[findAndShow]动作接受参数   输入[groovy.lang.Closure]。接口类型和抽象类类型   不支持作为命令对象。该参数将被忽略。

       def findAndShow(Closure closure, def id, def p)
    

1 个答案:

答案 0 :(得分:1)

如果您想要DRY代码,首先要担心的是定义更好的异常处理。在任何地方尝试捕获代码来处理对客户端的响应都不是很严重,如果将数据访问代码放在服务中,则可以从中抛出异常并使用全局控制器来捕获错误并处理响应。 E.g:

class ErrorController {

    def serverError() {
         if (request.format == 'json') {
            //Code for handling errors in json request, request.exception stores the data about the exception. 
        } else {
            //Code for handling errors in non-json request, e.g:
            render(view: 'error', model: [msg: 'Something went wrong']) //add an error view for this
        }
    }
}

如果您愿意,还可以为其他类型的错误添加处理程序(403,404等)

添加到UrlMappings.groovy

    "500"(controller: "error", action: "serverError")

现在,您可以使用新的错误处理和反射重构代码:

控制器:

   class MyController {

        def myService

        def show() {
            def result = myService.myFind(params.className,params.id)
            render result as JSON //Render stuff
        }
    }

服务:

       import grails.util.Holders

       class MyService {

            def myFind(String className, Long id) {
                def result = Holders.getGrailsApplication().getDomainClass('com.mypack.'+ className).findById(id)
                if(!result) {
                    throw new ServiceException('really descriptive and usefull error msg')
                }
            }
        }

我定义了一个ServiceException类,所以我可以使用instanceOf运算符在我的ErrorController中为它添加自定义逻辑。