t
t
t
t
t t 15) Informatique distribuée
tttt
15) Informatique distribuée
Texte original t Traducteur : Jean-Pierre VIDAL, Alban PEIGNIER
t
t
///
Ce chapitre contient 12 pages
1 2 3 4 5 6 7 8 9 10 11 12
\\\
t t t
t t t
t
t t t
The following program uses the CIDConnect and CIDSQL information to load the JDBC driver, make a connection to the database, and then create the table structure diagrammed above. To connect with the database, you call the static method DriverManager.getConnection( ), passing it the database URL, the user name, and a password to get into the database. You get back a Connection object that you can use to query and manipulate the database. Once the connection is made you can simply push the SQL to the database, in this case by marching through the CIDSQL array. However, the first time this program is run, the “drop table” command will fail, causing an exception, which is caught, reported, and then ignored. The reason for the “drop table” command is to allow easy experimentation: you can modify the SQL that defines the tables and then rerun the program, causing the old tables to be replaced by the new. t Le programme qui suit utilise l'information de CIDConnect et CIDSQL pour charger le driver JDBC, se connecter à la base de données, puis créer la structure de la table conforme au diagramme ci-dessus. Pour se connecter à la base, on appelle la méthode static DriverManager.getConnection( ), en lui passant l'URL de base de données, le nom d'utilisateur et un mot de passe. On obtient en retour un objet Connection que l'on peut utiliser pour interroger et manipuler la base. La connexion établie, il suffit d'envoyer le SQL à la base, dans ce cas en balayant le tableau CIDSQL. Toutefois, au premier lancement du programme, la commande « drop table » échouera, lançant une exception, qui sera capturée, rapportée, puis ignorée. La commande « drop table » n'a d'autre but que de permettre une expérimentation plus facile : on peut modifier le code SQL définissant les tables puis exécuter à nouveau le programme, les anciennes tables étant remplacées par les nouvelles.
t t t
In this example, it makes sense to let the exceptions be thrown out to the console: t Dans cet exemple, il est intéressant de laisser les exceptions s'afficher sur la console :
t t t
//: c15:jdbc:CIDCreateTables.java
// Creates database tables for the
// community interests database.
import java.sql.*;

public class CIDCreateTables {
  public static void main(String[] args)
  throws SQLException, ClassNotFoundException,
  IllegalAccessException {
    // Load the driver (registers itself)
    Class.forName(CIDConnect.dbDriver);
    Connection c = DriverManager.getConnection(
      CIDConnect.dbURL, CIDConnect.user,
      CIDConnect.password);
    Statement s = c.createStatement();
    for(int i = 0; i < CIDSQL.sql.length; i++) {
      System.out.println(CIDSQL.sql[i]);
      try {
        s.executeUpdate(CIDSQL.sql[i]);
      } catch(SQLException sqlEx) {
        System.err.println(
          "Probably a 'drop table' failed");
      }
    }
    s.close();
    c.close();
  }
} ///:~
t
//: c15:jdbc:CIDCreateTables.java
// Crée les tables d'une base de données pour la
// «community interests database».
import java.sql.*;

public class CIDCreateTables {
  public static void main(String[ « args)
  throws SQLException, ClassNotFoundException,
  IllegalAccessException {
    // Charger le driver (qui s'enregistrera lui-même)
    Class.forName(CIDConnect.dbDriver);
    Connection c = DriverManager.getConnection(
      CIDConnect.dbURL, CIDConnect.user,
      CIDConnect.password);
    Statement s = c.createStatement();
    for(int i = 0; i < CIDSQL.sql.length; i++) {
      System.out.println(CIDSQL.sql[i]);
      try {
        s.executeUpdate(CIDSQL.sql[i]);
      } catch(SQLException sqlEx) {
        System.err.println(
          "Probably a 'drop table' failed");
      }
    }
    s.close();
    c.close();
  }
} ///:~
t t t
Note that all changes in the database can be controlled by changing Strings in the CIDSQL table, without modifying CIDCreateTables. t Remarquons que les modifications de la base peuvent être contrôlées en changeant Strings dans la table CIDSQL, sans modifier CIDCreateTables.
t t t
executeUpdate( ) will usually return the number of rows that were affected by the SQL statement. executeUpdate( ) is more commonly used to execute INSERT, UPDATE, or DELETE statements that modify one or more rows. For statements such as CREATE TABLE, DROP TABLE, and CREATE INDEX, executeUpdate( ) always returns zero. t La méthode executeUpdate( ) renvoie généralement le nombre d'enregistrements affectés par l'instruction SQL. Elle est très souvent utilisée pour exécuter des instructions INSERT, UPDATE, ou DELETEmodifiant une ou plusieurs lignes. Pour les instructions telles que CREATE TABLE, DROP TABLE, et CREATE INDEX, executeUpdate( )renvoie toujours zéro.
t t t
To test the database, it is loaded with some sample data. This requires a series of INSERTs followed by a SELECT to produce result set. To make additions and changes to the test data easy, the test data is set up as a two-dimensional array of Objects, and the executeInsert( ) method can then use the information in one row of the table to create the appropriate SQL command. t Pour tester la base, celle-ci est chargée avec quelques données exemples. Ceci est réalisé au moyen d'une série d'INSERTface="Georgia">suivie d'un SELECTafin de produire le jeu de données. Pour effectuer facilement des additions et des modifications aux données de test, ce dernier est construit comme un tableau d'Objectà deux dimensions, et la méthode executeInsert( ) peut alors utiliser l'information d'une ligne de la table pour construire la commande SQL appropriée.
t t t
//: c15:jdbc:LoadDB.java
// Loads and tests the database.
import java.sql.*;

class TestSet {
  Object[][] data = {
    { "MEMBERS", new Integer(1),
      "dbartlett", "Bartlett", "David",
      "123 Mockingbird Lane",
      "Gettysburg", "PA", "19312",
      "123.456.7890",  "bart@you.net" },
    { "MEMBERS", new Integer(2),
      "beckel", "Eckel", "Bruce",
      "123 Over Rainbow Lane",
      "Crested Butte", "CO", "81224",
      "123.456.7890", "beckel@you.net" },
    { "MEMBERS", new Integer(3),
      "rcastaneda", "Castaneda", "Robert",
      "123 Downunder Lane",
      "Sydney", "NSW", "12345",
      "123.456.7890", "rcastaneda@you.net" },
    { "LOCATIONS", new Integer(1),
      "Center for Arts",
      "Betty Wright", "123 Elk Ave.",
      "Crested Butte", "CO", "81224",
      "123.456.7890",
      "Go this way then that." },
    { "LOCATIONS", new Integer(2),
      "Witts End Conference Center",
      "John Wittig", "123 Music Drive",
      "Zoneville", "PA", "19123",
      "123.456.7890",
      "Go that way then this." },
    { "EVENTS", new Integer(1),
      "Project Management Myths",
      "Software Development",
      new Integer(1), new Float(2.50),
      "2000-07-17 19:30:00" },
    { "EVENTS", new Integer(2),
      "Life of the Crested Dog",
      "Archeology",
      new Integer(2), new Float(0.00),
      "2000-07-19 19:00:00" },
    // Match some people with events
    {  "EVTMEMS",
      new Integer(1),  // Dave is going to
      new Integer(1),  // the Software event.
      new Integer(0) },
    { "EVTMEMS",
      new Integer(2),  // Bruce is going to
      new Integer(2),  // the Archeology event.
      new Integer(0) },
    { "EVTMEMS",
      new Integer(3),  // Robert is going to
      new Integer(1),  // the Software event.
      new Integer(1) },
    { "EVTMEMS",
      new Integer(3), // ... and
      new Integer(2), // the Archeology event.
      new Integer(1) },
  };
  // Use the default data set:
  public TestSet() {}
  // Use a different data set:
  public TestSet(Object[][] dat) { data = dat; }
}

public class LoadDB {
  Statement statement;
  Connection connection;
  TestSet tset;
  public LoadDB(TestSet t) throws SQLException {
    tset = t;
    try {
      // Load the driver (registers itself)
      Class.forName(CIDConnect.dbDriver);
    } catch(java.lang.ClassNotFoundException e) {
      e.printStackTrace(System.err);
    }
    connection = DriverManager.getConnection(
      CIDConnect.dbURL, CIDConnect.user,
      CIDConnect.password);
    statement = connection.createStatement();
  }
  public void cleanup() throws SQLException {
    statement.close();
    connection.close();
  }
  public void executeInsert(Object[] data) {
    String sql = "insert into "
      + data[0] + " values(";
    for(int i = 1; i < data.length; i++) {
      if(data[i] instanceof String)
        sql += "'" + data[i] + "'";
      else
        sql += data[i];
      if(i < data.length - 1)
        sql += ", ";
    }
    sql += ')';
    System.out.println(sql);
    try {
      statement.executeUpdate(sql);
    } catch(SQLException sqlEx) {
      System.err.println("Insert failed.");
      while (sqlEx != null) {
        System.err.println(sqlEx.toString());
        sqlEx = sqlEx.getNextException();
      }
    }
  }
  public void load() {
    for(int i = 0; i< tset.data.length; i++)
      executeInsert(tset.data[i]);
  }
  // Throw exceptions out to console:
  public static void main(String[] args)
  throws SQLException {
    LoadDB db = new LoadDB(new TestSet());
    db.load();
    try {
      // Get a ResultSet from the loaded database:
      ResultSet rs = db.statement.executeQuery(
        "select " +
        "e.EVT_TITLE, m.MEM_LNAME, m.MEM_FNAME "+
        "from EVENTS e, MEMBERS m, EVTMEMS em " +
        "where em.EVT_ID = 2 " +
        "and e.EVT_ID = em.EVT_ID " +
        "and m.MEM_ID = em.MEM_ID");
      while (rs.next())
        System.out.println(
          rs.getString(1) + "  " +
          rs.getString(2) + ", " +
          rs.getString(3));
    } finally {
      db.cleanup();
    }
  }
} ///:~
t
//: c15:jdbc:LoadDB.java
// Charge et teste la base de données.
import java.sql.*;

class TestSet {
  Object[][ « data = {
    { "MEMBERS", new Integer(1),
      "dbartlett", "Bartlett", "David",
      "123 Mockingbird Lane",
      "Gettysburg", "PA", "19312",
      "123.456.7890",  "bart@you.net" },
    { "MEMBERS", new Integer(2),
      "beckel", "Eckel", "Bruce",
      "123 Over Rainbow Lane",
      "Crested Butte", "CO", "81224",
      "123.456.7890", "beckel@you.net" },
    { "MEMBERS", new Integer(3),
      "rcastaneda", "Castaneda", "Robert",
      "123 Downunder Lane",
      "Sydney", "NSW", "12345",
      "123.456.7890", "rcastaneda@you.net" },
    { "LOCATIONS", new Integer(1),
      "Center for Arts",
      "Betty Wright", "123 Elk Ave.",
      "Crested Butte", "CO", "81224",
      "123.456.7890",
      "Go this way then that." },
    { "LOCATIONS", new Integer(2),
      "Witts End Conference Center",
      "John Wittig", "123 Music Drive",
      "Zoneville", "PA", "19123",
      "123.456.7890",
      "Go that way then this." },
    { "EVENTS", new Integer(1),
      "Project Management Myths",
      "Software Development",
      new Integer(1), new Float(2.50),
      "2000-07-17 19:30:00" },
    { "EVENTS", new Integer(2),
      "Life of the Crested Dog",
      "Archeology",
      new Integer(2), new Float(0.00),
      "2000-07-19 19:00:00" },
    // Met en relation personnes et événements
    {  "EVTMEMS",
      new Integer(1),  // Dave est mis en relation avec
      new Integer(1),  // l'événement Software.
      new Integer(0) },
    { "EVTMEMS",
      new Integer(2),  // Bruce est mis en relation avec
      new Integer(2),  // l'événement Archeology.
      new Integer(0) },
    { "EVTMEMS",
      new Integer(3),  // Robert est mis en relation avec
      new Integer(1),  // l'événement Software...
      new Integer(1) },
    { "EVTMEMS",
      new Integer(3), // ... et
      new Integer(2), // l'événement Archeology.
      new Integer(1) },
  };
  // Utiliser les données par défaut:
  public TestSet() {}
  // Utiliser un autre ensemble de données:
  public TestSet(Object[][ « dat) { data = dat; }
}

public class LoadDB {
  Statement statement;
  Connection connection;
  TestSet tset;
  public LoadDB(TestSet t) throws SQLException {
    tset = t;
    try {
      // Charger le driver (qui s'enregistrera lui-même)
      Class.forName(CIDConnect.dbDriver);
    } catch(java.lang.ClassNotFoundException e) {
      e.printStackTrace(System.err);
    }
    connection = DriverManager.getConnection(
      CIDConnect.dbURL, CIDConnect.user,
      CIDConnect.password);
    statement = connection.createStatement();
  }
  public void cleanup() throws SQLException {
    statement.close();
    connection.close();
  }
  public void executeInsert(Object[ « data) {
    String sql = "insert into "
      + data[0 « + " values(";
    for(int i = 1; i < data.length; i++) {
      if(data[i « instanceof String)
        sql += "'" + data[i « + "'";
      else
        sql += data[i];
      if(i < data.length - 1)
        sql += ", ";
    }
    sql += ')';
    System.out.println(sql);
    try {
      statement.executeUpdate(sql);
    } catch(SQLException sqlEx) {
      System.err.println("Insert failed.");
      while (sqlEx != null) {
        System.err.println(sqlEx.toString());
        sqlEx = sqlEx.getNextException();
      }
    }
  }
  public void load() {
    for(int i = 0; i< tset.data.length; i++)
      executeInsert(tset.data[i]);
  }
  // Lever l'exception en l'envoyant vers la console:
  public static void main(String[ « args)
  throws SQLException {
    LoadDB db = new LoadDB(new TestSet());
    db.load();
    try {
      // Obtenir un ResultSet de la base chargée:
      ResultSet rs = db.statement.executeQuery(
        "select " +
        "e.EVT_TITLE, m.MEM_LNAME, m.MEM_FNAME "+
        "from EVENTS e, MEMBERS m, EVTMEMS em " +
        "where em.EVT_ID = 2 " +
        "and e.EVT_ID = em.EVT_ID " +
        "and m.MEM_ID = em.MEM_ID");
      while (rs.next())
        System.out.println(
          rs.getString(1) + "  " +
          rs.getString(2) + ", " +
          rs.getString(3));
    } finally {
      db.cleanup();
    }
  }
} ///:~
t t t
The TestSet class contains a default set of data that is produced if you use the default constructor; however, you can also create a TestSet object using an alternate data set with the second constructor. The set of data is held in a two-dimensional array of Object because it can be any type, including String or numerical types. The executeInsert( ) method uses RTTI to distinguish between String data (which must be quoted) and non-String data as it builds the SQL command from the data. After printing this command to the console, executeUpdate( ) is used to send it to the database. t La classe TestSet contient un ensemble de données par défaut qui est mis en oeuvre lorsqu'on appelle le constructeur par défaut ; toutefois, il est possible de créer au moyen du deuxième constructeur un objet TestSet utilisant un deuxième ensemble de données. L'ensemble de données est contenu dans un tableau à deux dimensions de type Object car il peut contenir n'importe quel type, y compris String ou des types numériques. La méthode executeInsert( ) utilise RTTI pour différencier les données String (qui doivent être entre guillemets) et les données non-String en construisant la commande SQL à partir des données. Après avoir affiché cette commande sur la console, executeUpdate( ) l'envoie à la base de données.
t t t
The constructor for LoadDB makes the connection, and load( ) steps through the data and calls executeInsert( ) for each record. cleanup( ) closes the statement and the connection; to guarantee that this is called, it is placed inside a finally clause. t Le constructeur de LoadDB établit la connexion, et load( )parcourt les données en appelant executeInsert( )pour chaque enregistrement. Cleanup( )termine l'instruction et la connexion  ; tout ceci est placé dans une clause finally afin d'en garantir l'appel.
t t t
Once the database is loaded, an executeQuery( ) statement produces a sample result set. Since the query combines several tables, it is an example of a join. t Une fois la base chargée, une instruction executeQuery( )produit un ensemble résultat. La requête concernant plusieurs tables, nous avons bien un exemple de base de données relationnelle.
t t t
There is more JDBC information available in the electronic documents that come as part of the Java distribution from Sun. In addition, you can find more in the book JDBC Database Access with Java (Hamilton, Cattel, and Fisher, Addison-Wesley, 1997). Other JDBC books appear regularly. t On trouvera d'autres informations sur JDBC dans les documents électroniques livrés avec la distribution Java de Sun. Pour en savoir plus, consulter le livre JDBC Database Access with Java (Hamilton, Cattel, and Fisher, Addison-Wesley, 1997). D'autres livres à propos de JDBC sortent régulièrement.
t t t

Servlets

t

Les Servlets

t t t
Client access from the Internet or corporate intranets is a sure way to allow many users to access data and resources easily[74]. This type of access is based on clients using the World Wide Web standards of Hypertext Markup Language (HTML) and Hypertext Transfer Protocol (HTTP). The Servlet API set abstracts a common solution framework for responding to HTTP requests. t Les accès clients sur l'Internet ou les intranets d'entreprise représentent un moyen sûr de permettre à beaucoup d'utilisateurs d'accéder facilement aux données et ressources [74]. Ce type d'accès est basé sur des clients utilisant les standards du World Wide Web Hypertext Markup Language (HTML) et Hypertext Transfer Protocol (HTTP). L'API Servlet fournit une abstraction pour un ensemble de solutions communes en réponse aux requêtes HTTP.
t t t
Traditionally, the way to handle a problem such as allowing an Internet client to update a database is to create an HTML page with text fields and a “submit” button. The user types the appropriate information into the text fields and presses the “submit” button. The data is submitted along with a URL that tells the server what to do with the data by specifying the location of a Common Gateway Interface (CGI) program that the server runs, providing the program with the data as it is invoked. The CGI program is typically written in Perl, Python, C, C++, or any language that can read from standard input and write to standard output. That’s all that is provided by the Web server: the CGI program is invoked, and standard streams (or, optionally for input, an environment variable) are used for input and output. The CGI program is responsible for everything else. First it looks at the data and decides whether the format is correct. If not, the CGI program must produce HTML to describe the problem; this page is handed to the Web server (via standard output from the CGI program), which sends it back to the user. The user must usually back up a page and try again. If the data is correct, the CGI program processes the data in an appropriate way, perhaps adding it to a database. It must then produce an appropriate HTML page for the Web server to return to the user. t Traditionnellement, la solution permettant à un client Internet de mettre à jour une base de données est de créer une page HTML contenant des champs texte et un bouton « soumission ». L'utilisateur frappe l'information requise dans les champs texte puis clique sur le bouton « soumission ». Les données sont alors soumises au moyen d'une URL qui indique au serveur ce qu'il doit en faire en lui indiquant l'emplacement d'un programme Common Gateway Interface (CGI) lancé par le serveur, qui prend ces données en argument. Le programme CGI est généralement écrit en Perl, Python, C, C++, ou n'importe quel langage capable de lire sur l'entrée standard et d'écrire sur la sortie standard. Le rôle du serveur Web s'arrête là : le programme CGI est appelé, et des flux standard (ou, optionnellement pour l'entrée, une variable d'environnement) sont utilisés pour l'entrée et la sortie. Le programme CGI est responsable de toute la suite. Il commence par examiner les données et voir si leur format est correct. Si ce n'est pas le cas, le programme CGI doit fournir une page HTML décrivant le problème ; cette page est prise en compte par le serveur Web (via la sortie standard du programme CGI), qui la renvoie à l'utilisateur. Habituellement, l'utilisateur revient à la page précédente et fait une nouvelle tentative. Si les données sont correctes, le programme CGI traite les données de la manière appropriée, par exemple en les ajoutant à une base de données. Il élabore ensuite une page HTML appropriée que le serveur Web enverra à l'utilisateur.
t t t
It would be ideal to go to a completely Java-based solution to this problem—an applet on the client side to validate and send the data, and a servlet on the server side to receive and process the data. Unfortunately, although applets are a proven technology with plenty of support, they have been problematic to use on the Web because you cannot rely on a particular version of Java being available on a client’s Web browser; in fact, you can’t rely on a Web browser supporting Java at all! In an intranet, you can require that certain support be available, which allows a lot more flexibility in what you can do, but on the Web the safest approach is to handle all the processing on the server side and deliver plain HTML to the client. That way, no client will be denied the use of your site because they do not have the proper software installed. t Afin d'avoir une solution basée entièrement sur Java, l'idéal serait d'avoir côté client une applet qui validerait et enverrait les données, et côté serveur une servlet qui les recevrait et les traiterait. Malheureusement, bien que les applets forment une technologie éprouvée et bien supportée, leur utilisation sur le Web s'est révélée problématique car on ne peut être certain de la disponibilité d'une version particulière de Java sur le navigateur Web du client ; en fait, on ne peut même pas être certain que le navigateur Web supporte Java ! Dans un intranet, on peut exiger qu'un support donné soit disponible, ce qui apporte une certaine flexibilité à ce qu'on peut faire, mais sur le Web l'approche la plus sûre est d'effectuer tout le traitement du côté serveur puis de délivrer une page HTML au client. De cette manière, aucun client ne se verra refuser l'utilisation de votre site simplement parce qu'il ne dispose pas dans sa configuration du software approprié.
t t t
Because servlets provide an excellent solution for server-side programming support, they are one of the most popular reasons for moving to Java. Not only do they provide a framework that replaces CGI programming (and eliminates a number of thorny CGI problems), but all your code has the platform portability gained from using Java, and you have access to all the Java APIs (except, of course, the ones that produce GUIs, like Swing). t Parce que les servlets fournissent une excellente solution pour le support de programmation côté serveur, ils représentent l'une des raisons les plus populaires pour passer à Java. Non seulement ils fournissent un cadre pour remplacer la programmation CGI (et éliminer nombre de problèmes CGI épineux), mais tout le code gagne en portabilité inter plate-forme en utilisant Java, et l'on a accès à toutes les API Java (exceptées, bien entendu, celles qui fournissent des GUI, comme Swing).
t t t

The basic servlet

t

Le servlet de base

t t t
The architecture of the servlet API is that of a classic service provider with a service( ) method through which all client requests will be sent by the servlet container software, and life cycle methods init( ) and destroy( ), which are called only when the servlet is loaded and unloaded (this happens rarely). t L'architecture de l'API servlet est celle d'un fournisseur de services classique comportant une méthode service( ) appartenant au software conteneur de la servlet, chargée de recevoir toutes les requêtes client, et les méthodes liées au cycle de vie, init( )et destroy( ), qui sont appelées seulement lorsque la servlet est chargée ou déchargée (ce qui arrive rarement).
t t t
public interface Servlet {
  public void init(ServletConfig config)
    throws ServletException;
  public ServletConfig getServletConfig();
  public void service(ServletRequest req,
    ServletResponse res)
    throws ServletException, IOException;
  public String getServletInfo();
  public void destroy();
}
t
public interface Servlet {
  public void init(ServletConfig config)
    throws ServletException;
  public ServletConfig getServletConfig();
  public void service(ServletRequest req,
    ServletResponse res)
    throws ServletException, IOException;
  public String getServletInfo();
  public void destroy();
}
t t t
getServletConfig( )’s sole purpose is to return a ServletConfig object that contains initialization and startup parameters for this servlet. getServletInfo( ) returns a string containing information about the servlet, such as author, version, and copyright. t La raison d'être de getServletConfig( )est de renvoyer un objet ServletConfig contenant l'initialisation et les paramètres de départ de cette servlet. La méthode getServletInfo( )renvoie une chaîne contenant des informations à propos de la servlet, telles que le nom de l'auteur, la version, et le copyright.
t t t
The GenericServlet class is a shell implementation of this interface and is typically not used. The HttpServlet class is an extension of GenericServlet and is designed specifically to handle the HTTP protocol— HttpServlet is the one that you’ll use most of the time. t La classe GenericServlet est une implémentation de cette interface et n'est généralement pas utilisée. La classe HttpServlet est une extension de GenericServlet, elle est explicitement conçue pour traiter le protocole HTTP. C'est cette classe, HttpServlet, que vous utiliserez la plupart du temps.
t t t
The most convenient attribute of the servlet API is the auxiliary objects that come along with the HttpServlet class to support it. If you look at the service( ) method in the Servlet interface, you’ll see it has two parameters: ServletRequest and ServletResponse. With the HttpServlet class these two object are extended for HTTP: HttpServletRequest and HttpServletResponse. Here’s a simple example that shows the use of HttpServletResponse: t Les attributs les plus commodes de l'API servlet sont les objets auxiliaires fournis par la classe HttpServlet. En regardant la méthode service( )de l'interface Servlet, on constate qu'elle a deux paramètres : ServletRequest et ServletResponse. Dans la classe HttpServlet, deux objets sont développés pour HTTP : HttpServletRequest and HttpServletResponse. Voici un exemple simple montrant l'utilisation de HttpServletResponse  :
t t t
//: c15:servlets:ServletsRule.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class ServletsRule extends HttpServlet {
  int i = 0; // Servlet "persistence"
  public void service(HttpServletRequest req,
  HttpServletResponse res) throws IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();
    out.print("<HEAD><TITLE>");
    out.print("A server-side strategy");
    out.print("</TITLE></HEAD><BODY>");
    out.print("<h1>Servlets Rule! " + i++);
    out.print("</h1></BODY>");  
    out.close();    
  }
} ///:~
t
//: c15:servlets:ServletsRule.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class ServletsRule extends HttpServlet {
  int i = 0; // «persistance» de Servlet
  public void service(HttpServletRequest req,
  HttpServletResponse res) throws IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();
    out.print("<HEAD><TITLE>");
    out.print("A server-side strategy");
    out.print("</TITLE></HEAD><BODY>");
    out.print("<h1>Servlets Rule! " + i++);
    out.print("</h1></BODY>");  
    out.close();    
  }
} ///:~
t t t
ServletsRule is about as simple as a servlet can get. The servlet is initialized only once by calling its init( ) method, on loading the servlet after the servlet container is first booted up. When a client makes a request to a URL that happens to represent a servlet, the servlet container intercepts this request and makes a call to the service( ) method, after setting up the HttpServletRequest and HttpServletResponse objects. t La classe ServletsRule est la chose la plus simple que peut recevoir une servlet. La servlet est initialisée au démarrage en appelant sa méthode init( ), en chargeant la servlet après que le conteneur de la servlet soit chargé. Lorsqu'un client envoie une requête à une URL qui semble reliée à une servlet, le conteneur de servlet intercepte cette demande et effectue un appel de la méthode service( ), après avoir créé les objets HttpServletRequest et HttpServletResponse.
t t t
The main responsibility of the service( ) method is to interact with the HTTP request that the client has sent, and to build an HTTP response based on the attributes contained within the request. ServletsRule only manipulates the response object without looking at what the client may have sent. t La principale responsabilité de la méthode service( )est d'interagir avec la requête HTTP envoyée par le client, et de construire une réponse HTTP basée sur les attributs contenus dans la demande. La méthode ServletsRule se contente de manipuler l'objet réponse sans chercher à savoir ce que voulait le client.
t t t
After setting the content type of the response (which must always be done before the Writer or OutputStream is procured), the getWriter( ) method of the response object produces a PrintWriter object, which is used for writing character-based response data (alternatively, getOutputStream( ) produces an OutputStream, used for binary response, which is only utilized in more specialized solutions). t Après avoir mis en place le type du contenu de la réponse (ce qui doit toujours être fait avant d'initialiser Writer ou OutputStream), la méthode getWriter( ) de l'objet réponse renvoie un objet PrintWriter, utilisé pour écrire les données en retour sous forme de caractères (de manière similaire, getOutputStream( )fournit un OutputStream, utilisé pour les réponses binaires, uniquement dans des solutions plus spécifiques).
t t t
The rest of the program simply sends HTML back to the client (it’s assumed you understand HTML, so that part is not explained) as a sequence of Strings. However, notice the inclusion of the “hit counter” represented by the variable i. This is automatically converted to a String in the print( ) statement. t Le reste du programme se contente d'envoyer une page HTML au client (on suppose que le lecteur comprend le langage HTML, qui n'est pas décrit ici) sous la forme d'une séquence de Strings. Toutefois, il faut remarquer l'inclusion du « compteur de passages » représenté par la variable i. Il est automatiquement converti en String dans l'instruction print( ).
t t t
When you run the program, you’ll notice that the value of i is retained between requests to the servlet. This is an essential property of servlets: since only one servlet of a particular class is loaded into the container, and it is never unloaded (unless the servlet container is terminated, which is something that only normally happens if you reboot the server computer), any fields of that servlet class effectively become persistent objects! This means that you can effortlessly maintain values between servlet requests, whereas with CGI you had to write values to disk in order to preserve them, which required a fair amount of fooling around to get it right, and resulted in a non-cross-platform solution. t En lançant le programme, on peut remarquer que la valeur de i ne change pas entre les requêtes vers la servlet. C'est une propriété essentielle des servlets : tant qu'il n'existe qu'une servlet d'une classe particulière chargée dans le conteneur, et jamais déchargée (sauf en cas de fin du conteneur de servlet, ce qui ne se produit normalement que si l'on reboote l'ordinateur serveur), tous les champs de cette classe servlet sont des objets persistants ! Cela signifie que vous pouvez sans effort supplémentaire garder des valeurs entre les requêtes à la servlet, alors qu'avec CGI vous auriez dû écrire ces valeurs sur disque afin de les préserver, ce qui aurait demandé du temps supplémentaire et fini par déboucher sur une solution qui n'aurait pas été inter-plate-forme.
t t t
Of course, sometimes the Web server, and thus the servlet container, must be rebooted as part of maintenance or during a power failure. To avoid losing any persistent information, the servlet’s init( ) and destroy( ) methods are automatically called whenever the servlet is loaded or unloaded, giving you the opportunity to save data during shutdown, and restore it after rebooting. The servlet container calls the destroy( ) method as it is terminating itself, so you always get an opportunity to save valuable data as long as the server machine is configured in an intelligent way. t Bien entendu, le serveur Web ainsi que le conteneur de servlet doivent de temps en temps être rebootés pour des raisons de maintenance ou après une coupure de courant. Pour éviter de perdre toute information persistante, les méthodes de servlet init( ) et destroy( ) sont appelées automatiquement chaque fois que la servlet est chargée ou déchargée, ce qui nous donne l'opportunité de sauver des données lors d'un arrêt, puis de les restaurer après que la machine ait été rebootée. Le conteneur de la servlet appelle la méthode destroy( ) lorsqu'il se termine lui-même, et on a donc toujours une opportunité de sauver des données essentielles pour peu que la machine serveur soit intelligemment configurée.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel