RequestOutput.generate(resp, req);
}
}
В методе performTask() происходит обращение к другому классу-обработчику запроса пользователя с передачей ему объектов HttpServletRequest req иHttpServletResponse resp.
/* пример # 5 : извлечение информации из запроса клиента : RequestOutput.java */
package chapt18;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestOutput {
public static void generate(HttpServletResponse resp,
HttpServletRequest req) {
try {
String name, value;
resp.setContentType("text/html; charset=utf-8");
PrintWriter out = resp.getWriter();
out.print("<HTML><HEAD>");
out.print("<TITLE>Результат</TITLE>");
out.print("</HEAD><BODY>");
out.print("<TABLE BORDER=3>");
Enumeration names = req.getParameterNames();
while (names.hasMoreElements()) {
name = (String) names.nextElement();
value = req.getParameterValues(name)[0]; /*
name = new String(name.getBytes("ISO-8859-1"), "utf-8");
value = new String(value.getBytes("ISO-8859-1"), "utf-8");
*/
out.print("<TR>");
out.print("<TD>" + name + "</TD>");
out.print("<TD>" + value + "</TD>");
out.print("</TR>");
}
out.print("</TABLE></BODY></HTML>");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
В классе в объекте resp задается тип содержимого text/html и кодировка UTF-8, если нужно отобразить кириллицу. После этого объект out устанавливается в выходной поток resp.getWriter(), в который будут помещаться данные. Из запроса HttpServletRequest req извлекается объект типа Enumeration с текстовыми значениями имен переменных формы. Далее, итерируя по элементам этого объекта, последовательно извлекаются все параметры. Для каждого имени переменной можно при необходимости (если не указана кодовая страница) произвести перекодировку: вначале извлекается объект итерации
в кодировке, в которой он передается, а именно ISO-8859-1, после создается новая строка с необходимой кодировкой, в данном случае UTF-8. Для каждой из переменных извлекаются из запроса соответствующие им значения при помощи метода getParameterValues(name). Тем же способом их кодировка может быть изменена и добавлена в выходной поток.
Класс сервлета относится к пакету chapt18, поэтому файл
FormRequest.class должен быть размещен в папке
/webapps/FirstProject3/WEB-INF/classes/chapt18
и обращение к этому классу, например из документа HTML, должно производиться как chapt18.FormRequest. В файле web.xml должны находиться строки:
<servlet>
<servlet-name>MyForm</servlet-name>
<servlet-class>chapt18.FormRequest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyForm</servlet-name>
<url-pattern>/testform</url-pattern>
</servlet-mapping>
Обращение к сервлету производится по его URL-имени testform. Результат выполнения:
Рис. 18.2. Результат выполнения запроса
Метод getParameterValues() возвращает значения любой переменной формы по имени этой переменной. Массив возвращается потому, что некоторые переменные формы могут иметь несколько значений, например группа флажков или радиокнопок. Другой метод доступа не предполагает предварительного знания их имен. Метод getParameterNames() возвращает объект Enumeration, в котором содержатся все имена переменных, извлеченных из формы.
Многопоточность
Контейнер сервлетов будет иметь несколько потоков выполнения, распределяемых согласно запросам клиентов. Вероятна ситуация, когда два клиента одновременно вызовут методы doGet() или doPost(). Метод service() должен быть написан с учетом вопросов многопоточности. Любой доступ к разделяемым ресурсам, которыми могут быть файлы, объекты, необходимо защитить ключевым словом synchronized. Ниже приведен пример посимвольного вывода строки сервлетом с паузой между выводом символов в 500 миллисекунд, что позволяет другим клиентам, вызвавшим сервлет, успеть вклиниться в процесс вывода при отсутствии синхронизации.
/* пример # 6 : доступ к синхронизированным ресурсам :
ServletSynchronization.java */
package chapt18;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class ServletSynchronization extends HttpServlet {
// синхронизируемый объект
private StringBuffer locked = new StringBuffer();
protected void doGet(HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException {
performTask(req, res);
}
private void performTask(HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException {
try {
Writer out = res.getWriter();
out.write(
"<HTML><HEAD>"
+ "<TITLE>SynchronizationDemo</TITLE>"
+ "</HEAD><BODY>");
out.write(createString());
out.write("</BODY></HTML>");
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(
"Failed to handle request: " + e);
}
}
protected String createString() {
// оригинал строки
final String SYNCHRO = "SYNCHRONIZATION";
synchronized (locked) {
try {
for (int i = 0; i < SYNCHRO.length(); i++) {
locked.append(SYNCHRO.charAt(i));
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
String result = locked.toString();
locked.delete(0, SYNCHRO.length() - 1);
return result;
}
}
}
Результаты работы сервлета при наличии и отсутствии синхронизации представлены на рисунках.
Рис. 18.3. Результат работы сервлета Synchronization
с блоком синхронизации
Рис. 18.4. Результат работы сервлета Synchronization
без синхронизации
Можно синхронизировать и весь сервлет целиком, но причиной, почему это не делается, является возможность нахождения критической секции вне основного пути выполнения программы.
Электронная почта
Рассылка электронной почты, в том числе и автоматическая, является стандартным родом деятельности при использовании Web-приложений. Собственный почтовый сервер создать достаточно легко, только необходимо указать адрес почтового севера, который будет использован в качестве транспорта.
Следующий пример использует интерфейсы API JavaMail для работы с электронной почтой в сервлетах и JSP. API JavaMail содержит классы, с помощью которых моделируется система электронной почты. Класс javax.mail.Session представляет сеанс почтовой связи, класс javax.mail.Message – почтовое сообщение, класс javax.mail.internet.InternetAddress – адреса электронной почты.
Рис. 18.5. Формирование запроса на отправку письма
Для работы с данной частью платформы J2EE необходимо скачать zip-файлы, расположенные по адресу http://java.sun.com/products/javamail/, содержащие архивы mail.jar и activation.jar. И добавить эти файлы в каталог jar-файлов серверам приложений (common/lib для Tomcat). Также необходимо запустить почтовую программу James, являющуюся также одним из проектов apache.org.
Ниже приведена страница JSP, содержащая форму для заполнения основных полей: «Кому» – «to», «От кого» – «from», «Тема сообщения» – «subj»
<!-- пример # 7 : страница создания электронного письма : index.jsp-->
<%@ page language="java" contentType=
"text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html><head><title>SendMail Application</title></head>
<b>Мой почтовый сервер</b>
<form method="post" action="sendmail">
<table>
<tr><td><b>To(email):</b></td><td>
<input name="to" type="text" size=40></td></tr>
<tr><td><b>From(email):</b></td><td>
<input name="from" type="text" size=40></td></tr>
<tr><td><b>Subject:</b></td><td>
<input name="subj" type="text" size=40></td></tr>
</table>
<hr>
<textarea name="body" type="text" rows=5 cols=45>
Добрый день!</textarea>
<br>
<input type="submit" value="Отправить!">
</form>
</body></html>
Параллельные процессы по отправке письма и предложению пользователю в это же самое время создать новое письмо организуются с применением потока
в следующем сервлете.
/* пример # 8 : доступ к синхронизированным ресурсам :
SendMailServlet.java */
packagechapt18;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.activation.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class SendMailServlet
extendsjavax.servlet.http.HttpServlet
implements javax.servlet.Servlet {
//объект почтовой сессии
private Session mailSession = null;
public void init(ServletConfig config)
throws ServletException {
//mailSession = Session.getDefaultInstance(System.getProperties());
final String host = "mail.smtphost";
final String port = "mail.smtpport";
//запрос параметров почтового сервера из web.xml
String hostvalue = config.getInitParameter(host);
String portvalue = config.getInitParameter(port);
java.util.Properties props = new java.util.Properties();
//загрузка параметров почтового сервера в объект свойств
props.put(host, hostvalue);
props.put(port, portvalue);
//загрузка параметров почтового сервера в объект почтовой сессии
mailSession = Session.getDefaultInstance(props, null);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
//извлечение параметров письма из запроса
String from = request.getParameter("from");
String to = request.getParameter("to");
String subject = request.getParameter("subj");
String content = request.getParameter("body");
if((from == null) || (to == null)
|| (subject == null) || (content == null)) {
/*при отсутствии одного из параметров предлагается повторить
ввод*/
response.sendRedirect("index.jsp");
return;
}
//запуск процесса отправки почты в отдельном потоке
(new MailSender(to, from, subject, content)).start();
//формирование страницы с предложение о создании нового письма
response.setContentType("text/html; charset=CP1251");
PrintWriter out = response.getWriter();
out.println("<html><head><title>");
out.println("SendMail Application</title></head>");
out.println("Message to <b>" + to
+ "</b> sending in progress");
out.println("<a href = \"index.jsp\">New message</a>");
out.println("</body></html>");
}
private class MailSender extends Thread {
private String mailTo;
private String mailFrom;
private String mailSubject;
private String mailContent;
MailSender(String mailTo, String mailFrom,
String mailSubject, String mailContent) {
setDaemon(true);
this.mailTo = mailTo;
this.mailFrom = mailFrom;
this.mailSubject = mailSubject;
this.mailContent = mailContent;
}
public void run() {
try {
//создание объекта почтового сообщения
Message message = new MimeMessage(mailSession);
//загрузка параметров в объект почтового сообщения
message.setFrom(new InternetAddress(mailFrom));
message.setRecipient(Message.RecipientType.TO,
new InternetAddress(mailTo));
message.setSubject(mailSubject);
message.setContent(mailContent, "text/plain");
//отправка почтового сообщения
Transport.send(message);
} catch(AddressException e) {
e.printStackTrace();
System.err.print("Ошибка адреса");
} catch(MessagingException e) {
e.printStackTrace();
System.out.print("Ошибка сообщения");
}
}
}
}
В результате в браузер будет выведено:
Message to blinov@gmail.com sending in progress New message
где New message представляет собой активную ссылку, перенаправляющую при запуске на index.jsp для создания еще одного письма. Процесс же отправки письма будет функционировать независимо от дальнейшей работы приложения.
Файл web.xml для данного приложения имеет вид:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>FirstMail</display-name>
<servlet>
<display-name>
SendMailServlet</display-name>
<servlet-name>SendMailServlet</servlet-name>
<servlet-class>
SendMailServlet</servlet-class>
<init-param>
<param-name>mail.smtphost</param-name>
<param-value>mail.bsu.bsu</param-value>
</init-param>
<init-param>
<param-name>mail.smtpport</param-name>
<param-value>25</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>chapt18.SendMailServlet</servlet-name>
<url-pattern>/sendmail</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
В качестве значения параметра mail.smtphost можно попробовать использовать адрес почтового сервера mail.attbi.com.
Задания к главе 18
Вариант А
Создать сервлет и взаимодействующие с ним пакеты Java-классов и JSP-страницы, выполняющие следующие действия:
1. Генерация таблиц по переданным параметрам: заголовок, количество строк и столбцов, цвет фона.
2. Вычисление тригонометрических функций в градусах и радианах с указанной точностью. Выбор функций должен осуществляться через выпадающий список.
3. Поиск слова, введенного пользователем. Поиск и определение частоты встречаемости осуществляется в текстовом файле, расположенном на сервере.
4. Вычисление объемов тел (параллелепипед, куб, сфера, тетраэдр, тор, шар, эллипсоид и т.д.) с точностью и параметрами, указываемыми пользователем.
5. Поиск и (или) замена информации в коллекции по ключу (значению).
6. Выбор текстового файла из архива файлов по разделам (поэзия, проза, фантастика и т.д.) и его отображение.
7. Выбор изображения по тематике (природа, автомобили, дети и т.д.)
и его отображение.
8. Информация о среднесуточной температуре воздуха за месяц задана
в виде списка, хранящегося в файле. Определить:
а) среднемесячную температуру воздуха; б) количество дней, когда температура была выше среднемесячной; в) количество дней, когда температура опускалась ниже 0ºC; г) три самых теплых дня.
9. Игра с сервером в “21”.
10. Реализация адаптивного теста из цепочки в 3–4 вопроса.
11. Определение значения полинома в заданной точке. Степень полинома
и его коэффициенты вводятся пользователем.
12. Вывод фрагментов текстов шрифтами различного размера. Размер шрифта и количество строк задаются на стороне клиента.
13. Информация о точках на плоскости хранится в файле. Выбрать все точки, наиболее приближенные к заданной прямой. Параметры прямой
и максимальное расстояние от точки до прямой вводятся на стороне клиента.
14. Осуществить сортировку введенного пользователем массива целых чисел. Числа вводятся через запятую.
15. Реализовать игру с сервером в крестики-нолики.
16. Осуществить форматирование выбранного пользователем текстового файла, так чтобы все абзацы имели отступ ровно 3 пробела, а длина каждой строки была ровно 80 символов и не имела начальными и конечными символами пробел.
Вариант B
Для заданий варианта В главы 4 на основе сервлетов разработать механизм аутентификации и авторизации пользователя. Сервлет должен сгенерировать приветствие с указанием имени, роли пользователя, а также указать текущую дату и IP-адрес компьютера пользователя.
Тестовые задания к главе 18
Вопрос 18.1.
Каким образом в методе init() сервлета получить параметр инициализации сервлета с именем “URL”? (выберите два)
1) ServletConfig.getInitParameter("URL");
2) getServletConfig().getInitParameter("URL");
3) this.getInitParameter("URL");
4) HttpSerlet.getInitParameter("URL");
5) ServletContext.getInitParameter("URL").
Вопрос 18.2.
Какой метод сервлета FirstServlet будет вызван при активизации ссылки следующего HTML-документа?
<html><body>
<a href="/FirstProject/FirstServlettest">OK!</a>
</body><html>
Соответствующий сервлету тег <url-pattern> в файле web.xml имеет вид:
<url-pattern>/FirstServlettest</url-pattern>
1) doGet();
2) doGET();
3) performTask();
4) doPost();
5) doPOST().
Вопрос 18.3.
Контейнер вызывает метод init() экземпляра сервлета…
1) при каждом запросе к сервлету;
2) при каждом запросе к сервлету, при котором создается новая сессия;
3) при каждом запросе к сервлету, при котором создается новый поток;
4) только один раз за жизненный цикл экземпляра;
5) когда сервлет создается впервые;
6) если время жизни сессии пользователя, от которого пришел запрос, истекло.
Вопрос 18.4.
Каковы типы возвращаемых значений методов getResource()
и getResourceAsStream()интерфейса ServletContext?
1) ServletContext не имеет таких методов;
2) String и InputStream;
3) URL и InputStream;
4) URL и StreamReader.
Вопрос 18.5.
Какие интерфейсы находятся в пакете javax.servlet?
1) ServletRequest;
2) ServletOutputStream;
3) PageContext;
4) Servlet;
5) ServletContextEvent;
6) ни один из перечисленных.
Вопрос 18.6.
Как можно получить всю информацию из запроса, посланного следующей формой? (выберите два варианта ответа)
<HTML><BODY>
<FORM action="/com/MyServlet">
<INPUT type="file" name="filename">
<INPUT type="submit" value="Submit">
</FORM></BODY></HTML>
1) request.getParameterValues("filename");
2) request.getAttribute("filename");
3) request.getInputStream();
4) request.getReader();
5) request.getFileInputStream().
Java Server Pages
Технология Java Server Pages (JSP) была разработана компанией Sun Microsystems, чтобы облегчить создание страниц с динамическим содержанием.
В то время как сервлеты наилучшим образом подходят для выполнения контролирующей функции приложения в виде обработки запросов и определения вида ответа, страницы JSP выполняют функцию формирования текстовых документов типа HTML, XML, WML и некоторых других.
под терминами “динамическое/статическое содержание” обычно понимаются не части JSP, а содержание Web-приложения:
1) динамические ресурсы, изменяемые в процессе работы: сервлеты, JSP, а также java-код;
2) статические ресурсы, не изменяемые в процессе работы – HTML, 5-72622.php" class="back_link">⇐ Назад