« 返回到 Templating Languages

Custom Velocity Variables

Introduction #

If you ever wanted to create more custom Velocity Variables that would be available for your theme to reference it's as easy as setting an attribute in ServicePreAction.java!

Background #

If you look at the template code inside a typical Liferay theme, you will see many velocity variables being referenced. For example inside of the Classic theme's dock.vm, there is a line of code:

 <h2 class="user-greeting">
  <span>$user_greeting</span>
 <h2>

$user_greeting fetches the "Welcome Joe Bloggs" sign you'll see when you log in as test@liferay.com Where did $user_greeting come from? Look inside init.vm, and you'll that it's set here:

 #set ($user_greeting = $user.getGreeting())

It gets the User object ($user) and retrieves the 'greeting' (.getGreeting()) from the database. Where is the User object set as a velocity variable? The magic happens inside of VelocityVariables.java:

 vc.put("user", themeDisplay.getUser());

'vc' is an instance of VelocityContext, and all we are doing here is getting the user object (themeDisplay.getUser()) and assigning it the key of "user". This translates to the ability to using $user as the User object.

Custom Velocity Variables #

  1. First see what variables are already available.
    1. Some commonly used ones that are already available include $user, $company, $layout, and $themeDisplay. You probably don't want to create a new one for getting a user's screen name, because you can just do $user.getScreenName().
  2. ServicePreAction.java
    1. You'll want to extend the ServicePreAction class first and reference it in portal-ext.properties:
 servlet.service.events.pre=com.liferay.portal.events.ServicePreAction,your.custom.EXTServicePreAction

Inside your extended ServicePreAction class, create a Map object with the key and value of the vm variables you want to insert, and then set that into the attribute under the key WebKeys.VM_VARIABLES.

Finally, the WebKeys.VM_VARIABLES gets picked up in VelocityVariables.java:

 // Insert custom vm variables
 Map vmVariables = (Map)req.getAttribute(WebKeys.VM_VARIABLES);
 if (vmVariables != null) {
   Iterator itr = vmVariables.entrySet().iterator();
   while (itr.hasNext()) {
    Map.Entry entry = (Map.Entry)itr.next();
    String key = (String)entry.getKey();
    Object value = entry.getValue();
    if (Validator.isNotNull(key)) {
      vc.put(key, value);
    }
   }
 }
0 附件
124608 查看
平均 (9 票)
满分为 5,平均得分为 4.11111111111111。
评论
讨论主题回复 作者 日期
I managed to do this. Create a class with a... Alex Brdar 2008年11月27日 上午7:59
Since this is read at the end of setting the... Tor Iver Wilhelmsen 2009年5月14日 上午5:50
I am facing one problem. I created the class... Arunjyoti Banik 2015年3月16日 下午9:25
If I am not mistaken the... Edgar Vonk 2009年9月28日 上午6:02
I am also facing the same problem..... Nitesh Kr Sahay 2013年7月3日 上午8:07
This does not seem to work for a CMS template. ... Thomas Kellerer 2009年11月27日 上午2:44
This is a great explanation. Thank you! jeff Leitman 2010年3月18日 上午10:58
"1. You'll want to extend the ServicePreAction... Eric Dobbs 2010年6月14日 下午1:07
You can put it under liferay-portal-ext in... Leon Fleysher 2010年8月26日 上午12:17
Hi, Leon. I create my EXTServicePerAction... Blair Long 2011年3月29日 上午1:12
Sorry for my bad english, If anybody know more... Blair Long 2011年3月29日 上午1:49
See this example: Look at this example: public... Diego Andres Garcia 2011年3月30日 下午12:07
Thank you, Diego! I create a new EXT... Blair Long 2011年3月30日 下午10:29
And, If I re-name my custom class in existing... Blair Long 2011年3月30日 下午10:49
I realize this page has been here for a long... Dana Oredson 2012年3月13日 上午8:35
if you use 6.1 see... 凌 李 2013年5月6日 上午1:49
My question is we do we need to iterate the... Adnan Yaqoob 2015年7月30日 上午8:52

I managed to do this. Create a class with a no-arg constructor that extends com.liferay.portal.kernel.events.Action:
<pre>
public class EXTServicePreAction extends Action {
public void run(HttpServletRequest req, HttpServletResponse res)
throws ActionException {
Map<String, Object> vmVariables = new HashMap<String, Object>();
// Setup some variables
vmVariables.put("extendedVariable", "test");
req.setAttribute(WebKeys.VM_VARIABLES, vmVariables);
}
}
</pre>

Now you can define this in portal-ext.properties, you still need ServicePreAction included first:
<pre>
servlet.service.events.pre=com.liferay.portal.events.ServicePreAction­,your.custom.EXTServicePreAction
<pre>

And that's it, the Velocity theme templates can now see the variables!
在 08-11-27 上午7:59 发帖。
Since this is read at the end of setting the variables you can also use this to override the preexisting variables. E.g. we have some custom page types where we want to have "Add Application" available, and added an action listener like this which set "show_add_content" based on permissions instead of permissions plus "portlet" and whatever else it uses hardcoded.
在 09-5-14 上午5:50 发帖以回复 Alex Brdar
If I am not mistaken the servlet.service.events.pre is triggered for _every_ HTTP request in Liferay? Is this true? When I load a page (with just one portlet on it) I see that my custom action is invoked around 10 times..

Since I invoke quite heavy business logic in my action (calling a remote EJemoticon I am looking for another solution. Is there another event I can couple my custom action to?

One solution I can think of could be: create a custom post login action, do the business logic there, set the result in the session, and then from my servlet.service.events.pre action retrieve this result from the session and place it in the Velocity variables in the request.
在 09-9-28 上午6:02 发帖。
This does not seem to work for a CMS template.
I can see the variable in the request attributes and I can retrieve something, but calling a method on it doesn't work:

#set ($vars = $request.get('attributes').get('VM_VARIABLES'))
#set ($myHelper = $vars.get('myHelper'))

If I show $vars.toString() it display a "toString" of the map, including the key "myHelper", but when trying to call a method on $myHelper it does not work.

What am I missing?
在 09-11-27 上午2:44 发帖。
This is a great explanation. Thank you!
在 10-3-18 上午10:58 发帖。
"1. You'll want to extend the ServicePreAction class first and reference it in portal-ext.properties"

Where do I create the package for this class???
在 10-6-14 下午1:07 发帖。
You can put it under liferay-portal-ext in whatever package you want -- just write the same package name in portal-ext.properties when referencing your ServicePreAction. I'd also recommend to change the name of your extended class.
在 10-8-26 上午12:17 发帖以回复 Eric Dobbs
Hi, Leon.
I create my EXTServicePerAction extends ServicePreAction and override "run" method. Is it right?
My code below:
public class CustomVelocityVariableAction extends ServicePreAction{
public void run(HttpServletRequest request, HttpServletResponse response)
throws ActionException {
super.run(request, response);
Map vmVariables = (Map)request.getAttribute(WebKeys.VM_VARIABLES);
if (vmVariables != null) {
vmVariables.put("my_vm_var", "my_vm_var");
}

}
}


Which portal-ext.properties file I need to change?
"webapps\ROOT\WEB-INF\classes" or EXT plugins project?
在 11-3-29 上午1:12 发帖以回复 Leon Fleysher
Sorry for my bad english, If anybody know more material about custom velocity variables, A thousand thanks !
在 11-3-29 上午1:49 发帖以回复 Blair Long
See this example:
Look at this example:
public void run(HttpServletRequest request, HttpServletResponse response)throws ActionException {
Map<String, Object> variablesVM= new HashMap<String, Object>();
variablesVM.put("test", "test");
request.setAttribute(WebKeys.VM_VARIABLES, variablesVM);
}

Change the properties in EXT project and deploy it.

In the .VM you can use the var:
$test

...good luck
在 11-3-30 下午12:07 发帖以回复 Blair Long
Thank you, Diego!
I create a new EXT project and follow your example. It's ok.
But I can't apply it in existing EXT project, Because portal-ext.properties file doesn't copy to %Tomcat%webapps\ROOT\WEB-INF\classes this folder.
I see that just deploy project first will copy this file.
在 11-3-30 下午10:29 发帖以回复 Diego Andres Garcia
And, If I re-name my custom class in existing EXT project, then change portal-ext.properties suitably, Copy this file to tomcat manually. When re-start tomcat, It occured "ClassNotFoundException". This mean my custom class didn't deploy successfully.
Does this issue cause some difference between Community Edition and Enterprise Edition?
在 11-3-30 下午10:49 发帖以回复 Blair Long
I realize this page has been here for a long time, but if your theme depends on these velocity variables, isn't it better to use the theme's init_custom.vm?

Then you can pick up your theme and deploy it on a separate site that doesn't have the service pre action defined and your theme should still work.
在 12-3-13 上午8:35 发帖。
if you use 6.1 see this:http://www.opensourceforlife.com/2012/06/custom-velocity-variable-in-lifera­y-61.html
在 13-5-6 上午1:49 发帖。
I am also facing the same problem.....
在 13-7-3 上午8:07 发帖以回复 Edgar Vonk
I am facing one problem. I created the class inside a hook project and referenced it as said in portal-ext.properties. When I am restarting the server, console messages are throwing ClassNotFoundException (Unable to load ServicePreActionExtended with the portal class loader or the current context class loader).

But when I am placing the same code in portal.properties of the hook it is throwing ClassNotFoundException for the original ServicePreAction class.
Cant figure out where I am wrong .............. Can you give a suggestion??
在 15-3-16 下午9:25 发帖以回复 Alex Brdar
My question is we do we need to iterate the vmVariables unless we need to locate some existing variable.
Why can't we simple put a new entry after getting the map from request
在 15-7-30 上午8:52 发帖。