How do I call a Grails service from a gsp?

30,882

Solution 1

<%@ page import="com.myproject.MyService" %>
<%
    def myService = grailsApplication.classLoader.loadClass('com.myproject.MyService').newInstance()
%>

And then you can call ${myService.method()} in your gsp view

Be aware that calling transactional service methods from views hurts performance. Better to move all your transactional service method calls to the controller (if you can)

Solution 2

Best to use the tag library because creating a service instance directly in the view via the class loader WILL NOT autowire other services declared that may live in the service you are trying to use.

Using the tag library you will have auto-wiring of those services.

In your gsp view <g:customTag param1="$modelObjec" param2="someString" />

In your taglib folder (yourApp/grails-app/taglib/com/something/MyAppTagLib):

package com.something

class MyAppTagLib {

    def myService  // This will be auto-wired

    def customTag = { attribs ->
        def modelObj = attribs['param1']
        def someString = attribs['param2']

        // Do something with the params

        myService.method()

        out << "I just used method of MyService class"
    }
}

Your MyService:

package com.something

class MyService {

def anotherService // This will be auto-wired

def method() {
    anotherService.anotherMethod()
}

}

Solution 3

Try this - much helpful

%{--Use BlogService--}%
<g:set var="blog" bean="blogService"/>

<ul>
    <g:each in="${blog.allTitles()}" var="title">
        <li>${title}</li>
    </g:each>
</ul>

Refer this

Also this is not a recommened thing, you can always use taglib

Solution 4

I think the best way of doing it is:

<%
    def myService = grailsApplication.mainContext.getBean("myService");
%>

This way, you get the service instance without losing the autowired services.

Share:
30,882
xain
Author by

xain

SW PM,architect and programmer

Updated on March 05, 2020

Comments

  • xain
    xain about 4 years

    How can I invoke a service directly from a view? I'm trying with ${my.domain.service.method}, but it complains it can't find the property.

    And no, I don't want to use a controller because the view is a template.

  • xain
    xain about 14 years
    Thanks for your reply. I set transactional = false, that should improve performance.
  • Urs Reupke
    Urs Reupke about 13 years
    While this works, it would be far more elegant to either inject the service into the view via model or to create a taglib for the service and use this from the view.
  • Kapil Gund
    Kapil Gund about 13 years
    @Urs Yes, but this was not the scope of the question : "how can I invoke a service directly from a view ?". Notice the word 'directly'
  • Kapil Gund
    Kapil Gund about 13 years
    @Urs And it is not always more elegant to wrap your service call into a taglib or model. Suppose that you have a Service with many calculation methods (e.g. 100) used by views, controllers then it means that you need to encapsulate all of the 100 methods into tags !! This is not really DRY. Concerning your second suggestion to have the service injected via model, it doesn't look like an elegant solution. As always, there is no bullet silver but many solutions to many situations
  • Urs Reupke
    Urs Reupke about 13 years
    @Fabien, thanks for clarifying. I misunderstood the question. And I see your point regarding DRY-ness. No Silver Bullet and all such - agreed.
  • Ruben
    Ruben over 11 years
    Without knowing the exact problem definition this does point to using a specific view model instead of solving it all directly in the GSP.
  • Cray
    Cray almost 11 years
    Just a note, it seems that even if the service's scope is default (singleton), the service instance created in this way will NOT be the same one that is injected into the rest of the project. (Not very surprising considering '.newInstance()'.)
  • Lucas Eduardo
    Lucas Eduardo over 10 years
    Definitely the best way
  • Alexander Suraphel
    Alexander Suraphel about 10 years
    I'm getting org.springframework.beans.factory.NoSuchBeanDefinitionExcept‌​ion
  • Alexander Suraphel
    Alexander Suraphel about 10 years
    can you tell me what the difference of this call is from the one in @fabien7474's answer?
  • Lucas Eduardo
    Lucas Eduardo about 10 years
    @spartacus this is not a normal Grails class, I think this only work with services classes (grails.org/doc/2.3.x/guide/services.html)
  • David Paulo
    David Paulo about 10 years
    @spartacus in his answer, he creates a new instance of the service and, therefore, he gets just a plain object of Service´s class with all its dependences unsatisfied. In my answer, i get the service bean from the Container used by the framework, already injected with the beans it needs.
  • David Paulo
    David Paulo about 10 years
    @Spartacus Suganthan's answer is better than mine, though.
  • Ibrahim.H
    Ibrahim.H over 5 years
    This works for grails 3, even without include ìmport` statement above, either way it's better to use taglib or any other frontend view engine.