Dalle specifiche JSP 1.2, si consiglia vivamente di utilizzare la libreria di tag standard JSP (JSTL) nell'applicazione Web per ridurre la necessità di scriptlet JSP nelle pagine. Le pagine che utilizzano JSTL sono, in generale, più facili da leggere e gestire.
...
Ove possibile, evitare gli scriptlet JSP ogni volta che le librerie di tag offrono funzionalità equivalenti. Ciò semplifica la lettura e la gestione delle pagine, aiuta a separare la logica aziendale dalla logica di presentazione e faciliterà l'evoluzione delle pagine in pagine in stile JSP 2.0 (le specifiche JSP 2.0 supportano ma non sottolineano l'uso degli scriptlet).
...
Nello spirito dell'adozione del modello di progettazione modello-view-controller (MVC) per ridurre l'accoppiamento tra il livello di presentazione dalla logica aziendale, gli scriptlet JSP non devono essere utilizzati per scrivere la logica aziendale. Piuttosto, gli scriptlet JSP vengono utilizzati, se necessario, per trasformare i dati (chiamati anche "oggetti valore") restituiti dall'elaborazione delle richieste del client in un formato adeguato pronto per il client. Anche in questo caso, sarebbe meglio farlo con un servlet del front controller o un tag personalizzato.
Se si desidera invocare lo stesso codice Java su ogni richiesta, meno o più indipendentemente dalla pagina richiesta, ad esempio controllando se un utente ha effettuato l'accesso, quindi implementare un filtro e scrivere il codice di conseguenza nel doFilter()
metodo. Per esempio:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
} else {
chain.doFilter(request, response); // Logged in, just continue request.
}
}
Se mappato su un'apposita <url-pattern>
copertura delle pagine JSP di interesse, non è necessario copiare nuovamente lo stesso pezzo di codice complessivo delle pagine JSP.
Se si desidera invocare un codice Java per preelaborare una richiesta, ad esempio precaricando un elenco da un database da visualizzare in una tabella, se necessario basato su alcuni parametri di query, implementare un servlet e scrivere il codice di conseguenza nel doGet()
metodo. Per esempio:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productService.list(); // Obtain all products.
request.setAttribute("products", products); // Store products in request scope.
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
} catch (SQLException e) {
throw new ServletException("Retrieving products failed!", e);
}
}
In questo modo è più semplice gestire le eccezioni. Al DB non si accede nel mezzo del rendering JSP, ma molto prima che il JSP fosse visualizzato. Hai ancora la possibilità di modificare la risposta ogni volta che l'accesso al DB genera un'eccezione. Nell'esempio sopra, verrà visualizzata la pagina di errore 500 predefinita che è comunque possibile personalizzare con un <error-page>
in web.xml
.
Se si desidera invocare del codice Java per postelaborare una richiesta, ad esempio l'elaborazione di un modulo inoltrato, implementare un servlet e scrivere il codice di conseguenza nel doPost()
metodo. Per esempio:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirect to home page.
} else {
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
}
}
In questo modo è più semplice gestire diverse destinazioni della pagina dei risultati: rivisualizzare il modulo con errori di convalida in caso di errore (in questo esempio particolare è possibile visualizzarlo di nuovo utilizzando ${message}
in EL ) o semplicemente passare alla pagina di destinazione desiderata in caso di successo.
Se si desidera invocare del codice Java per controllare il piano di esecuzione e / o la destinazione della richiesta e della risposta, implementare un servlet secondo il modello di controller anteriore di MVC . Per esempio:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
} else {
response.sendRedirect(view);
}
} catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
O semplicemente adotta un framework MVC come JSF , Spring MVC , Wicket , ecc. In modo da finire con solo una pagina JSP / Facelets e una classe JavaBean senza la necessità di un servlet personalizzato.
Se si desidera richiamare del codice Java per controllare il flusso all'interno di una pagina JSP, è necessario acquisire un taglib di controllo del flusso (esistente) come JSTL core . Ad esempio, la visualizzazione List<Product>
in una tabella:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
Con tag in stile XML che si adattano perfettamente a tutto l'HTML, il codice è meglio leggibile (e quindi meglio mantenibile) rispetto a un mucchio di scriptlet con varie parentesi graffe di apertura e chiusura ( "Dove diamine appartiene questa parentesi graffa di chiusura?" ). Un semplice aiuto è configurare l'applicazione Web in modo da generare un'eccezione ogni volta che gli scriptlet vengono ancora utilizzati aggiungendo il seguente pezzo a web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
Nel Facelets , il successore di JSP, che fa parte del Java EE fornito framework MVC JSF , è già non è possibile utilizzare scriptlet . In questo modo sei automaticamente costretto a fare le cose "nel modo giusto".
Se si desidera invocare del codice Java per accedere e visualizzare i dati "back-end" all'interno di una pagina JSP, è necessario utilizzare EL (Expression Language), queste ${}
cose. Ad esempio, rivisualizzando i valori di input inviati:
<input type="text" name="foo" value="${param.foo}" />
I ${param.foo}
visualizza il risultato di request.getParameter("foo")
.
Se si desidera richiamare un codice Java di utilità direttamente nella pagina JSP (in genere public static
metodi), è necessario definirli come funzioni EL. C'è un taglib di funzioni standard in JSTL, ma puoi anche creare facilmente funzioni da solo . Ecco un esempio di come JSTL fn:escapeXml
sia utile per prevenire gli attacchi XSS .
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
Si noti che la sensibilità XSS non è in alcun modo specificamente correlata a Java / JSP / JSTL / EL / qualunque cosa, questo problema deve essere preso in considerazione in ogni applicazione Web sviluppata. Il problema degli scriptlet è che non fornisce alcun modo per prevenire le builtin, almeno non usando l'API Java standard. Il successore di JSP Facelets ha già implicito l'escaping HTML, quindi non devi preoccuparti dei buchi XSS in Facelets.