Bagaimana cara mereferensikan konstanta di EL?

106

Bagaimana Anda mereferensikan konstanta dengan EL di halaman JSP?

Saya memiliki antarmuka Addressesdengan nama konstan URL. Saya tahu saya dapat mereferensikannya dengan skrip dengan membuka:, <%=Addresses.URL%>tetapi bagaimana cara melakukannya menggunakan EL?

tau-neutrino
sumber

Jawaban:

156

EL 3.0 atau yang lebih baru

Jika Anda sudah menggunakan Java EE 7 / EL 3.0, maka @page importkonstanta kelas juga akan diimpor dalam lingkup EL.

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

Ini akan di bawah sampul diimpor melalui ImportHandler#importClass()dan tersedia sebagai${YourConstants.FOO} .

Perhatikan bahwa semua java.lang.*kelas sudah diimpor secara implisit dan tersedia seperti itu ${Boolean.TRUE}dan ${Integer.MAX_VALUE}. Ini hanya membutuhkan server kontainer Java EE 7 yang lebih baru karena versi awal memiliki bug dalam hal ini. Misalnya GlassFish 4.0 dan Tomcat 8.0.0-1x gagal, tetapi GlassFish 4.1+ dan Tomcat 8.0.2x + berfungsi. Dan Anda harus benar-benar memastikan bahwa Anda web.xmldinyatakan sesuai dengan versi servlet terbaru yang didukung oleh server. Jadi dengan web.xmlyang dinyatakan sesuai dengan Servlet 2.5 atau lebih tua, tidak ada fitur Servlet 3.0+ yang akan bekerja.

Perhatikan juga bahwa fasilitas ini hanya tersedia di JSP dan bukan di Facelet. Dalam kasus JSF + Facelet, taruhan terbaik Anda adalah menggunakan OmniFaces<o:importConstants> seperti di bawah ini:

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

Atau menambahkan pendengar konteks EL yang memanggil ImportHandler#importClass()seperti di bawah ini:

@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 atau lebih tua

Ini tidak mungkin di EL 2.2 dan yang lebih lama. Ada beberapa alternatif:

  1. Tempatkan mereka di tempat Map<String, Object>yang Anda masukkan dalam ruang lingkup aplikasi. Dalam EL, nilai peta dapat diakses dengan cara Javabean biasa dengan ${map.key}atau ${map['key.with.dots']}.

  2. Gunakan <un:useConstants>dari Unstandard taglib (maven2 repo di sini ):

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

    Dengan cara ini mereka dapat diakses dengan cara Javabean biasa ${constants.FOO}.

  3. Gunakan CCC Javaranch <ccc:constantsMap>seperti yang dijelaskan di suatu tempat di bagian bawah artikel ini .

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

    Dengan cara ini mereka dapat diakses dengan cara Javabean biasa ${constants.FOO}juga.

  4. Jika Anda menggunakan JSF2, maka Anda bisa menggunakan <o:importConstants>dari OmniFaces .

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

    Dengan cara ini mereka dapat diakses dengan cara Javabean biasa #{YourConstants.FOO}juga.

  5. Buat kelas pembungkus yang mengembalikannya melalui metode pengambil gaya Javabean.

  6. Buat resolver EL khusus yang terlebih dahulu memindai keberadaan konstanta dan jika tidak ada, lalu delegasikan ke resolver default, jika tidak, kembalikan nilai konstanta.

BalusC
sumber
4
Saya menemukan pertanyaan ini karena saya mengalami masalah yang sama ketika mencoba menggunakan bidang Daftar statis dengan tag form: options. Saya bisa membuatnya berfungsi dengan menambahkan getter non-statis yang mengembalikan daftar statis. Agak kludgy tapi hei, itu pengembangan JSP untukmu!
spaaarky21
1
Apakah Anda memiliki contoh cara mengkonfigurasi ini untuk JSF jika kacang dikelola oleh pegas? Terima kasih sebelumnya.
Pemondok
2
@Lodger: Saya tidak melakukan Spring.
BalusC
2
Apakah unstandard-taglibproyek Jakarta masih hidup? apakah ada alternatif lain?
davioooh
1
Apakah ada cara untuk memanfaatkan teknik ini untuk enum?
Niklas Peter
11

Hal berikut ini tidak berlaku untuk EL secara umum, tetapi hanya untuk SpEL (Spring EL) (diuji dengan 3.2.2.RELEASE di Tomcat 7). Saya rasa perlu disebutkan di sini jika seseorang mencari JSP dan EL (tetapi menggunakan JSP dengan Spring).

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

Anda biasanya menempatkan jenis konstanta ini dalam sebuah Configurationobjek (yang memiliki getter dan setter) dalam konteks servlet, dan mengaksesnya dengan${applicationScope.config.url}

Bozho
sumber
Sedikit pemula di sini dalam hal jsp's- bisakah Anda menjelaskannya lebih lengkap?
tau-neutrino
1
@ tau-neutrino: Sebenarnya sederhana. Buat kelas dengan urlsebagai properti String, beri nama Configuration, buat instance, dan setel urlke apa pun yang Anda suka. Setelah itu atur Configurationobjek itu ServletContext. Lakukan sesuatu seperti servletContext.setAttribute("config", config),. Dan begitulah.
Adeel Ansari
Apa perbedaan antara solusi yang Anda usulkan dan hanya menambahkan konstanta sebagai atribut ServletContext? Apakah hanya Anda bisa mengklasifikasikan konstanta dengan lebih rapi? misalnya: applicationScope.config.urlvs applicationScope.url.
mereka
7

Tidak boleh. Ini mengikuti konvensi Java Bean. Jadi, Anda harus memiliki tekad untuk itu.

Adeel Ansari
sumber
5

Properti statis tidak dapat diakses di EL. Solusi yang saya gunakan adalah membuat variabel non-statis yang menugaskan dirinya sendiri ke nilai statis.

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

Saya menggunakan lombok untuk menghasilkan pengambil dan penyetel jadi itu cukup baik. EL Anda terlihat seperti ini:

${bean.manager_role}

Kode lengkap di http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el

Roger Keays
sumber
5

Saya menerapkan seperti:

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

Langkah selanjutnya memasukkan instance kelas ini ke servlerContext

public class ApplicationInitializer implements ServletContextListener {


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

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

tambahkan pendengar ke web.xml

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

akses di jsp

${Constants.PAGE_SIZE}
Serhii Bohutskyi
sumber
4

Saya mendefinisikan sebuah konstanta di jsp saya tepat di awal:

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

Saya menyertakan taglib inti di JSP saya:

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

Kemudian, saya menyediakan konstanta untuk EL dengan pernyataan berikut:

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

Sekarang, saya bisa menggunakannya nanti. Berikut contoh, di mana nilainya hanya ditulis sebagai komentar HTML untuk tujuan debugging:

<!-- ${URI} -->

Dengan kelas konstan, Anda cukup mengimpor kelas dan menetapkan konstanta ke variabel lokal. Saya tahu bahwa jawaban saya adalah semacam peretasan cepat, tetapi pertanyaannya juga muncul ketika seseorang ingin mendefinisikan konstanta secara langsung di JSP.

koppor
sumber
1
lol mengapa tidak menggunakan Scriptlets secara langsung jika itu cara Anda menginisialisasi variabel EL?
Navin
Tiga baris di atas menjadi berantakan dan kemudian bersihkan EL di seluruh JSP ^^.
koppor
1
@poppoor kurasa begitu. Saya hanya akan menggunakan <%=URI%>: P
Navin
1
Saya memiliki tempat di mana penyutradaraan <%=URI%>tidak berfungsi, tetapi teknik ini berhasil.
englebart
3

Ya kamu bisa. Anda memerlukan tag khusus (jika Anda tidak dapat menemukannya di tempat lain). Saya telah melakukan ini:

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

dan tag tersebut disebut:

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

Semua variabel final statis publik akan dimasukkan ke dalam Map yang diindeks dengan nama Java mereka, jadi jika

public static final int MY_FIFTEEN = 15;

maka tag akan membungkus ini dalam Integer dan Anda dapat mereferensikannya dalam JSP:

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

dan Anda tidak perlu menulis getter!

Tim Sabin
sumber
3

Kamu bisa. Coba ikuti cara

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

Diuji pada TomCat 7 dan java6

Dmytro Boichenko
sumber
3
Itu terlihat seperti SpEL, dan bukan EL. Apakah saya salah Juga, apakah itu akan berhasil di Tomcat5.5 yang lebih lama?
Pytry
2

Meskipun mengetahui ini sedikit terlambat, dan bahkan mengetahui ini sedikit retasan - saya menggunakan solusi berikut untuk mencapai hasil yang diinginkan. Jika Anda pecinta Java-Naming-Conventions, saran saya adalah berhenti membaca di sini ...

Memiliki kelas seperti ini, mendefinisikan Konstanta, dikelompokkan berdasarkan kelas kosong untuk membuat semacam hierarki:

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

dapat digunakan dari dalam java PERMISSION.PAGE.SEEuntuk mengambil nilainya1L

Untuk mencapai kemungkinan akses yang serupa dari dalam EL-Expressions, saya melakukan ini: (Jika ada dewa pengkode - semoga dia bisa memaafkan saya: 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();
    }
}

Akhirnya, EL-Ekspresi untuk mengakses yang sama Longmenjadi: #{PERMISSION.PAGE.SEE}- persamaan untuk Java dan EL-Access. Saya tahu ini di luar konvensi mana pun, tetapi berfungsi dengan baik.

dognose
sumber
2

@Bozho sudah memberikan jawaban yang bagus

Anda biasanya menempatkan jenis konstanta ini dalam objek Konfigurasi (yang memiliki getter dan setter) dalam konteks servlet, dan mengaksesnya dengan $ {applicationScope.config.url}

Namun, saya merasa sebuah contoh dibutuhkan sehingga memberikan sedikit kejelasan dan meluangkan waktu seseorang

@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);
    }
}
lunohodov
sumber
0

Ada solusi yang tidak persis seperti yang Anda inginkan, tetapi memungkinkan Anda untuk aktif hampir sama dengan menyentuh scriptlet dengan cara yang sangat minimal. Anda dapat menggunakan scriptlet untuk memasukkan nilai ke dalam variabel JSTL dan menggunakan kode JSTL bersih nanti di halaman.

<%@ 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>
Artem
sumber
1
Saya tidak mengerti mengapa ini ditolak. Ini adalah pola yang sama dengan opsi # 3 di: stackoverflow.com/a/16692821/274677
Marcus Junius Brutus