I want to add a variable list of parameters to a Struts2 URL tag. I have a map of the parameters (name value pairs) in an object in the session. I'm struggling to find a good approach to this. Here is the relevant JSP code:
我想在Struts2 URL标记中添加一个变量参数列表。我有一个会话中对象的参数(名称值对)的映射。我正在努力寻找一个好方法。这是相关的JSP代码:
<s:iterator value="%{#session['com.strutsschool.interceptors.breadcrumbs']}" status="status">
<s:if test="#status.index > 0">
»
</s:if>
<s:url id="uri" action="%{action}" namespace="%{nameSpace}">
<s:param name="parameters" value="%{parameters}"/>
</s:url>
<nobr><s:a href="%{uri}"><s:property value="displayName"/></s:a></nobr>
</s:iterator>
The parameters variable is a Map that contains the params. This, of course does not work but I cannot see a way to approach this at the moment. I'm thinking at the moment that I might need a custom freemarker template for this. Can anyone suggest a better way?
参数变量是包含参数的Map。这当然不起作用,但我现在看不到办法解决这个问题。我现在想的是我可能需要一个自定义的freemarker模板。有谁能建议更好的方法?
4 个解决方案
#1
The Parameter tag populates parameters only to its direct antecessor. Wrappings an iterator tag around the parameter tag has no effect. :) To solve this you can easily write an alternative parameter tag wich can use a map direclty The tag may look like this.
Parameter标记仅将参数填充到其直接前导。对参数标记周围的迭代器标记进行包装无效。 :)要解决这个问题,你可以轻松编写一个替代参数标签,它可以使用map direclty标签可能看起来像这样。
package my.taglibs;
import java.io.Writer;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ComponentTagSupport;
import com.opensymphony.xwork2.util.ValueStack;
public class ParamTag extends ComponentTagSupport {
private String map;
private static final long serialVersionUID = 2522878390854066408L;
Log log = LogFactory.getLog(ParamTag.class);
@Override
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
return new Param(stack);
}
@Override
protected void populateParams() {
super.populateParams();
Param param = (Param) component;
param.setMap(map);
}
public void setMap(String map) {
this.map = map;
}
public class Param extends Component {
private String map;
public Param(ValueStack stack) {
super(stack);
}
@Override
public boolean end(Writer writer, String body) {
Component component = findAncestor(Component.class);
if (this.map == null) {
log.warn("Attribute map is mandatory.");
return super.end(writer, "");
}
Object o = findValue(this.map); //find map in vs
if(o == null) {
log.warn("map not found in ValueStack");
return super.end(writer, "");
}
if(!(o instanceof Map)) {
log.warn("Error in JSP. Attribute map must evaluate to java.util.Map. Found type: " + o.getClass().getName());
return super.end(writer, "");
}
component.addAllParameters((Map) o);
return super.end(writer, "");
}
public void setMap(String map) {
this.map = map;
}
}
}
And you need a corresponding tld-entry
而且你需要一个相应的tld-entry
<tag>
<description><![CDATA[Parametrize other tags]]></description>
<name>param</name>
<tag-class>my.taglibs.ParamTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>map</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<dynamic-attributes>false</dynamic-attributes>
</tag>
#2
Maybe you can use JSTL tags like this
也许你可以像这样使用JSTL标签
<c:url var="uri" value="${namespace}/${action}.action">
<c:forEach items="${parameters}" var="p">
<c:param name="${p.key}" value="${p.value}"/>
</c:forEach>
</c:url>
<a href="${uri}">Your Link</a>
I know there is some hesitation to mix EL with OGNL etc but this works...
我知道将EL与OGNL等混合有一些犹豫,但这有效......
#3
You can iterate over a map using
您可以使用迭代迭代地图
<s:url var="url" action="%{link}" >
<s:iterator value="parameters.keySet()" var="key">
<s:param name="%{key}" value="%{parameters.get(#key)}"/>
</s:iterator>
</s:url>
but the iterator will consume the parameters as it's the parent component of the param.
但迭代器将使用参数,因为它是param的父组件。
Check outAdding arbitrary parameters to a URL in Struts2 for how to do this with a custom tag which results in the similar
检查将任意参数添加到Struts2中的URL,以了解如何使用自定义标记执行此操作,从而产生类似的结果
<s:url var="url" action="%{link}" >
<s:iterator value="parameters.keySet()" var="key">
<ob:iterable-param name="%{key}" value="%{parameters.get(#key)}"/>
</s:iterator>
</s:url>
iterable-param is a custom component that returns the grandparent of the param in the case where the parent is an iterator.
iterable-param是一个自定义组件,在父级是迭代器的情况下返回param的祖父级。
#4
With reference to comment 3, please show how would you use this customized tag in your jsp to achive the required behaviour.
参考评论3,请说明如何在jsp中使用此自定义标记来实现所需的行为。
Also, to use the solution mentioned in comment 1, what is the entry that we need to do in a tld file?
另外,要使用注释1中提到的解决方案,我们需要在tld文件中执行什么操作?
Please let me know this.
请让我知道这一点。
#1
The Parameter tag populates parameters only to its direct antecessor. Wrappings an iterator tag around the parameter tag has no effect. :) To solve this you can easily write an alternative parameter tag wich can use a map direclty The tag may look like this.
Parameter标记仅将参数填充到其直接前导。对参数标记周围的迭代器标记进行包装无效。 :)要解决这个问题,你可以轻松编写一个替代参数标签,它可以使用map direclty标签可能看起来像这样。
package my.taglibs;
import java.io.Writer;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ComponentTagSupport;
import com.opensymphony.xwork2.util.ValueStack;
public class ParamTag extends ComponentTagSupport {
private String map;
private static final long serialVersionUID = 2522878390854066408L;
Log log = LogFactory.getLog(ParamTag.class);
@Override
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
return new Param(stack);
}
@Override
protected void populateParams() {
super.populateParams();
Param param = (Param) component;
param.setMap(map);
}
public void setMap(String map) {
this.map = map;
}
public class Param extends Component {
private String map;
public Param(ValueStack stack) {
super(stack);
}
@Override
public boolean end(Writer writer, String body) {
Component component = findAncestor(Component.class);
if (this.map == null) {
log.warn("Attribute map is mandatory.");
return super.end(writer, "");
}
Object o = findValue(this.map); //find map in vs
if(o == null) {
log.warn("map not found in ValueStack");
return super.end(writer, "");
}
if(!(o instanceof Map)) {
log.warn("Error in JSP. Attribute map must evaluate to java.util.Map. Found type: " + o.getClass().getName());
return super.end(writer, "");
}
component.addAllParameters((Map) o);
return super.end(writer, "");
}
public void setMap(String map) {
this.map = map;
}
}
}
And you need a corresponding tld-entry
而且你需要一个相应的tld-entry
<tag>
<description><![CDATA[Parametrize other tags]]></description>
<name>param</name>
<tag-class>my.taglibs.ParamTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>map</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<dynamic-attributes>false</dynamic-attributes>
</tag>
#2
Maybe you can use JSTL tags like this
也许你可以像这样使用JSTL标签
<c:url var="uri" value="${namespace}/${action}.action">
<c:forEach items="${parameters}" var="p">
<c:param name="${p.key}" value="${p.value}"/>
</c:forEach>
</c:url>
<a href="${uri}">Your Link</a>
I know there is some hesitation to mix EL with OGNL etc but this works...
我知道将EL与OGNL等混合有一些犹豫,但这有效......
#3
You can iterate over a map using
您可以使用迭代迭代地图
<s:url var="url" action="%{link}" >
<s:iterator value="parameters.keySet()" var="key">
<s:param name="%{key}" value="%{parameters.get(#key)}"/>
</s:iterator>
</s:url>
but the iterator will consume the parameters as it's the parent component of the param.
但迭代器将使用参数,因为它是param的父组件。
Check outAdding arbitrary parameters to a URL in Struts2 for how to do this with a custom tag which results in the similar
检查将任意参数添加到Struts2中的URL,以了解如何使用自定义标记执行此操作,从而产生类似的结果
<s:url var="url" action="%{link}" >
<s:iterator value="parameters.keySet()" var="key">
<ob:iterable-param name="%{key}" value="%{parameters.get(#key)}"/>
</s:iterator>
</s:url>
iterable-param is a custom component that returns the grandparent of the param in the case where the parent is an iterator.
iterable-param是一个自定义组件,在父级是迭代器的情况下返回param的祖父级。
#4
With reference to comment 3, please show how would you use this customized tag in your jsp to achive the required behaviour.
参考评论3,请说明如何在jsp中使用此自定义标记来实现所需的行为。
Also, to use the solution mentioned in comment 1, what is the entry that we need to do in a tld file?
另外,要使用注释1中提到的解决方案,我们需要在tld文件中执行什么操作?
Please let me know this.
请让我知道这一点。