Struts 2 对 Velocity 的支持力度

2023-10-21 08:38
文章标签 支持 struts velocity 力度

本文主要是介绍Struts 2 对 Velocity 的支持力度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文主要介绍如何解决 Struts 2 和最新版本的 Velocity 结合的问题以及进一步提升 Struts 2 对 Velocity 的支持力度。

Struts 2 是 Struts 框架的一个全新版本,它废弃了原有 Struts 1.x 的框架结构,在 WebWork 的基础上全面提升了代码的配置灵活性、可测试性以及超强的扩展性。Struts 2 更是提供了对 Velocity 和 FreeMarker 模板引擎的支持,这破天荒的举动大大的方便了 Velocity 和 FreeMarker 的开发者,从而也更有效的推动了模板技术的发展。

在进行 Struts 2 和 Velocity 结合的试验中发现下面几个问题:

与 VelocityTools 1.3 存在兼容性问题;
不支持 Velocity Layout;
处理 velocity 模板时存在编码问题;

好在由于 Struts 2 的超强扩展性,使得这三个问题的解决变得非常简单,而且我们无需修改 Struts 2 的源码,下面分别给出三个问题的解决办法。

第一个问题:与 VelocityTools 1.3 存在兼容性问题

这个问题是因为 VelocityTools 这个项目从 1.2 升级到 1.3 时修改了一些类的方法(Method)导致的。在 1.3 这个版本中 ToolboxManager 类的 getToolboxContext 方法改名为 getToolbox,因此在启动程序的时候就会报 getToolboxContext 方法没找到的异常。

Struts 2 是在 VelocityManager 类的 createContext 方法中调用 ToolboxManager 的,而 Struts 2 允许通过配置来修改 VelocityManager 的实现类,因此我们只需要从 VelocityManager 继承一个子类,并重写 createContext 方法即可。重写的代码很简单,直接从 VelocityManager 的 createContext 方法中拷贝代码然后将 getToolboxContext 改为 getToolbox。

接着需要修改 Struts 2 的配置来启用这个新的子类,配置如下(struts.xml):

<constant name="struts.velocity.manager.classname" value="struts2.VelocityFixedManager"/>


或者是 struts.properties:

struts.velocity.manager.classname = struts2.VelocityFixedManager


第二个问题:不支持 Velocity Layout

首先简单的介绍一下 Velocity 的 Layout 技术。Velocity 的 Layout 是通过 VelocityTools 这个项目来实现的。大多数网站上每个页面基本上都会遵循相同的排版,例如一个页面由 banner 条、内容和底部版权说明组成。那么对于该网站上的每个网页,我们都需要编写重复的代码来显示 banner 条以及底部版权说明。而 Velocity 的 Layout 技术可以让我们把页面的布局和页面的内容分开到不同 velocity 模板文件中。要使用 Layout 技术只需要把 VelocityViewServlet 换成 VelocityLayoutServlet 即可。VelocityLayoutServlet 内置了一个变量 $screen_content,它首先执行内容模板页面并把执行后的字符串结果存入 $screen_content 变量中,然后再去执行布局页面,这样就相当于把内容页面嵌入到布局页面。

关于 ResultType

Struts 2 中把各种各样的视图例如 JSP、Velocity、FreeMarker 等等都封装成 ResultType 的子类,也就是说每一种视图 Struts 2 都有与之对应的 ResultType 的实现类, 本文中 Velocity 视图对应的类是 VelocityResult

但是这个问题在 Struts 2 环境中就要麻烦很多。因为 Struts 2 并不是采用 Velocity Tools 那种基于 Servlet 的方式来调用 velocity 模板,所以我们没法只是简单的替换成 VelocityLayoutServlet 就能解决。在 Struts 2 的默认配置中定义了一个名为 velocity 的 ResultType,它对应的类是 org.apache.struts2.dispatcher.VelocityResult 。该类没有跟 Velocity Tools 打交道,而是直接调用 Velocity 的核心 API 来执行 velocity 模板。因此我们只好根据 Velocity Tools 项目中 VelocityLayoutServlet 的思路来改写 Struts 2 对 velocity 模板的处理方法。

在处理之前我们先大概解释一下 VelocityLayoutServlet 的工作原理,先看几个程序源码:

<!-- layout.vm -- >

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<HTML>

<HEAD>

<TITLE>${page_title}</TITLE>

</HEAD>

<BODY>

${screen_content}

</BODY>

</HTML>


上面是布局页面的代码,这个布局页面包含两个变量,一个是 $page_title,用来指定页面标题;第二个是 $screen_content,这是 VelocityLayoutServlet 定义的变量,这个变量最终会被替换成实际页面的内容。

## index.vm

#set($layout = “layout.vm”) ##选择布局页面

#set($page_title =”Struts2Velocity”)

#set($name = “Winter Lau”)

<p>

Hello <b>$name</b>, Welcome to Struts2 with velocity <br/>

</p>


上面是另外一个页面 index.vm 的代码。当 VelocityLayoutServlet 处理 index.vm 时,首先执行 index.vm,并把执行后的结果保存在一个字符串中,并往 VelocityContext 中增加变量名为 $screen_content,值为 index.vm 的执行结果,然后执行 layout.vm 页面,这样最终呈现在用户面前的就是 index.vm 嵌入在 layout.vm 的效果。

因此我们可以依照上面的原理,从 VelocityResult 中继承一个子类并重写其 doExecute 这个方法。详细的代码请看附件中的源码。

类编写完毕同样需要对 Struts 进行如下配置(struts.xml),这个配置是告诉 Struts 使用 struts2.VelocityLayoutResult 这个类来处理采用 velocity 开发的视图:

<result-types>

<result-type name="velocity" class="struts2.VelocityLayoutResult"/>

</result-types>


接下来就可以测试新的功能了,我们配置 action 如下,打开浏览器访问 http://localhost:<port>/index.do 看看效果吧。

<action name="index">

<result type="velocity">/index.vm</result>

</action>


这样我们不需要 VelocityTools 也可以让 Struts 2 支持 Velocity Layout 了。


第三个问题:处理 velocity 模板时存在编码问题

Velocity 有几个参数跟编码有关的分别是:

default.contentType=text/html

input.encoding=GBK

output.encoding=UTF-8


其中第一个参数指定了 velocity 模板执行后输出到浏览器时的 ContentType;第二个参数是 Velocity 引擎以什么编码方式读取 velocity 模板文件;第三个参数是输出页面的编码。

但是采用 Struts 2 后发现这三个参数并没有起作用,深入 Struts 2 的代码发现在处理 vm 编码时采用的是 Struts 2 的编码配置,而且读取 velocity 模板文件和输出 html 到浏览器采用的相同的编码,这种方式个人觉得 Struts 2 处理欠妥当,为了保留 Velocity 的特色,在 VelocityLayoutResult 的基础上进一步改进。我们需要重载 VelocityResult 的 setVelocityManager 方法,因为这个方法是用来初始化 Velocity 引擎的,我们在初始化的过程中读取前面提到的三个配置参数并把参数值保存在类的属性中,详细的代码如下:

@Inject

@Override

public void setVelocityManager(VelocityManager mgr) {

super.setVelocityManager(mgr);

if(mgr != null && velocityManager==null){

this.velocityManager = mgr;

ServletContext ctx = ServletActionContext.getServletContext();

velocityManager.init(ctx);

VelocityEngine engine = velocityManager.getVelocityEngine();

defaultLayout = (String)engine.getProperty(PROPERTY_DEFAULT_LAYOUT);

layoutDir = (String)engine.getProperty(PROPERTY_LAYOUT_DIR);

if (!layoutDir.endsWith("/")){

layoutDir += '/';

}


if (!layoutDir.startsWith("/")){

layoutDir = "/" + layoutDir;

}


// for efficiency's sake, make defaultLayout a full path now

defaultLayout = layoutDir + defaultLayout;


inputEncoding = (String)engine.getProperty(PROPERTY_INPUT_ENCODING);

outputEncoding = (String)engine.getProperty(PROPERTY_OUTPUT_ENCODING);

contentType = (String)engine.getProperty(PROPERTY_CONTENT_TYPE);


if (outputEncoding != null && contentType != null) {

contentType = contentType + ";charset=" + outputEncoding;

}

}

}


同时修改 doExecute 方法以使用正确的编码进行处理,主要代码如下(请注意标识为粗体的代码):

Template t = getTemplate(stack, velocityManager.getVelocityEngine(),

invocation, finalLocation, inputEncoding);


Context context = createContext(velocityManager, stack, request, response, finalLocation);

//将页面执行结果写入到字符串缓存中

StringWriter sw = new StringWriter();

t.merge(context, sw);

context.put(KEY_SCREEN_CONTENT, sw.toString());


Object obj = context.get(KEY_LAYOUT);

String layout = (obj == null) ? null : obj.toString();

if (layout == null)

{

// no alternate, use default

layout = defaultLayout;

}

else

{

// make it a full(er) path

layout = layoutDir + layout;

}


Template layout_vm = null;

try

{

//System.err.println("-------------- > layout=" + layout);

//load the layout template

layout_vm = getTemplate(stack, velocityManager.getVelocityEngine(),

invocation, layout, inputEncoding);

}

catch (Exception e)

{

velocityManager.getVelocityEngine().getLog().error(

"VelocityLayoutResult: Can't load layout /"" + layout + "/": " + e);


// if it was an alternate layout we couldn't get...

if (!layout.equals(defaultLayout))

{

// try to get the default layout

// if this also fails, let the exception go

layout_vm = getTemplate(stack, velocityManager.getVelocityEngine(),

invocation, defaultLayout, inputEncoding);

}

}


Writer writer = new OutputStreamWriter(response.getOutputStream(),

outputEncoding);

response.setContentType(contentType);

layout_vm.merge(context, writer);

writer.flush();

这篇关于Struts 2 对 Velocity 的支持力度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/253226

相关文章

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

sqlite不支持中文排序,采用java排序

方式一 不支持含有重复字段进行排序 /*** sqlite不支持中文排序,改用java排序* 根据指定的对象属性字段,排序对象集合,顺序* @param list* @param field* @return*/public static List sortListByField(List<?> list,String field){List temp = new ArrayList(

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬

Science Robotics 首尔国立大学研究团队推出BBEX外骨骼,实现多维力量支持!

重复性举起物体可能会对脊柱和背部肌肉造成损伤,由此引发的腰椎损伤是工业环境等工作场所中一个普遍且令人关注的问题。为了减轻这类伤害,有研究人员已经研发出在举起任务中为工人提供辅助的背部支撑装置。然而,现有的这类装置通常无法在非对称性的举重过程中提供多维度的力量支持。此外,针对整个人体脊柱的设备安全性验证也一直是一个缺失的环节。 据探索前沿科技边界,传递前沿科技成果的X-robot投稿,来自首尔国立

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密 可以将表情,动物,水果,表情,手势,猫语,兽语,狗语,爱语,符号,数字,字母,加密和解密 可以将文字、字母、数字、代码、标点符号等内容转换成新的文字形式,通过简单的文字以不同的排列顺序来表达不同的内容 源码截图: https://www.httple.net/152649.html

QtC++截图支持窗口获取

介绍 在截图工具中你会发现,接触到窗口后会自动圈出目标窗口,个别强大一点的还能进行元素识别可以自动圈出元素,那么今天简单分析一下QTc++如何获取窗口并圈出当前鼠标下的窗口。 介绍1.如何获取所有窗口2.比较函数3.实现窗口判断 结尾 1.如何获取所有窗口 1.我们需要调用windows接口EnumWindowsProc回调函数来获取所有顶级窗口,需要包含windows.

Nacos Config 配置中心支持配置共享

文章目录 一、什么是配置中心二、Nacos Config2.1 Nacos Config 工作原理 (★)2.2 Nacos Config 的使用2.3 动态刷新2.4 配置共享2.4.1 同一个微服务的不同环境之间共享配置2.4.2 不同微服务中间共享配置 一、什么是配置中心 微服务架构下关于配置文件的存在以下问题: 配置文件相对分散。在一个微服务架构下,配置文件会随

spring笔记 多线程的支持

spring的工作机制 136  属性编辑器 140 spring事件的体系结构 168 Bean间的关系 109 继承 依赖 引用     Bean的继承          1 为了简化初始化的属性注入;          2 子Bean和父Bean相同的属性值,使用子Bean的     Bean的依赖 Srping控制相互依赖的Bean之间,属性注入的顺序,防止出错  depend-on

在struts.xml中,如何配置请求转发和请求重定向!

<span style="font-size:18px;"><span style="white-space:pre"> </span><!--<strong>下面用请求转发action </strong>,<strong>这样过去id不会丢</strong>,如果用重定向的话,id会丢 --><result name="updatePopedom"<span style="color:#ff00

修改struts中:fielderror.ftl 模板

在项目登录页面: 当验证码输入有误时,应该提示:验证码输入有误,请重新输入 ,但是页面出现乱了! 错误原因: 在产生错误信息时,页面中增加了<ul> <li><span></span></li></ul>标签,该如何修改改, 解决方法(一): 在项目的src下,新建文件夹:template.simple,在文件夹里面放修改好的fielderror.ftl文件。 fi