Jakarta Servlets

Problem

  • Каждый запрос несет изолированный контекст.

  • Дублирование кода на уровне Servlets.

  • Например: создать пользователя и отобразить пользователя клиенту:

    • Создать пользователя - один Servlet.

    • Отобразить пользователя - второй Servlet.

    • Но пишем все в одном.

Solution

  • Хранить state.

  • Использовать методы взаимодействия между Jakarta Servlet.

Переадресация и перенаправление запроса

Перенаправление запроса

  • Один запрос может выполняться несколькими Servlets.

  • Механизм перенаправления запросов позволяет передать выполнение запроса другому запрашиваемому ресурсу.

  • Чтобы сделать перенаправление, используется специальный объект класса RequestDispatcher.

Перенаправление запроса

  • Создается он методом getRequestDispatcher() объекта класса ServletContext.

  • Этот метод в качестве аргумента берет URL запрашиваемого ресурса.

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher =
            context.getRequestDispatcher("/servlets/SecondServlet");
    }
}

include()

  • Если необходимо вставить результат работы второго Servlet, и продолжить выполнение, используется метод include().

  • Методу надо передать объекты запроса и ответа: dispatcher.include(request, response)

  • В результате работы этого метода будет вызван второй Servlet

  • Он выполнит свою часть работы

  • После этого первый Servlet продолжит выполнение.

include()

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher =
            context.getRequestDispatcher("/servlets/SecondServlet");
        dispatcher.include(request, response);
        // This code will run after include()
    }
}

forward()

  • Запрос можно также перенаправить другим методом: forward().

  • Данный метод отличается от include() тем, что не возвращает обработку в вызвавший запрос, а сам заканчивает обработку запроса.

  • Так как вызванный по forward() Servlet сам будет заканчивать обработку запроса, все что стоит после него выполнено не будет.

forward()

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher =
            context.getRequestDispatcher("/servlets/SecondServlet");
        dispatcher.forward(request, response);
        // This code won't run after forward()
    }
}

sendRedirect()

  • Запрос можно переслать другому Servlet, но при этом инициировать новый запрос от браузера.

  • Для этого используется метод sendRedirect() объекта HttpServletResponse.

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        response.sendRedirect("/servlets/SecondServlet");
    }
}

Redirect vs Forward

Redirect vs Forward

Обмен информацией

HTTP Request

  • Servlets могут обмениваться данными через запрос.

  • Для этого используется метод setAttribute() у объекта запроса.

  • Переменные, создаваемые в объекте запроса будут существовать только пока существует данный запрос.

  • То есть, этот метод имеет смысл использовать только если один запрос обрабатывают несколько Servlets, например с помощью методов include() или forward().

  • Как только закончится выполнение запроса, будет удален его объект, и соответственно, потеряны хранимые в нем данные.

HTTP Request

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        request.setAttribute("userId", "us1000");

        ServletContext context = getServletContext();
        RequestDispatcher dispatcher =
            context.getRequestDispatcher("/servlets/SecondServlet");
        dispatcher.forward(request, response);
    }
}

HTTP Request

  • Например, если происходит формирование разных частей страницы в разных Servlets

  • Основной Servlet должен сообщить другому, формирующему заголовок, какое название туда вставить

  • Основной Servlet может положить нужное значение в объект запроса:

request.setAttribute("header", "value");

HTTP Request

  • После чего, Servlet формирующий шапку страницы получает это значение

  • Выводит его на страницу:

String headVal = (String) request.getAttribute("header");
out.println(headVal);

ServletContext and ServletConfig

Начальные данные Servlet и приложения

Файл web.xml позволяет записать различные исходные данные, как для отдельных Servlets, так и для приложения в целом.

ServletContext

Чтобы указать начальные данные, доступные всему приложению, в файле web.xml используются теги <context-param>.

<context-param>
    <param-name>contextParam</param-name>
    <param-value>context param value</param-value>
</context-param>

ServletContext

  • Для получения начальных данных приложения нужно воспользоваться объектом класса ServletContext

  • Для этого нужно вызвать метод getInitParameter(String paramName).

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        ServletContext servletCont = request.getServletContext();
        out.println(servletCont.getInitParameter("contextParam"));
    }
}

ServletContext

  • Так же в рамках ServletContext можно обмениваться информацией

  • setAttribute() - задает значение в контекст

  • getAttribute() - получает значение из контекста

ServletConfig

Если исходные данные предназначены не для всего приложения, а только для одного Servlet, используется тег <init-param>, находящийся внутри тега <servlet>.

<servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>servlet.TestServlet</servlet-class>
    <init-param>
        <param-name>initParam</param-name>
        <param-value>init param value</param-value>
    </init-param>
</servlet>

ServletConfig

Для получения начальных данных Servlet нужно воспользоваться объектом класса ServletConfig, вызвав метод getInitParameter(String paramName).

public class FirstServlet extends HttpServlet {
    private ServletConfig sc;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        sc = config;
    }

    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println(sc.getInitParameter("initParam"));
    }
}

State

State

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

  • Для обмена можно использовать собственные механизмы реализованные в Servlet.

  • Так же можно воспользоваться хранением state (состояния).

  • Т.е. хранить некоторые данные (они же state) для конкретного клиента.

State

  • State можно хранить на Client или Server.

  • Хранение state на Client, если используется браузер, можно осуществлять с помощью cookies

  • Хранение state на Server, можно осуществлять с помощью session.

Cookies

Cookies

  • Cookies (куки) — информация, хранящаяся в браузере конечного пользователя.

  • Они хранятся в текстовом виде

  • Они доступны любому пользователю, имеющему непосредственный доступ к данному браузеру.

Cookies

  • Cookie состоит из следующей информации:

    • Имени cookie

    • Значения

    • Срока хранения

    • Домена, его создавшего

Создание и добавление

  • Для создания Cookie используется класса Cookie пакета javax.servlet.http.

  • Объект создается обычным образом с помощью оператора new, конструктор имеет два параметра.

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        Cookie myCookie = new Cookie("testCookie", "cookieValue");
        myCookie.setMaxAge(24 * 60 * 60);
        response.addCookie(myCookie);
    }
}

Получение cookies

  • Если в Servlet вы используете Writer для вывода информации на страницу, надо закончить всю работу с cookie до его создания.

  • Для того, что бы получить значение уже существующей cookie, следует воспользоваться специальным методом getCookies() объекта HttpServletRequest.

  • Этот объект возвращает массив из объектов класса Cookie.

Получение cookies

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        Cookie[] myCookies = request.getCookies();
        String cookieName = "testCookie";
        String cookieValue = "";
        for (int i = 0; i < myCookies.length; i++) {
            Cookie cookie = myCookies[i];
            if (cookieName.equals(cookie.getName())) {
               cookieValue = cookie.getValue();
               break;
            }
        }
    }
}

Session

Session

  • Session (сессия) — набор данных.

  • Хранятся на сервере (обычно в оперативной памяти).

  • Хранение начиная с первого захода пользователя.

  • Хранение заканчивается после закрытия браузера.

  • Если хранение осуществляется в оперативной памяти, тогда после перезагрузки сервера.

Session

  • В отличие от cookies, данные сессии хранятся не в браузере пользователя, а на сервере.

  • У пользователя хранится только идентификатор сессии (обычно как cookie).

  • Благодаря которому, можно определить, что это именно тот пользователь с той сессией.

Создание

  • Чтобы начать работу с сессией, надо создать ее объект.

  • Объект не создается обычным образом, а получается методом getSession() объекта HttpServletRequest.

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        HttpSession session = request.getSession();
    }
}

Добавление данных

  • В session можно занести значение с помощью метода setAttribute(String name, Object value).

  • name - имя переменной в сессии, value - значение переменной.

  • Следует обратить внимание, что тип второго аргумента - Object.

  • Т.е. в session может храниться любой объектный тип, а не только строка, как в случае с cookies.

Добавление данных

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        HttpSession session = request.getSession();
        session.setAttribute("userId", "us1000");
    }
}

Получение данных

  • Чтобы получить данные занесенные в сессию, можно воспользоваться методом getAttribute(String name)

  • Он возвращает ссылку на хранимый объект.

  • Возвращаемое значение имеет тип Object.

  • При получении значения должно использоваться приведение типов.

Получение данных

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        HttpSession session = request.getSession();
        String str = (String) session.getAttribute("userId");
    }
}

Methods Session

  • invalidate() уничтожение сессии.

  • removeAttribute(String name) удаление переменной в сессии.

  • isNew() определяет, является ли сессия только что созданной, и возвращает соответствующее логическое значение.

Methods Session

  • getCreationTime() возвращает дату создания сессии в виде большого целого числа.

  • getLastAccessedTime() возвращает дату последнего обращения в виде большого целого числа.

  • getMaxInactiveInterval() возвращает временной интервал в секундах, сколько сессия может существовать на сервере без обращений к ней.

???

Какие ошибки присутствуют в следующем коде?

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse resp)
        throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();
        String str = session.getAttribute("value");
        out.println("String length:" + str.length());
    }
}