Grails has a request object which is defined here.
The problem is when I try to use it, I get:
No such property: request for class:xxx
Reading the first 100 hits googling this error only produced one suggestion:
import javax.servlet.http.HttpServletRequest
import org.springframework.web.context.request.ServletRequestAttributes
:
def my() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
}
However, this gives:
groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService
How does one get a handle on the request object in Grails?
How do you find out about this? So few people have asked this question, it must be documented somewhere, or in some example, but I can't find either.
In Grails 3.0, from a service get the request object using:
grails-app/services/com/example/MyService.groovy
import org.grails.web.util.WebUtils
...
def request = WebUtils.retrieveGrailsWebRequest().getCurrentRequest()
def ip = request.getRemoteAddr()
Documentation:
https://docs.grails.org/latest/api/org/grails/web/util/WebUtils.html#retrieveGrailsWebRequest()
Note:
The old codehaus package has been deprecated.
Try following code:
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.codehaus.groovy.grails.web.util.WebUtils
...
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
I expect that you probably got "groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService" because you didn't import the "org.springframework.web.context.request.RequestContextHolder" class in your ReportService.
The most common place to want access to the request object is in a controller. From a controller you simply refer to the request property and it will be there. See http://grails.org/doc/latest/ref/Controllers/request.html.
The answer to how to access the request object from somewhere else may depend on what the somewhere else is.
UPDATE
I don't know why you are having trouble passing the request from a controller to a service, but you can. I suspect you are invoking the method incorrectly, but something like this will work...
// grails-app/services/com/demo/HelperService.groovy
package com.demo
class HelperService {
// you don't have to statically type the
// argument here... but you can
def doSomethingWithRequest(javax.servlet.http.HttpServletRequest req) {
// do whatever you want to do with req here...
}
}
A controller...
// grails-app/controllers/com/demo/DemoController.groovy
package com.demo
class DemoController {
def helperService
def index() {
helperService.doSomethingWithRequest request
render 'Success'
}
}
Related
I recently posted a question about multiple data sources. Things were going well until I hit this issue:
Controller
def doSomething() {
def user=userService.getCurrentUser()
}
Service
class UserService {
def getCurrentUser() {
def principal = springSecurityService.principal
String username = principal.username
return find(username)
}
def find(String user) {
return User.find{username==user}
}
}
This had been working previously on single DataSource but now with both enabled I see this on the browser:
Error 500: Internal Server Error URI /xxx/xxx Class
org.springframework.beans.factory.NoUniqueBeanDefinitionException
Message No qualifying bean of type
[org.springframework.transaction.PlatformTransactionManager] is
defined: expected single matching bean but found 3:
transactionManager,transactionManager_countrycity,$primaryTransactionManager
Okay this is now resolved.
I think I found the issue: under grails 3 with multiple data sources if you have this import :
import org.springframework.transaction.annotation.Transactional
You will run into the above problems:
If you how ever have :
import grails.transaction.Transactional
things will work as expected. I hadn;t paid attention and let ide choose wrong declaration
Does anyone know how I can get the original header fields from request? I would like to validate, if client will receive html or just plain/text response. Can I get this fields inside 'toResponse' method of exceptionMapper?
I created exceptionMapper like in this post:
http://gary-rowe.com/agilestack/2012/10/23/how-to-implement-a-runtimeexceptionmapper-for-dropwizard/
If you did want to get information from the original request object, you can add the following to your controller.
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
#Path("/my")
#Produces(["application/json", "application/hal+json"])
class MyController {
#Context
protected HttpServletRequest httpRequest
#Timed
#GET
public Response getOne(){
httpRequest.getHeaders();
... //do something with headers
return Response.ok(new Person(id:1), httpRequest.getContentType());
}
I have the following action in a controller
class RegisterController {
static allowedMethods = [register: 'POST']
def register(User user) {
// action body omitted
}
}
If a user tries to invoke this action via GET /register/register/newUser, I get a databinding failure because newUser cannot be bound to the user's Long id property.
This seems reasonable at first, however IMO no attempt should ever be made to bind the user when it is invoked via HTTP GET, because I've declared that only POST is allowed.
Curiously, if I change the action to:
class RegisterController {
static allowedMethods = [register: 'POST']
def register() {
User user = new User(params)
}
}
and again try to invoke it with GET /register/register/newUser, then I get the expected HTTP method not allowed (405) error. It seems to me that databinding is happening before the HTTP request type is checked, and this is why I get a binding error in the first case and a 405 error in the second.
Shouldn't I get a 405 in both cases?
Yes, you should get a 405 in both cases. File a report at https://jira.grails.org/browse/GRAILS and we will get it straightened out. We have an AST transformation which adds the command object handling code and adds the allowedMethods handling code. It sounds like they may not be in the right order. Will get it straightened out. Thanks for the feedback.
I want to use g.formatNumber in service, I have tried a below method, Which i got online. This is not working, its giving me the error "Cannot invoke method formatNumber() on null object", The code is below
import org.springframework.beans.factory.InitializingBean
class MyService implements InitializingBean {
boolean transactional = false
def gspTagLibraryLookup // being automatically injected by spring
def g
public void afterPropertiesSet() {
g = gspTagLibraryLookup.lookupNamespaceDispatcher("g")
assert g
}
def getFormattedNumber(){
def number = g.formatNumber(number: 5000,234 , type: "number" , maxFractionDigits: 2)
return number
}
}
How to do this.
I want to use g.formatNumber in service
Rather than jumping through the hoops you need to use a taglib within a service, it would be simpler to just use java.text.NumberFormat directly
NumberFormat format = NumberFormat.getNumberInstance()
format.maximumFractionDigits = 2
def number = format.format(5000.234)
If the service method is being called from a web request handling thread then you may wish to use the LocaleContextHolder to get the correct locale for the current web request, rather than just using the server's default.
This should work
def g = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib');
You will of course need grailsApplication injected by defining it ala
def grailsApplication
Well I am new to Groovy/Grails. I have written a Groovy script that uses RESTClient to make HTTP POST request to JIRA server. The POST request sends a JQL query and receives the result in JSON format. Here's the full code:
import groovyx.net.http.RESTClient;
import groovyx.net.http.HttpResponseDecorator;
import org.apache.http.HttpRequest;
import org.apache.http.protocol.HttpContext;
import org.apache.http.HttpRequestInterceptor;
import groovy.json.JsonSlurper;
import static groovyx.net.http.Method.*
import static groovyx.net.http.ContentType.*
#Grab(value = 'org.codehaus.groovy:groovy-all:2.1.6',
initClass = false)
#Grapes([
#Grab(group = 'org.codehaus.groovy.modules.http-builder',
module = 'http-builder', version = '0.5.2'),
#GrabExclude('org.codehaus.groovy:groovy')
])
// connect to JIRA
def jiraApiUrl = 'http://my-jira.com/rest/api/2/'
def jiraClient = new RESTClient(jiraApiUrl);
// authentication
def basic = 'Basic ' + 'username:password'.bytes.encodeBase64().toString()
jiraClient.client.addRequestInterceptor (
new HttpRequestInterceptor() {
void process(HttpRequest httpRequest,
HttpContext httpContext) {
httpRequest.addHeader('Authorization', basic)
}
})
// http post method
def uriPath = 'search'
def param = [maxResults : 1, jql : '<jql-query>']
def Issues = jiraClient.post(requestContentType : JSON, path : uriPath, body : param)
def slurpedIssues = new JsonSlurper().parseText(Issues.data.toString())
println Issues.data.total
I need to migrate this script to a Grails app. Any suggestions as to how to do the same?
Define dependencies in BuildConfig (except the groovy dependency)
copy script contents to a Service
Possible extension:
use the grails rest plugin or grails rest-client-builder plugin instead of http-builder
Putting the logic into Service object will give you the ability to do dependency injection, which is native to grails services.
Also, you should consider using AsyncHTTPBuilder if your app has many users trying to make requests.
I strongly believe that the service response will be directly rendered to JSON
//your controller
class AbcController{
//your action
def save() {
render(abcService.save(params) as JSON)//your service response now been rendered to JSON
}
}
//your service class class AbcService {
def save(params){
....
return something
}
}