Hinweis: Es fällt mir schwer, mir "versteckte Funktionen" für JSP / Servlet vorzustellen. Meiner Meinung nach ist "Best Practices" eine bessere Formulierung, und ich kann mir jede davon vorstellen. Es hängt auch wirklich von Ihrer Erfahrung mit JSP / Servlet ab. Nach Jahren der Entwicklung sehen Sie diese "versteckten Funktionen" nicht mehr. Auf jeden Fall werde ich einige dieser kleinen "Best Practices" auflisten, von denen ich jahrelang herausgefunden habe, dass viele Starter sich dessen nicht voll bewusst sind. Diese würden im Auge vieler Starter als "versteckte Merkmale" eingestuft. Wie auch immer, hier ist die Liste :)
Verstecken Sie JSP-Seiten vor dem direkten Zugriff
Indem Sie JSP-Dateien in einem /WEB-INF
Ordner ablegen, verbergen Sie sie beispielsweise effektiv vor dem direkten Zugriff http://example.com/contextname/WEB-INF/page.jsp
. Dies führt zu a 404
. Sie können dann nur über ein RequestDispatcher
In-Servlet oder mit darauf zugreifen jsp:include
.
Vorverarbeitungsanforderung für JSP
Die meisten sind über Servlet bewusst schreiben eine Anfrage (ein Formular) -Prozess, aber die meisten wissen nicht , dass Sie Servlet verwenden Methode vorab eine Anfrage für eine JSP -Prozess. Zum Beispiel:doPost()
doGet()
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Item> items = itemDAO.list();
request.setAttribute("items", items);
request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
}
Hiermit werden einige tabellarische Daten vorgeladen, die mithilfe von JSTLs angezeigt werden sollen c:forEach
:
<table>
<c:forEach items="${items}" var="item">
<tr><td>${item.id}</td><td>${item.name}</td></tr>
</c:forEach>
</table>
Ordnen Sie ein solches Servlet einem url-pattern
von /page
(oder /page/*
) zu und rufen Sie es einfach über die http://example.com/contextname/page
Adressleiste des Browsers oder einen einfachen Vanille-Link auf, um es auszuführen. Siehe auch zB doGet und doPost in Servlets .
Dynamische Includes
Sie können EL verwenden in jsp:include
:
<jsp:include page="/WEB-INF/${bean.page}.jsp" />
Sie bean.getPage()
können nur einen gültigen Seitennamen zurückgeben.
EL kann auf jeden Getter zugreifen
EL verlangt per se nicht, dass das Objekt, auf das zugegriffen werden soll, ein vollwertiger Javabean ist. Das Vorhandensein einer No-Arg-Methode, der ein Präfix vorangestellt ist get
oder is
mehr als ausreichend ist, um in EL darauf zuzugreifen. Z.B:
${bean['class'].name}
Dies gibt den Wert zurück, von bean.getClass().getName()
dem die getClass()
Methode tatsächlich geerbt wird Object#getClass()
. Beachten Sie, dass dies aus den hier genannten Gründen unter class
Verwendung der "Klammer-Notation" angegeben wird .[]
${pageContext.session.id}
Dieser gibt den Wert von pageContext.getSession().getId()
der in ao nützlich ist , kann ein Applet kommuniziert mit einer Instanz eines Servlets .
${pageContext.request.contextPath}
Dies gibt den Wert zurück, der pageContext.getRequest().getContextPath()
in ao nützlich ist. Wie verwende ich relative Pfade ohne den Kontextstammnamen?
EL kann auch auf Karten zugreifen
Die folgende EL-Notation
${bean.map.foo}
beschließt zu bean.getMap().get("foo")
. Wenn der Map
Schlüssel einen Punkt enthält, können Sie die "Klammernotation" []
mit einem zitierten Schlüssel verwenden:
${bean.map['foo.bar']}
was sich auflöst bean.getMap().get("foo.bar")
. Wenn Sie einen dynamischen Schlüssel möchten, verwenden Sie auch die Klammernotation, die jedoch nicht in Anführungszeichen gesetzt ist:
${bean.map[otherbean.key]}
was sich auflöst bean.getMap().get(otherbean.getKey())
.
Iterieren Sie mit JSTL über die Karte
Sie können auch verwenden c:forEach
, um über a zu iterieren Map
. Jede Iteration gibt ein Map.Entry
was wiederum hat getKey()
und getValue()
Methoden (so dass Sie einfach in EL durch ${entry.key}
und darauf zugreifen können ${entry.value}
). Beispiel:
<c:forEach items="${bean.map}" var="entry">
Key: ${entry.key}, Value: ${entry.value} <br>
</c:forEach>
Siehe auch zB Debuggen mit jstl - wie genau?
Aktuelles Datum in JSP abrufen
Sie können das aktuelle Datum mit jsp:useBean
abrufen und mithilfe von JSTL formatierenfmt:formatDate
<jsp:useBean id="date" class="java.util.Date" />
...
<p>Copyright © <fmt:formatDate value="${date}" pattern="yyyy" /></p>
Dies wird (ab sofort) wie folgt gedruckt: "Copyright © 2010".
Einfache freundliche URLs
Eine einfache Möglichkeit, benutzerfreundliche URLs zu haben, besteht darin, JSPs zu verwenden HttpServletRequest#getPathInfo()
und zu verbergen in /WEB-INF
:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
Wenn Sie dieses Servlet beispielsweise zuordnen /pages/*
, wird eine Anforderung am http://example.com/contextname/pages/foo/bar
effektiv angezeigt /WEB-INF/foo/bar.jsp
. Sie können einen Schritt weiter gehen, indem Sie die Pfadinfo aufteilen /
und nur den ersten Teil als JSP-Seiten-URL und den Rest als "Geschäftsaktionen" verwenden (lassen Sie das Servlet als Seiten-Controller fungieren ). Siehe auch zB webbasierte Anwendungen für Entwurfsmuster .
Benutzereingaben mit erneut anzeigen ${param}
Das implizite EL-Objekt, ${param}
das sich auf das bezieht, HttpServletRequest#getParameterMap()
kann verwendet werden, um Benutzereingaben nach dem Senden eines Formulars in JSP erneut anzuzeigen:
<input type="text" name="foo" value="${param.foo}">
Dies macht im Grunde das gleiche wie request.getParameterMap().get("foo")
. Siehe auch zB Wie kann ich HTML-Formularfeldwerte in JSP beibehalten, nachdem ich das Formular an Servlet gesendet habe?
Vergessen Sie nicht, XSS zu verhindern! Siehe folgendes Kapitel.
JSTL, um XSS zu verhindern
Um zu verhindern, dass Ihre Site XSS enthält , müssen Sie lediglich benutzergesteuerte Daten mit JSTL fn:escapeXml
oder (erneut) anzeigen c:out
.
<p><input type="text" name="foo" value="${fn:escapeXml(param.foo)}">
<p><c:out value="${bean.userdata}" />
Abwechselnde <table>
Zeilen mitLoopTagStatus
Das varStatus
Attribut von JSTL c:forEach
gibt Ihnen ein LoopTagStatus
Back, das wiederum mehrere Getter-Methoden hat (die in EL verwendet werden können!). Um nach geraden Zeilen zu suchen, prüfen Sie einfach, ob loop.getIndex() % 2 == 0
:
<table>
<c:forEach items="${items}" var="item" varStatus="loop">
<tr class="${loop.index % 2 == 0 ? 'even' : 'odd'}">...</tr>
<c:forEach>
</table>
was effektiv in enden wird
<table>
<tr class="even">...</tr>
<tr class="odd">...</tr>
<tr class="even">...</tr>
<tr class="odd">...</tr>
...
</table>
Verwenden Sie CSS, um ihnen eine andere Hintergrundfarbe zu geben.
tr.even { background: #eee; }
tr.odd { background: #ddd; }
Füllen Sie die kommasparierte Zeichenfolge aus List / Array mit LoopTagStatus
:
Eine weitere nützliche LoopTagStatus
Methode ist die isLast()
:
<c:forEach items="${items}" var="item" varStatus="loop">
${item}${!loop.last ? ', ' : ''}
<c:forEach>
Was zu so etwas führt item1, item2, item3
.
EL-Funktionen
Sie können public static
Dienstprogrammmethoden als EL-Funktionen deklarieren (z. B. als JSTL-Funktionen ), damit Sie sie in EL verwenden können. Z.B
package com.example;
public final class Functions {
private Functions() {}
public static boolean matches(String string, String pattern) {
return string.matches(pattern);
}
}
mit /WEB-INF/functions.tld
dem wie folgt aussehen:
<?xml version="1.0" encoding="UTF-8" ?>
<taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<short-name>Custom_Functions</short-name>
<uri>http://example.com/functions</uri>
<function>
<name>matches</name>
<function-class>com.example.Functions</function-class>
<function-signature>boolean matches(java.lang.String, java.lang.String)</function-signature>
</function>
</taglib>
welches als verwendet werden kann
<%@taglib uri="http://example.com/functions" prefix="f" %>
<c:if test="${f:matches(bean.value, '^foo.*')}">
...
</c:if>
Rufen Sie die ursprüngliche Anforderungs-URL und die Abfragezeichenfolge ab
Wenn die JSP weitergeleitet wurde, können Sie die ursprüngliche Anforderungs-URL erhalten über:
${requestScope['javax.servlet.forward.request_uri']}
und die ursprüngliche Anforderungsabfragezeichenfolge von,
${requestScope['javax.servlet.forward.query_string']}
Das war es soweit. Vielleicht füge ich früher oder später noch etwas hinzu.