Многие,
вероятно, видели web-страницы, где пользователю
предлагается ввести разного рода информацию. Это
и поисковые системы, и электронные магазины, и
службы, предоставляющие пользователям услуги по
размещению web сайтов и т.д.
На таких сайтах для ввода
информации на стороне клиента используются HTML
формы, а на стороне сервера - разного рода
скрипты, чаще всего Perl/CGI. Если же передается
секретная информация - имена, пароли, номера
кредитных карточек и т.п., то для передачи данных
подобного рода используется протокол HTTPS (HTTP
Security, технология SSL - Secure Socket Layer) вместо обычного
HTTPS. Он полностью идентичен HTTP, за исключением
того, что данные, передающиеся между серером и
клиентом шифруются с помощью метода с открытым
ключом (закрытый ключ содержится на сервере, а
открытые - в клиентских броузерах). Кроме того, он
использует по умолчанию порт 443 вместо 80 у HTTP.
Для реализации такой схемы требуются:
1. Приложение Web сервера, поддерживающее
протоколы HTTP и HTTPS, а также скрипты.
2. SSL сертификат, устанавливаемый на сервере и
содержащий закрытый ключ.
Что касается серверных
приложений, то их существует великое множество, в
том числе и бесплатных. Далее мы будем
пользоваться бесплатным сервером Apache
(http://www.apache.org).
Сложнее дело обстоит с
сертификатом - за него нужно платить. Вы заходите,
например, на www.verisign.com, указываете данные о себе (в
том числе и номер кредитной карточки) и после
проверки действительности карточки сервер
вышлет сертификат по e-mail. На том же сайте можно
бесплатно получить сертификат с ограниченным
сроком действия - 14 дней (хотя у меня он работает
вот уже 2 месяца).
Существует еще одна проблема
при использовании HTTPS - как показывает практика,
его пропускают не все proxy-сервера. Если proxy не
пропускает HTTPS, то клиент чаще всего получает
ошибку "Данная страница недоступна", иногда
- "Запрошенный узел не найден".
Все эти причины вынуждают
искать другие пути решения передачи секретных
данных.
Наиболее простой способ
заключается в использовании JavaScript/JScript/ VBScript. Они
позволяют реализовать шифрование, однако
исходный текст таких процедур находится в теле
HTML кода и легко читается любым текстовым
редактором. Кроме того, эти скрипты имеют
языковые особенности (например, отсутствие
типизации), не позволяющие реализовать
эффективный алгоритм шифровки.
В настоящее время огромную
популярность приобрел язык Java. Он позволяет
создавать обычные приложения, апплеты
(приложения, работающие в среде броузера) и
сервлеты - аналоги CGI скриптов. Разработчик языка,
фирма Sun, бесплатно распространяет множество
дополнительных пакетов (библиотек функций),
среди которых есть и криптографический. Он
называется JCE (Java Cryptography Extension). Его можно скачать
с сайта Sun, посвященного Java - http://java.sun.com. С его
помощью можно организовать самые разные виды
шифра, начиная от простых симметричных кодов до
сложных методов с открытым ключом. Однако здесь
мы не будем касаться этого пакета.
Опишем реализацию на Java аналога
HTML форм на стороне клиента, а также серверные
части, необходимые для этого. Далее мы будем
освещать вопросы, относящиеся только к передаче
данных, введенных пользователем и предполагаем,
что читатель знаком с Java и способен реализовать в
апплете строку ввода, чекбокс и другие элементы
управления.
Рассмотрим клиентскую часть.
Протокол HTTP (HTTPS) поддерживает два способа
передачи данных форм: GET и POST. Точнее сказать, GET и
POST - команды, подаваемые броузером HTTP серверу.
Более подробную о них можно получить из RFC
документов по адресам:
http://www.cis.ohio-state.edu/htbin/rfc/rfc1945.html - HTTP 1.0
http://www.cis.ohio-state.edu/htbin/rfc/rfc2068.html - HTTP 1.1
Здесь же будут рассмотрены те аспекты этих
команд, которые необходимы для решения нашей
задачи.
Способ передачи данных броузером определяется
атрибутом method HTML тега FORM.
<form action=/servlets/Info method=GET>
<input type=hidden>
How Many Employees in your Company?
<BR><input type=radio name=employee value=1-100>1-100
<BR><input type=radio name=employee value=100-200>100-200
<BR><input type=radio name=employee value=200-300>200-300
<BR><input type=radio name=employee value=300-400>300-400
<BR><input type=radio name=employee value=500-more>500-more
<BR>General Comments?
<BR><input type=text name=comment>
<BR>What IDEs do you use?
<BR><input type=checkbox name=ide value=JavaWorkShop>JavaWorkShop
<BR><input type=checkbox name=ide value=J++>J++
<BR><input type=checkbox name=ide value=Cafe>Cafe
<BR><BR>
<input type=submit><input type=reset>
</form>
На месте POST здесь может стоять GET:
<form action=/servlets/Info method=GET>
...
</form>
Разница заключается только в способе передачи
данных серверу.
Рассмотрим ее на примере вышеприведенной
формы.
1) При использовании метода GET броузер передает
команду (в виде одной строки):
GET
/servlets/Info?employee=200-300&comment=comment&ide=JavaWorkShop&ide=J%2B%2B
2) При использовании метода POST:
POST /servlets/Info
...
employee=200-300&comment=comment&ide=JavaWorkShop&ide=J%2B%2B
Строка аргументов передается
броузером как часть HTTP заголовка, поэтому
пользователь не видит ее в строке адреса, в
отличие от GET метода.
Отсюда видно основное отличие -
GET передает все одной строкой, а POST разбивает на
две части - команда с именем скрипта, затем -
аргументы.
При реализации формы на Java
апплет должен полностью повторить приведенную
выше схему.
Перед рассмотрением
реализации каждого метода необходимо отметить,
что поле <INPUT type="file" name="XXXX"> в
апплете нереализуемо вследствие того, что в
подавляющем большинстве случаев апплету
запрещен доступ к накопителям
компьютера-клиента. Некоторые броузеры,
например, IE5.0, позволяет разрешить апплетам
заниматься файловым вводом-выводом, однако мы не
будем касаться этой темы в данной статье. Кроме
того, как показывает опыт, предлагаемый ниже
способ реализации POST не работает (не передаются
аргументы) на Netscape Navigator. В этом случае можно
использовать только GET. На IE 5.0 работают и POST и GET.
Рассмотрим реализацию каждого метода.
Сначала приведем полный текст апплета,
реализовывающего и GET и POST, а затем
проанализируем самые главные его места.
// Test.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.util.*;
import java.io.*;
public class Test extends Applet implements ActionListener
{
TextField comment;
Checkbox[] radioBut;
Checkbox[] checkBut;
URL docBase; // http://servername/dir1/dir2/
String servletName, // Servlet name
method; // "GET" or "POST"
String radioButNames[]={ "1-100", "100-200", "200-300",
"300-400", "500-more" };
String checkButNames[]={"JavaWorkShop", "J++", "Cafe" };
public void init()
{ // Initialize the applet. Get parameters.
// servletName="/servlets/Info";
// method="GET";
servletName = getParameter("SERVLET"); // Servlet name
method = getParameter("METHOD"); // Method name
docBase = getDocumentBase();
//----------> Добавить панель управления
// Assign a BorderLayout manager with margins for this frame.
setLayout(new BorderLayout(10, 10));
// -------------------
// Create two panels to contain two columns of components. Use our custom
// ColumnLayout layout manager for each. Add them on the west and
// center of the frame's border layout
Panel column1 = new Panel();
// column1.setLayout(new ColumnLayout(5, 10, 2, ColumnLayout.LEFT));
column1.setLayout(new ColumnLayout(5, 10, 2, ColumnLayout.LEFT));
add(column1, "West");
// -------------------
// Create a panel to contain the buttons at the bottom of the window
// Give it a FlowLayout layout manager, and add it along the south border
Panel buttonbox = new Panel();
buttonbox.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
add(buttonbox, "South");
// Create pushbuttons and add them to the buttonbox
Button accept = new Button("Accept");
buttonbox.add(accept);
Button reset = new Button("Reset");
buttonbox.add(reset);
// Handle events on the buttons
ActionListener buttonlistener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Button b=(Button)e.getSource();
if(b.getLabel() == "Accept")
{ // Accept button pressed - send data to server
// Вначале формируем строку аргументов:
// Переключатели radioBut имеют имя "employee";
// Строка comment - "comment";
// Переключатели checkBut - "ide";
String argsLine; // Строка аргументов
// employee=200-300&comment=comment&ide=JavaWorkShop&ide=J%2B%2B
// Записать состояния элементов управления в
список
Vector args = new Vector();
for(int i=0; i<radioBut.length; i++)
if(radioBut[i].getState())
args.addElement("employee="+radioButNames[i]);
String commLine=comment.getText();
if(commLine.length()!=0) args.addElement("comment="+commLine);
for(int i=0; i<checkBut.length; i++)
if(checkBut[i].getState())
args.addElement("ide="+checkButNames[i]);
argsLine=getArgsLine(args); // Перенести список в строку для
передачи
if(method.compareTo("GET")==0)
{ // Передаем данные, используя GET
String link=servletName+"?"+argsLine;
try
{
URL url = new URL(docBase, link);
getAppletContext().showDocument(url, "_self");
} // try
catch (MalformedURLException exc)
{ // Исключение игнорируем
// exc.printStackTrace();
} // catch
} // if GET
if(method.compareTo("POST")==0)
{ // Передаем данные, используя POST
try
{
URL servlet = new URL(docBase, servletName);
URLConnection conn = servlet.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
// Send data to server
PrintStream out = new PrintStream(conn.getOutputStream());
out.print(argsLine);
out.close(); // ESSENTIAL for this to work!
// Получить имя файла ответа
InputStream result=conn.getInputStream(); // Входной поток
BufferedReader in = new BufferedReader(new InputStreamReader(result));
String fname=in.readLine(); // Имя файла-ответа
System.out.println("fname="+fname);
// Запросить ответ сервера
URL url = new URL(docBase, fname);
getAppletContext().showDocument(url, "_self");
} // try
catch(Exception exc)
{ // Исключение игнорируем (MalformedURLException, IOException)
// exc.printStackTrace();
} // catch
} // if POST
} // if pressedAccept
if(b.getLabel() == "Reset")
{ // Reset button pressed
radioBut[0].setState(true);
radioBut[1].setState(false);
radioBut[2].setState(false);
radioBut[3].setState(false);
radioBut[4].setState(false);
comment.setText("");
checkBut[0].setState(false);
checkBut[1].setState(false);
checkBut[2].setState(false);
} // if
} // actionPerformed
};
accept.addActionListener(buttonlistener);
reset.addActionListener(buttonlistener);
// -------------------
// Create checkboxes, and group them in a CheckboxGroup to give them
// "radio button" behavior.
CheckboxGroup checkbox_group = new CheckboxGroup();
radioBut=new Checkbox[5];
radioBut[0]=new Checkbox(radioButNames[0], checkbox_group, true);
radioBut[1]=new Checkbox(radioButNames[1], checkbox_group, false);
radioBut[2]=new Checkbox(radioButNames[2], checkbox_group, false);
radioBut[3]=new Checkbox(radioButNames[3], checkbox_group, false);
radioBut[4]=new Checkbox(radioButNames[4], checkbox_group, false);
column1.add(new Label("How Many Employees in your Company?"));
for(int i = 0; i < radioBut.length; i++) column1.add(radioBut[i]);
// -------------------
// Create one 1-line text field and add to left column, with a labels
comment = new TextField(25);
column1.add(new Label("General Comments?"));
column1.add(comment);
// -------------------
column1.add(new Label("What IDEs do you use? "));
checkBut=new Checkbox[3];
checkBut[0]=new Checkbox(checkButNames[0], null, false); column1.add(checkBut[0]);
checkBut[1]=new Checkbox(checkButNames[1], null, false); column1.add(checkBut[1]);
checkBut[2]=new Checkbox(checkButNames[2], null, false); column1.add(checkBut[2]);
} // init
public void actionPerformed(ActionEvent ev)
{
} // actionPerformed
private String getArgsLine(Vector args)
{ // Encode the arguments in the property set as a URL-encoded string.
// Multiple name=value pairs are separated by ampersands.
// return the URLEncoded string with name=value pairs
StringBuffer sb = new StringBuffer();
String sep = "";
Enumeration names = args.elements();
while(names.hasMoreElements())
{
String name=(String)names.nextElement();
sb.append(sep+Encoder.encode(name));
sep = "&";
} // while
return sb.toString();
} // getArgsLine
/*
public static void main(String args[])
{
Frame f = new Frame("Test");
Test test = new Test();
test.init();
test.start();
f.add("Center", test);
f.setSize(300, 300);
f.show();
} // main
*/
} // class Test
class Encoder
{
static BitSet dontNeedEncoding;
static final int caseDiff = ('a' - 'A');
static
{
dontNeedEncoding = new BitSet(256);
int i;
for (i = 'a'; i <= 'z'; i++) dontNeedEncoding.set(i);
for (i = 'A'; i <= 'Z'; i++) dontNeedEncoding.set(i);
for (i = '0'; i <= '9'; i++) dontNeedEncoding.set(i);
dontNeedEncoding.set(' '); /* encoding a space to a + is done in the encode()
method */
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*');
dontNeedEncoding.set('=');
} // static
public static String encode(String s)
{
int maxBytesPerChar = 10;
StringBuffer out = new StringBuffer(s.length());
ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
OutputStreamWriter writer = new OutputStreamWriter(buf);
for (int i = 0; i < s.length(); i++)
{
int c = (int)s.charAt(i);
if (dontNeedEncoding.get(c))
{
if (c == ' ') c = '+';
out.append((char)c);
} // if
else
{
// convert to external encoding before hex conversion
try
{
writer.write(c);
writer.flush();
} // try
catch(IOException e)
{
buf.reset();
continue;
} // catch
byte[] ba = buf.toByteArray();
for (int j = 0; j < ba.length; j++)
{
out.append('%');
char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
// converting to use uppercase letter as part of
// the hex value if ch is a letter.
if (Character.isLetter(ch)) ch -= caseDiff;
out.append(ch);
ch = Character.forDigit(ba[j] & 0xF, 16);
if (Character.isLetter(ch)) ch -= caseDiff;
out.append(ch);
} // for
buf.reset();
} // else
} // for
return out.toString();
} // encode
} // class
И простой HTML код для запуска данного апплета
(test.htm):
<html>
<head>
<title>Test</title>
</head>
<body>
<TABLE border=0>
<TR>
<TD>
<applet code=Test.class width=300 height=350>
<param name=servlet value=/servlets/Info>
<param name=method value=POST>
</applet>
</TD>
<TD>
<form action=/servlets/InfoF method=POST>
<input type=hidden>
How Many Employees in your Company?
<BR><input type=radio name=employee value=1-100>1-100
<BR><input type=radio name=employee value=100-200>100-200
<BR><input type=radio name=employee value=200-300>200-300
<BR><input type=radio name=employee value=300-400>300-400
<BR><input type=radio name=employee value=500-more>500-more
<BR>General Comments?
<BR><input type=text name=comment>
<BR>What IDEs do you use?
<BR><input type=checkbox name=ide value=JavaWorkShop>JavaWorkShop
<BR><input type=checkbox name=ide value=J++>J++
<BR><input type=checkbox name=ide value=Cafe>Cafe
<BR><BR>
<input type=submit>
<input type=reset>
</form>
</TD>
</TR>
</TABLE>
</body>
</html>
Этот файл показывает как запускать данный
апплет и реализовывает аналогичную ему HTML форму.
Все действия по отправке данных реализованы в
функции actionPerformed подкласса ActionListener,
обрабатывающего реакцию на нажатие кнопок.
Функция actionPerformed запускается при нажатии на
любую из двух кнопок (Accept и Reset). Далее
проверяется, какая кнопка была нажата. Если
нажали Accept, то конструируется строка, содержащая
аргументы. Эта строка приблизительно выглядит
так: employee=200-300&comment=comment&ide=JavaWorkShop&ide=J%2B%2B. Для
этого состояние всех элементов управления
заносятся в список, а затем функция getArgsLine
формирует строку. Класс Encoder, применяющийся при
этом, является переделкой стандартного
java.net.URLEncoder. Его пришлось переделать из-за того,
что он превращает знак равенства в %3D, в
результате чего сервер не может автоматически
разбить строку на части.
Реализация метода GET
Этот способ использует стандартную функцию
showDocument стандартного интерфейса AppletContext. Эта
функция имеет две формы:
public void showDocument(URL url);
public void showDocument(URL url, String target);
Они позволяют отобразить в окне броузера
указанную аргументом url страницу. Первая форма
открывает указанную страницу в том же окне
(фрейме), где находится сам апплет. Вторая
позволяет явно указать имя окна (фрейма), в
котором требуется отобразить страницу. Это те же
самые имена, которые допускаются в
необязательном атрибуте TARGET тега <A HREF> языка
HTML. Более подробно об этом можно прочитать в
справочнике по HTML или в описании указанных
функций в документации по Java, поставляемой с JDK. В
документации также указано, что эти функции
могут игнорироваться броузером. В этом случае
для приема данных от клиента можно использовать
только HTML формы.
Все, что нам требуется - это сформировать строку
аргументов GET (см. выше) и передать ее функции
showDocument, вместе с именем серверного скрипта,
который обработает запрос.
Реализация метода POST
Реализовать метод POST несколько
сложнее, поскольку Java API не имеет функции, его
инкасулирующей.
Выходом из этой ситуации является
создание выходного потока и вывод в него той же
самой строки с аргументами, что и для GET. Обо всем
остальном заботится броузер.
Единственное, на что хотелось бы
обратить внимание, - способ принятия ответа от
сервера. Дело в том, что IE не открывает канал
ввода после отсылки. Иными словами, ответ сервера
игнорируется и клиент его не увидит.
Обойти это ограничение позволяет
следующий прием: серверный скрипт обрабатывает
запрос клиента, генерирует у себя на серверном
жестком диске HTML файл-результат и пересылает
клиенту его имя. После чего клиент просто
запрашивает этот файл через showDocument. Единственный
недостаток - это не работает на Netscape Navigator.
Рассмотрим теперь серверную часть.
Для того, чтобы сервер мог
принимать и обрабатывать данные от клиентов, на
нем должен работать соответствующее приложение.
В настоящее время существут множество разных
серверных скриптов, мы же рассмотрим Java сервлеты.
Они гораздо эффективней CGI/Perl аналогов, т. к.
требуют гораздо меньше накладных расходов,
особенно при запуске и останове.
Для запуска приведенных ниже
сервлетов необходимо иметь:
- приложение Web сервера,
поддерживающее Java сервлеты;
- пакет JSDK (Java Servlet Development Kit),
желательно версии 2.0, он доступен на сайте java.sun.com.
Мне известны три таких сервера
(больше я не искал): Apache Web Server (www.apache.org), Java Web Server
(java.sun.com) и Vqserver (www.vqserver.com). Все они бесплатные,
доступны для свободного скачивания с указанных
сайтов и устанавливаются без проблем. Apache сам по
себе не поддерживает Java, для этого существует
специальный модуль - Apache JServ (Apache Java Server). Его можно
взять на том же сайте. JServ требует, чтобы на том же
компьютере были установлены: JDK - Java Development Kit (или
JRE - Java Runtime Environment) и JSDK.
Приведенные ниже сервлеты
необходимо откомпилировать и поместить .class туда,
куда требует использемый Вами сервер и прописать
путь к сервлету в приведеном выше HTML файле.
// Info.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Info extends HttpServlet
{
ServletConfig config;
String dir; // Здесь должен быть путь к временному
файлу
String fname; // Здесь должно быть имя временного файла
public void init(ServletConfig tconfig) throws ServletException
{
super.init(tconfig);
config=tconfig;
dir=getInitParameter("dir");
fname=getInitParameter("fname");
} // init
public String getServletInfo()
{
return "Info servlet";
} // getServletInfo
public void doGet(HttpServletRequest req, HttpServletResponse rep) throws
ServletException, IOException
{
PrintWriter os=rep.getWriter();
dostuff(os, req, rep);
}
public void doPost(HttpServletRequest req, HttpServletResponse rep) throws
ServletException, IOException
{
// Создать временный HTML файл, записать в него
результаты работы
String filename=dir+System.getProperty("file.separator")+fname;
// log("dir="+dir);
// log("fname="+fname);
// log("filename="+filename);
File f=new File(filename);
if(f.exists()) f.delete(); // Если существует, удалить
PrintWriter os=new PrintWriter(new FileOutputStream(f));
dostuff(os, req, rep);
os.close();
// передать имя сгенерированного файла клиенту
os=rep.getWriter();
os.print(fname);
os.flush();
} // doPost
private void pp(PrintWriter os, String name, String value)
{
os.print("<b>"+name+": </b>");
if (value==null) os.print("<b>none</b>");
else os.print(value);
os.println("<br>");
} // pp
private void pp(PrintWriter os, String name, int value)
{
pp(os, name, String.valueOf(value));
} // pp
public void dostuff(PrintWriter os, HttpServletRequest req, HttpServletResponse rep)
throws ServletException, IOException
{
log("invoked");
rep.setContentType("text/html");
os.println("<html>");
os.println("<head><title>Info servlet</title></head>");
os.println("<body bgcolor=#add8af>");
os.println("<table border=0 cellspacing=0 cellpadding=2 cols=3
width=100%>");
os.println("<tr><td valign=top>");
os.println("<h1 align=center>Info servlet</h1>");
os.println("<hr>");
os.println("<p>This page was generated by <i>Info</i>
servlet./");
os.println("<i>Info</i> lists its initialisation parameters, information
about the http request which invoked it and the http request parameters passed to
it.</p>");
os.println("<hr>");
os.println("<h3>Servlet initialisation parameters</h3>");
Enumeration e=config.getInitParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=config.getInitParameter(name);
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Request parameters</h3>");
pp(os, "Request method", req.getMethod());
pp(os, "Request URI", req.getRequestURI());
pp(os, "Request protocol", req.getProtocol());
pp(os, "Servlet path", req.getServletPath());
pp(os, "Path info", req.getPathInfo());
pp(os, "Path translated", req.getPathTranslated());
pp(os, "Query string", req.getQueryString());
pp(os, "Content length", req.getContentLength());
pp(os, "Content type", req.getContentType());
pp(os, "Server name", req.getServerName());
pp(os, "Server port", req.getServerPort());
pp(os, "Remote user", req.getRemoteUser());
pp(os, "Remote address", req.getRemoteAddr());
pp(os, "Remote host", req.getRemoteHost());
pp(os, "Authorization scheme", req.getAuthType());
os.println("<hr>");
os.println("<h3>Request headers</h3>");
e=req.getHeaderNames();
if(!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=(String) req.getHeader(name);
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Servlet parameters</h3>");
e=req.getParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=req.getParameter(name);
StringBuffer tbuffer=new StringBuffer();
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Servlet parameters (Multiple Value style):</h3>");
e = req.getParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while(e.hasMoreElements())
{
String name=(String)e.nextElement();
String vals[]=(String [])req.getParameterValues(name);
if(vals!=null)
{
for (int i=0; i<vals.length; i++)
{
os.print("<b>" + name + " = </b>");
os.print(vals[i]+"<br>");
} // for
} // if
} // while
os.println("</table>");
os.println("</body></html>");
os.flush();
} // doStuff
} // Info
Сервлет для HTML формы:
// InfoF.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class InfoF extends HttpServlet
{
ServletConfig config;
public void init(ServletConfig tconfig) throws ServletException
{
super.init(tconfig);
config=tconfig;
} // init
public String getServletInfo()
{
return "Info servlet";
} // getServletInfo
public void doGet(HttpServletRequest req, HttpServletResponse rep) throws
ServletException, IOException
{
PrintWriter os=rep.getWriter();
dostuff(os, req, rep);
} // doGet
public void doPost(HttpServletRequest req, HttpServletResponse rep) throws
ServletException, IOException
{
PrintWriter os=rep.getWriter();
dostuff(os, req, rep);
} // doPost
private void pp(PrintWriter os, String name, String value)
{
os.print("<b>"+name+": </b>");
if (value==null) os.print("<b>none</b>");
else os.print(value);
os.println("<br>");
} // pp
private void pp(PrintWriter os, String name, int value)
{
pp(os, name, String.valueOf(value));
} // pp
public void dostuff(PrintWriter os, HttpServletRequest req, HttpServletResponse rep)
throws ServletException, IOException
{
log("invoked");
rep.setContentType("text/html");
os.println("<html>");
os.println("<head><title>Info servlet</title></head>");
os.println("<body bgcolor=#add8af>");
os.println("<table border=0 cellspacing=0 cellpadding=2 cols=3
width=100%>");
os.println("<tr><td valign=top>");
os.println("<h1 align=center>Info servlet</h1>");
os.println("<hr>");
os.println("<p>This page was generated by <i>Info</i>
servlet./");
os.println("<i>Info</i> lists its initialisation parameters, information
about the http request which invoked it and the http request parameters passed to
it.</p>");
os.println("<hr>");
os.println("<h3>Servlet initialisation parameters</h3>");
Enumeration e=config.getInitParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=config.getInitParameter(name);
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Request parameters</h3>");
pp(os, "Request method", req.getMethod());
pp(os, "Request URI", req.getRequestURI());
pp(os, "Request protocol", req.getProtocol());
pp(os, "Servlet path", req.getServletPath());
pp(os, "Path info", req.getPathInfo());
pp(os, "Path translated", req.getPathTranslated());
pp(os, "Query string", req.getQueryString());
pp(os, "Content length", req.getContentLength());
pp(os, "Content type", req.getContentType());
pp(os, "Server name", req.getServerName());
pp(os, "Server port", req.getServerPort());
pp(os, "Remote user", req.getRemoteUser());
pp(os, "Remote address", req.getRemoteAddr());
pp(os, "Remote host", req.getRemoteHost());
pp(os, "Authorization scheme", req.getAuthType());
os.println("<hr>");
os.println("<h3>Request headers</h3>");
e=req.getHeaderNames();
if(!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=(String) req.getHeader(name);
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Servlet parameters</h3>");
e=req.getParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while (e.hasMoreElements())
{
String name=(String) e.nextElement();
String value=req.getParameter(name);
StringBuffer tbuffer=new StringBuffer();
pp(os, name, value);
} // while
os.println("<hr>");
os.println("<h3>Servlet parameters (Multiple Value style):</h3>");
e = req.getParameterNames();
if (!e.hasMoreElements()) os.println("<b>None!</b>");
else
while(e.hasMoreElements())
{
String name=(String)e.nextElement();
String vals[]=(String [])req.getParameterValues(name);
if(vals!=null)
{
for (int i=0; i<vals.length; i++)
{
os.print("<b>" + name + " = </b>");
os.print(vals[i]+"<br>");
} // for
} // if
} // while
os.println("</table>");
os.println("</body></html>");
os.flush();
} // doStuff
} // InfoF
Когда сервер фиксирует
обращение к сервлету, от вызывает либо doGet, либо
doPost, в зависимости от того, что указано
атрибуте/параметре method. Далее сервлет
запрашивает данные через функции getParameterNames и
getParameterValues и обрабатывает их. В нашем случае он
просто выдает их обратно клиенту в теле HTML
файла-ответа.
Следует обратить внимание, на
то, что для сервлета Info требуется один
инициализационный параметр, содержащий полное
имя каталога, где находятся HTML файлы. Это
необходимо для того, чтобы сервлет создавал файл
там, откуда сервер сможет его взять по запросу
клиента.
Вот собственно и все, что требуется для
реализации Java форм.
Павел Негробов.
Email: pavel@imail.dc.ukrtel.net