Freemarker 和 Struts 2,有时它被评估为一个序列+extended_hash

Freemarker and Struts 2, sometimes it evaluates as a sequence+extended_hash

首先让我说使用 Struts2 + Freemarker 是一个真正的爆炸。 然而,有些事情让我发疯,因为我不明白为什么会这样。我在这里问,因为也许其他人有想法可以分享。

我有一个动作,属性。 说

private String myText;

然后我有一个 setter 和一个 getter:

public void setMyText(String myText)
{
  this.myText = myText;
}

public String getMyText()
{
  if (myText == null)
    myText = "(empty)";

  return this.myText;
}

结果(在 struts.xml 中)是 freemarker 结果。 所以在我的 Freemarker 模板中有一行如下所示:

<p>The text is: ${myText}</p>

现在考虑我调用没有任何文本参数的操作:假设 url 是

http:localhost:8080/myapp/myaction

由于getter提供了默认值,当处理动作并将结果传递到我的模板时,属性设置为默认值;所以我得到(html 在浏览器端)

<p>The text is: (empty)</p>

如果我用参数集调用我的操作,而不是(我的意思是像这样:

http:localhost:8080/myapp/myaction?myText=hallo

) 出了问题。 Freemarker 触发以下异常:

Exception occurred during processing request: For "${...}" content:
Expected a string or something automatically convertible to string
(number, date or boolean), but this has evaluated to a
sequence+extended_hash (String[] wrapped into f.e.b.ArrayModel)

好像"myText"找了两次... 我究竟做错了什么?或者,至少,有人可以向我解释为什么会这样吗?

P.S.: 真的找了两次;以下是解决该问题的方法:

<#if myText?is_sequence>${myText[0]}<#else>${myText}</#if>

但在我看来,以这种方式包装每个变量似乎并不可行。

P.P.S.: 进一步的提示:在 freemarker 模板中,前面几行调用了另一个动作。类似于:

<@s.action var="innerAction" name="getTable" namespace="/foo" />

如果我注释上面的行,一切正常。

myText 可以是来自 freemarker 上下文的变量,但是如果你想使用操作 属性

<p>The text is: ${action.myText}</p>

请注意,访问操作属性不需要 action 前缀。解析 freemarker 变量时应用 property resolution 方法:

Property Resoloution:

Your action properties are automatically resolved - just like in a velocity view.

for example ${name} will result in stack.findValue("name"), which generally results in action.getName() being executed.

A search process is used to resolve the variable, searching the following scopes in order, until a value is found :

  • freemarker variables
  • value stack
  • request attributes
  • session attributes
  • servlet context attributes

稍后您可以从上下文中读取哪些对象是可访问的。

Objects in the Context:

The following variables exist in the FreeMarker views

  • req - the current HttpServletRequest
  • res - the current HttpServletResponse
  • stack - the current OgnlValueStack
  • ognl - the OgnlTool instance This class contains useful methods to execute OGNL expressions against arbitary objects, and a method to generate a select list using the <s:select> pattern. (i.e. taking the name of the list property, a listKey and listValue)
  • struts - an instance of StrutsBeanWrapper
  • action - the current Struts action
  • exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view

错误可能是由于从值堆栈中搜索并根据执行时堆栈的结构返回了您不期望的内容。

为变量添加前缀以指出 属性 的确切位置应该可以修复在值堆栈中搜索时代码中的冗余。