Grails render view from service?

2019-07-07 03:07发布

问题:

I am just starting to use Services in Grails and I am having an issue when trying to render a page from inside a service, I have tried a few methods as shown below with no luck:

Service Call 1:

GroupCheckService.isEnabled(userObjects.group.notenabled)

Service Attempt 1:

import grails.gsp.PageRenderer

class GroupCheckService {

    PageRenderer groovyPgeRenderer
    static transactional = false

    def isEnabled(boolean notenabled) {

        if(notenabled == true){
            groovyPgeRenderer.render(view: '/locked')

        }else{
            return
        }

    }
}

Service Call 2:

GroupCheckService.isEnabled(render, userObjects.group.notenabled)

Service Attempt 2:

class GroupCheckService {

    PageRenderer groovyPgeRenderer
    static transactional = false

    def isEnabled(Closure render, boolean notenabled) {

        if(notenabled == true){
            render.call view:"/locked"

        }else{
            return
        }

    }
}

Now when I try method 1 I don't get an error but the page is not rendered when the IF is satisfied, with method 2 I get the following error:

no such property render

I would really appreciate some advise or help on how to achieve this, thanks in advance :)

回答1:

You shouldn't render views from service - this is a part for the controller.

Use the service for business logic and/or (transactional) database operations.

From grails docs:

Services in Grails are the place to put the majority of the logic in your application, leaving controllers responsible for handling request flow with redirects and so on.

If you realy want to render a view from service, mrhaki has blogged about using the PageRenderer from service.

import grails.gsp.PageRenderer

class GroupCheckService {
    PageRenderer groovyPageRenderer

    def isEnabled(Closure render, boolean notenabled) {
        if(notenabled == true){
            groovyPageRenderer.render view: "/locked"
        }else{
            return
        }
    }
}

Notice that you can't use Sitemesh layouts due to the PageRenderer works outside of the request scope.

The best way is to redesign your application to leave the render stuff in the controller.



回答2:

First of all - it's very bad practice to render HTTP response from a service.

As about your code - you have to use first approach, with groovyPgeRenderer.render. But you aren't using result of this call. It's a method that returns a String (see docs)

So, you need to put that string into HTTP response manually. You can get HttpServlet response from Controller, or from RequestContextHolder.currentRequestAttributes() (see docs). Like:

String html = groovyPageRenderer.render(view: '/locked')
def response = RequestContextHolder.currentRequestAttributes().response
response.setStatus(200)
response.setContentType('text/html')
response.writer.write(html)