Практическое занятие 2. Создание JSP. Сессии и фильтры.

Технология проектирования Java Server Pages (JSP) - это одна из технологий J2EE, которая представляет собой расширение технологии сервлетов для упрощения работы с Web-содержимым. Страницы JSP позволяет легко разделить Web-содержимое на статическую и динамическую часть, допускающую многократное использование ранее определенных компонентов.

Сервлетный фильтр, в соответствии со спецификацией, это Java-код, пригодный для повторного использования и позволяющий преобразовать содержание HTTP-запросов, HTTP-ответов и информацию, содержащуюся в заголовках HTML. Сервлетный фильтр занимается предварительной обработкой запроса, прежде чем тот попадает в сервлет, и/или последующей обработкой ответа, исходящего из сервлета.

Сервлетные фильтры могут:

  • перехватывать инициацию сервлета прежде, чем сервлет будет инициирован;
  • определить содержание запроса прежде, чем сервлет будет инициирован;
  • модифицировать заголовки и данные запроса, в которые упаковывается поступающий запрос;
  • модифицировать заголовки и данные ответа, в которые упаковывается получаемый ответ;
  • перехватывать инициацию сервлета после обращения к сервлету.

Сервлетный фильтр может быть конфигурирован так, что он будет работать с одним сервлетом или группой сервлетов. Основой для формирования фильтров служит интерфейс javax.servlet.Filter, который реализует три метода:

  • void init (FilterConfig config) throws ServletException;
  • void destroy();
  • void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

Метод init вызывается прежде, чем фильтр начинает работать, и настраивает конфигурационный объект фильтра. Метод doFilter выполняет непосредственно работу фильтра. Таким образом, сервер вызывает init один раз, чтобы запустить фильтр в работу, а затем вызывает doFilter столько раз, сколько запросов будет сделано непосредственно к данному фильтру. После того, как фильтр заканчивает свою работу, вызывается метод destroy.

package common;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class FilterConnect implements Filter{

private FilterConfig config = null;

private boolean active = false;

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

public void init (FilterConfig config) throws ServletException{

this.config = config;

String act = config.getInitParameter("active");

if (act != null)

active = (act.toUpperCase().equals("TRUE"));

}

 

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public void doFilter (ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException{

if (active){

// Здесь можно вставить код для обработки

Параметры инициализации задаются внутри объявления аннотации @WebFilter аннотацией @WebInitParam. Аналогичная конфигурация для предыдущей версии определяется в дескрипторе web.xml:

<filter>

<filter-name>encodingfilter</filter-name>

<filter-class>by.bsu.sample.filter.EncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>encodingfilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

В большинстве бизнес-приложений необходима идентификация клиентов. Технология сервлетов предусматривает стандартное решение этой задачи: механизм cookies и сессии.
Cookie - это некие данные, хранящиеся в браузере клиента. С программной точки зрения, cookie - это просто несколько пар «название - значение», которые используются при обращении браузера к определенному серверу. Этот механизм позволяет на протяжении нескольких HTTP запросов сохранять на браузере ту или иную информацию, полученную от сервера. Например, это могут быть те или иные настроечные параметры клиента или его персональный идентификатор. Чтобы из сервлета получить доступ к набору cookie клиента, чей запрос находится на обработке, достаточно воспользоваться методом getCookies() объекта HttpServletRequest:

Cookie cookies[] = request.getCookies();


Название и значение любой записи в cookie можно получить с помощью методов getName() и getValue().

Процедура помещения в браузер клиента новой записи cookie выглядит следующим образом:

 

Cookie theCookie = new Cookie(название нового cookie, значение нового cookie);

 

response.setContentType = "test/html";

 

response.addCookie( theCookie );


Сессии. Наряду с другими сервисами, класс HttpServlet реализует механизм сессий, который не был реализован протоколом HTTP. Если объект сервлета - это служебный механизм для обработки потока HTTP запросов, то объект сессии создается каждый раз при получении запроса от нового клиента и впоследствии идентифицирует его уникальным образом. Разным пользователям соответствуют различные объекты сессий. Получить доступ из сервлета к объекту сессии, и тем самым идентифицировать клиента, чей запрос находится на обработке, можно с помощью метода getSession():

 

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletRequest {

HttpSession session = request.getSession(true);

 

...


Если объект сервлета позволяет хранить информацию, общую для всех клиентов, то в объекте сессии можно хранить персональную информацию о соответствующем клиенте. Как и в случае с cookie, соответствующая информация хранится в виде нескольких пар «название - значение». Однако, если в cookie значение записи - это некая строка (String), то в случае с сессией это некий объект (Object). Доступ к значениям, хранящимся в сессии, осуществляется с помощью методов putValue и getValue. Например:

 

private static final String SUM_KEY = "sum";

 

Integer count = 100;

 

session.putValue (SUM_KEY, count);

 

...

 

Integer sum = (Integer) session.getAttribute (SUM_KEY);


Все классы, объекты которых планируется помещать в экземпляр класса HttpSession, должны реализовывать интерфейс Serializable. Тем самым гарантируется отсутствие в системе каких-либо дополнительных взаимосвязей помимо тех, что оговорены для web контейнера. Доступ к объектам атрибутов осуществляется посредством методов setAttribute() и getAttribute(). Однако для некоторых атрибутов в объекте сессии может потребоваться дополнительное анонсирование, которое выполняется с помощью методов valueBound() и valueUnbound().


Объект сессии сохраняется до тех пор, пока продолжают поступать HTTP запросы от соответствующего клиента. Если в течение определенного контрольного интервала времени новых запросов от клиента не поступает, соответствующий объект сессии автоматически уничтожается, а персональная информация о клиенте - теряется.

 

Рассмотрим пример создания простого веб-приложения, в котором необходимо залогиниться.

1. Создайте новый проект BSAC. Сгенерируйте дискриптор развертывания web.xml.

2. Затем создайте фильтр с именем SessionFilter.

 

 

3. В дискрипторе развертывания создайте конфигурацию. Дополните существующий текст.

<filter>

<filter-name>SessionFilter</filter-name>

<filter-class>by.bsac.session.SessionFilter</filter-class>

<init-param>

<param-name>ignore-urls</param-name>

<param-value>/BSAC/login,/BSAC/LoginController,/BSAC/error-login.jsp</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>SessionFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

 

Где: filter-name - имя фильтра;

filter-class - полное название класса с пакетом, где он находится;

init-param – содержит параметры, котрые будут передаваться в фильтр при его инициализации;

param-value – значение параметра;

filter-mapping – осуществляется привязка urla с шаблоном;

url-pattern – шаблон urla.

Т.о. наш фильтр будет работать по шаблону /* (при любом url).

 

Итоговый вариант web.xml выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

<display-name>BSAC</display-name>

<welcome-file-list>

<welcome-file>index.html</welcome-file>

<welcome-file>index.htm</welcome-file>

<welcome-file>index.jsp</welcome-file>

<welcome-file>default.html</welcome-file>

<welcome-file>default.htm</welcome-file>

<welcome-file>default.jsp</welcome-file>

</welcome-file-list>

<filter>

<filter-name>SessionFilter</filter-name>

<filter-class>by.bsac.session.SessionFilter</filter-class>

<init-param>

<param-name>ignore-urls</param-name>

<param-value>/BSAC/login,/BSAC/LoginController,/BSAC/error-login.jsp</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>SessionFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

<servlet>

<description></description>

<display-name>LoginController</display-name>

<servlet-name>LoginController</servlet-name>

<servlet-class>by.bsac.profile.LoginController</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>LoginController</servlet-name>

<url-pattern>/login</url-pattern>

<url-pattern>/logout</url-pattern>

</servlet-mapping>

</web-app>

 

4. Исходный код фильтра приведен ниже:

package by.bsac.session;

 

import java.io.IOException;

import java.util.ArrayList;

import java.util.StringTokenizer;

 

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import by.bsac.profile.ProfileTools;

 

public class SessionFilter implements Filter {

 

private ArrayList<String> ignoredUrlList;

 

/**

* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)

*/

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest) request;

HttpServletResponse res = (HttpServletResponse) response;

// получить текущий uri

String requestUri = req.getRequestURI();

 

boolean shouldBeIgnored = isIgnoredUrl(requestUri);

// проверяем "Это url, который нужно проигнорировать?"

//Если url в списке не отработаных и пользователь не залогинен,

//то перенаправляем на страницу login.jsp

if (!shouldBeIgnored && !ProfileTools.isLoggedIn(req)) {

res.sendRedirect(req.getContextPath() + "/login.jsp");

 

} else {

// pass the request along the filter chain

chain.doFilter(request, response); // выход из фильтра

}

}

 

/**

*

* @see Filter#init(FilterConfig)

*/

public void init(FilterConfig fConfig) throws ServletException {

// считаем параметры фильтра заданную в параметре web.xml ignore-urls

ignoredUrlList = new ArrayList<String>();

// в параметре fConfig хранится список параметров, которые заданы в блоке init-param

String urls = fConfig.getInitParameter("ignore-urls");

// преобразуем значение параметра из строки в список и запишем его в urlList

StringTokenizer token = new StringTokenizer(urls, ",");

while (token.hasMoreTokens()) {

ignoredUrlList.add(token.nextToken());

}

}

/**

* проверяем принадлежность параметра url к списку игнорируемых urlов

* @param url - url для проверки

*/

private boolean isIgnoredUrl(String url) {

for (String ignoredUrl : getIgnoredUrlList()) {

if (url.startsWith(ignoredUrl)) {

return true;

}

}

return false;

}

 

public ArrayList<String> getIgnoredUrlList() {

return ignoredUrlList;

}

 

public void setIgnoredUrlList(ArrayList<String> urlList) {

this.ignoredUrlList = urlList;

}

 

@Override

public void destroy() {

// TODO Auto-generated method stub

 

}

 

}

 

5. Создайте класс ProfileTools:

package by.bsac.profile;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

 

public class ProfileTools {

public static String SESSION_LOGGEDIN_ATTRIBUTE_NAME = "user";

/* метод возвращает true в том случае,

* если пользователь залогинился. в противном - false*/

public static boolean isLoggedIn(HttpServletRequest request) {

HttpSession session = request.getSession(false);

return session != null && session.getAttribute(SESSION_LOGGEDIN_ATTRIBUTE_NAME) != null;

}

}

 

6. Создадим страницу login.jsp

1. <%@ page language="java" contentType="text/html; charset=UTF-8"

2. pageEncoding="UTF-8"%>

3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

4. <html>

5. <head>

6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

7. <title>Login</title>

8. </head>

9. <body>

10. <form action="login" method="post">

11. <input type="hidden" name="authAction" value="login">

12. <p>Please login by

13. <label for="email">Email</label>

14. <input type="radio" name="authType" value="email" id="email" checked/>

15. or

16. <label for="userName">User name</label>

17. <input type="radio" name="authType" value="userName" id="userName" />

18. <input type="text" name="loginValue">

19. </p>

20. <label for="psw">Password</label>

21. <input type="password" name="psw" id="psw">

22. <p>The characters in a password field are masked (shown as asterisks or circles).</p>

23.

24. <input type="submit" value="Submit" />

25. </form>

26. </body>

27. </html>

 

7. Создайте сервлет LoginController

 

package by.bsac.profile;

 

import java.io.IOException;

 

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

 

/**

* Servlet implementation class LoginController

*/

public class LoginController extends HttpServlet {

private static final long serialVersionUID = 1L;

 

/**

* @see HttpServlet#HttpServlet()

*/

public LoginController() {

super();

// TODO Auto-generated constructor stub

}

 

/**

* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.sendRedirect("login.jsp");

}

 

/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String authAction = request.getParameter("authAction");

if (authAction.equals("login")){

login(request, response);

} else if (authAction.equals("logout")){

logout(request, response);

} else {

 

}

}

 

 

private void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

HttpSession session = request.getSession(false);

if (session!=null) {

session.invalidate();

}

response.sendRedirect("login.jsp");

 

}

 

private void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String authTypeParam = request.getParameter("authType");

Authenticator authenticator = new AuthenticatorImpl();

boolean isAuthentificated = false;

String password = request.getParameter("psw");

String authValue = request.getParameter("loginValue");

if (authTypeParam.equals("email")) {

isAuthentificated = authenticator.authenticateByUserEmail(authValue, password);

} else {

isAuthentificated = authenticator.authenticateByUserName(authValue, password);

}

if (isAuthentificated) {

HttpSession session=request.getSession();

session.setAttribute(ProfileTools.SESSION_LOGGEDIN_ATTRIBUTE_NAME, authValue);

response.sendRedirect("home.jsp");

}

else{

response.sendRedirect("error-login.jsp");

}

}

 

}

 

8. Создайте интерфейс Authenticator:

package by.bsac.profile;

 

public interface Authenticator {

public boolean authenticateByUserName(String username, String password);

public boolean authenticateByUserEmail(String email, String password);

}

 

9. Создайте класс AuthenticatorImpl, который имплементирует интерфейс:

package by.bsac.profile;

 

public class AuthenticatorImpl implements Authenticator {

private String username = "user";

private String password = "password";

private String email = "test@test.qwe";

 

@Override

public boolean authenticateByUserName(String username, String password) {

if ((getUsername().equalsIgnoreCase(username))

&& (getPassword().equals(password))) {

return true;

} else {

return false;

}

}

@Override

public boolean authenticateByUserEmail(String email, String password) {

if ((getEmail().equalsIgnoreCase(email))

&& (getPassword().equals(password))) {

return true;

} else {

return false;

}

}

 

public String getPassword() {

return password;

}

public String getUsername() {

return username;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

 

}

 

10. Создайте error-login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Login failed</title>

</head>

<body>

Login failed, please <a href="/BSAC/login.jsp">try again</a>.

</body>

</html>

 

11. Создайте home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Home</title>

</head>

<body>

<h1>

Hello, <%= session.getAttribute("user") %>

</h1>

<form action="logout" method="post">

<input type="hidden" name="authAction" value="logout">

<input type="submit" value="Logout" />

</form></body>

</html>

 

12. Запустите приложение и попытайтесь открыть любой url. Вас перенаправит на страницу login.jsp. При корректном вводе имени пользователи/или email и пароля, перенаправит на страницу home.jsp.

 

 

Задания для самостоятельного решения:

Для всех заданий использовать авторизованный вход в приложение. Параметры авторизации, дату входа в приложение и время работы сохранять в сессии.

1. В тексте, хранящемся в файле, определить длину содержащейся в нем максимальной серии символов, отличных от букв. Все такие серии символов с найденной длиной сохранить в cookie.

2. В файле хранится текст. Для каждого из слов, которые вводятся в текстовые поля HTML-документа, вывести в файл cookie, сколько раз они встречаются в тексте.

3. В файле хранится несколько стихотворений, которые разделяются строкой, состоящей из одних звездочек. В каком из стихотворений больше всего восклицательных предложений? Результат сохранить в файле cookie.

4. Записать в файл cookie все вопросительные предложения текста, которые хранятся в текстовом файле.

5. Код программы хранится в файле. Подсчитать количество операторов этой программы и записать результаты поиска в файл cookie, перечислив при этом все найденные операторы.

6. Код программы хранится в файле. Сформировать файл cookie, записи которого дополнительно слева содержат уровень вложенности циклов. Ограничения на входные данные: ключевые слова используются только для обозначения операторов, операторы цикла записываются первыми в строке.

7. Подсчитать, сколько раз в исходном тексте программы, хранящейся на диске, встречается оператор, который вводится с терминала. Сохранить в файле cookie также номера строк, в которых этот оператор записан. Ограничения: ключевые слова используются только для обозначения операторов.

8. Сохранить в cookie информацию, введенную пользователем, и восстановить ее при следующем обращении к странице.

9. Выбрать из текстового файла все числа-полиндромы и их количество. Результат сохранить в файле cookie.

10. В файле хранится текст. Найти три предложения, содержащие наибольшее количество знаков препинания, и сохранить их в файле cookie.

11. Подсчитать количество различных слов в файле и сохранить информацию в файл cookie.

12. В файле хранится код программы. Удалить из текста все комментарии и записать измененный файл в файл cookie.

13. В файле хранится HTML-документ. Проверить его на правильность и записать в файл cookie первую строку и позицию (если они есть), нарушающую правильность документа.

14. В файле хранится HTML-документ. Найти и вывести все незакрытые теги с указанием строки и позиции начала в файл cookie.

15. В файле хранится HTML-документ с незакрытыми тегами. Закрыть все незакрытые теги так, чтобы документ HTML стал правильным, и записать измененный файл в файл cookie.

16. В файле хранятся слова русского языка и их эквивалент на английском языке. Осуществить перевод введенного пользователем текста и записать его в файл cookie.

17. Выбрать из файла все адреса электронной почты и сохранить их в файле cookie.

18. Выбрать из файла имена зон (*.by, *.kz и т. д.), вводимые пользователем, и сохранить их в файле cookie.

19. Выбрать из файла все заголовки разделов и подразделов (оглавление) и записать их в файл cookie.

20. При работе приложения сохранять в сессии имена всех файлов, к которым

обращался пользователь.