项目使用的是Velocity来渲染主体内容,大的框架还是使用JSP.
总体来说就是JSP + Velocity.
请求使用JSP, 异步使用VM
你问什么用Velocity不用freemarker 因为项目比较老.修改比较麻烦.
现在有一个需求,因为项目的生产和UAT使用的图片路径是不一样的.
这样导致在渲染Velocity模板的时候,需要有一个属性去判断使用什么版本的资源.
JSP很好判断,应为能够获取HttpServletRequest, 直接拿取RequestURL方法即可.
但是Velocity里面是无法获取Request的,难道要把URL作为参数传递过去.
那修改的代码量,无法想象.
大部分的Velocity模板都会有一个公共的头,在这个头中存储通用的信息,我们要是能够把
URL传入到这个头,就好了.
查阅资料,网上有一个通过编写指令来获取Request的想法提示了我.
可以通过指令来获取HttpServletRequest,把URL存入到变量中即可. 然后就设计了下面一个类.
package com.itheima.util; import java.io.IOException; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.velocity.context.InternalContextAdapter; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.directive.Directive; import org.apache.velocity.runtime.parser.node.Node; import org.springframework.web.servlet.support.RequestContext; /** * 路径存在,是一个velocity的指令类. * 用来判断url对应的生产环节 * @author 陈淼 * @time 2017年7月11日 下午3:25:37 */ public class UrlObtain extends Directive { // 可以使用反射去突破安全防线, private boolean canSecurity = true; @Override public String getName() { return "UrlObtain"; } // Block块标示要使用#end结束 Line不需要 @Override public int getType() { return LINE; } @Override public boolean render(InternalContextAdapter context, Writer writer, Node node ) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { // 写入一个默认的域 String requestUrl = ""; int count = node.jjtGetNumChildren(); // 给定了 默认的url if(count > 0) { Node jjtGetChild = node.jjtGetChild(0); if(jjtGetChild != null) { requestUrl = (String) jjtGetChild.value(context); } } // 限制了反射 if(count > 1) { Node jjtGetChild = node.jjtGetChild(1); if(jjtGetChild != null) { String securityValue = (String) jjtGetChild.value(context); canSecurity = Boolean.valueOf(securityValue); } } RequestContext requestContext = (RequestContext) context.get("rc"); if(requestContext == null) { throw new ResourceNotFoundException("please open velocity requestContextAttribute set value rc"); } // 如果没有提供默认的url,并且 不允许使用反射, 那么报错. if(StringUtils.isEmpty(requestUrl) && !canSecurity) { throw new IOException("Either set the default URL, or open the reflect"); } HttpServletRequest request = null; if(canSecurity) { try { Method method = requestContext.getClass().getDeclaredMethod("getRequest", null); method.setAccessible(true); request = (HttpServletRequest) method.invoke(requestContext, null); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } // 获取真实url if(request != null) { requestUrl = request.getRequestURL().toString(); } context.put("RequestURL", requestUrl); //requestContext.getModel().put("RequestURL", requestUrl); return true; } }## UrlObtain 具有两个参数, 默认是url地址和是否使用反射(默认为使用) 结果保存在RequestURL变量中
## 如果不使用反射, 则RequestURL变量时默认url地址,
## 如果没有传递默认url并且 禁止使用反射, 会抛出异常.
## UrlObtain 需要视图解析器开启requestContextAttribute属性 并命名为rc
## 不然会抛出异常.
#UrlObtain("www.baidu.com")
这样子 $RequestURL将可以获取到现在的URL
展开来说,既然反射可以拿到Request,那么Response也可以拿到.
还可以把Request和Response作为变量传递到Velocity模板中去.
需要注意的是.视图解析器的配置
<bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="exposeSessionAttributes" value="true" /> <property name="allowSessionOverride" value="true" /> <property name="requestContextAttribute" value="rc" /> <!-- 把request的属性扩展到模板中去 --> <property name="cache" value="true" /> <property name="prefix" value="" /> <property name="suffix" value=".vm" /> <property name="order" value="1" /> <property name="viewNames"> <list> <value>test</value> </list> </property> <property name="dateToolAttribute" value="dateTool" /> <property name="numberToolAttribute" value="numberTool" /> <property name="contentType" value="text/html;charset=UTF-8"></property> </bean>end
