How to Avoid Using Scriptlets in My Jsp Page

How to avoid using scriptlets in my JSP page?

I think it helps more if you see with your own eyes that it can actually be done entirely without scriptlets.

Here's a 1 on 1 rewrite with help of among others JSTL (just drop jstl-1.2.jar in /WEB-INF/lib) core and functions taglib:

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

<html>
<head>
<title>My Events - <decorator:title /></title>
<link href="${pageContext.request.contextPath}/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
<a
${fn:contains(pageContext.request.requestURI, '/events/') ? 'class="selected"' : ''}
href="${pageContext.request.contextPath}/events/Listing.action">Events</a>
<a
${fn:contains(pageContext.request.requestURI, '/people/') ? 'class="selected"' : ''}
href="${pageContext.request.contextPath}/people/Listing.action">People</a>
</div>

<div class="submenu">
<c:if test="${fn:contains(pageContext.request.requestURI, '/events/')}">
<a href="Listing.action">List of Events</a>
|<a href="New.action">New Event</a>
</c:if>
<c:if test="${fn:contains(pageContext.request.requestURI, '/people/')}">
<a href="Listing.action">List of People</a>
|<a href="New.action">New Person</a>
</c:if>
 
</div>

Here's a more optimized rewrite, note that I used c:set to "cache" expression results for reuse and that I use HTML <base> tag to avoid putting the context path in every link (just make all relative URL's in your webpage relative to it --without the leading slash!):

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

<c:set var="isEvents" value="${fn:contains(pageContext.request.requestURI, '/events/')}" />
<c:set var="isPeople" value="${fn:contains(pageContext.request.requestURI, '/people/')}" />

<html>
<head>
<title>My Events - <decorator:title /></title>
<base href="${pageContext.request.contextPath}">
<link href="assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
<a ${isEvents ? 'class="selected"' : ''} href="events/Listing.action">Events</a>
<a ${isPeople ? 'class="selected"' : ''} href="people/Listing.action">People</a>
</div>

<div class="submenu">
<c:if test="${isEvents}">
<a href="Listing.action">List of Events</a>|<a href="New.action">New Event</a>
</c:if>
<c:if test="${isPeople}">
<a href="Listing.action">List of People</a>|<a href="New.action">New Person</a>
</c:if>
 
</div>

It can actually be optimized more if you collect all those "hardcoded" values like events and people and link texts in a Map in the application scope and use under each the JSTL <c:forEach> to display the tabs.

As to your actual question, you can disable scriptlets (and get runtime errors about using it) by adding the following entry in webapp's web.xml. It may help to spot overseen scriptlets.

<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>

To learn more about EL, check the Java EE tutorial part II chapter 5. Implicit EL objects, such as ${pageContext} are described here. To learn more about JSTL, check the Java EE tutorial part II chapter 7. Note that JSTL and EL are two separate things. JSTL is a standard taglib and EL just enables to access backend data programmatically. Although it is normally used in taglibs like JSTL, it can also be used standalone in template text.

JSP - What is wrong with scriptlets, and what to use instead

This is my personal opinion, of course. I say scriptlets are:

  1. A 1998 vintage technology that needs to disappear; a failed response to Microsoft's ASP.
  2. Ugly
  3. Hard to read
  4. Hard to maintain
  5. Discourage reuse and encapsulation
  6. Encourage putting complex logic in pages

What to use instead?

  1. The world has gone in the direction of HTML5, CSS3, JavaScript, jQuery, Bootstrap, and web technologies talking to REST web services. It's a good direction.
  2. If you must stick with JSPs, start with the JSP standard template library. Keep your HTML pages looking like HTML - it'll make it easier for UI developers to maintain them.
  3. Try a more modern template solution like Thymeleaf to generate your HTML from the server side.

How can I avoid Java code in JSP files, using JSP 2?

The use of scriptlets (those <% %> things) in JSP is indeed highly discouraged since the birth of taglibs (like JSTL) and EL (Expression Language, those ${} things) way back in 2001.

The major disadvantages of scriptlets are:

  1. Reusability: you can't reuse scriptlets.
  2. Replaceability: you can't make scriptlets abstract.
  3. OO-ability: you can't make use of inheritance/composition.
  4. Debuggability: if scriptlet throws an exception halfway, all you get is a blank page.
  5. Testability: scriptlets are not unit-testable.
  6. Maintainability: per saldo more time is needed to maintain mingled/cluttered/duplicated code logic.

Sun Oracle itself also recommends in the JSP coding conventions to avoid use of scriptlets whenever the same functionality is possible by (tag) classes. Here are several cites of relevance:

From JSP 1.2 Specification, it is highly recommended that the JSP Standard Tag Library (JSTL) be used in your web application to help reduce the need for JSP scriptlets in your pages. Pages that use JSTL are, in general, easier to read and maintain.

...

Where possible, avoid JSP scriptlets whenever tag libraries provide equivalent functionality. This makes pages easier to read and maintain, helps to separate business logic from presentation logic, and will make your pages easier to evolve into JSP 2.0-style pages (JSP 2.0 Specification supports but de-emphasizes the use of scriptlets).

...

In the spirit of adopting the model-view-controller (MVC) design pattern to reduce coupling between the presentation tier from the business logic, JSP scriptlets should not be used for writing business logic. Rather, JSP scriptlets are used if necessary to transform data (also called "value objects") returned from processing the client's requests into a proper client-ready format. Even then, this would be better done with a front controller servlet or a custom tag.


How to replace scriptlets entirely depends on the sole purpose of the code/logic. More than often this code is to be placed in a fullworthy Java class:

  • If you want to invoke the same Java code on every request, less-or-more regardless of the requested page, e.g. checking if a user is logged in, then implement a filter and write code accordingly in doFilter() method. E.g.:

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

    When mapped on an appropriate <url-pattern> covering the JSP pages of interest, then you don't need to copypaste the same piece of code overall JSP pages.



  • If you want to invoke some Java code to process a GET request, e.g. preloading some list from a database to display in some table, if necessary based on some query parameters, then implement a servlet and write code accordingly in doGet() method. E.g.:

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

    This way dealing with exceptions is easier. The DB is not accessed in the midst of JSP rendering, but far before the JSP is been displayed. You still have the possibility to change the response whenever the DB access throws an exception. In the above example, the default error 500 page will be displayed which you can anyway customize by an <error-page> in web.xml.



  • If you want to invoke some Java code to process a POST request, such as gathering data from a submitted HTML form and doing some business stuff with it (conversion, validation, saving in DB, etcetera), then implement a servlet and write code accordingly in doPost() method. E.g.:

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

    This way dealing with different result page destinations is easier: redisplaying the form with validation errors in case of an error (in this particular example you can redisplay it using ${message} in EL), or just taking to the desired target page in case of success.



  • If you want to invoke some Java code to control the execution plan and/or the destination of the request and the response, then implement a servlet according to the MVC's Front Controller Pattern. E.g.:

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

    Or just adopt an MVC framework like JSF, Spring MVC, Wicket, etc so that you end up with just a JSP/Facelets page and a JavaBean class without the need for a custom servlet.



  • If you want to invoke some Java code to control the flow inside a JSP page, then you need to grab an (existing) flow control taglib like JSTL core. E.g. displaying List<Product> in a table:

      <%@ 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>

    With XML-style tags which fit nicely among all that HTML, the code is better readable (and thus better maintainable) than a bunch of scriptlets with various opening and closing braces ("Where the heck does this closing brace belong to?"). An easy aid is to configure your web application to throw an exception whenever scriptlets are still been used by adding the following piece to web.xml:

      <jsp-config>
    <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
    </jsp-config>

    In Facelets, the successor of JSP, which is part of the Java EE provided MVC framework JSF, it is already not possible to use scriptlets. This way you're automatically forced to do things "the right way".



  • If you want to invoke some Java code to access and display "backend" data inside a JSP page, then you need to use EL (Expression Language), those ${} things. E.g. redisplaying submitted input values:

      <input type="text" name="foo" value="${param.foo}" />

    The ${param.foo} displays the outcome of request.getParameter("foo").



  • If you want to invoke some utility Java code directly in the JSP page (typically public static methods), then you need to define them as EL functions. There's a standard functions taglib in JSTL, but you can also easily create functions yourself. Here's an example how JSTL fn:escapeXml is useful to prevent XSS attacks.

      <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    ...
    <input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />

    Note that the XSS sensitivity is in no way specifically related to Java/JSP/JSTL/EL/whatever, this problem needs to be taken into account in every web application you develop. The problem of scriptlets is that it provides no way of builtin preventions, at least not using the standard Java API. JSP's successor Facelets has already implicit HTML escaping, so you don't need to worry about XSS holes in Facelets.

See also:

  • What's the difference between JSP, Servlet and JSF?
  • How does Servlet, ServletContext, HttpSession and HttpServletRequest/Response work?
  • Basic MVC example with JSP, Servlet and JDBC
  • Design patterns in Java web applications
  • Hidden features of JSP/Servlet

Replace scriptlet to avoid java code inside .jsp file

To replace the if/else part, you can use <c:if> or <c:choose>

The first one provides a single choice and no else (but two tags with opposite conditions will do the trick).

Better to use <c:choose> in your case.

<c:choose>
<c:when test="${condition}">...</c:when>
<c:otherwise>...</c:otherwise>
</c:choose>

As for the rest, you will need to use a bean to transfer the data between your servlet and the JSP

Avoid Scriptlets in Jsp for displaying data on page load

The fact that the request comes from a form or not doesn't change anything. The servlet receives a request, and then can do some processing and forward to a JSP:

  1. servlet gets request parameters
  2. servlets uses those parameters to get requested data from a database, and populate some beans with said data. It may also build some beans from scratch, to display a form with default values
  3. servlet puts those beans in request attributes
  4. servlet forwards to a JSP
  5. JSP avoids using scriptlets and rather uses JSP EL, the JSTL and custom tags to display the information stored in the beans in request scope

JSP and scriptlets

It is not just about making others life easier, it is also about making YOUR life easier. JSTL and other tags force/help you to write a JSP properly. A problem with scriptlets is that people do things in a JSP that they shouldn't. I mean, JSTL (among other tags) helps you to keep MVC pattern because basically, if there is something that you cannot do with JSTL in a JSP, it is because you should not. If you do not respect MVC and do things in JSPs that you shouldn't

You can use JSTL, struts tags, springs tags, etc. There are few options and you can combine them.



Related Topics



Leave a reply



Submit