Веб Дизайн - статьи

       

Сервлеты на базе Java Web Server


Сервлеты являются объектами, которые образуют специфический интерфейс, с помощью которого их можно свободно встраивать в Java-ориентированные Web-сервера. В отличие от апплетов, они являются облегченными Java-объектами (без графики и GUI-компонентов), но зато, будучи кроссплатформенными и динамически загружаемыми и, используя все возможности Java, они могут использовать практически любой HTML и взаимодействовать с любым браузером. Естественно, что сервлеты можно использовать и используют для доступа к базам данных, программируя все удаленные операции с базой из браузера. В настоящее время большинство Web серверов поддерживают технологию сервлетов. Java Web-Server хорош тем, что что он наиболее полно реализует эту технологию. Стандартный Servlet-API реализован как в самом Java Web Server, так и в отдельном продукте JSDK, но начиная с версии 1.2, он включен в состав JDK. Характерной особенностью сервлетов является то, что они не требуют создания новых процессов при каждом новом запросе. Множество сервлетов выполняются параллельно в рамках одного процесса на сервере и по своей производительности превосходят как CGI, так и Fast-CGI приложения (см. Рис.3).


Рис. 3. Возможные процессы на Web-сервере.

Несмотря на то, что сервлеты используют HTTP-протокол, им нет необходимости перезагружать процесс при каждом новом запросе и это также повышает их быстродействие. К сожалению, когда вы используете сервлеты, опять-таки, возникает проблема использования кириллических символов. Дело в том, что стандартный путь прохождения данных тут не действует, потому что Web-сервер при старте запускает так называемый Java-handler, которому передает на выполнение все Java-сервлеты и обменивается вводом-выводом именно с ним через специальную библиотеку классов. Поэтому, если вы хотите получать в браузере от вашего Web-сервера, который исполняет сервлеты, кириллические строки, вам надо использовать вместо стандартных примитивов ввода/вывода некоторые специальные методы для работы со строками, например: // Определение необходимого кодификатора // в зависимости от используемого типа кодировки String dos = new String(_Cp866_); String win = new String(_Cp1251_); String iso = new String(_8859_5_); String im = new String(_Кириллический текст_); .......................................................


out.println(_<body>_); //out.write(im.getBytes(dos)); out.write(im1.getBytes(win)); //out.write(im2.getBytes(iso)); out.println(_</body></html>_);

Но и весьма эффективная функция Java - getBytes() не действует, когда вы извлекаете данные при помощи сервлетов из баз данных. Здесь необходимо применить метод, который мы уже использовали при работе с базами данных при помощи интерфейса JDBC. Кроме того, файл font.properties в каталоге $JDK_HOME/lib или в специальном каталоге вашего браузера должен быть соответствущим образом настроен. Во многих пакетах Java имеются образцы файла font.properties.ru, который можно взять в качестве основы. Если вы работаете с уже русифицированным Web-сервером, например, русской версией Apache, то он позаботится за вас и сам перекодирует данные, поступающие из базы данных от сервлета. Каким образом программируются операции с базой данных в сервере? Сервлет не накладывает никаких ограничений на использование интерфейсов с базой данных. Можно использовать обыкновенный JDBC-ODBC, или специфические драйвера ориентированные на конкретные SQL-сервера и базы данных. Рассмотрим типичный DBServlet.java, который с успехом будет выполняться как на Java Web Server, так и Web сервере Apache. /* * @(#)DBServlet.java 1.6 97/06/13 */ import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.net.*; import java.sql.*; /** * DBServlet * * Этот сервлет демонстрирует как использовать JDBC стек * и получать доступ к базам данных при помощи сервлетов. Для того, чтобы выполнить этот * сервлет, переменные CLASSPATH, LD_LIBRARY_PATH, ODBCINI * должны быть соответствующим образом установлены. */ public class DBServlet extends HttpServlet { /** * init method */ public void init(ServletConfig conf) throws ServletException { super.init(conf); } /** * service method */ public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String stack, username, password, query; Connection con; PrintStream out; /* ServletOutputStream out = res.getOutputStream();*/ // Загрузка параметров.


Именно эти параметры должны будут вводиться // в специально прорисованном окне браузера, с которым будет // взаимодействовать наш сервлет stack = req.getParameter(_stack_); username = req.getParameter(_username_); password = req.getParameter(_password_); query = req.getParameter(_query_); res.setContentType(_text/html_); out = new PrintStream(res.getOutputStream()); printPageHeader(out); // в том случае, если параметры отсутствуют if (stack == null username == null password == null query == null) { printPageFooter(out); return; } String url = _jdbc:odbc:_+stack; out.println(_<hr><h3>Previous Query</h3>_); out.println(_<pre>_); out.println(_Database Stack : _+stack); out.println(_ User ID : _+username); out.println(_ Password : _+password); out.println(_ Query : _+query); out.println(_</pre>_); try { // Найти jdbc стек. Может существовать несколько зарегистрированных драйверов Class.forName(_sun.jdbc.odbc.JdbcOdbcDriver_); //Class.forName(_jdbc.odbc.JdbcOdbcDriver_); // Получить соединение с базой данных con = DriverManager.getConnection(url, username, password); out.println(_<hr>_); out.println(_<h3>ODBC Driver and Database Messages</h3>_); checkForWarning(con.getWarnings(), out); DatabaseMetaData dma = con.getMetaData(); out.println(_Connected to _ + dma.getURL() + _<br>_); out.println(_Driver _ + dma.getDriverName() + _<br>_); out.println(_Version _ + dma.getDriverVersion() + _<br>_); // Создать и выполнить запрос. Конкретный оператор SQL // вводится удаленным пользователем в окне его браузера Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(query); // Печать результатов. Они переназначаются на стандартный вывод // и поступают в браузер клиента dispResultSet(rs, out); rs.close(); stmt.close(); con.close(); out.println(_<hr>_); } catch (SQLException ex) { out.println(_<hr>*** SQLException caught ***_); while (ex != null) { out.println(_SQLState: _ + ex.getSQLState() + _<br>_); out.println(_Message: _ + ex.getMessage() + _<br>_); out.println(_Vendor: _ + ex.getErrorCode() + _<br>_); ex = ex.getNextException(); } } catch (java.lang.Exception ex) { ex.printStackTrace(); } printPageFooter(out); } /** * возврат запрошенной информации */ public String getServletInfo() { return _Это простой сервлет, который показывает как использовать JDBC_; } /* * проверка и печать информации сервера */ private void checkForWarning(SQLWarning warn, PrintStream out) throws SQLException { boolean rc = false; if (warn != null) { out.println(_<hr>*** Warning ***_); rc = true; while (warn != null) { out.println(_SQLState: _ + warn.getSQLState() + _<br>_); out.println(_Message: _ + warn.getMessage() + _<br>_); out.println(_Vendor: _ + warn.getErrorCode() + _<br>_); warn = warn.getNextWarning(); } } } /* * Показ результатов запроса в табличном html формате */ private void dispResultSet(ResultSet rs, PrintStream out) throws SQLException, IOException { int i; // метаданные используются для получения информации о схеме ResultSetMetaData rsmd = rs.getMetaData(); int numCols = rsmd.getColumnCount(); out.println(_<hr>_); out.println(_<h3>Database Columns and Data</h3>_); out.println(_<table border=3>_); out.println(_<tr>_); for (i=1; i<=numCols; i++) { out.println(_<th>_ + rsmd.getColumnLabel(i) + _</th>_); } out.println(_</tr>_); // для всех данных while (rs.next()) { out.println(_<tr>_); // for one row for (i=1; i<=numCols; i++) { dispElement(rs, rsmd.getColumnType(i), out, i); } out.println(_</tr>_); } out.println(_</table>_); } // печать одного элемента private void dispElement(ResultSet rs, int dataType, PrintStream out, int col) throws SQLException, IOException { String cp1 = new String(_Cp1251_); // в зависимости от типа данных, определяем различные типы обработки switch(dataType) { case Types.DATE: java.sql.Date date = rs.getDate(col); out.println(_<th>_ + date.toString() + _</th>_); break; case Types.TIME: java.sql.Time time = rs.getTime(col); out.println(_<th>_ + time.toString() + _</th>_); break; case Types.TIMESTAMP: java.sql.Timestamp timestamp = rs.getTimestamp(col); out.println(_<th>_ + timestamp.toString() + _</th>_); break; case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: String str = rs.getString(col); // Возможно, что здесь вам понадобятся кириллические преобразования out.println(_<th>_ + str + _</th>_); break; case Types.NUMERIC: case Types.DECIMAL: java.math.BigDecimal numeric = rs.getBigDecimal(col, 10); out.println(_<th>_ + numeric.toString() + _</th>_); break; case Types.BIT: boolean bit = rs.getBoolean(col); out.println(_<th>_ + new Boolean(bit) + _</th>_); break; case Types.TINYINT: byte tinyint = rs.getByte(col); out.println(_<th>_ + new Integer(tinyint) + _</th>_); break; case Types.SMALLINT: short smallint = rs.getShort(col); out.println(_<th>_ + new Integer(smallint) + _</th>_); break; case Types.INTEGER: int integer = rs.getInt(col); out.println(_<th>_ + new Integer(integer) + _</th>_); break; case Types.BIGINT: long bigint = rs.getLong(col); out.println(_<th>_ + new Long(bigint) + _</th>_); break; case Types.REAL: float real = rs.getFloat(col); out.println(_<th>_ + new Float(real) + _</th>_); break; case Types.FLOAT: case Types.DOUBLE: double longreal = rs.getDouble(col); out.println(_<th>_ + new Double(longreal) + _</th>_); break; case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: byte[] binary = rs.getBytes(col); out.println(_<th>_ + new String(binary, 0) + _</th>_); break; } } private void printPageHeader(PrintStream out) { out.println(_<html>_); out.println(_<head>_); out.println(_<tltle> Типичный сервлет для работы с базами данных </title>_); out.println(_</head>_); out.println(_<body>_); out.println(_<center><font size=5>_ + _<b>Jeeves Database Servlet</b>_ + _</font></center>_); out.println(_<hr>_); out.println(_<form action=\_/servlet/dbServlet\_ method=\_get\_>_); out.println(_<pre>_); out.println(_ODBC DSN : <input type=textarea name=stack>_); out.println(_ User ID : <input type=textarea name=username>_); out.println(_ Password : <input type=textarea name=password>_); out.println(_ SQL Query : <input type=textarea name=query>_); out.println(_</pre>_); out.println(_<input type= submit>_); out.println(_</form>_); } private void printPageFooter(PrintStream out) { out.println(_</body>_); out.println(_</html>_); out.flush(); } }



В этой программе содержатся пакеты классов для поддержки сервлетов - javax.servlet.* и javax.servlet.http.*, которые находятся в специальном продукте фирмы JavaSoft JSDK1.0.1 или непосредственно в JDK1.2.

Главная вещь, которую необходимо при этом понять, - это каким образом извлекаются переданные сервлету аргументы на вводе и каким образом передаются ответные параметры на выводе. public void service (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ... }

Специальный метод request содержит список параметров, которые могут быть извлечены при помощи HttpServletRequest::getParameterNames метода. stack = req.getParameter(_stack_);

возвращает вам значение вами же определенного в htm-форме параметра stack, в котором вы можете задавать с клавиатуры имя ODBC-источника (ODBC DSN).

Можно установить специальный цикл обработки для извлечения каждого параметра, переданного из HTML-формы, когда она направлена для обработки к сервлету: while ( values.hasMoreElements() ) { ... }

Имя и значение каждого извлекаемого параметра можно получать во время работы цикла. String name, value; name = (String)values.nextElement(); value = req.getParameter (name);

Этих знаний вполне достаточно для того, чтобы начать писать простые сервлеты, расширяющие функциональность JavaServer"а для обработки форм, вместо того, чтобы писать cложные CGI. Имеется, впрочем, еще одна проблема, которую также необходимо изучить - обработка событий и исключительных ситуаций. Убедитесь, что вы специфицировали этот сервис и init методы в вашем подклассе HttpServlet как ServletException: public void init (ServletConfig conf) throws ServletException ... public void service (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException ...

Внутри DBServlet сервлета метод service может использовать один или несколько блоков try/catch, которые обеспечивают пользователю или программисту обработку событий, связанных с некоторыми неверными действиями или ситуациями.В первом блоке try пользователь может обработать ситуацию при возникновении проблемы соединения с сервером базы данных или выполнении sql-запроса. Второй блок try можно использовать по своему усмотрению, например, при записи результатов в файл и последующей проверке - должным ли образом он закрыт перед выходом из обслуживающей процедуры. Если нет - в стандартное устройство вывода выдается соответствующая трассировка.

Эту программу легко модифицировать в соответствии с вашими нуждами и получать не только содержимое таблиц и колонок, но и любые метаданные Потому в стандартном пакете java.sql содержится гораздо больше методов, чем те, которые предлагают стандартные средства для построения стандартных ODBC-приложений.


Содержание раздела