使用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类
1 package org.springframework.web.servlet.view.velocity; 2 3 import java.util.Map; 4 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 import org.apache.velocity.context.Context; 9 import org.apache.velocity.tools.Scope; 10 import org.apache.velocity.tools.ToolManager; 11 import org.apache.velocity.tools.view.ViewToolContext; 12 import org.springframework.web.servlet.view.velocity.VelocityToolboxView; 13 14 public class VelocityToolbox2View extends VelocityToolboxView { 15 @Override 16 protected Context createVelocityContext(Map<String, Object> model, 17 HttpServletRequest request, HttpServletResponse response) 18 throws Exception {// Create a 19 // ChainedContext 20 // instance. 21 ViewToolContext ctx; 22 23 ctx = new ViewToolContext(getVelocityEngine(), request, response, 24 getServletContext()); 25 26 ctx.putAll(model); 27 28 if (this.getToolboxConfigLocation() != null) { 29 ToolManager tm = new ToolManager(); 30 tm.setVelocityEngine(getVelocityEngine()); 31 tm.configure(getServletContext().getRealPath( 32 getToolboxConfigLocation())); 33 if (tm.getToolboxFactory().hasTools(Scope.REQUEST)) { 34 ctx.addToolbox(tm.getToolboxFactory().createToolbox( 35 Scope.REQUEST)); 36 } 37 if (tm.getToolboxFactory().hasTools(Scope.APPLICATION)) { 38 ctx.addToolbox(tm.getToolboxFactory().createToolbox( 39 Scope.APPLICATION)); 40 } 41 if (tm.getToolboxFactory().hasTools(Scope.SESSION)) { 42 ctx.addToolbox(tm.getToolboxFactory().createToolbox( 43 Scope.SESSION)); 44 } 45 } 46 return ctx; 47 } 48 }
View Code
注:31行tm.configure(getServletContext().getRealPath(getToolboxConfigLocation()));这里,在某些容器,比如weblogic中,getRealPath可能取不到值,可改成
getResource试试
然后在spring mvc的servlet配置文件中参考如下设置:
1 <bean 2 class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> 3 <property name="order" value="0" /> 4 <property name="cache" value="true" /> 5 <property name="prefix" value="" /> 6 <property name="suffix" value=".vm" /> 7 <property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml" /> 8 <property name="contentType" value="text/html;charset=UTF-8" /> 9 <property name="viewClass" value="org.springframework.web.servlet.view.velocity.VelocityToolbox2View"></property> 10 </bean>
View Code
2. 如何获取当前应用的contextPath
1 <tool> 2 <key>link</key> 3 <scope>request</scope> 4 <class>org.apache.velocity.tools.view.LinkTool</class> 5 </tool>
借助velocity-tools的LinkTool类,在velocity中直接用${link.contextPath}即可得到当前的contextPath
3、如何获取url参数
1 <tool> 2 <key>params</key> 3 <scope>request</scope> 4 <class>org.apache.velocity.tools.view.ParameterTool</class> 5 </tool>
然后就可以用类似$params.returnUrl,来获取类似 http://xxx.com/login?returnUrl=abc 中的 abc部分
4、如何与Spring-Security集成
1 <sec:authorize access="isAnonymous()"> 2 ... 3 </sec:authorize>
View Code
之类的标签无法在velocity中使用,而velocity-tools中也未提供相应的支持,在老外的一篇博客上,看到了解决方案:
1 package com.cnblogs.yjmyzz.utils; 2 3 import java.util.Collection; 4 import java.util.HashSet; 5 import java.util.Set; 6 import org.springframework.security.core.GrantedAuthority; 7 import org.springframework.security.core.context.SecurityContextHolder; 8 import org.springframework.security.core.userdetails.UserDetails; 9 10 public class VelocitySecurityUtil { 11 12 public static String getPrincipal() { 13 14 Object obj = SecurityContextHolder.getContext().getAuthentication() 15 .getPrincipal(); 16 17 if (obj instanceof UserDetails) { 18 return ((UserDetails) obj).getUsername(); 19 } else { 20 return "anonymous"; 21 } 22 } 23 24 public static boolean isAuthenticated() { 25 return !getPrincipal().equals("anonymous"); 26 } 27 28 public static boolean allGranted(String[] checkForAuths) { 29 Set<String> userAuths = getUserAuthorities(); 30 for (String auth : checkForAuths) { 31 if (userAuths.contains(auth)) 32 continue; 33 return false; 34 } 35 return true; 36 } 37 38 public static boolean anyGranted(String[] checkForAuths) { 39 Set<String> userAuths = getUserAuthorities(); 40 for (String auth : checkForAuths) { 41 if (userAuths.contains(auth)) 42 return true; 43 } 44 return false; 45 } 46 47 public static boolean noneGranted(String[] checkForAuths) { 48 Set<String> userAuths = getUserAuthorities(); 49 for (String auth : checkForAuths) { 50 if (userAuths.contains(auth)) 51 return false; 52 } 53 return true; 54 } 55 56 private static Set<String> getUserAuthorities() { 57 Object obj = SecurityContextHolder.getContext().getAuthentication() 58 .getPrincipal(); 59 Set<String> roles = new HashSet<String>(); 60 if (obj instanceof UserDetails) { 61 @SuppressWarnings("unchecked") 62 Collection<GrantedAuthority> gas = (Collection<GrantedAuthority>) ((UserDetails) obj) 63 .getAuthorities(); 64 for (GrantedAuthority ga : gas) { 65 roles.add(ga.getAuthority()); 66 } 67 } 68 return roles; 69 } 70 71 }
View Code
然后修改配置:
1 <bean id="velocitySecurityUtil" class="com.cnblogs.yjmyzz.utils.VelocitySecurityUtil" /> 2 3 <bean 4 class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 5 <property name="order" value="1" /> 6 ... 7 <property name="viewResolvers"> 8 <list> 9 <bean 10 class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> 11 <property name="order" value="0" /> 12 ... 13 <property name="attributesMap"> 14 <map> 15 <entry key="sec"> 16 <ref bean="velocitySecurityUtil" /> 17 </entry> 18 </map> 19 </property> 20 21 </bean> 22 ...
View Code
页面就能用了:
1 #if(${sec.authenticated}) 2 ... 3 #end
View Code
注:这个思路也可以用于实现自己的Velocity-Tools类,比如我们创建了一个自己的RequestUtil类
1 package com.cnblogs.yjmyzz.utils; 2 import javax.servlet.http.HttpServletRequest; 3 public class RequestUtil{ 4 5 /** 6 * 获取当前请求的基地址(例如:http://localhost:8080/ctas/xxx.do 返回 http://localhost:8080/ctas/) 7 * 8 * @param request 9 * @return 10 */ 11 public static String getBaseUrl(HttpServletRequest request) { 12 return request.getRequestURL().substring(0, 13 request.getRequestURL().indexOf(request.getContextPath()) + request.getContextPath().length()) + "/"; 14 } 15 16 }
View Code
然后在配置里,加上
1 <bean id="requestUtil" class="com.cnblogs.yjmyzz.utils.RequestUtil"/> 2 3 <bean 4 class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 5 <property name="order" value="1"/> 6 ... 7 <property name="viewResolvers"> 8 <list> 9 ... 10 <bean 11 class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> 12 <property name="order" value="0"/> 13 ... 14 <property name="viewClass" 15 value="com.cnblogs.yjmyzz.utils.VelocityToolbox2View"></property> 16 <property name="attributesMap"> 17 <map> 18 ... 19 <entry key="req"> 20 <ref bean="requestUtil"/> 21 </entry> 22 </map> 23 </property> 24 </bean> 25 ... 26 </bean>
View Code
vm页面这样用
1 #*取得页面链接基地址*# 2 #macro(baseHref)${req.getBaseUrl($request)}#end 3 ... 4 <base href="#{baseHref}"> 5 ... 6 <script type="text/javascript"> 7 var baseHref = "#{baseHref}"; 8 </script> 9 ...
View Code
顺便提一句:网上有一堆文章和教程,让你在toolbox.xml中添加类似
1 <tool> 2 <key>req</key> 3 <scope>request</scope> 4 <class>com.cnblogs.yjmyzz.utils.RequestUtil</class> 5 </tool>
View Code
在Spring MVC4 + Velocity Tools2的组合下,然而,这并没有什么用,在Spring MVC4 + Velocity-Tools2下,已经不好使了。
最后,Velocity还允许自定义标签(也有人称为自定义指令),支持开发人员定义自己的标签,比如#YourDirective,详情可参考: