如何在Grails中的控制器中调用服务?

如何在Grails中的控制器中调用服务?,grails,oauth,Grails,Oauth,我正在用Grails编写一个REST客户机,我需要使用OAUTH与第三方CRM集成,所以我使用的是HTTPBuilder。我想将OAUTH内容抽象为一个服务,并使令牌和实例url可用于控制器和视图 这是我的服务: import org.springframework.transaction.annotation.Transactional; import groovyx.net.http.HTTPBuilder import groovyx.net.http.HttpResponseExcep

我正在用Grails编写一个REST客户机,我需要使用OAUTH与第三方CRM集成,所以我使用的是HTTPBuilder。我想将OAUTH内容抽象为一个服务,并使令牌和实例url可用于控制器和视图

这是我的服务:

import org.springframework.transaction.annotation.Transactional;

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseException
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.Method.POST
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON

class APIConnectorService {

    def sf_login_domain = 'STUFFTHATWORKS'
    def instance_domain
    def access_token = ''
    def consumer_key =    'STUFFTHATWORKS'
    def consumer_secret = 'STUFFTHATWORKS'
    def auth_username = 'STUFFTHATWORKS'
    def auth_password = 'STUFFTHATWORKS'

    def serviceMethod() {

        //Request Access_token and instance domain for work
            def http = new HTTPBuilder(sf_login_domain)
            def postBody = [
                grant_type: 'password',
                client_id: consumer_key,
                client_secret: consumer_secret,
                username: auth_username,
                password: auth_password+auth_security_token
                ]
        try{

            http.post( path : 'services/oauth2/token',
                      body : postBody,
                      requestContentType: URLENC) { resp, json ->
                            access_token = json.access_token
                            instance_domain = json.instance_url +"/"
                        }

        }catch(HttpResponseException e){
            println "Error code: ${e.statusCode}"
            println "Post form: $postBody"
        }

        println "Access Token $access_token"
        println "Instance domain $instance_domain \n"

  }
  }
这是我的控制器

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseException
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.Method.POST
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON



class APIConnectorController {

def APIConnectorService

def index(){


    http = new HTTPBuilder(APIConnectorService.serviceMethod())
    http.request(GET,JSON) { req ->
      uri.path = 'services/data/v28.0/'
      headers['Authorization'] = "Bearer $access_token"


    response.success = { resp, json  ->
        assert resp.status == 200
        json.each{ key,value ->
        render(view:"index", model: [json: json])
            }
        }

    response.failure = { resp, json ->
        println resp.status
        println json.errorCode
        println json.message
      } 
    }
    }
 }
因此,当我将所有服务代码直接包含在控制器中时,它会以我希望的方式运行,但正如我所说的,我希望将OAUTH令牌生成抽象为一个服务(至少,这对我来说最有意义)

我在尝试上述配置时遇到此错误

ERROR errors.GrailsExceptionResolver  - MissingMethodException occurred when processing request: [GET] /SFAPITest/APIConnector
No signature of method: sfapitest.APIConnectorController.HTTPBuilder() is applicable for argument types: (null) values: [null]. Stacktrace follows:
Message: No signature of method: sfapitest.APIConnectorController.HTTPBuilder() is applicable for argument types: (null) values: [null]
更新

我正在获取从服务传递到控制器的访问令牌和实例域,但现在我得到了错误:

ERROR errors.GrailsExceptionResolver  - MissingMethodException occurred when processing request: [GET] /SFAPITest/ApiConnector
No signature of method: sfapitest.ApiConnectorController.HTTPBuilder() is applicable for argument types: (java.lang.String) values: [https://scholastica--FullBox.cs16.my.salesforce.com/]. Stacktrace follows:
Message: No signature of method: sfapitest.ApiConnectorController.HTTPBuilder() is applicable for argument types: (java.lang.String) values: [https://ourschool--FullBox.cs16.my.forcefulCRM.com/]
这是我的最新服务

package sfapitest

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseException
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.Method.POST
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON

class ApiConnectorService {

def transactional = false

def sf_login_domain = 'STUFFTHATWORKS'
def instance_domain
def access_token = ''
def consumer_key = 'STUFFTHATWORKS'
def consumer_secret = 'STUFFTHATWORKS'
def auth_username = 'STUFFTHATWORKS'
def auth_password = 'STUFFTHATWORKS'
def auth_security_token = 'STUFFTHATWORKS'
def api_token_path = 'services/oauth2/token'
def oauthObject

 def serviceMethod() {

    //Request Access_token and instance domain for work
        def http = new HTTPBuilder(sf_login_domain)
        def postBody = [
                grant_type: 'password',
                client_id: consumer_key,
                client_secret: consumer_secret,
                username: auth_username,
                password: auth_password+auth_security_token
                ]
        try{

            http.post( path : api_token_path,
                       body : postBody,
                       requestContentType: URLENC) { resp, json ->
                             access_token = json.access_token
                             instance_domain = json.instance_url +"/"
                        }

                    oauthObject = [access_token, instance_domain]

        }catch(HttpResponseException e){
            println "Error code: ${e.statusCode}"
            println "Post form: $postBody"
        }

    return oauthObject
}
}
因此,感谢下面的建议,我将把access_令牌和instance_域的数组返回给serviceMethod()

这是我的控制器:

package sfapitest


import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseException
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.Method.POST
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON



class ApiConnectorController {

def apiConnectorService

def index(){

    def access_token = apiConnectorService.serviceMethod()[0]
    def instance_domain = apiConnectorService.serviceMethod()[1]


    http = HTTPBuilder(instance_domain)
    http.request(GET,JSON) { req ->
      uri.path = 'services/data/v28.0/'
      headers['Authorization'] = "Bearer $access_token"


    response.success = { resp, json  ->
        assert resp.status == 200
        json.each{ key,value ->
        render(view:"index", model: [json: json])
            }
        }

    response.failure = { resp, json ->
        println resp.status
        println json.errorCode
        println json.message
      } 
    }
}
}

MissingMethodException可能意味着我没有正确数量的参数。我可以从cotroller呈现access_令牌和instance_域,它们显示正确的值。任何关于如何使这项工作更有效、更优雅的提示和建议都将不胜感激。我的目标是制作一个RESTful/OAUTH应用程序,可以用于各种第三方Web服务集成。

我认为问题在于您声明您的服务的方式

APIConnectorService apiConnectorService
def aPIConnectorService

而不是

def APIConnectorService

最好将服务名称更改为ApiConnectorService,并在控制器中声明,如下所示


def apiConnectorService

您的serviceMethod的最后一个操作是导致返回null的println。
要访问http builder对象,您必须在post请求成功后返回它。

您正在将
APIConnectorService.serviceMethod()
作为参数传递到中

http = new HTTPBuilder(APIConnectorService.serviceMethod())
您的方法
serviceMethod()
不返回任何内容,因此我认为您会遇到此错误

serviceMethod()
应返回
objectdefaultURI

创建具有空默认URI的新实例

HTTPBuilder(Object defaultURI)
为所有不显式接受URI参数的请求方法提供一个默认URI

HTTPBuilder(Object defaultURI, Object defaultContentType)

为所有未显式接受URI参数的请求方法提供一个默认URI,并为请求编码和响应解析提供一个默认内容类型。

可能是由于没有遵循正确的命名约定造成的

第一个建议是通过遵循类命名约定来更改服务名称

ApiConnectorService
然后在控制器中为您的服务使用camel case声明

def apiConnectorService
    def http = new HTTPBuilder(instance_domain)
    http.request(GET,JSON) { req ->
    uri.path = 'services/data/v28.0/'
    headers['Authorization'] = "Bearer $access_token"
grails使用其约定查找名称及其类

也可以尝试使用

APIConnectorService apiConnectorService

好的,经过多次尝试、出错和解析HTTPBuilder文档之后,最后一步是在我的控制器中正确定义新的HTTPBuilder()实例

def apiConnectorService
    def http = new HTTPBuilder(instance_domain)
    http.request(GET,JSON) { req ->
    uri.path = 'services/data/v28.0/'
    headers['Authorization'] = "Bearer $access_token"
这现在允许我将OAUTH组件从控制器中抽象出来。我绝对相信,对于我想要实现的目标,有一个更优雅的解决方案。我很想听到一些关于如何清理的建议

  • 我是否需要在服务和控制器中导入
  • OAUTH可以放在config.groovy中吗

在省略了println之后,我从服务中获得了一些信息,而不是我想要的对象元素。我怎样才能干净利落地归还物品?Stacktrace如下所示:消息:没有方法的签名:sfapitest.ApiConnectorController.HTTPBuilder()适用于参数类型:(java.lang.String)值:['@Lorenzo,我现在将访问令牌和实例域从服务返回给控制器。谢谢!但我得到错误“没有方法签名:ApiConnectorController.HTTPBuilder()适用于参数类型:(java.lang.String)值:[”