2012-09-27 21 views
3

我有我的Utility类的静态导入:静态常量值没有在Spring MVC表单动作元素显示

<%@ page import="static com.groupgti.webclient.util.MappingUtils.*" %> 

我在这个类中的一些常量:

public static final String HTM = ".htm"; 

public static final String SECURE_REQUEST_MAPPING = "/secure/"; 

public static final String CANDIDATE_DETAILS_DATA_FORM_MAPPING = "assessments/candidate-details-data"; 

我有一个Spring MVC的形式:

<form:form cssClass="springForm" 
     action="${pageContext.servletContext.contextPath}<%=SECURE_REQUEST_MAPPING + CANDIDATE_DETAILS_DATA_FORM_MAPPING + HTM%>" 
     commandName="assessments/candidate-details-request"> 
</form:form> 

为什么当我使用这样的:

<a href="${pageContext.servletContext.contextPath}<%=SECURE_REQUEST_MAPPING + CANDIDATE_DETAILS_DATA_FORM_MAPPING + HTM%>"> 
    some text 
</a> 

href属性的值被正确地产生,并且在弹簧形式action属性的HTML代码是这样的:/webclient<%=SECURE_REQUEST_MAPPING + CANDIDATE_DETAILS_DATA_FORM_MAPPING + HTM%>。这些常量的值未显示。为什么是这样,我应该怎么做才能使它工作?

回答

1

JSP允许您在自定义标记的属性(如<form:form>)中使用scriptlet表达式(<%= ... %>),但它必须是该属性的唯一内容。因此,不能将<%= ... %>表达式与EL表达式或纯文本混合在自定义标记的属性中。

但是,您可以在常规HTML标记的属性中使用任何内容,因为这些标记对JSP没有特殊含义,这就是为什么它可以与<a>一起使用。

一种可能的解决方案是将scriptlet的表达的结果为请求属性,并用它在EL表达式:

<c:set var = "url" 
    value = "<%=SECURE_REQUEST_MAPPING + CANDIDATE_DETAILS_DATA_FORM_MAPPING + HTM%>" /> 
<form:form action="${pageContext.servletContext.contextPath}${url}" ...> 
    ... 
</form:form> 

或者,也可以选择使用的scriptlet没有EL,例如,通过定义的方法即在附加上下文路径您MappingUtils

... <%= url(...) %> ... 

注意,由于历史的原因(EL表达式旨在取代小脚本)JSP不提供优雅的方式混合EL和脚本,所以这种问题非常期待。

+0

谢谢,现在我明白为什么这个和您的解决方案适用于我。 –

2

由于在工作中我们不允许在JSP中内联Java,所以我使用自定义标签来“导入”JSP中的静态最终类字段。它使用Spring Framework的utils和通用支持从废弃的Jakarta'非标准'自定义标签库API稍微修改UseConstantsTag。 (我现在甚至找不到原始代码;这里是original API documentation。)

该标签基本上将所有静态最终字段(通过反射)公开为Map,它们可以很容易地在JSP中使用。Take a look at full code in this gist,实质是:

/** 
* Tag that exposes all of the public constants in a class as a map stored in 
* a scoped attribute. The scope may be specified, but defaults to page scope. 
* <p/> 
* Based on abandoned project taglibs-unstandard, specifically 
* {@code org.apache.taglibs.unstandard.UseConstantsTag}. Uses Spring's TagUtils 
* and ClassUtils instead of utils bundled in taglibs-unstandard, plus it 
* supports generics. 
* 
* @see http://jakarta.apache.org/taglibs/unstandard 
*/ 
public class UseConstantsTag extends TagSupport { 
    private static final long serialVersionUID = 1L; 

    /** 
    * The fully qualified name of the Java class for which constants are to be 
    * exposed. 
    */ 
    private String className; 

    /** 
    * The scope in which the exposed map will be stored. 
    */ 
    private String scope = TagUtils.SCOPE_PAGE; 

    /** 
    * The name of the scoped attribute in which the constants will be stored. 
    */ 
    private String var; 

    /** 
    * Construct an instance of this class. 
    */ 
    public UseConstantsTag() { 
    } 

    /** 
    * Retrieve the name of the class for which constants are to be exposed. 
    * 
    * @return The fully qualified class name. 
    */ 
    public String getClassName() { 
    return className; 
    } 

    /** 
    * Set the name of the class for which constants are to be exposed. 
    * 
    * @param className The fully qualified class name. 
    */ 
    public void setClassName(final String className) { 
    this.className = className; 
    } 

    /** 
    * Retrieve the scope in which the exposed map will be stored. 
    * 
    * @return The name of the scope. 
    */ 
    public String getScope() { 
    return scope; 
    } 

    /** 
    * Set the scope in which the exposed map will be stored. 
    * 
    * @param scope The name of the scope. 
    */ 
    public void setScope(final String scope) { 
    Assert.notNull(scope, "Scope cannot be null"); 
    this.scope = scope; 
    } 

    /** 
    * Retrieve the variable name in which the exposed map will be stored. 
    * 
    * @return The name of the variable. 
    */ 
    public String getVar() { 
    return var; 
    } 

    /** 
    * Set the variable name in which the exposed map will be stored. 
    * 
    * @param var The name of the variable. 
    */ 
    public void setVar(final String var) { 
    this.var = var; 
    } 

    /** 
    * Expose the constants for a class as a scoped attribute. 
    * 
    * @return A constant that identifies what the container should do next. 
    * 
    * @throws JspException if a fatal error occurs. 
    */ 
    @Override 
    public int doStartTag() throws JspException { 
    if (className != null && var != null) { 
     Map<String, Object> constants; 
     try { 
     constants = ClassReflectionUtils.getClassConstants(className); 
     } catch (final ClassNotFoundException e) { 
     throw new JspTagException("Class not found: " + className, e); 
     } catch (final IllegalArgumentException e) { 
     throw new JspTagException("Illegal argument: " + className, e); 
     } catch (final IllegalAccessException e) { 
     throw new JspTagException("Illegal access: " + className, e); 
     } 
     if (!constants.isEmpty()) { 
     pageContext.setAttribute(var, constants, TagUtils.getScope(scope)); 
     } 
    } 

    return SKIP_BODY; 
    } 

    /** 
    * Free up any resources being used by this tag handler. 
    */ 
    @Override 
    public void release() { 
    super.release(); 
    className = null; 
    scope = null; 
    var = null; 
    } 

} 

/** 
* Utility class for working with Class instances. 
*/ 
final class ClassReflectionUtils { 

    /** 
    * Private constructor to prevent instantiation of this class. 
    */ 
    private ClassReflectionUtils() { 
    } 

    /** 
    * Creates and returns a map of the names of public static final constants to 
    * their values, for the specified class. 
    * 
    * @param className The fully qualified name of the class for which the 
    *     constants should be determined 
    * 
    * @return {@code Map<String, Object>} from constant names to values 
    * @throws ClassNotFoundException 
    * @throws IllegalAccessException 
    * @throws IllegalArgumentException 
    */ 
    public static Map<String, Object> getClassConstants(final String className) 
     throws ClassNotFoundException, IllegalArgumentException, 
     IllegalAccessException { 
    final Map<String, Object> constants = new HashMap<String, Object>(); 
    final Class<?> clazz = ClassUtils.forName(className, 
     ClassUtils.getDefaultClassLoader()); 

    for (final Field field : clazz.getFields()) { 
     final int modifiers = field.getModifiers(); 
     if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) 
      && Modifier.isFinal(modifiers)) { 
     // null as argument because it's ignored when field is static 
     final Object value = field.get(null); 
     if (value != null) { 
      constants.put(field.getName(), value); 
     } 
     } 
    } 
    return constants; 
    } 

} 

标签定义:

<tag> 
    <name>useConstants</name> 
    <tag-class>com.github.xaerxess.UseConstantsTag</tag-class> 
    <body-content>empty</body-content> 

    <display-name>useConstants</display-name> 

    <description> 
    Exposes all of the public constants in a class as a map stored in 
    a scoped attribute. The scope may be specified, but defaults to page 
    scope. 
    </description> 

    <variable> 
     <name-from-attribute>var</name-from-attribute> 
     <variable-class>java.lang.Object</variable-class> 
     <declare>true</declare> 
     <scope>AT_BEGIN</scope> 
     <description>The name of the attribute into which the map will be stored.</description> 
    </variable> 

    <attribute> 
     <name>var</name> 
     <required>yes</required> 
     <rtexprvalue>no</rtexprvalue> 
     <description>Name of the scoped attribute into which the map will be stored.</description> 
    </attribute> 

    <attribute> 
     <name>className</name> 
     <required>yes</required> 
     <rtexprvalue>no</rtexprvalue> 
     <description>Fully qualified name of the class from which constants will be extracted.</description> 
    </attribute> 

    <attribute> 
     <name>scope</name> 
     <required>no</required> 
     <rtexprvalue>no</rtexprvalue> 
     <description>Scope into which to store the map. Default is page scope.</description> 
    </attribute> 

    <example> 
To expose all of the constants in the Integer class: 
<![CDATA[<un:useConstants var="const" className="java.lang.Integer" />]]> 
    </example> 
</tag> 

这样使用它:

<custom:useConstants var="MappingUtils" 
    className="com.groupgti.webclient.util.MappingUtils" scope="application" /> 

然后:

<p>My const: ${MappingUtils.SECURE_REQUEST_MAPPING}</p>