r19-05.doc

(273 KB) Pobierz
Szablon dla tlumaczy

W niniejszym rozdziale:

·         Analiza parametrów

·         Wysyłanie poczty elektronicznej

·         Stosowanie wyrażeń regularnych

·         Uruchamianie programów

·         Stosowanie rdzennych metod

·         Występowanie jako klient RMI

·         Usuwanie błędów

·         Poprawa wydajności

Rozdział 19.

Informacje dodatkowe

W każdym domu znajduje się szuflada na szpargały — szuflada załadowana do pełna rzeczami, które nie do końca pasują do żadnej zorganizowanej szuflady, ale nie mogą też zostać wyrzucone, ponieważ kiedy są potrzebne, to są naprawdę potrzebne. Niniejszy rozdział pełni funkcję takiej szuflady. Zawiera spory zestaw przydatnych przykładów serwletów i porad, które nie pasują do żadnego innego miejsca. Zawarto tu serwlety, które analizują parametry, wysyłają pocztę elektroniczną, uruchamiają programy, wykorzystują mechanizmy wyrażeń regularnych i rdzenne metody oraz działają jako klienty RMI. Rozdział ten zawiera również demonstrację technik usuwania błędów, a także pewne sugestie dotyczące poprawy wydajności serwletów.

Analiza parametrów

Osoby, które próbowały tworzyć własne serwlety podczas lektury niniejszej książki przypuszczalnie zauważyły, że pobieranie i analiza parametrów żądania może być dość nieprzyjemnym zajęciem, zwłaszcza jeżeli parametry te muszą zostać przekonwertowane do formatu innego niż String. Na przykład, konieczne jest odczytanie parametru count i zmiany jego wartości na format int. Poza tym, obsługa warunków błędów powinna być wykonywana przez wywołanie obslugaBezCount(), jeżeli count nie jest podany, a obslugaZlyCount(), jeżeli count nie może zostać przekształcony na liczbę całkowitą. Wykonanie tego działania przy pomocy standardowego Servlet API wymaga następującego kodu:

int count;

 

String param = zad.getParameter("count");

if (param=null || param.length() == 0) {

  obslugaBezCount();

}

else {

try {

    count = Integer.parseInt(param);

  }

  catch (NumberFormatException w) {

    obslugaZlyCount();

  }

}

Czy to wygląda jak porządny kod? Nie jest zbyt piękne, prawda? Lepszym rozwiązaniem jest przekazanie odpowiedzialności za pobieranie i analizę parametrów klasie narzędziowej. Klasa com.oreilly.servlet.ParameterParser jest właśnie taką klasą. Przy pomocy ParameterParser możliwe jest przepisanie powyższego kodu w bardziej elegancki sposób:

int count;

 

ParameterParser analiza = new ParameterParser(zad);

try {

  count = analiza.getIntParameter("count");

}

catch (NumberFormatException w) {

  obslugaZlyCount();

}

catch (ParameterNotFoundException w) {

  obslugaBezCount();

}

Analizująca parametry metoda getIntParameter() zwraca wartość określonego parametru jako int. Zgłasza wyjątek NumberFormatException, jeżeli parametr nie może zostać przekonwertowany na int oraz ParameterNotFoundException, jeżeli parametr nie jest częścią żądania. Zgłasza również ParameterNotFoundException, jeżeli wartość parametru to pusty łańcuch. Często dzieje się tak w przypadku wysyłanych formularzy, gdy nie wpisano żadnych wiadomości do pól tekstowych, co we wszystkich przypadkach powinno być traktowane w ten sam sposób, co brakujący parametr.

Jeżeli wystarczy, aby w przypadku problemów z parametrem serwlet wykorzystywał domyślną wartość, co jest częstą praktyką, kod może zostać uproszczony w jeszcze większym stopniu:

ParameterParser analiza = new ParameterParser(zad);

int count = analiza.getIntParameter("count", 0);

Powyższa druga wersja getIntParameter() pobiera domyślną wartość 0, która jest zwracana zamiast zgłoszenia błędu.

Istnieje również możliwość sprawdzenia, czy w żądaniu brakuje jakichkolwiek parametrów:

ParameterParser analiza = new ParameterParser(zad);

String[] wymagane = { "nazwa1", "nazwa2", "konto" };

String[] brakujace = analiza.getMissingParameters(wymagane);

Powyższa metoda zwraca null, jeżeli nie brakuje żadnego parametru.

ParameterParser obsługuje także internacjonalizację poprzez metodę setCharacterEncoding(). Określa ona kodowanie, które powinno zostać wykorzystane podczas interpretacji wartości parametrów. Wartość może pochodzić z cookie użytkownika, ukrytego pola formularza lub sesji użytkownika:

ParameterParser analiza = new ParameterParser(zad);

analiza.setCharacterEncoding("Shift_JIS");

String wartoscJaponia = analiza.getStringParameter("nazwaLatin");

Wewnętrznie ParameterParser wykorzystuje sztuczkę getBytes() przedstawioną w rozdziale 13, „Internacjonalizacja” do obsługi konwersji. Nazwy parametrów muszą być ciągle podane w kodowaniu Latin1, ponieważ mechanizm poszukiwania wykorzystuje jeszcze nie zinternalizowane metody Servlet API getParameter() i getParameterValues().

Kod ParameterParser

Klasa ParameterParser zawiera ponad tuzin metod, które zwracają parametry żądania — dwie dla każdego rdzennego typu Javy. Posiada również dwie metody getStringParameter() w przypadku, gdyby konieczne było pobranie parametru w jego surowym formacie String. Kod ParameterParser jest przedstawiony w przykładzie 19.1. Wyjątek ParameterNotFoundExceptoion znajduje się w przykładzie 19.2.

Przykład 19.1.

Klasa ParameterParser

package com.oreilly.servlet;

 

import java.io.*;

import java.util.*;

import javax.servlet.*;

 

 

public class ParameterParser {

 

  private ServletRequest req;

private String encoding;

 

  public ParameterParser(ServletRequest req) {

    this.req = req;

  }

 

  public void setCharacterEncoding(String encoding)

                 throws UnsupportedEncodingException {

    // Sprawdzenie prawidłowości kodowania

    new String("".getBytes("8859_1"), encoding);

    // Jeżeli tutaj, to prawidłowe, więc jego ustawienie

    this.encoding = encoding;

  }

 

  public String getStringParameter(String name)

      throws ParameterNotFoundException {

    String[] values = req.getParameterValues(name);

    if (values == null) {

      throw new ParameterNotFoundException(name + " not found");

    }

    else if (values[0].length() == 0) {

      throw new ParameterNotFoundException(name + " was empty");

    }

    else {

      if (encoding == null) {

        return values[0];

      }

      else {

        try {

          return new String(values[0].getBytes("8859_1"), encoding);

        }

        catch (UnsupportedEncodingException e) {

          return values[0];  // should never happen

        }

      }

    }

  }

 

  public String getStringParameter(String name, String def) {

    try { return getStringParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public boolean getBooleanParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    String value = getStringParameter(name).toLowerCase();

    if ((value.equalsIgnoreCase("true")) ||

        (value.equalsIgnoreCase("on")) ||

        (value.equalsIgnoreCase("yes"))) {

        return true;

    }

    else if ((value.equalsIgnoreCase("false")) ||

             (value.equalsIgnoreCase("off")) ||

             (value.equalsIgnoreCase("no"))) {

        return false;

    }

    else {

      throw new NumberFormatException("Parameter " + name + " value " + value +

                                      " is not a boolean");

    }

  }

 

  public boolean getBooleanParameter(String name, boolean def) {

    try { return getBooleanParameter(name); }

    catch (Exception e) { return def; }

  }

 

 

  public byte getByteParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return Byte.parseByte(getStringParameter(name));

  }

 

  public byte getByteParameter(String name, byte def) {

    try { return getByteParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public char getCharParameter(String name)

      throws ParameterNotFoundException {

    String param = getStringParameter(name);

    if (param.length() == 0)

      throw new ParameterNotFoundException(name + " is empty string");

    else

      return (param.charAt(0));

  }

 

  public char getCharParameter(String name, char def) {

    try { return getCharParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public double getDoubleParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return new Double(getStringParameter(name)).doubleValue();

  }

 

  public double getDoubleParameter(String name, double def) {

    try { return getDoubleParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public float getFloatParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return new Float(getStringParameter(name)).floatValue();

  }

 

  public float getFloatParameter(String name, float def) {

    try { return getFloatParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public int getIntParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return Integer.parseInt(getStringParameter(name));

  }

 

 

  public int getIntParameter(String name, int def) {

    try { return getIntParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public long getLongParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return Long.parseLong(getStringParameter(name));

  }

 

  public long getLongParameter(String name, long def) {

    try { return getLongParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public short getShortParameter(String name)

      throws ParameterNotFoundException, NumberFormatException {

    return Short.parseShort(getStringParameter(name));

  }

 

  public short getShortParameter(String name, short def) {

    try { return getShortParameter(name); }

    catch (Exception e) { return def; }

  }

 

  public String[] getMissingParameters(String[] required) {

    Vector missing = new Vector();

    for (int i = 0; i < required.length; i++) {

      String val = getStringParameter(required[i], null);

      if (val == null) {

        missing.addElement(required[i]);

      }

    }

    if (missing.size() == 0) {

      return null;

    }

    else {

      String[] ret = new String[missing.size()];

      missing.copyInto(ret);

      return ret;

    }

  }

}

Przykład 19.2.

Klasa ParameterNotFoundException

package com.oreilly.servlet;

 

public class ParameterNotFoundException extends Exception {

 

  public ParameterNotFoundException() {

    super();

  }

 

  public ParameterNotFoundException(String s) {

    super(s);

  }

}

Wysyłanie poczty elektronicznej

Czasami wysłanie przez serwlet wiadomości jest konieczne, a czasami jest to po prostu ułatwienie. Na przykład, proszę sobie wyobrazić serwlet otrzymujący dane z formularza użytkownika, który umieszcza tam swoje komentarze. Serwlet ten może chcieć przesłać dane formularza na listę dystrybucyjną zainteresowanych stron. Albo proszę sobie wyobrazić serwlet, który napotyka niespodziewany problem i może wysłać administratorowi pocztą stronę prosząc o pomoc.

Serwlet może wykorzystać do wysłania poczty elektronicznej jedną z czterech metod:

·         Może sam zarządzać szczegółami — nawiązać połączenie przez zwykły port z serwerem poczty i wysyłając wiadomość poprzez protokół pocztowy niskiego poziomu, zazwyczaj tak zwany Simple Mail Transfer Protocol (Prosty Protokół Transferu Poczty — SMTP).

·         Może uruchomić z wiersza poleceń zewnętrzny program pocztowy, jeżeli system serwera posiada taki program.

·         Może wykorzystać interfejs JavaMail, zaprojektowany do pomocy w skomplikowanej obsłudze, tworzeniu i przetwarzaniu poczty (proszę zobaczyć http://java.sun.com/products/javamail).

·         Może wykorzystać jedną z wielu dostępnych bezpłatnie klas pocztowych, które zmieniają szczegóły wysyłania poczty na proste i łatwe do wywołania metody.

W przypadku nieskomplikowanego wysyłania poczty poleca się ostatni sposób ze względu na jego prostotę. Dla bardziej skomplikowanych zastosowań rekomendowany jest JavaMail — zwłaszcza w przypadku serwletów działających pod kontrolą serwera J2EE, w którym na pewno dostępne są dwa pliki JAR wymagane przez JavaMail.

...

Zgłoś jeśli naruszono regulamin