ELで定数を参照するにはどうすればよいですか?


106

JSPページでELを使用して定数をどのように参照しますか?

Addressesという定数のインターフェースがありますURL。私は次のようにしてスクリプトレットでそれを参照できることを知って<%=Addresses.URL%>いますが、ELを使用してこれを行うにはどうすればよいですか?

回答:


156

EL 3.0以降

すでにJava EE 7 / EL 3.0を使用している場合は、@page importクラス定数もELスコープにインポートされます。

<%@ page import="com.example.YourConstants" %>

これはカバーの下にインポートされImportHandler#importClass()、として利用できます${YourConstants.FOO}

すべてのことに注意java.lang.*クラスがすでに暗黙的にインポートされ、そのような利用可能である${Boolean.TRUE}${Integer.MAX_VALUE}。初期のバージョンにはバグがあったため、これには最新のJava EE 7コンテナサーバーのみが必要です。たとえば、GlassFish 4.0とTomcat 8.0.0-1xは失敗しますが、GlassFish 4.1+とTomcat 8.0.2x +は機能します。またweb.xml、サーバーでサポートされている最新のサーブレットバージョンに準拠していることを宣言する必要があります。したがって、web.xmlがServlet 2.5以前の準拠として宣言されている場合、Servlet 3.0以降の機能はどれも機能しません。

また、この機能はJSPでのみ使用でき、Faceletsでは使用できないことにも注意してください。JSF + Faceletsの場合、最善の<o:importConstants>は以下のようにOmniFacesを使用することです。

<o:importConstants type="com.example.YourConstants" />

またはImportHandler#importClass()、以下のように呼び出すELコンテキストリスナーを追加します。

@ManagedBean(eager=true)
@ApplicationScoped
public class Config {

    @PostConstruct
    public void init() {
        FacesContext.getCurrentInstance().getApplication().addELContextListener(new ELContextListener() {
            @Override
            public void contextCreated(ELContextEvent event) {
                event.getELContext().getImportHandler().importClass("com.example.YourConstants");
            }
        });
    }

}

EL 2.2以前

これはEL 2.2以前では不可能です。いくつかの選択肢があります:

  1. それらをMap<String, Object>アプリケーションスコープに配置したものに配置します。ELでは、${map.key}またはを使用して、通常のJavabeanの方法でマップ値にアクセスできます${map['key.with.dots']}

  2. 使用<un:useConstants>Unstandardのtaglib(Maven2をレポこちら):

    <%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
    <un:useConstants className="com.example.YourConstants" var="constants" />

    この方法では、通常のJavabeanの方法でにアクセスできます${constants.FOO}

  3. この記事の下部のどこかに記載されているJavaranchのCCC <ccc:constantsMap>を使用してください。

    <%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
    <ccc:constantsMap className="com.example.YourConstants" var="constants" />

    この方法で、通常のJavabeanの方法でもアクセスできます${constants.FOO}

  4. JSF2を使用している場合<o:importConstants>は、OmniFacesを使用できます。

    <html ... xmlns:o="http://omnifaces.org/ui">
    <o:importConstants type="com.example.YourConstants" />

    この方法で、通常のJavabeanの方法でもアクセスできます#{YourConstants.FOO}

  5. Javabeanスタイルのgetterメソッドを介してそれらを返すラッパークラスを作成します。

  6. 最初に定数の存在をスキャンし、存在しない場合はデフォルトのリゾルバーに委任するカスタムELリゾルバーを作成します。そうでない場合は代わりに定数値を返します。


4
form:optionsタグで静的リストフィールドを使用しようとしたときに同じ問題が発生したため、この質問が見つかりました。静的リストを返す非静的ゲッターを追加することで機能させることができました。それは少し不器用ですがねえ、それはあなたのためのJSP開発です!
spaaarky21

1
BeanがSpringによって管理されている場合、JSFに対してこれを構成する方法の例はありますか?事前にTHX。
ロッジャー

2
@Lodger:春はやらない。
BalusC 2013年

2
ジャカルタunstandard-taglibプロジェクトはまだ生きていますか?いくつかの選択肢はありますか?
davioooh 2014年

1
列挙型にこの手法を活用する方法はありますか?
Niklas Peter

11

以下はELには一般的に適用されず、SpEL(Spring EL)のみに適用されます(Tomcat 7で3.2.2.RELEASEでテストされています)。誰かがJSPおよびELを検索する場合(ただし、SpringでJSPを使用する場合)は、ここで言及する価値があると思います。

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>

9

通常、これらの種類の定数Configurationは、サーブレットコンテキストのオブジェクト(ゲッターとセッターを持つ)に配置し、次のようにしてアクセスします${applicationScope.config.url}


jspに関しては、初心者の方に少し詳しく説明していただけますか。
タウニュートリノ

1
@ tau-neutrino:実際には単純です。urlStringプロパティとしてクラスを作成し、それに名前を付けてConfigurationインスタンス化し、urlを好きなように設定します。その後、そのConfigurationオブジェクトをに設定しますServletContext。のような何かをしてくださいservletContext.setAttribute("config", config)。そして、あなたは行き​​ます。
Adeel Ansari、2010

提案されたソリューションと、定数を属性として追加するだけの違いは何ServletContextですか?定数をよりきれいに分類できるというだけですか?例:applicationScope.config.urlapplicationScope.url
theyuv


5

ELでは静的プロパティにアクセスできません。私が使用する回避策は、それ自体を静的な値に割り当てる非静的変数を作成することです。

public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;

私はロンボクを使用してゲッターとセッターを生成しているので、それはかなりうまくいきます。ELは次のようになります。

${bean.manager_role}

完全なコード(http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el)


5

私は次のように実装しました:

public interface Constants{
    Integer PAGE_SIZE = 20;
}

-

public class JspConstants extends HashMap<String, String> {

        public JspConstants() {
            Class c = Constants.class;
            Field[] fields = c.getDeclaredFields();
            for(Field field : fields) {
                int modifier = field.getModifiers();
                if(Modifier.isPublic(modifier) && Modifier.isStatic(modifier) && Modifier.isFinal(modifier)) {
                    try {
                        Object o = field.get(null);
                        put(field.getName(), o != null ? o.toString() : null);
                    } catch(IllegalAccessException ignored) {
                    }
                }
            }
        }

        @Override
        public String get(Object key) {
            String result = super.get(key);
            if(StringUtils.isEmpty(result)) {
                throw new IllegalArgumentException("Check key! The key is wrong, no such constant!");
            }
            return result;
        }
    }

次のステップでは、このクラスのインスタンスをservlerContextに配置します

public class ApplicationInitializer implements ServletContextListener {


    @Override
    public void contextInitialized(ServletContextEvent sce) {
        sce.getServletContext().setAttribute("Constants", new JspConstants());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
}

リスナーをweb.xmlに追加する

<listener>
    <listener-class>com.example.ApplicationInitializer</listener-class>
</listener>

jspでのアクセス

${Constants.PAGE_SIZE}

4

最初にjspで定数を定義しています:

<%final String URI = "http://www.example.com/";%>

JSPにコアtaglibを含めます。

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

次に、次のステートメントによってELで定数を使用できるようにします。

<c:set var="URI" value="<%=URI%>"></c:set>

これで、後で使用できます。以下の例では、値はデバッグ目的でHTMLコメントとして記述されています。

<!-- ${URI} -->

定数クラスを使用すると、クラスをインポートして、ローカル変数に定数を割り当てることができます。私の答えは一種の簡単なハックであることはわかっていますが、JSPで定数を直接定義したい場合にも問題が発生します。


1
EL変数を初期化する方法でスクリプトレットを直接使用しないのはなぜですか?
Navin、2015年

上の3行はめちゃくちゃなので、残りのJSP全体でELをきれいにします^^。
koppor

1
@koppoorそうだね。私はただ使用するつもりです<%=URI%>:P
Navin

1
私はダイレクト<%=URI%>が機能しない場所がありましたが、このテクニックは機能しました。
englebart

3

はい、できます。カスタムタグが必要です(他の場所で見つからない場合)。私はこれをやった:

package something;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;

/**
 * Get all class constants (statics) and place into Map so they can be accessed
 * from EL.
 * @author Tim.sabin
 */
public class ConstMapTag extends TagSupport {
    public static final long serialVersionUID = 0x2ed23c0f306L;

    private String path = "";
    private String var = "";

    public void setPath (String path) throws JspException {
        this.path = (String)ExpressionUtil.evalNotNull ("constMap", "path",
          path, String.class, this, pageContext);
    }

    public void setVar (String var) throws JspException {
        this.var = (String)ExpressionUtil.evalNotNull ("constMap", "var",
          var, String.class, this, pageContext);
    }

    public int doStartTag () throws JspException {
        // Use Reflection to look up the desired field.
        try {
            Class<?> clazz = null;
            try {
                clazz = Class.forName (path);
            } catch (ClassNotFoundException ex) {
                throw new JspException ("Class " + path + " not found.");
            }
            Field [] flds = clazz.getDeclaredFields ();
            // Go through all the fields, and put static ones in a Map.
            Map<String, Object> constMap = new TreeMap<String, Object> ();
            for (int i = 0; i < flds.length; i++) {
                // Check to see if this is public static final. If not, it's not a constant.
                int mods = flds [i].getModifiers ();
                if (!Modifier.isFinal (mods) || !Modifier.isStatic (mods) ||
                  !Modifier.isPublic (mods)) {
                    continue;
                }
                Object val = null;
                try {
                    val = flds [i].get (null);    // null for static fields.
                } catch (Exception ex) {
                    System.out.println ("Problem getting value of " + flds [i].getName ());
                    continue;
                }
                // flds [i].get () automatically wraps primitives.
                // Place the constant into the Map.
                constMap.put (flds [i].getName (), val);
            }
            // Export the Map as a Page variable.
            pageContext.setAttribute (var, constMap);
        } catch (Exception ex) {
            if (!(ex instanceof JspException)) {
                throw new JspException ("Could not process constants from class " + path);
            } else {
                throw (JspException)ex;
            }
        }
        return SKIP_BODY;
    }
}

タグが呼び出されます:

<yourLib:constMap path="path.to.your.constantClass" var="consts" />

すべてのpublic static final変数は、Java名で索引付けされたMapに入れられるため、

public static final int MY_FIFTEEN = 15;

その後、タグはこれを整数でラップし、JSPで参照できます。

<c:if test="${consts['MY_FIFTEEN'] eq 15}">

ゲッターを書く必要はありません!


3

あなたはできる。フォロー方法で試してください

 #{T(com.example.Addresses).URL}

TomCat 7およびjava6でテスト済み


3
それはELではなくSpELのように見えます。私は間違っていますか?また、それは古いTomcat5.5で動作しますか?
パイトリー2014年

2

少し遅れていることを知っていても、これが少しハックであることを知っていても、次の解決策を使用して目的の結果を達成しました。あなたがJava-Naming-Conventionsの愛好家なら、私のアドバイスはここを読むのをやめることです...

このようなクラスを作成し、定数を定義し、空のクラスでグループ化して、一種の階層を作成します。

public class PERMISSION{
    public static class PAGE{
       public static final Long SEE = 1L; 
       public static final Long EDIT = 2L; 
       public static final Long DELETE = 4L; 
       ...
    }
}

PERMISSION.PAGE.SEE値を取得するためにJava内から使用できます1L

EL-Expressions内から同様のアクセス可能性を実現するために、私はこれを行いました:(コーディング神がいる場合-彼はうまくいけば私を許してくれるでしょう:D)

@Named(value="PERMISSION")
public class PERMISSION{
    public static class PAGE{
       public static final Long SEE = 1L; 
       public static final Long EDIT = 2L; 
       public static final Long DELETE = 4L; 
       ...

       //EL Wrapper
       public Long getSEE(){
           return PAGE.SEE;
       }

       public Long getEDIT(){
           return PAGE.EDIT;
       }

       public Long getDELETE(){
           return PAGE.DELETE;
       }
    }

    //EL-Wrapper
    public PAGE getPAGE() {
        return new PAGE();
    }
}

最終的には、EL-発現はアクセスに非常に同じことがLong次のようになります#{PERMISSION.PAGE.SEE}- JavaとEL-アクセスの平等。これは慣例ではありませんが、完全に正常に動作します。


2

@Bozhoはすでに素晴らしい答えを提供してくれました

通常、これらの種類の定数は、サーブレットコンテキストのConfigurationオブジェクト(ゲッターとセッターを持つ)に配置し、$ {applicationScope.config.url}を使用してアクセスします

しかし、例が必要だと思うので、もう少し明確にして誰かの時間を節約できます

@Component
public Configuration implements ServletContextAware {
    private String addressURL = Addresses.URL;

    // Declare other properties if you need as also add corresponding
    // getters and setters

    public String getAddressURL() {
        return addressURL;
    }

    public void setServletContext(ServletContext servletContext) {
        servletContext.setAttribute("config", this);
    }
}

0

必要な回避策はありませんが、最小限の方法でスクリプトレットを操作することでほぼ同じようにアクティブにできます。スクリプトレットを使用してJSTL変数に値を入力し、ページの後半でクリーンなJSTLコードを使用できます。

<%@ taglib prefix="c"       uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.whichever.namespace.Addresses" %>
<c:set var="ourUrl" value="<%=Addresses.URL%>"/>
<c:if test='${"http://www.google.com" eq ourUrl}'>
   Google is our URL!
</c:if>

1
なぜ反対票が投じられたのかわかりません。これは、次のオプション#3と同じパターンです。stackoverflow.com
Marcus Junius Brutus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.