Доступ к базам данных из Javaпрограмм и проблемы русификации

       

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



Рисунок 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 * должны быть соответствующим образом установлены. */


// Печать результатов. Они переназначаются на стандартный вывод // и поступают в браузер клиента 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-приложений.


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