Jakarta Server Pages (JSP)

Intro

Intro

  • С помощью Servlets удобно:

    • Читать данные формы

    • Читать и устанавливать заголовки HTTP-запросов

    • Работать с cookies

    • Передавать данные между Servlets

  • Но неудобно:

    • Использовать write() для генерации HTML

    • Поддерживать этот HTML

Java EE Web history

Java for Web history

Jakarta Server Pages

  • JSP (Jakarta Server Pages) — технология, позволяющая web-разработчикам легко создавать содержимое, которое имеет как статические, так и динамические компоненты.

  • JSP является составной частью единой технологии создания бизнес-приложений Jakarta EE.

Jakarta Server Pages

  • Разделение динамического и статического содержания. Возможность разделить логику приложения и дизайн Web-страницы снижает сложность разработки Web-приложений и упрощает их поддержку.

  • Независимость от платформы. Так как JSP-технология, основанная на языке программирования Java, не зависит от платформы, то JSP могут выполняться практически на любом Web-сервере. Разрабатывать JSP можно на любой платформе.

Jakarta Server Pages

  • Скрипты и теги. Спецификация JSP объявляет собственные теги, кроме того, JSP поддерживают как JavaScript, так и HTML-теги. JavaScript обычно используется, чтобы добавить функциональные возможности на уровне HTML-страницы.

Example with Servlet

@WebServlet("/example/jsp/without")
public class ProcessWithoutJspServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("header", "Apache Tomcat");
        // code
        String view = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\" />\n" +
                "    <title>First JSP App</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "    <h2>" + req.getAttribute("header") + "</h2>\n" +
                "    <p>Today " + new java.util.Date() + "</p>\n" +
                "</body>\n" +
                "</html>";
        PrintWriter writer = resp.getWriter();
        writer.write(view);
    }
}

Example

<% String header = "Apache Tomcat"; %> (1)
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h2><%= header %></h2> (1)
    <p>Today <%= new java.util.Date() %></p> (1)
</body>
</html>
  1. Dynamic content

Example

curl http://localhost:8080/example/jsp
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h2>Apache Tomcat</h2>
    <p>Today Mon Jun 15 05:51:28 MSK 2020</p>
</body>
</html>

Lifecycle

Lifecycle

JSP lifecycle

JSP is Servlet

JSP is Servlet
  1. translated to - Jasper (JSP engine/JSP container, находится в поставке Tomcat) преобразует JSP в Servlet

  2. compiles to - javac компилирует Servlet

  3. loaded as - Catalina (Servlet container) загружает Servlet

Example JSP

<% String header = "Apache Tomcat"; %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h2><%= header %></h2>
    <p>Today <%= new java.util.Date() %></p>
</body>
</html>

Example Servlet (prepared with Jasper)

Path for project with JSP:

/opt/apache-tomcat-9/work/Catalina/localhost/artist_demo/

Path for autogenerated Servlet:

org/apache/jsp/WEB_002dINF/jsp/example_jsp.java

Example Servlet (prepared with Jasper)

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.35
 * Generated at: 2020-06-15 02:43:24 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp.WEB_002dINF.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class example_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      final java.lang.String _jspx_method = request.getMethod();
      if ("OPTIONS".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        return;
      }
      if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
        return;
      }
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

 String header = "Apache Tomcat";
      out.write("\n");
      out.write("<!DOCTYPE html>\n");
      out.write("<html>\n");
      out.write("<head>\n");
      out.write("    <meta charset=\"UTF-8\" />\n");
      out.write("    <title>First JSP App</title>\n");
      out.write("</head>\n");
      out.write("<body>\n");
      out.write("    <h2>");
      out.print( header );
      out.write("</h2>\n");
      out.write("    <p>Today ");
      out.print( new java.util.Date() );
      out.write("</p>\n");
      out.write("</body>\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

Example

curl http://localhost:8080/jsp/example
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h2>Apache Tomcat</h2>
    <p>Today Mon Jun 15 05:51:28 MSK 2020</p>
</body>
</html>

Syntax

Basic syntax

Кроме стандартных HTML конструкций есть три основных типа конструкций JSP, которые можно включить в jsp-страницу:

  • Script Elements

  • Directives

  • Actions

Script Elements

Script Elements

  • Expressions

  • Declarations

  • Scriptlets

Script Elements

JSP Script Elements позволяют вставлять Java-code в Servlet, создаваемый из текущей JSP. Существуют три формы:

  • <%= Expression %> вставка фрагмента Java-code, который обрабатывается и направляется на вывод

  • <%! Declarations; %> вставка объявлений, которые вставляются в тело класса Servlet, вне существующих методов

  • <% Scriptlets; %> вставка фрагмента Java-code, которые вставляются в метод service() класса Servlet

Expressions

JSP Expressions применяются для того, чтобы вставить значения Java непосредственно в вывод. Для этого используется следующая форма:

<%= Java-expression %>
Текущее время: <%= new java.util.Date() %> (1)
  1. Отобразит дату и время запроса данной страницы

Scriptlets

JSP Scriptlets дают возможность вставить любой код в метод service() класса Servlet. Scriptlet имеют следующий вид:

<% Java-code %>

Scriptlets также имеют доступ к тем же автоматически определенным переменным, что и Expressions.

<%
    Date currentDate = new java.util.Date();
    out.println("Текущее время: " + currentDate);
%>

Example

<%
    String[] people = new String[] {"Tom", "Bob", "Sam"};
    String header = "Users list";
%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h3><%= header %></h3>
    <ul>
    <%
        for (String person : people) {
            out.println("<li>" + person + "</li>");
        }
    %>
    </ul>
</body>
</html>

Declarations

JSP Declarations позволят задать методы/поля, для вставки в тело класса Servlet (вне метода service(), обрабатывающего запрос). Они имеют следующую форму:

<%! Java-code; %>

Declarations

Поскольку объявления не осуществляют вывода, обычно они используются совместно с JSP Expressions или Scriptlets.

<%! private int accessCount = 0; %>

Количество обращений к странице с момента загрузки сервера:

<%= ++accessCount %>

Example

<%!
    int square(int n) {
        return n * n;
    }
%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <p><%= square(6) %></p>
    <ul>
    <%
        for (int i = 1; i <= 5; i++) {
            out.println("<li>" + square(i) + "</li>");
        }
    %>
    </ul>
</body>
</html>

JSP Objects

JSP Objects

В JSP автоматически создаются и становятся доступными ряд объектов, необходимых для создания страниц и обмена информацией.

  • request - объект HttpServletRequest

  • response - объект HttpServletResponse

  • session - объект HttpSession

  • out - объект JspWriter, аналогичен используемому в Servlet PrintWriter

JSP Objects

  • application - объект ServletContext

  • config - объект ServletConfig

  • pageContext - объект PageContext

Examples

Имя хоста сделавшего запрос:

<%= request.getRemoteHost() %>

Получение значения параметра title:

<%= request.getParameter("title") %>

Comments

Comments

<%-- Первое приложение на JSP --%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>First JSP App</title>
</head>
<body>
    <h2>Hello</h2>
</body>
</html>

Comments

<%
    /*
        Пример цикла
        в JSP
    */
    // вывод строки Hello четыре раза
    for (int i = 1; i < 5; i++) {
        out.println("<br>Hello " + i);
    }
%>

Directives

Directives

Тег <%@ Directive %> служит для выполнения различных служебных операций и применения настроек.

Сразу после <%@ у этого тега должно следовать имя директивы. Чаще всего используются следующие:

  • page управление страницей

  • include подключение других JSP и HTML

  • taglib подключение дополнительных библиотек тегов (например, JSTL)

Directive page

При использовании директивы page, в тэг вставляются параметры, выполняющие ту или иную функцию. Чаще всего используются следующие:

  • language - язык программирования (обычно используется только Java)

  • import - подключение классов, аналогично import в обычных java-файлах

  • contentType - тип содержимого страницы (чаще всего text/html), аналогично response.setContentType("text/html");

  • pageEncoding - кодировка текста страницы

Example

<%@ page
    language="java"
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"
%>

<%@ page import ="java.io.InputStream"%>

Directive include

  • Directive include позволяет включать в JSP другие JSP или HTML файлы.

  • Сходные возможности предлагает метод include() класса RequestDispatcher, который можно получить из ServletContext. Между этими методами существует заметная разница.

Example: include

include.jsp:

<% x = 5; %>

main.jsp:

<html>
<head>
    <title>First JSP</title>
</head>
<body>
    <h1>Hello World!!!</h1>
    <% int x = 2 * 2; %>
    <%@ include file="include.jsp" %>
    <%= x %>
</body>
</html>

Example: include

В результате выполнения, файл main.jsp будет иметь следующий исходный код:

<html>
<head>
    <title>First JSP</title>
</head>
<body>
    <h1>Hello World!!!</h1>
    <% int x =2 * 2; %>
    <% x = 5; %>
    <%= x %>
</body>
</html>

Directive taglib

Directive taglib позволяет подключать библиотеки тегов.

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

<%@ taglib prefix="test" uri="/WEB-INF/mylib.tld" %>

Атрибут uri ссылается на URI, который однозначно идентифицирует дескриптор библиотеки тегов (TLD). TLD описывает набор пользовательских тегов, которые ассоциируются с названным префиксом.

Actions

Actions

JSP Actions используют конструкции с синтаксисом XML для управления работой движка Servlet, тем самым расширяя возможности JSP:

  • динамическое включение файлов в JSP

  • переиспользование JavaBeans задавая различные scope

  • …​

Actions: конструкции

  • jsp:include - подключение файла в момент запроса страницы

  • jsp:forward - перенаправление запроса на другую страницу

  • jsp:useBean - поиск или создание нового экземпляра JavaBean

  • jsp:setProperty - установка значения свойства JavaBean

  • jsp:getProperty - получение и вывод в поток вывода значения свойства JavaBean

  • …​

Actions equivalent

Конструкция JSP

Конструкция в XML

<% page …​ %>

<%jsp:directive.page …​ />

<% include …​ %>

<%jsp:directive.include …​ />

<%! …​ %>

<%jsp:declaration>…​<%/jsp:declaration>

<% …​ %>

<%/jsp:scriptlet>…​<%/jsp:scriptlet>

<%= …​ %>

<%/jsp:expression>…​<%/jsp:expression>

Action jsp:include

Это действие позволяет вставлять файлы в генерируемую страницу. Синтаксис действия:

<jsp:include page="относительный URL" flush="true" />

В отличие от директивы include, которая вставляет файл на этапе трансляции JSP страницы, это действие вставляет файл при запросе страницы.

Action jsp:forward

Это действие позволяет передать запрос другой странице. Оно использует атрибут page, который должен содержать относительный URL страницы. Ей может быть как статическое значение, так и вычисляемое в процессе запроса, что и показано на следующих двух примерах:

<jsp:forward page="/utils/errorReporter.jsp"/>
<jsp:forward page="<%= Выражение на Java %>"/>

Action jsp:useBean

Этот Action позволяет загружать JavaBean для последующего использования на JSP странице. Простейший синтаксис для указания используемого JavaBean:

<jsp:useBean id="имя" class="${JavaBeanClassPath}.class"/>

Action jsp:setProperty

Action jsp:setProperty используется для присвоения значений свойствам ранее описанных JavaBeans. Существует двумя способами.

Можно использовать jsp:setProperty после, но вне элемента jsp:useBean:

<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="fieldName" value="fieldValue"/>

В этом случае jsp:setProperty выполняется независимо от того, был ли найден существующий JavaBean или был создан новый экземпляр.

Action jsp:setProperty

Можно размещать jsp:setProperty в теле элемента jsp:useBean:

<jsp:useBean id="myName" ... >
    ...
    <jsp:setProperty name="myName" property="fieldName" value="fieldValue"/>
</jsp:useBean>

При этом jsp:setProperty выполняется лишь в том случае, если был создан новый экземпляр объекта, а не тогда, когда находится уже существующий.

Action jsp:setProperty

<jsp:setProperty name="name" property="*"/>

Устанавливает все property для Bean используя данные формы.

<jsp:useBean id="product" scope="request" class="entities.Product">
    <jsp:setProperty name="product" property="*"/>
</jsp:useBean>

<jsp:useBean id="product" scope="request" class="entities.Product">
    <jsp:setProperty name="product" property="model" param="model"/>
</jsp:useBean>

Action jsp:getProperty

Этот элемент определяет значение свойства bean, конвертирует его в строку и направляет в поток вывода.

<jsp:useBean id="itemBean" ... />
...
<ul>
	<li>Количество предметов:
		<jsp:getProperty name="itemBean" property="numItems"/>
	</li>
	<li>Цена за штуку:
		<jsp:getProperty name="itemBean" property="unitCost"/>
	</li>
</ul>