API Servlet

Définition

Java component that extends the capabilities of a server.
https://en.wikipedia.org/wiki/Java_servlet
— Wikipedia

Partie intégrante d’une application web

Application web

  • Web archive - WAR

  • Structure spécifique

web module

Accessibilité des resources

  • Dans WEB-INF, inaccessible en HTTP

  • En dehors de WEB-INF, accessible en HTTP via le chemin vers la ressource :

Descripteur de déploiement

  • Pages d’accueil

  • Déclaration de servlets

  • Déclaration de filtres

  • Paramètres d’initialisation

  • etc.

web.xml

  • Situé dans répertoire WEB-INF

  • Référence un schéma XSD

  • Dépend de la version de Java EE

  • Optionnel !

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1">
</web-app>

Composant servlet

  • Corrélé à une URL

  • Modèle requête réponse :

    • Activé par l’envoi d’une requête

    • Retourne (souvent) une réponse

Cycle de vie

  • Le cycle de vie est géré par le serveur d’applications

    1. Instanciation

    2. Service

    3. Destruction

  • Il peut exister n instances à un moment t

  • On ne sait pas quelle instance est appelée

servlet sequence

Mapping d’URL

  • Double lien :

    • URL - Nom logique

    • Nom logique - Classe pleinement qualifiée

Via le descripteur

<web...>
  <servlet>
    <servlet-name>HelloWorld</servlet-name>
    <servlet-class>ch.frankel.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloWorld</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
</web>

Via les annotations

package ch.frankel;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet { ... }

Modèles d’URL

  1. Strict, par exemple /hello

  2. Générique, mais limité :

    • /hello/*

    • *.do

  3. Spécifiques :

    • /*

    • /

servlet

Implémentation de servlet

  1. Créer une classe enfant de HttpServlet

  2. Implémenter la méthode qui correspond au verbe HTTP désiré

    • doGet()

    • doPost()

    • etc.

Http Servlet Response

Représentation Java d’une réponse HTTP :

  • Envoi d’un code erreur HTTP

  • Redirection vers une autre URL

  • Gestion des en-têtes HTTP

  • Gestion des cookies

  • Ecriture :

    • de caractères (texte)

    • d’octets (binaire)

servlet response

Envoi de code d’erreur

public class SendErrorServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req,
                      HttpServletResponse res) {
        res.sendError(500);
    }
}

Redirection

  • Le navigateur reçoit un code HTTP 30x :

    • Lecture de l’URL configurée dans l’en-tête HTTP Location

    • Nouvelle requête GET à cette URL

Redirection

redirect

Types de redirection

TypeCode statut HTTP

Permanent

301

Temporary

302

Redirection

public class RedirectServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req,
                      HttpServletResponse resp) {
        resp.sendRedirect("https://www.google.com");
    }
}

Print Writer

  • Permet d’écrire du texte dans le flux de réponse

  • Nécessite de spécifier le type MIME

Print Writer

public class PrintServlet extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req,
                      HttpServletResponse resp) {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("<html><body>");
        out.println("Hello world!");
        out.println("</body></html>");
    }
}

Output Stream

  • Permet d’écrire des octets dans le flux de réponse

  • Nécessite de spécifier le type MIME

  • Génération dynamique :

    • d’images

    • de tableaux Excel

    • etc.

Http Servlet Request

Représentation Java d’une requête HTTP :

GET /java/index.html HTTP/1.1
Host: formations.github.io
Accept: image/gif, image/jpeg, */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)

API

  • Analyse de la requête :

    • Accès à l’URL (protocole, domaine, paramètres, etc.)

    • Accès aux cookies

    • Accès aux en-têtes HTTP

  • Accès à la session HTTP

  • Accès au RequestDispatcher

servlet request

URL

complex url

Request Dispatcher

  • Fait suivre la chaîne de traitement au prochain servlet

  • Inclut la réponse du prochain servlet dans le flux actuel

Utilisation du Request Dispatcher

public class ForwardServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req,
                         HttpServletResponse resp)
                   throws ServletException, IOException {

        req.getRequestDispatcher("/resource")
                          .forward(req, resp);
    }
}
rd forward include

Java Server Pages

  • Ecrire du HTML via le PrintWriter est laborieux

  • Prévisualisation impossible pour les web designers

Composant JSP

  • Format texte

  • Au premier appel, le container :

    • Translate la JSP en servlet

    • Compile le servlet

Exemple de JSP

<!DOCTYPE html>
<html>
<head>
    <title>Hello world</title>
<body>
  <% Object n = request.getAttribute("name"); %>
  Hello <% out.println(n); %>
</body>

Un autre exemple

<!DOCTYPE html>
<html>
<head>
    <title>Hello world</title>
<body>
  Hello <%= request.getAttribute("name") %>
</body>

Un dernier exemple

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <title>Hello world</title>
<body>
  Hello <c:out value="requestScope.name" />
</body>

Scriptlet

  • N’importe quel code Java

  • Balisé par <% et %>

Expression

  • Equivalent à out.println()

  • Balisé par <%= et %>

Directives

TypeExemple

Import

<%@page import="java.util.List" %>

Inclusion

<%@include file="response.jsp" %>

Taglib

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

Commentaires

  • Ignoré dans le processus de compilation

  • Ne sera pas disponible dans le HTML généré

  • Balisé par <%-- et --%>

Déclarations

  • Déclaration de méthodes et d’attributs

  • Pour information (très peu utilisé)

  • Balisé par <%! et %>

Objets implicites

VariableType

 out

JspWriter

 request

HttpServletRequest

 response

HttpServletResponse

 config

ServletConfig

VariableType

 application

ServletContext

 session

HttpSession

 pageContext

PageContext

 page

Object

 exception

Throwable

Modèle Vue Contrôleur

Principe de séparation des responsabilités

RôleComposantFonctionnalité

Contrôleur

Servlet

Gère le flux de contrôle

Vue

JSP

Affiche la page

Modèle

  • JavaBean

  • EJB

  • etc.

Gère les données

mvc

Attributs de requête

  • Comment transférer des données au travers du pipeline de traitement d’une requête ?

  • Par exemple, du contrôleur (servlet) à la vue (JSP)

Exemple de formulaire d’enregistrement

  • Servlet dédié au traitement des données (validation, enregistrement, etc.)

  • JSP dédiée à l’affichage du HTML

    • "Bravo M. Dupont, vous avez bien été enregistré"

  • Il faut transférer les données (titre et nom) du servlet à la JSP

Utilisation des attributs

  • A chaque HttpServletRequest est associée une Map<String, Object>.

    1. Le servlet stocke l’objet comme attribut de requête sous la clé key

    2. Le servlet forward à la JSP

    3. La JSP récupère l’attribut de requête sous la clé key

    4. Le transtype dans le type correct

Périmètre des attributs

NomObjetObjet implicite JSP

Application

ServletContext

application

Session

HttpSession

session

Requête

HttpServletRequest

request

Page

PageContext

page

Session

  • HTTP est un protocole déconnecté

    • Impossible de savoir si 2 requêtes proviennent de la même session navigateur

    • Utilisation d’un cookie JSESSIONID

  • Cookie géré automatiquement par le serveur d’applications

Http Session

  • Ensemble d’attributs spécifiques à une session navigateur

  • Stockés en mémoire

  • Attention :

    • Aux collections sans limite de taille

    • Aux objets de taille trop importante

session
HttpSession session = req.getSession();
session.setAttribute("person", new Person("John", "Doe"));

// in another component (servlet, jsp, filter)
Object object = session.getAttribute("person");
Person person = (Person) object;

Taglibs, tag files et Expression Language

Le problème des scriptlets

  • Dans le modèle MVC, la JSP joue le rôle de vue

  • Mais les scriptlets permettent tout

    • Par exemple, d’accéder à la base de données

Solution

  • Une spécification décrit comment créer une librairie

  • La librairie comporte des fonctionnalités spécifiques

  • Intégrable dans les JSPs

Taglib

Balise XML à laquelle est associée une classe Java compilée

Tag file

Balise XML à laquelle est associée un fichier .tag

Expression Language - EL

Exécute du code arbitraire

Exemples d’expressions EL

  • ${sessionScope.cart.numberOfItems}

  • ${param['mycom.productId']}

  • ${requestScope['javax.servlet.forward.servlet_path']}

  • ${!empty param.Add}

  • etc.

Taglib

Spécifiée par un fichier Tag Library Descriptor

  • Dans le répertoire META-INF du JAR de taglib

  • Référence les classes de Taglib

Exemple de taglib

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="urn:foo:bar"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://foo.bar/bar.xsd"
        version="2.1">
  <display-name>Foo Bar</display-name>
  <tlib-version>1.0</tlib-version>
  <short-name>foo</short-name>
  <uri>http://foo.com/bar</uri>
  <tag>
    <name>bar</name>
    <tag-class>ch.frankel.BarTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>baz</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
  </tag>
</taglib>

Exemple d’utilisation

example.jsp
<%@ taglib uri="http://foo.com/bar" prefix="foo" %>
<html>
  <body>
    <foo:bar baz="hello">
      <h1>Title</h1>
    </foo:bar>
  </body>
</html>

Hiérarchie des classes

tag

Java Standard TagLibs - JSTL

  • Core - c

  • Internationalisation - fmt

  • Tag Library Validator - tlv

  • (SQL - sql)

Fonctionnalités de core

  • Test

  • Itération

  • Affichage

  • etc.

Exemple de scriptlet

<% List person = (List) request.getAttribute("persons"); %>
<% for (Person person: persons) { %>
  <%= person.getName() %>
<% } %>

Equivalent JSTL + EL

<c:forEach var="person" items="${requestScope.persons}">
  <c:out value="${person}" />
</c:forEach>

Filtres de servlet

First, they provide the ability to encapsulate recurring tasks in reusable units. […​] Second, filters can be used to transform the response from a servlet or a JSP page.
http://www.oracle.com/technetwork/java/filters-137243.html
— Oracle Tech Network

Fonctionnalités communes

  • Authentification

  • Logging

  • Conversion d’image

  • Compression de données

  • Cryptage

  • etc.

Composant Filtre

  • Corrélé à une URL

  • Intercepte :

    • Soit la requête

    • Soit la réponse

    • Soit les 2

tfessh pic 1

Mapping d’URL

Comme pour un servlet

filter servlet mapping

Via le descripteur

<web...>
  <filter>
    <filter-name>Authenticate</filter-name>
    <filter-class>ch.frankel.AuthenticateFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>Authenticate</filter-name>
    <url-pattern>/secure/*</url-pattern>
  </filter-mapping>
</web>

Via les annotations

package ch.frankel;

@WebFilter("/secure/*")
public class AuthenticateFilter implements Filter { ... }
filter

Implémentation de filtre

  1. Créer une classe enfant de Filter

  2. Dans doFilter() :

    • Appeler chain.doFilter() pour passer à la prochaine étape

    • Sinon, le flux s’arrête là

Exemple d’implémentation

@Override
public void doFilter(ServletRequest req,
                     ServletResponse res,
                     FilterChain chain)
                   throws IOException, ServletException {
  HttpServletRequest httpReq = (HttpServletRequest) req;
  HttpSession session = httpReq.getSession();
  if (authenticated(session)) {
    chain.doFilter(req, res);
  } else {
    HttpServletResponse httpRes = (HttpServletResponse) res;
    httpRes.sendError(401, "Not authentified");
  }
}

Généralités sur la sécurité

  • Authentification

  • Autorisations

  • Intégrité des données

  • Confidentialité des données

  • Non-répudiation

  • Audit

Restrictions d’accès

  • Le modèle de sécurité en Java EE 7 est plutôt réduit

    • Authentification et autorisations d’accès à une URL

  • La majeure partie de la configuration est propriétaire côté serveur d’applications

Callback

  • Si une URL est protégée

  • Et le client n’est pas authentifié

  • Alors, déclenchement de la procédure d’authentification

Configuration du serveur d’applications

  • Utilisateurs

  • Groupes

  • Rôles

user group role

Déclaration des rôles

<security-role> dans le descripteur de déploiement

<security-role>
    <role-name>ADMIN</role-name>
</security-role>

Configuration standard

<security-constraint> dans le descripteur de déploiement

TypeBalise

Ressource web

<web-resource-collection>

Contrainte d’autorisation

<auth-constraint>

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Partie sécurisée</web-resource-name>
    <url-pattern>/secure/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>ADMIN</role-name>
  </auth-constraint>
</security-constraint>

Modes d’authentification

ModeConfiguration

Popup native

BASIC

Formulaire

FORM

Certificat SSL

CLIENT-CERT

Configuration native

<login-config>
    <auth-method>BASIC</auth-method>
</login-config>

Configuration du formulaire

<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/error.jsp</form-error-page>
  </form-login-config>
</login-config>

Contraintes sur le formulaire

ComposantContrainte

Formulaire

action="j_security_check"

Champ de login

name= "j_username"

Champ de mot de passe

name= "j_password"

<form method=post action="j_security_check">
  <input type="text" name= "j_username" />
  <input type="password" name= "j_password" />
  <input type="submit" value="Login" />
</form>

API

  • HttpServletRequest.isUserInRole(String role)

  • HttpServletRequest.getUserPrincipal()

  • HttpServletRequest.getRemoteUser()

  • (HttpSession.invalidate())

Evènements Java EE

  • Java EE implémente la Programmation Orientée Evènements

  • Divers évènements liés au cycle de vie :

    • Démarrage/arrêt de l’application

    • Gestion des attributs dans les différents contextes

    • etc.

  • Possibilité de s’abonner à ces évènements

Evènements d’application

Classe associéeEvènement

ServletContextListener

Démarrage de l’application

Arrêt de l’application

Evènements de contexte de servlet

Classe associéeEvènement

ServletContextAttributeListener

Ajout d’attribut

Suppression d’attribut

Remplacement d’attribut

Evènements de requête

Classe associéeEvènement

ServletRequestListener

Initialisation de la requête

Destruction de la requête

Evènements de contexte de requête

Classe associéeEvènement

ServletRequestAttributeListener

Ajout d’attribut

Suppression d’attribut

Remplacement d’attribut

Evènements de session

Classe associéeEvènement

HttpSessionListener

Création de la session

Destruction de la session

Evènements de contexte de session

Classe associéeEvènement

HttpSessionAttributeListener

Ajout d’attribut

Suppression d’attribut

Remplacement d’attribut

Evènements de stockage dans la session

Classe associéeEvènement

HttpSessionBindingListener

Objet stocké en session

Objet supprimé de la session

Evènements d’activation de session

Classe associéeEvènement

HttpSessionActivationListener

Activation de la session

Déactivation de la session

servlet listener

Via le descripteur

<web...>
  <listener>
    <listener-class>
      ch.frankel.ASessionListener
    </listener-class>
  </listener>
</web>

Via les annotations

@WebListener
public class SessionListener implements HttpSessionListener {
}

Exemple d’implémentation

@WebListener
public class DatabaseInitializationListener implements ServletContextListener {

  @Override
  public void contextInitialized(ServletContextEvent event) {
    // Create sample data in database
  }

  @Override
  public void contextDestroyed(ServletContextEvent event) {}
}

Gestion des erreurs

  • Gérer les exceptions qui ne sont pas traitées par le servlet

  • De manière transversale

Le serveur a rencontré une erreur qui l'a empêché de servir la requête

Pages d’erreur

  • A chaque type d’exception

  • Ou à chaque type d’erreur HTTP

    • Correspond une page d’erreur

  • Ou une page d’erreur catch all

Configuration

<error-page>
    <exception-type>java.lang.NullPointerException</exception-type>
    <location>/WEB-INF/npe.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/404.jsp</location>
</error-page>
<error-page>
    <location>/WEB-INF/errors.jsp</location>
</error-page>

Tips & tricks

  • Garder les pages d’erreur simples

  • Dans la JSP, il est possible d’accéder à l’exception via la variable exception

    • Nécessite la directive <%@ page isErrorPage="true" %>

Internationalisation

  • i18n fait partie de Java SE

  • Mais utilisé dans Java EE

    • Via la librairie JSTL fmt

JSTL fmt

TagDescription

<fmt:setLocale>

Set la locale depuis une variable

<fmt:setBundle>

Charge le bundle et le stocke dans une variable

<fmt:message>

Affiche le message internationalisé

Exemple d’utilisation

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

<fmt:setLocale value="${request.locale}" />
<fmt:setBundle basename="ch.hesge.messages" var="msg" />

<html>
 <body>
   <ul>
     <li><fmt:message key="key.one" bundle="${msg}" /></li>
     <li><fmt:message key="key.two" bundle="${msg}" /></li>
   </ul>
 </body>
</html>