W jaki sposób odwołujesz się do stałych za pomocą EL na stronie JSP?
Mam interfejs Addresses
ze stałą o nazwie URL
. Wiem, że mogę odwołać się do tego rysikiem, przechodząc: <%=Addresses.URL%>
ale jak to zrobić za pomocą EL?
W jaki sposób odwołujesz się do stałych za pomocą EL na stronie JSP?
Mam interfejs Addresses
ze stałą o nazwie URL
. Wiem, że mogę odwołać się do tego rysikiem, przechodząc: <%=Addresses.URL%>
ale jak to zrobić za pomocą EL?
Odpowiedzi:
Jeśli korzystasz już z języka Java EE 7 / EL 3.0, program @page import
zaimportuje również stałe klasy w zakresie EL.
<%@ page import="com.example.YourConstants" %>
Będzie to pod okładkami importowane przez ImportHandler#importClass()
i dostępne jako ${YourConstants.FOO}
.
Zauważ, że wszystkie java.lang.*
klasy są już niejawnie zaimportowane i dostępne, tak jak ${Boolean.TRUE}
i ${Integer.MAX_VALUE}
. Wymaga to tylko nowszego serwera kontenerów Java EE 7, ponieważ wczesne wersje miały w tym błędy. Np. Zawodzą GlassFish 4.0 i Tomcat 8.0.0-1x, ale GlassFish 4.1+ i Tomcat 8.0.2x + działają. I musisz mieć absolutną pewność, że web.xml
deklarowana jest zgodność z najnowszą wersją serwletu obsługiwaną przez serwer. Zatem w przypadku web.xml
deklaracji zgodności z serwletem 2.5 lub starszym żadna z funkcji Servlet 3.0+ nie będzie działać.
Należy również pamiętać, że ta funkcja jest dostępna tylko w JSP, a nie w Facelets. W przypadku JSF + Facelets najlepszym rozwiązaniem jest użycie OmniFaces,<o:importConstants>
jak poniżej:
<o:importConstants type="com.example.YourConstants" />
Lub dodanie odbiornika kontekstu EL, który wywołuje ImportHandler#importClass()
jak poniżej:
@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");
}
});
}
}
Nie jest to możliwe w EL 2.2 i starszych. Istnieje kilka alternatyw:
Umieść je w tym, Map<String, Object>
który umieścisz w zakresie aplikacji. W EL wartości map są dostępne w zwykły sposób w Javabean przez ${map.key}
lub ${map['key.with.dots']}
.
Korzystanie <un:useConstants>
z niestandardowego taglib ( tutaj repozytorium maven2 ):
<%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
<un:useConstants className="com.example.YourConstants" var="constants" />
W ten sposób są one dostępne w zwykły sposób w Javabean przez ${constants.FOO}
.
Użyj CCC Javarancha, <ccc:constantsMap>
jak opisano gdzieś na dole tego artykułu .
<%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
<ccc:constantsMap className="com.example.YourConstants" var="constants" />
W ten sposób są one również dostępne w zwykły sposób w Javabean ${constants.FOO}
.
Jeśli używasz JSF2, następnie można użyć <o:importConstants>
z OmniFaces .
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
W ten sposób są one również dostępne w zwykły sposób w Javabean #{YourConstants.FOO}
.
Utwórz klasę opakowującą, która zwraca je za pomocą metod pobierających w stylu Javabean.
Utwórz niestandardowy program rozpoznawania nazw EL, który najpierw skanuje obecność stałej, a jeśli jej nie ma, następnie deleguje do domyślnego programu rozpoznawania nazw, w przeciwnym razie zwraca stałą wartość.
unstandard-taglib
projekt Dżakarta wciąż żyje? czy jest jakaś alternatywa?
Poniższe informacje nie odnoszą się ogólnie do EL, ale tylko do SpEL (Spring EL) (testowane z 3.2.2.RELEASE na Tomcat 7). Myślę, że warto o tym tutaj wspomnieć na wypadek, gdyby ktoś szukał JSP i EL (ale używa JSP ze Spring).
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
Zazwyczaj tego rodzaju stałe umieszcza się w Configuration
obiekcie (który ma metody pobierające i ustawiające) w kontekście serwletu i uzyskuje do nich dostęp za pomocą${applicationScope.config.url}
url
właściwością String, nazwij ją Configuration
, utwórz jej instancję i ustaw url
dowolną wartość. Następnie ustaw ten Configuration
obiekt ServletContext
. Zrób coś takiego jak servletContext.setAttribute("config", config)
. I gotowe.
ServletContext
? Czy po prostu możesz dokładniej klasyfikować stałe? np applicationScope.config.url
vs applicationScope.url
.
Nie możesz. Jest zgodny z konwencją Java Bean. Więc musisz mieć do tego getter.
Właściwości statyczne nie są dostępne w EL. Sposób obejścia tego problemu polega na utworzeniu zmiennej niestatycznej, która przypisuje się do wartości statycznej.
public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;
Używam lomboka do generowania gettera i settera, więc to całkiem nieźle. Twój EL wygląda tak:
${bean.manager_role}
Pełny kod na http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el
Zrealizowałem tak:
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;
}
}
W następnym kroku umieść instancję tej klasy w servlerContext
public class ApplicationInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("Constants", new JspConstants());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
dodaj odbiornik do web.xml
<listener>
<listener-class>com.example.ApplicationInitializer</listener-class>
</listener>
dostęp w jsp
${Constants.PAGE_SIZE}
Na początku definiuję stałą w moim jsp:
<%final String URI = "http://www.example.com/";%>
Dołączam rdzeń taglib do mojej strony JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Następnie udostępniam stałą EL, wykonując następujące oświadczenie:
<c:set var="URI" value="<%=URI%>"></c:set>
Teraz mogę tego użyć później. Oto przykład, w którym wartość jest zapisywana jako komentarz HTML do celów debugowania:
<!-- ${URI} -->
Za pomocą swojej stałej klasy możesz po prostu zaimportować swoją klasę i przypisać stałe do zmiennych lokalnych. Wiem, że moja odpowiedź to rodzaj szybkiego hackowania, ale pytanie pojawia się również, gdy chce się zdefiniować stałe bezpośrednio na JSP.
<%=URI%>
: P
<%=URI%>
nie działał, ale ta technika działała.
Tak, możesz. Potrzebujesz niestandardowego tagu (jeśli nie możesz go znaleźć gdzie indziej). Zrobiłem to:
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;
}
}
a tag nazywa się:
<yourLib:constMap path="path.to.your.constantClass" var="consts" />
Wszystkie publiczne statyczne zmienne końcowe zostaną umieszczone w Mapie indeksowanej według ich nazwy w Javie, więc jeśli
public static final int MY_FIFTEEN = 15;
wtedy tag zawinie to w liczbę całkowitą i możesz odwołać się do niego na stronie JSP:
<c:if test="${consts['MY_FIFTEEN'] eq 15}">
i nie musisz pisać getters!
Możesz. Spróbuj naśladować
#{T(com.example.Addresses).URL}
Przetestowano na TomCat 7 i java6
Nawet wiedząc, że jest trochę za późno, a nawet wiedząc, że to mały hack - zastosowałem następujące rozwiązanie, aby osiągnąć pożądany rezultat. Jeśli jesteś miłośnikiem konwencji nazewnictwa języka Java, radzę przestać czytać tutaj ...
Posiadanie takiej klasy, definiowanie stałych, pogrupowanych według pustych klas, aby stworzyć rodzaj hierarchii:
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;
...
}
}
może być używany z poziomu java, PERMISSION.PAGE.SEE
aby pobrać wartość1L
Aby uzyskać podobną możliwość dostępu z poziomu EL-Expressions, zrobiłem to: (Jeśli istnieje bóg kodujący - mam nadzieję, że może mi wybaczyć: 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();
}
}
na koniec EL-Expression, aby uzyskać dostęp do tego samego, Long
staje się: #{PERMISSION.PAGE.SEE}
- równością dla Java i EL-Access. Wiem, że to jest poza jakąkolwiek konwencją, ale działa doskonale.
@Bozho już udzielił świetnej odpowiedzi
Zazwyczaj tego rodzaju stałe umieszcza się w obiekcie konfiguracyjnym (który ma metody pobierające i ustawiające) w kontekście serwletu i uzyskuje do nich dostęp za pomocą $ {applicationScope.config.url}
Uważam jednak, że potrzebny jest przykład, który daje trochę więcej klarowności i oszczędza komuś czas
@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);
}
}
Istnieje obejście, które nie jest dokładnie tym, czego chcesz, ale pozwala na prawie takie samo działanie z dotykaniem skryptów w dość minimalny sposób. Możesz użyć skryptletu, aby umieścić wartość w zmiennej JSTL i użyć czystego kodu JSTL w dalszej części strony.
<%@ 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>