Pergunta

Eu quero adicionar uma lista variável de parâmetros para uma etiqueta de Struts2 URL. Eu tenho um mapa dos parâmetros (valor pares nome) em um objeto na sessão. Eu estou lutando para encontrar uma abordagem boa para isso. Aqui está o código JSP relevante:

    <s:iterator value="%{#session['com.strutsschool.interceptors.breadcrumbs']}" status="status">
    <s:if test="#status.index > 0">
        &#187;
    </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>

A variável de parâmetros é um mapa que contém os parâmetros. Isto, naturalmente não funciona, mas eu não posso ver uma maneira de abordar esta questão no momento. Estou pensando no momento em que eu poderia precisar de um modelo freemarker personalizado para isso. Alguém pode sugerir uma maneira melhor?

Foi útil?

Solução

O parâmetro tag Popula parâmetros apenas ao seu antecessor direto. Wrappings uma tag iterador em torno da tag parâmetro não tem efeito. :) Para resolver isso, você pode facilmente escrever um tag parâmetro alternativo wich pode usar um mapa direclty A tag pode ser parecido com isso.

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;
        }
    }
}

E você precisa de um TLD-entrada correspondente

<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>

Outras dicas

Talvez você pode usar tags JSTL como este

 <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>

Eu sei que há alguma hesitação para misturar EL com OGNL etc, mas isso funciona ...

Você pode iterar sobre um mapa usando

<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>

mas o iterador irá consumir os parâmetros como é o componente principal do param.

Confira Adicionando parâmetros arbitrários para uma URL em Struts2 para saber como fazer isto com uma marca personalizada que resulta na semelhantes

<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 é um componente personalizado que retorna o avô do param no caso em que o pai é um iterador.

Com referência ao comentário 3, por favor, mostre como você usaria essa tag personalizado em seu jsp para achive o comportamento necessário.

Além disso, a utilização da solução indicada no comentário 1, que é a entrada que precisamos fazer em um arquivo TLD?

Por favor, deixe-me saber isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top