Scriptless JSP

When you put Java code into JSP it can become a nightmare to manage, with the new JSP 2.0 spec there is a new Expression Language (EL), it looks and feels like Java but it isn't, there are slight differences.

In the MVC tutorial, the servlet controller talked to the model then sent an attribute in the request scope before forwarding to the JSP view. The JSP had to get the attribute from the request scope and use it to render a response to send back to the client.

Servlet (controller) code String name = request.getParameter("userName");
request.setAttribute("name", name);

RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);
JSP (view) code <html><body>
Hello
<%= request.getAttribute("name") %>
</body></html>

But what if the the attribute is not a String but an instance of Person (we are presuming that the Person object has a setName and a getName method).

Servlet (controller) code foo.Person p = new foo.Person();
p.setName("Paul");
request.setAttribute("person", p);

RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);
JSP (view) code <html><body>
  Person is: <%= request.getAttribute("person") %>
</body></html>

The out put would be Person is foo.Person@676e44 not what we wanted, this is because the object's toString() method was run, there are two ways to obtain the results we want

JSP code <% foo.Person p = (foo.Person) request.getAttribute("person");
Person is: <%= p.getName() %>
Expression Person is: <%= ((foo.Person) request.getAttribute("person")).getName() %>

Standard Actions

But this is way over the top, embedding scripting is bad remember and its just plain ugly, with a couple of standard actions, we can eliminate all scripting code in out JSP, the scope defaults to page if not specified

standard actions <jsp:useBean id="person" class="foo.Person" scope="request" />
Person is: <jsp:getProperty name="person" property="name" />

The <jsp:useBean> tag is away of declaring and initializing the actual bean object you're using in <jsp:getProperty>

<jsp:useBean>
  • jsp:useBean - indentifies the standard action
  • id= - declares the identifier for the bean object this is the name in request.setAttribute("person",p);
  • class= - declares the class type (fully-qualified) for the bean object
  • scope= - identifies the attribute scope for this bean object
<jsp:getProperty>
  • jsp:getProperty - identifies the standard action
  • name= - identifies the actual bean object, this will be the id value from the <jsp:useBean> tag
  • property= - identifies the property name (the thing with the getter and setter in the bean class)

if the <jsp:useBean> tag cannot find an attribute named person" it can make one, it first searches for an existing one but if it does not find one it creates one.

Example ## The below tag
<jsp:useBean id="person" class="foo.Person" scope="request" />

## Gets Turned into this code in the _jspService() method
foo.Person person = null;

synchronized (request) {
  
  person = (foo.Person)_jspx_page_context.getAttribute("person", PageContext.REQUEST_SCOPE);

  // if there is not a Person object already then create one
  if (person == null) {

    person = foo.Person();
    _jspx_page_context.setAttribute("person", person, PageContext.REQUEST_SCOPE);
  }
}

You can also set the value in the Bean

<jsp:setProperty> <jsp:setProperty name="person" property="name" value="Fred" />

The <jsp:useBean> can also have a body, this can stop a bean that has already been created value from being reset

<jsp:useBean> Body
<jsp:useBean id="person" class="foo.Person" scope="page" >

  <jsp:setProperty name="person" property="name" value="Fred" />

</jsp:useBean>

The above code means that the property value will only be set if this is a new Bean, if an existing bean with that scope and id are found the body never runs.

What if we wanted the reference type to be different from the actual object type in other words the Person class is an abstract class and make a concrete subclass called Employee

We need to make the reference variable type Person and the object an instance of the class Employee and adding a type attribute to the tag lets us do this. Type can be a class type, abstract type or an interface as long as it does not break the Java typing rules.

example <jsp:useBean id="person" type="foo.Person" class="foo.Employee" scope="page">

There are a number of things to remember

You can send a request parameter straight into a bean, without scripting using the param attribute

HTML form <html><body>

<form action="TestBean.jsp">
  name: <input type="text" name="userName">
  ID: <input type="text" name"userID">
  <input type="submit">
</form>

</body></html>
Inside the bean <jsp:useBean id="person" type"foo.Person" class="foo.Employee">
  <jsp:setProperty name="person" property="name" param="userName" />
</jsp:useBean>

If the param property name is the same as name as the property name in your bean then you do not have to specify it

HTML form <html><body>

<form action="TestBean.jsp">
  name: <input type="text" name="name">
  ID: <input type="text" name"userID">
  <input type="submit">
</form>

</body></html>
Inside the bean <jsp:useBean id="person" type"foo.Person" class="foo.Employee">
  <jsp:setProperty name="person" property="name" />
</jsp:useBean>

If the bean has multiple properties you can match them all

HTML form <html><body>

<form action="TestBean.jsp">
  name: <input type="text" name="name">
  ID: <input type="text" name"empID">
  <input type="submit">
</form>

</body></html>
Inside the bean

<jsp:useBean id="person" type"foo.Person" class="foo.Employee">
  <jsp:setProperty name="person" property="*" />
</jsp:useBean>

Note: the person bean has two properties - name and empID

Expression Language

Using the above JSP tags worked fine and reduces the code but the actions aren't as elegant as they could be, for instance what if we wanted to print attribute when the attribute is a non-String attribute what if it was another object, it is possible but the code starts to become complex, enter Expression Language (EL) which was added to the JSP 2.0 specification, thus reducing scripting.

servlet code foo.Person p = new foo.Person();
p.setName("Paul");

foo.Dog dog = new foo.Dog();
dog.setName("Spike");
p.setDog(dog);

request.setAttribute("person", p);
using tags <%= ((foo.Person) request.getAttribute("person")).getDog.getName() %>
JSP Code using EL <html><body>

Dog's name is: ${person.dog.name}

</body></html>

Although EL looks like Java it behaves differently, so do not try and map the same Java with EL, expressions are always within curly braces and prefixed with the dollar sign. The first named variable in the expression is either an implicit object or an attribute

When the variable is on the left side of the dot its either a Map (something with keys) or a bean (something with properties), this is true regardless of whether the variable is an implicit object or an attribute.

If the expression has a variable followed by a bracket [], the left-hand variable can be a Map, a Bean, a List or an Array.

The below is an example using the [] operator with an array

Servlet code String[] footballTeams = { "Liverpool", "Manchester Utd", "Arsenal", "Chelsea" }
request.setAttribute("footballList", footballTeams);
JSP Code

Favorite Team: ${footballList[0]}
Worst Team: ${footballList["1"]}

<%-- using the arraylist toString()
All the teams: ${footballList}

Note: The index value in the brackets is a String literal which means it gets coerced into an int, which means ["one"] would not work but ["10"] would.

When using JavaBeans and Maps you can use either the [] operator or the dot operator.

Servlet code java.util.Map foodMap = new java.util.HashMap();

foodMap.put("Fruit", "Banana");
foodMap.put("TakeAway", "Indian");
foodMap.put("Drink", "Larger");
foodMap.put("Dessert", "IceCream");
foodMap.put("HotDrink", "Coffee");

String[] foodTypes = {"Fruit", "TakeAway", "Drink", "Dessert", "HotDrink"}

request.setAttribute("foodMap", foodMap);
JSP Code Favorite Hot Drink is: ${foodMap.HotDrink}

Favorite Take-Away is: ${foodMap["TakeAway"]}

Favorite Dessert is: ${foodMap[foodTypes[3]]}

There may be cases when you want multiple values for one given parameter name, which is when you use paramValues

HTML Form <html><body>

<form action="TestBean.jsp">
  name: <input type="text" name="name">
  ID: <input type="text" name"empID">

  First food: <input type="text" name="food">
  Second food: <input type="text" name="food">

  <input type="submit">
</form>

</body></html>
JSP Code Request param name is: ${param.name} <br>

Request param empID is: ${param.empID} <br>

<%-- you will only get the first value -->
Request param food is: ${param.food} <br>

First food is: ${paramValues.food[0]} <br>

Second food is: ${paramValues.food[1]} <br>

Here are some other parameters you can obtain, I have also compare some of them with scripting

host header Host is: <%= request.getHeader("host) %>

Host is: ${header["host"]}
Host is: $header.host}
Request method (Post or Get) Method is: ${pageContext.request.method}
Cookie information Username is: ${cookie.userName.value}
Context init parameter email is: <%= application.getInitParameter("mainEmail") %>

email is: {$initParam.mainEmail}

note: you need to configure the parameter in the DD

EL Functions

You can get EL to call Java methods, which is an easy way of calling a static method in a plain old Java class that you have written. The Java method must be public and static. Now for an example

Java Code package foo;

public class DiceRoller {
  public static int rollDice() {
    return (int) ((Math.random() * 6) + 1);
  }
}

Note: the compiled class should go in the /WEB-INF/classes/foo directory
Tag Library Descriptor (TLD) <taglib ...>
<uri>DiceFunctions</uri>
  <function>
    <name>rollIt</name>
    <function-class>foo.DiceRoller</function-class>
    <function-signature>int rollDice()</function-signature>
  </function>
</taglib>

Note: the Tag Library lives in WEB-INF directory with an extension of .tld
JSP Code <%@ taglib prefix="mine" uri="DiceFunctions"%>

<html><body>

${mine:rollIt()}

</body></html>

A point to remember is that the method does not have to return anything but you can supply arguments to the method.

EL has a number of other operators but remember the JSP is the View and it should not do any calculations that not its responsibility that's the job of the Controller and Model.

Arithmetic + - * / %
Logical && || !
Relational == != < > <= >=

JSP Include

I mentioned in another topic Using JSP that you can you can include other HTML pages into your JSP page page (like headers and footers), however there is a <jsp:include> tag that also do this

JSP directive <%@ include file="datadiskHeader.jsp" %>
standard action <jsp:include page="datadiskHeader.jsp" />

There is a difference deep down, with the directive there is no difference between you opening your JSP page and pasting in the contents of the HTML file, so in other words it is really just as though you duplicated the code from the header file into your JSP code and the container does this as translation time. The <jsp:include> is completely different rather than copying in the source code from the header file the include standard action inserts the response of the header jsp file at runtime. he key to <jsp:include> is that the Container is creating a RequestDispatcher from the page attribute and applying the include() method. The dispatched/include JSP executes against the same request and response objects within the same thread.

This means that there is a performance hit with every <jsp:include>, with the directive the hit happens only once when the including page is translated, so if you are sure the included file won't change the directive would be the way to go.

There is one thing that you should remember that when you write reusable code like headers/footers is that it does paste everything into the page and certain browsers may have a big problem with this, because you will end up with multiple <html><body> tags in the page. Designing reusable chunks of code so that you can compose complete layouts from smaller pieces without duplicating the code by hand, they are not meant to live on their own. This goes for both directive and jsp include options.

header/footer file <img src=images/datadisk.jgp" ><br>
<em<strong>Notice no html or body tags.</strong></em><br>

You can also supply the header/footer pages with information using <jsp:param>

Header.jsp <img src=images/datadisk.jgp" ><br>
<em<strong>${param.subTitle}</strong></em><br>
JSP code <jsp:include page="Hedare.jsp" >
  <jsp:param name="subTitle" value="Using jsp:param in our page" />
</jsp:include>

The last jsp standard action is the <jsp:forward> which can redirect you to another page, although bad practices it may help.

<jsp:forward> <% if (request.getParameter("userName") == null) { %>
     <jsp:forward page="handleIt.jsp" />
<% } %>