背景
我们有一个现有的webapp,使用Struts 2和Freemarker构建,我通过复制一些代码和模板创建了一个变体。克鲁迪,但可管理。然而,我们将很快制作其他一些变体(需要单独的WAR),使复制变得站不住脚。我的想法是将所有共享内容放入每个webapp包含的jar中:公共文件可以在一个地方维护,甚至更好的给定webapp可以覆盖类路径中的文件。到目前为止,我已经能够使用代码执行此操作,但是使用Convention插件会使Freemarker模板难以执行相同操作。
问题
到目前为止,我们的webapp依靠Convention来找到应用程序启动时的动作的Freemarker“动作结果”(即模板),从而使我们不必繁琐地注释它们中的每一个。如果我已经正确地跟踪了事情,那么班级DefaultResultMapBuilder
负责找到行动结果;特别是,方法createFromResources
在webapp中查找,然后在类路径中查找与我们的操作匹配的模板文件。
这正是我想要的 - 除了我们将模板放在/WEB-INF
下以保护它们免受外部访问(在我们的Struts配置中使用struts.convention.result.path
常量)。到目前为止,这种方法运行良好,所有模板文件都位于/WEB-INF
下,但它也不能在类路径上使用文件。 DefaultResultMapBuilder
当然可以在类路径上找到文件,但仅当webapp模板直接位于上下文根目录下时,因为任何类路径模板都必须位于与上下文根目录下模板的目录结构等效的包结构中。对于“struts.convention.result.path”以“/ WEB-INF /”开头的行为结果,需要一个名为“web-inf”的根包 - 但当然包名中不允许使用连字符。
(请注意,此问题独立于稍后用于实际获取模板文件的TemplateLoader
类。加载过程很容易配置为在许多地方查找 - 但应用程序永远不会得到远程如果在启动时找不到“动作结果”。如果两个进程使用相同的配置会很好......)
方案吗
所以...我可以将所有模板移到/WEB-INF
之外,但我真的不愿意。或者我可以为每个动作类提供特定的注释,并且我不想再这样做(实际上它可能会遇到同样的问题)。
或者我可以通过复制和稍微改变ResultMapBuilder
来自己实现DefaultResultMapBuilder
(后者中的每个成员都是私有的,所以我无法扩展类并只更改相关部分 - 唉!),然后弄清楚如何覆盖“struts-plugin.xml”Struts配置文件(更改org.apache.struts2.convention.ResultMapBuilder
bean),因此我可以让Convention忽略“/ WEB-INF”在classpath上看。或者更好的是,在查看ServletContext时始终使用“/ WEB-INF /”为路径添加前缀。
但也许有一种更简单的方法?一些未记载的配置魔术?