使用velocity后,原来的很多标签无法使用了,必须借助velocity tools来完成,目前velocity tools最新版本是2.0,下面是velocity tools的一些注意事项:
1. 与Spring MVC 3.x/4.x的集成问题
Spring 3.x/4.x只支持1.3.x的velocity tools,要使用2.0必须自己扩展VelocityToolboxView类
package org.springframework.web.servlet.view.velocity; import java.util.Map; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.velocity.context.Context;
import org.apache.velocity.tools.Scope;
import org.apache.velocity.tools.ToolManager;
import org.apache.velocity.tools.view.ViewToolContext;
import org.springframework.web.servlet.view.velocity.VelocityToolboxView; public class VelocityToolbox2View extends VelocityToolboxView {
@Override
protected Context createVelocityContext(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {// Create a
// ChainedContext
// instance.
ViewToolContext ctx; ctx = new ViewToolContext(getVelocityEngine(), request, response,
getServletContext()); ctx.putAll(model); if (this.getToolboxConfigLocation() != null) {
ToolManager tm = new ToolManager();
tm.setVelocityEngine(getVelocityEngine());
tm.configure(getServletContext().getRealPath(
getToolboxConfigLocation()));
if (tm.getToolboxFactory().hasTools(Scope.REQUEST)) {
ctx.addToolbox(tm.getToolboxFactory().createToolbox(
Scope.REQUEST));
}
if (tm.getToolboxFactory().hasTools(Scope.APPLICATION)) {
ctx.addToolbox(tm.getToolboxFactory().createToolbox(
Scope.APPLICATION));
}
if (tm.getToolboxFactory().hasTools(Scope.SESSION)) {
ctx.addToolbox(tm.getToolboxFactory().createToolbox(
Scope.SESSION));
}
}
return ctx;
}
}
注:31行tm.configure(getServletContext().getRealPath(getToolboxConfigLocation()));这里,在某些容器,比如weblogic中,getRealPath可能取不到值,可改成
getResource试试
然后在spring mvc的servlet配置文件中参考如下设置:
<bean
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="order" value="0" />
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".vm" />
<property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="viewClass" value="org.springframework.web.servlet.view.velocity.VelocityToolbox2View"></property>
</bean>
2. 如何获取当前应用的contextPath
<tool>
<key>link</key>
<scope>request</scope>
<class>org.apache.velocity.tools.view.LinkTool</class>
</tool>
借助velocity-tools的LinkTool类,在velocity中直接用${link.contextPath}即可得到当前的contextPath
3、如何获取url参数
<tool>
<key>params</key>
<scope>request</scope>
<class>org.apache.velocity.tools.view.ParameterTool</class>
</tool>
然后就可以用类似$params.returnUrl,来获取类似 http://xxx.com/login?returnUrl=abc 中的 abc部分
4、如何与Spring-Security集成
<sec:authorize access="isAnonymous()">
...
</sec:authorize>
之类的标签无法在velocity中使用,而velocity-tools中也未提供相应的支持,在老外的一篇博客上,看到了解决方案:
package com.cnblogs.yjmyzz.utils; import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails; public class VelocitySecurityUtil { public static String getPrincipal() { Object obj = SecurityContextHolder.getContext().getAuthentication()
.getPrincipal(); if (obj instanceof UserDetails) {
return ((UserDetails) obj).getUsername();
} else {
return "anonymous";
}
} public static boolean isAuthenticated() {
return !getPrincipal().equals("anonymous");
} public static boolean allGranted(String[] checkForAuths) {
Set<String> userAuths = getUserAuthorities();
for (String auth : checkForAuths) {
if (userAuths.contains(auth))
continue;
return false;
}
return true;
} public static boolean anyGranted(String[] checkForAuths) {
Set<String> userAuths = getUserAuthorities();
for (String auth : checkForAuths) {
if (userAuths.contains(auth))
return true;
}
return false;
} public static boolean noneGranted(String[] checkForAuths) {
Set<String> userAuths = getUserAuthorities();
for (String auth : checkForAuths) {
if (userAuths.contains(auth))
return false;
}
return true;
} private static Set<String> getUserAuthorities() {
Object obj = SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
Set<String> roles = new HashSet<String>();
if (obj instanceof UserDetails) {
@SuppressWarnings("unchecked")
Collection<GrantedAuthority> gas = (Collection<GrantedAuthority>) ((UserDetails) obj)
.getAuthorities();
for (GrantedAuthority ga : gas) {
roles.add(ga.getAuthority());
}
}
return roles;
} }
然后修改配置:
<bean id="velocitySecurityUtil" class="com.cnblogs.yjmyzz.utils.VelocitySecurityUtil" /> <bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
...
<property name="viewResolvers">
<list>
<bean
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="order" value="0" />
...
<property name="attributesMap">
<map>
<entry key="sec">
<ref bean="velocitySecurityUtil" />
</entry>
</map>
</property> </bean>
...
页面就能用了:
#if(${sec.authenticated})
...
#end
注:这个思路也可以用于实现自己的Velocity-Tools类,比如我们创建了一个自己的RequestUtil类
package com.cnblogs.yjmyzz.utils;
import javax.servlet.http.HttpServletRequest;
public class RequestUtil{ /**
* 获取当前请求的基地址(例如:http://localhost:8080/ctas/xxx.do 返回 http://localhost:8080/ctas/)
*
* @param request
* @return
*/
public static String getBaseUrl(HttpServletRequest request) {
return request.getRequestURL().substring(0,
request.getRequestURL().indexOf(request.getContextPath()) + request.getContextPath().length()) + "/";
} }
然后在配置里,加上
<bean id="requestUtil" class="com.cnblogs.yjmyzz.utils.RequestUtil"/> <bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
...
<property name="viewResolvers">
<list>
...
<bean
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="order" value="0"/>
...
<property name="viewClass"
value="com.cnblogs.yjmyzz.utils.VelocityToolbox2View"></property>
<property name="attributesMap">
<map>
...
<entry key="req">
<ref bean="requestUtil"/>
</entry>
</map>
</property>
</bean>
...
</bean>
vm页面这样用
#*取得页面链接基地址*#
#macro(baseHref)${req.getBaseUrl($request)}#end
...
<base href="#{baseHref}">
...
<script type="text/javascript">
var baseHref = "#{baseHref}";
</script>
...
顺便提一句:网上有一堆文章和教程,让你在toolbox.xml中添加类似
<tool>
<key>req</key>
<scope>request</scope>
<class>com.cnblogs.yjmyzz.utils.RequestUtil</class>
</tool>
在Spring MVC4 + Velocity Tools2的组合下,然而,这并没有什么用,在Spring MVC4 + Velocity-Tools2下,已经不好使了。
最后,Velocity还允许自定义标签(也有人称为自定义指令),支持开发人员定义自己的标签,比如#YourDirective,详情可参考: