sem2practice1
Практика №1
Будем разрабатывать простой чат (без AJAX).
Скриншоты для Netbeans 8.2, для IDEA инструкция по созданию проекта тут: https://yadi.sk/i/yMsPxbISPg55lg
Создание заготовки
-
Добавьте к проекту заготовки классов Message (Сообщение чата с автором, адресатом и датой) и MessageService (хранилище сообщений) Message.javaMessageService.java#
-
Скопируйте в основную папку веб-страниц проекта страницу index.jsp index.jsp
-
Добавьте к проекту новую JSP-страницу (потом переименуете, чтобы была доступна c index.jsp)
Поместите на неё форму посылки сообщения
<form action="адрес, куда послать запрос, относительно текущего пути" method="HTTP-метод посылки запроса"> Ваше имя:<br/> <input name="user"/><br/> Ваше сообщение:<br/> <textarea cols="50" rows="3" name="msg"></textarea><br/> <input type="submit" title="Опубликовать"/> </form>
-
Соберите WAR-архив проекта (кнопка полной сборки в Netbeans рядом с кнопкой запуска). Просмотрите его содержимое архиватором или IDE. Где классы? Выкладывается ли на сервер исходный java-код или скомпилированные JSP?
-
Проверьте запуск приложения. Если ошибка - отключите прокси в NetBeans или корректно настройте интеграцию с сервером приложений в другой IDE.
-
Убедитесь, что в порядке файл WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee webapp_4_0.xsd" version="4.0"> </web-app>
Без version могут не работать EL-выражения ${m} или что-то еще, без xmlns - автодополнение в этом файле.
Добавление и показ сообщений
-
Создайте сервлет AddServlet, обрабатывающий POST-запрос на адрес /add.do . Использовать аннотации для назачения сервлета на адрес. Установите в форме адрес и метод для перехода на этот сервлет. Проверьте, что ему передаётся управление с формы
- Обратите внимание, в сервлетах "/" считается корнем этого приложения (http://localhost/Chat/), а в html для браузера - путем к серверу (http://localhost)
-
Получите в сервлете объект типа MessageList из атрибутов приложения.
MessageService svc = (MessageService) getServletContext().getAttribute("msgSvc") // если атрибута нет, вернет null
-
Чтобы атрибут приложения появился, занесите его туда при старте приложения - создайте класс AppListener, методы которого будут запускаться автоматически
@WebListener public class AppListener implements ServletContextListener { ... sce.getServletContext().setAttribute("msgSvc", new MessageService()); ... }
-
Принимайте параметры user и msg из запроса в AddServlet
public class AddServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String user = req.getParameter("user"); String msg = req.getParameter("msg");
Если они допустимые (не null и не пустые строки), добавтье новое сообщение в список (вызвать метод объекта MessageService).
-
Реализуйте в сервлете вывод текущего списка сообщений в ответ клиенту (UL/LI или таблицы HTML). Список сообщений - getAllMessages() у MessageService.
try (PrintWriter out = response.getWriter()) { for (Message m: ....) { out.println(....); } }
проверьте работу.
-
Перенесите этот код в отдельный файл oldstylejsp.jsp со скриптлетом в html/body
<body> ... <% MessageService svc = (MessageService) application.getAttribute("msgSvc"); for (Message m: ....) { out.println(....); } %>
-
Передайте управление на JSP-страницу из сервлета. Попробуйте передачу forward
request.getRequestDispatcher("oldStyleJsp.jsp").forward(request, response);
и response.sendRedirect(). В чём отличие?
-
Создайте более современную jsp-страницу messages.jsp с использованием JSTL-тегов. Добавьте библиотеку JSTL к проекту (Netbeans - в дереве проекта добавить библиотеку из числа стандартных, в других средах - найти jar-файлы jstl или через Maven)
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> .... <ul> <c:forEach var="m" items="${messages}" > <li>${m}</li> </c:forEach> </ul>
В случае maven подойдет вот такой фрагмент pom.xml:
<dependencies>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1-b5</version>
<scope>provided</scope>
</dependency>
</dependencies>
-
Передайте управление на новую страницу, предварительно заполнив список сообщений messages в атрибуты запроса:
request.setAttribute("messages", svc.getAllMessages());
-
Сделайте вывод сообщений более красивым (например,
${m.svoistvo}
вызываетm.getSvoistvo()
). -
Если выводить сообщения с помощью
<c:out value="${m.text}"
, то появится защита от подстановки произвольного HTML/JS кода. Для имен пользователя тоже можно.
Вход в систему
Сделаем имитацию входа в систему.
-
Добавьте в папку WEB-INF фрагмент JSP login.jspf
<%@ page pageEncoding="UTF-8" %> <form> <input type="text" placeholder="имя" /> <input type="password" placeholder="пароль" name="p"/> <input type="submit" value="Вход"/> </form>
(создать jsp - галочка "создать в виде сегмента jsp", в IDEA - можно просто jsp)
-
Используйте
<%@include file="...."%>
для подключения фрагмента входа в систему в index.jsp. -
Добавьте форме action и method. Направьте запрос от формы на адрес login.do , которому назначьте новый сервлет. Сервлет должен проверить пароль (например, пуст будет всегда первая буква имени) и при успешном входе занести имя пользователя в атрибуты сессии.
request.getSession().setAttribute("username",...)
и перенаправить браузер на главную страницу приложения с помощью sendRedirect.
-
Скопируйте addMessage.jsp в newMessage.jsp . Поприветствуйте пользователя в заголовке, смените назначение поля формы user - теперь это адресат сообщения (если пустой - в общий чат). В сервлете AddServlet используйте имя пользователя из сессии
String user request.getSession().getAttribute("username"
Параметр запроса теперь соответствует адресату сообщения. Если он пустой, создаём сообщение без адресата, как раньше. Если не пустой - вызываем addMessage с тремя параметрами.
-
Назначьте сервлету AddServlet дополнительные адреса - "/view.do" "/viewPrivate.do". Проверьте их в начале кода (
String path = request.getServletPath()
). Если add.do, делаем все как раньше, если view.do - не добавляем сообщения, а только показываем, если viewPrivate.do - показываем личные сообщения пользователя. Заготовки методов поиска сообщений есть в классе MessageService.- Используйте одну и ту же страницу messages.jsp в качестве просмотрщика сообщений. Меняется содержимое атрибута messages.
- Ссылки на страницы view.do, viewPrivate.do можно добавить на стартовую страницу, форма и передача параметров для них не требуются.
-
(по желанию) Cгенерируйте ссылки "ответить" для каждого сообщения в списке личных сообщений. JSTL-EL. Можно направлять на
"newMessage.jsp?reply=username"
и использовать на странице newMessage.jsp EL-выражение ${param.user}.
Фильтр
-
Добавьте фильтр и опишите его в web.xml (хотя можно и аннотациями).
public class CounterFilter implements Filter { private FilterConfig filterConfig = null; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // сессия - ((HttpServletRequest) request).getSession() // приложение - filterConfig.getServletContext() // до передачи управления chain.doFilter(request, response); // после возврата управления } public FilterConfig getFilterConfig() { return (this.filterConfig); } public void destroy() { } public void init(FilterConfig filterConfig) { this.filterConfig = filterConfig; } }
Фильтр должен считать запросы в объектах класса AtomicInetger counter. Храните в сессии атрибут sessionCounter со счётчиком запросов в текущей сессии, а в приложении атрибут globalCounter с общим счётчиком. Если атрибута нет (null), пусть фильтр его заносит.
-
Покажите счётчики на какой-либо существующей jsp-странице через EL.
-
(по желанию) Создайте отдельный фильтр, блокирующий viewPrivate.do и add.do, если в сессии нет имени пользователя. Можно не вызывать chain.doFilter, а перенаправлять с помощью sendRedirect на страницу с ошибкой и формой входа в систему.
Стоит выложить результат в хранилище Gitlab (можно дублировать к себе). Создать проект в веб-интерфейсе, скопировать адрес и использовать его в диалогах