我在Grails中编写REST客户端,我需要使用OAUTH与第三方CRM集成,因此我使用HTTP-Builder。我想将OAUTH内容抽象为服务,并使令牌和instance_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]
UPDATE !!
我将访问令牌和实例域从服务传递到控制器但现在我已经#得到错误:
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_token和instance _domain的数组返回给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_token和instance_domain,它们显示正确的值。关于如何使这项工作更优雅的任何提示和指示将不胜感激。我的目标是创建一个RESTful / OAUTH应用程序,可用于各种第三方Web服务集成。
答案 0 :(得分:1)
您将APIConnectorService.serviceMethod()
作为
http = new HTTPBuilder(APIConnectorService.serviceMethod())
您的方法serviceMethod()
returns
没有任何内容,以至于我认为您收到此错误的原因。
serviceMethod()
应该返回Object defaultURI
HTTPBuilder()
使用null默认URI创建新实例。
HTTPBuilder(Object defaultURI)
提供一个默认URI,用于所有不明确接受URI参数的请求方法。
HTTPBuilder(Object defaultURI, Object defaultContentType)
提供一个默认URI,用于所有不明确接受URI参数的请求方法,以及用于请求编码和响应解析的默认内容类型。
答案 1 :(得分:1)
好的,经过大量试验,错误和解析HTTPBuilder文档后,最后一部分是在我的控制器中正确定义新的HTTPBuilder()实例。
def http = new HTTPBuilder(instance_domain)
http.request(GET,JSON) { req ->
uri.path = 'services/data/v28.0/'
headers['Authorization'] = "Bearer $access_token"
现在允许我从控制器中抽象出OAUTH组件。我绝对肯定有一个更优雅的解决方案,我正在努力实现。我很想听听有关如何清理它的一些建议。
答案 2 :(得分:0)
我认为问题在于您宣布服务尝试使用
的方式 def aPIConnectorService
而不是
def APIConnectorService
最好将服务名称更改为 ApiConnectorService ,并在控制器中声明如下
def apiConnectorService
答案 3 :(得分:0)
您的serviceMethod的最后一个操作是println,它导致返回null。 要访问http-builder对象,您必须在成功发布请求后返回它。
答案 4 :(得分:0)
可能是因为没有遵循正确的命名约定。
第一个建议是通过遵循类命名约定来更改服务名称。
ApiConnectorService
然后在控制器中为您的服务使用驼峰案例声明。
def apiConnectorService
Grails使用其约定来查找名称及其类。
也可以尝试使用
APIConnectorService apiConnectorService