使用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 }
注: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>
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>
之类的标签无法在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 }
然后修改配置:
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 ...
页面就能用了:
1 #if(${sec.authenticated})
2 ...
3 #end
注:这个思路也可以用于实现自己的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 }
然后在配置里,加上
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>
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 ...
顺便提一句:网上有一堆文章和教程,让你在toolbox.xml中添加类似
1 <tool>
2 <key>req</key>
3 <scope>request</scope>
4 <class>com.cnblogs.yjmyzz.utils.RequestUtil</class>
5 </tool>
在Spring MVC4 + Velocity Tools2的组合下,然而,这并没有什么用,在Spring MVC4 + Velocity-Tools2下,已经不好使了。
最后,Velocity还允许自定义标签(也有人称为自定义指令),支持开发人员定义自己的标签,比如#YourDirective,详情可参考: