Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><sup>Note: I find it hard to think of any "hidden features" for JSP/Servlet. In my opinion "best practices" is a better wording and I can think of any of them. It also really depends on your experience with JSP/Servlet. After years of developing you don't see those "hidden features" anymore. At any way, I'll list some of those little "best practices" of which I in years discovered that many starters aren't fully aware of it. Those would be categorized as "hidden features" in the eye of many starters. Anyway, here's the list :)</sup></p> <hr> <h2>Hide JSP pages from direct access</h2> <p>By placing JSP files in <code>/WEB-INF</code> folder you effectively hide them from direct access by for example <code>http://example.com/contextname/WEB-INF/page.jsp</code>. This will result in a <code>404</code>. You can then only access them by a <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/RequestDispatcher.html" rel="nofollow noreferrer"><code>RequestDispatcher</code></a> in Servlet or using <a href="http://www.oracle.com/technetwork/java/syntaxref12-149806.pdf" rel="nofollow noreferrer"><code>jsp:include</code></a>.</p> <hr> <h2>Preprocess request for JSP</h2> <p>Most are aware about Servlet's <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html#doPost-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-" rel="nofollow noreferrer"><code>doPost()</code></a> to <strong>post</strong>-process a request (a form submit), but most don't know that you can use Servlet's <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html#doGet-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-" rel="nofollow noreferrer"><code>doGet()</code></a> method to <strong>pre</strong>-process a request for a JSP. For example:</p> <pre><code>protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List&lt;Item&gt; items = itemDAO.list(); request.setAttribute("items", items); request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response); } </code></pre> <p>which is used to preload some tabular data which is to be displayed with help of JSTL's <code>c:forEach</code>:</p> <pre><code>&lt;table&gt; &lt;c:forEach items="${items}" var="item"&gt; &lt;tr&gt;&lt;td&gt;${item.id}&lt;/td&gt;&lt;td&gt;${item.name}&lt;/td&gt;&lt;/tr&gt; &lt;/c:forEach&gt; &lt;/table&gt; </code></pre> <p>Map such a servlet on an <code>url-pattern</code> of <code>/page</code> (or <code>/page/*</code>) and just invoke <code>http://example.com/contextname/page</code> by browser address bar or a plain vanilla link to run it. See also e.g. <a href="https://stackoverflow.com/questions/2349633/doget-and-dopost-in-servlets">doGet and doPost in Servlets</a>.</p> <hr> <h2>Dynamic includes</h2> <p>You can use EL in <a href="http://www.oracle.com/technetwork/java/syntaxref12-149806.pdf" rel="nofollow noreferrer"><code>jsp:include</code></a>:</p> <pre><code>&lt;jsp:include page="/WEB-INF/${bean.page}.jsp" /&gt; </code></pre> <p>The <code>bean.getPage()</code> can just return a valid pagename.</p> <hr> <h2>EL can access any getter</h2> <p>EL does not per-se require the object-to-be-accessed to be a <em>fullworthy</em> Javabean. The presence of a no-arg method which is prefixed with <code>get</code> or <code>is</code> is more than sufficient to access it in EL. E.g.:</p> <pre><code>${bean['class'].name} </code></pre> <p>This returns the value of <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getName--" rel="nofollow noreferrer"><code>bean.getClass().getName()</code></a> where the <code>getClass()</code> method is actually inherited from <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--" rel="nofollow noreferrer"><code>Object#getClass()</code></a>. Note that <code>class</code> is specified using "brace notation" <code>[]</code> for reasons mentioned here <a href="https://stackoverflow.com/questions/10314214/instanceof-check-in-el-expression-language/10317070#10317070">instanceof check in EL expression language</a>.</p> <pre><code>${pageContext.session.id} </code></pre> <p>This returns the value of <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html#getId--" rel="nofollow noreferrer"><code>pageContext.getSession().getId()</code></a> which is useful in a.o. <a href="https://stackoverflow.com/questions/2566496/can-an-applet-communicate-with-an-instance-of-a-servlet">Can an applet communicate with an instance of a servlet</a>.</p> <pre><code>${pageContext.request.contextPath} </code></pre> <p>This returns the value of <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getContextPath--" rel="nofollow noreferrer"><code>pageContext.getRequest().getContextPath()</code></a> which is useful in a.o. <a href="https://stackoverflow.com/questions/4764405/how-to-use-relative-paths-without-including-the-context-root-name">How to use relative paths without including the context root name?</a></p> <hr> <h2>EL can access Maps as well</h2> <p>The following EL notation</p> <pre><code>${bean.map.foo} </code></pre> <p>resolves to <code>bean.getMap().get("foo")</code>. If the <code>Map</code> key contains a dot, you can use the "brace notation" <code>[]</code> with a quoted key:</p> <pre><code>${bean.map['foo.bar']} </code></pre> <p>which resolves to <code>bean.getMap().get("foo.bar")</code>. If you want a dynamic key, use brace notation as well, but then unquoted:</p> <pre><code>${bean.map[otherbean.key]} </code></pre> <p>which resolves to <code>bean.getMap().get(otherbean.getKey())</code>.</p> <hr> <h2>Iterate over Map with JSTL</h2> <p>You can use <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/forEach.html" rel="nofollow noreferrer"><code>c:forEach</code></a> as well to iterate over a <code>Map</code>. Each iteration gives a <a href="http://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html" rel="nofollow noreferrer"><code>Map.Entry</code></a> which in turn has <code>getKey()</code> and <code>getValue()</code> methods (so that you can just access it in EL by <code>${entry.key}</code> and <code>${entry.value}</code>). Example:</p> <pre><code>&lt;c:forEach items="${bean.map}" var="entry"&gt; Key: ${entry.key}, Value: ${entry.value} &lt;br&gt; &lt;/c:forEach&gt; </code></pre> <p>See also e.g. <a href="https://stackoverflow.com/questions/15667052/debugging-with-jstl-how-exactly">Debugging with jstl - how exactly?</a></p> <hr> <h2>Get current date in JSP</h2> <p>You can get the current's date with <a href="http://www.oracle.com/technetwork/java/syntaxref12-149806.pdf" rel="nofollow noreferrer"><code>jsp:useBean</code></a> and format it with help of JSTL <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fmt/formatDate.html" rel="nofollow noreferrer"><code>fmt:formatDate</code></a></p> <pre><code>&lt;jsp:useBean id="date" class="java.util.Date" /&gt; ... &lt;p&gt;Copyright &amp;copy; &lt;fmt:formatDate value="${date}" pattern="yyyy" /&gt;&lt;/p&gt; </code></pre> <p>This prints (as of now) like follows: "Copyright &copy; 2010".</p> <hr> <h2>Easy friendly URL's</h2> <p>An easy way to have friendly URL's is to make use of <a href="http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29" rel="nofollow noreferrer"><code>HttpServletRequest#getPathInfo()</code></a> and JSP's hidden in <code>/WEB-INF</code>:</p> <pre><code>protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response); } </code></pre> <p>If you map this servlet on for example <code>/pages/*</code>, then a request on <code>http://example.com/contextname/pages/foo/bar</code> will effectively display <code>/WEB-INF/foo/bar.jsp</code>. You can get a step further by splitting the pathinfo on <code>/</code> and only take the first part as JSP page URL and the remnant as "business actions" (let the servlet act as a <em>page controller</em>). See also e.g. <a href="https://stackoverflow.com/questions/3541077/design-patterns-web-based-applications">Design Patterns web based applications</a>.</p> <hr> <h2>Redisplay user input using <code>${param}</code></h2> <p>The implicit EL object <code>${param}</code> which refers to the <a href="http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletRequest.html#getParameterMap%28%29" rel="nofollow noreferrer"><code>HttpServletRequest#getParameterMap()</code></a> can be used to redisplay user input after a form submit in JSP:</p> <pre><code>&lt;input type="text" name="foo" value="${param.foo}"&gt; </code></pre> <p>This basically does the same as <code>request.getParameterMap().get("foo")</code>. See also e.g. <a href="https://stackoverflow.com/questions/3937624/how-can-i-retain-html-form-field-values-in-jsp-after-submitting-form-to-servlet">How can I retain HTML form field values in JSP after submitting form to Servlet?</a> <br><sub>Don't forget to prevent from XSS! See following chapter.</sub></p> <hr> <h2>JSTL to prevent XSS</h2> <p>To prevent your site from <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" rel="nofollow noreferrer">XSS</a>, all you need to do is to (re)display <strong>user-controlled</strong> data using JSTL <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fn/escapeXml.fn.html" rel="nofollow noreferrer"><code>fn:escapeXml</code></a> or <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/out.html" rel="nofollow noreferrer"><code>c:out</code></a>.</p> <pre><code>&lt;p&gt;&lt;input type="text" name="foo" value="${fn:escapeXml(param.foo)}"&gt; &lt;p&gt;&lt;c:out value="${bean.userdata}" /&gt; </code></pre> <hr> <h2>Alternating <code>&lt;table&gt;</code> rows with <code>LoopTagStatus</code></h2> <p>The <code>varStatus</code> attribute of JSTL <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/c/forEach.html" rel="nofollow noreferrer"><code>c:forEach</code></a> gives you a <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/jstl/core/LoopTagStatus.html" rel="nofollow noreferrer"><code>LoopTagStatus</code></a> back which in turn has several getter methods (which can be used in EL!). So, to check for even rows, just check if <code>loop.getIndex() % 2 == 0</code>:</p> <pre><code>&lt;table&gt; &lt;c:forEach items="${items}" var="item" varStatus="loop"&gt; &lt;tr class="${loop.index % 2 == 0 ? 'even' : 'odd'}"&gt;...&lt;/tr&gt; &lt;c:forEach&gt; &lt;/table&gt; </code></pre> <p>which will effectively end up in</p> <pre><code>&lt;table&gt; &lt;tr class="even"&gt;...&lt;/tr&gt; &lt;tr class="odd"&gt;...&lt;/tr&gt; &lt;tr class="even"&gt;...&lt;/tr&gt; &lt;tr class="odd"&gt;...&lt;/tr&gt; ... &lt;/table&gt; </code></pre> <p>Use CSS to give them a different background color.</p> <pre><code>tr.even { background: #eee; } tr.odd { background: #ddd; } </code></pre> <hr> <h2>Populate commasepared string from List/Array with <code>LoopTagStatus</code>:</h2> <p>Another useful <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/jstl/core/LoopTagStatus.html" rel="nofollow noreferrer"><code>LoopTagStatus</code></a> method is the <a href="http://docs.oracle.com/javaee/7/api/javax/servlet/jsp/jstl/core/LoopTagStatus.html#isLast--" rel="nofollow noreferrer"><code>isLast()</code></a>:</p> <pre><code>&lt;c:forEach items="${items}" var="item" varStatus="loop"&gt; ${item}${!loop.last ? ', ' : ''} &lt;c:forEach&gt; </code></pre> <p>Which results in something like <code>item1, item2, item3</code>.</p> <hr> <h2>EL functions</h2> <p>You can declare <code>public static</code> utility methods as EL functions (like as <a href="http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/fn/tld-summary.html" rel="nofollow noreferrer">JSTL functions</a>) so that you can use them in EL. E.g.</p> <pre><code>package com.example; public final class Functions { private Functions() {} public static boolean matches(String string, String pattern) { return string.matches(pattern); } } </code></pre> <p>with <code>/WEB-INF/functions.tld</code> which look like follows:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt; &lt;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"&gt; &lt;tlib-version&gt;1.0&lt;/tlib-version&gt; &lt;short-name&gt;Custom_Functions&lt;/short-name&gt; &lt;uri&gt;http://example.com/functions&lt;/uri&gt; &lt;function&gt; &lt;name&gt;matches&lt;/name&gt; &lt;function-class&gt;com.example.Functions&lt;/function-class&gt; &lt;function-signature&gt;boolean matches(java.lang.String, java.lang.String)&lt;/function-signature&gt; &lt;/function&gt; &lt;/taglib&gt; </code></pre> <p>which can be used as </p> <pre><code>&lt;%@taglib uri="http://example.com/functions" prefix="f" %&gt; &lt;c:if test="${f:matches(bean.value, '^foo.*')}"&gt; ... &lt;/c:if&gt; </code></pre> <hr> <h2>Get the original request URL and query string</h2> <p>If the JSP has been forwarded, you can get the original request URL by,</p> <pre><code>${requestScope['javax.servlet.forward.request_uri']} </code></pre> <p>and the original request query string by,</p> <pre><code>${requestScope['javax.servlet.forward.query_string']} </code></pre> <hr> <p><sup>That was it as far. Maybe I'll add some more sooner or later.</sup></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload