Cодержание
- Введение
- Почему нужен Server-Filter?
- Что может сделать Servlet-Filter?
- Создать Project для начала с Servlet-Filter
- Конфигурация среды запуска
- Первый пример Servlet-Filter
- Модель работы Filter
- Инициализированные параметры Servlet-Filter
- Servlet-Filter url-pattern
- Servlet-Filter используя Annotation
- Установка соединения JDBC в Filter
- Руководство программирования JSP
Руководство Java Servlet Filter
View more Tutorials:
- Введение
- Почему нужен Server-Filter?
- Что может сделать Servlet-Filter?
- Создать Project для начала с Servlet-Filter
- Конфигурация среды запуска
- Первый пример Servlet-Filter
- Модель работы Filter
- Инициализированные параметры Servlet-Filter
- Servlet-Filter url-pattern
- Servlet-Filter используя Annotation
- Установка соединения JDBC в Filter
- Руководство программирования JSP

Статья основана на:
-
Eclipse 4.6 NEON
-
Tomcat 8.x
Вы должны иметь знание о Servlet перед тем, как прочитать статью про Servlet- Filter, если вы начинающий, вы можете посмотреть Java Servlet по ссылке:
Ситуация 1:
Обычно, когда пользователь запрашивает веб-страницу, запрос будет отправлен на server, он должен проходить через фильтры (Filter) до того как дойти до запрошенной страницы, как в изображении ниже.

Ситуация 2:
Однако существуют ситуации запроса пользователя, которые не проходят все уровни Filter.

Ситуация 3:
Ситуация когда пользователь отправляет запрос одной страницы (page1), этот запрос проходит через Filter, у определенного filter запрос будет перенаправлен на другую страницу (page2).
Пример ситуации:
- Пользователь посылает запрос, чтобы посмотреть страницу с личной информацией.
- Запрос будет отправлен на Server.
- Она проходит Filter, который записывает информацию log.
- Идет к Filter и проверяет вошел ли пользователь в систему, filter проверил, и увидел, что пользователь не вошел в систему, то перенаправляет запрос на страницу входа в систему пользователя.

Иногда у вас есть только одно понятие это Filter используется чтобы перенаправить запрос пользователя на другую страницу, или блокировать доступ к определенному сайту, если пользователь не имеет прав. Или используется для записи информации Log.
На самом деле Filter может быть использован для кодирования вебсайта (encoding). Например, установить кодировку UTF-8 для страницы. Открыть и закрыть соединение к Database и подготовить транзакцию JDBC (JDBC Transaction).
Сначала мы создаем WebApp проект для работы с Servlet-Filter.
- File/New/Other...

Ввести:
- Project Name: ServletFilterTutorial



Проект создан:

Создать файл index.html:

index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Home Page</title> </head> <body> <h2>Servlet-Filter Tutorial</h2> </body> </html>
Щелкните правой кнопкой мыши на проект и выберите Properties




Щелкните правой кнопкой мыши на проект и выберите:
- Run As/Run on Server




ОК!, Все готово, чтобы начать изучать Servlet- Filter.
Kласс Servlet Filter, который выполняет interface javax.servlet.Filter. Класс LogFilter ниже записывает время и путь запроса, отправленного к WebApp.
LogFilter.java
package org.o7planning.tutorial.servletfilter; import java.io.IOException; import java.util.Date; 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; public class LogFilter implements Filter { public LogFilter() { } @Override public void init(FilterConfig fConfig) throws ServletException { System.out.println("LogFilter init!"); } @Override public void destroy() { System.out.println("LogFilter destroy!"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String servletPath = req.getServletPath(); System.out.println("#INFO " + new Date() + " - ServletPath :" + servletPath // + ", URL =" + req.getRequestURL()); // Разрешить request продвигаться дальше. (Перейти данный Filter). chain.doFilter(request, response); } }
Configure filter in web.xml:
Добавить в фрагмент конфигурации в web.xml:
<!-- Declaring a filter named logFilter --> <filter> <filter-name>logFilter</filter-name> <filter-class>org.o7planning.tutorial.servletfilter.LogFilter</filter-class> </filter> <!-- Declare the path (of the page) will have the effect of logFilter /* for all paths --> <filter-mapping> <filter-name>logFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletFilterTutorial</display-name> <filter> <filter-name>logFilter</filter-name> <filter-class>org.o7planning.tutorial.servletfilter.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>logFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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> </web-app>
Перезапустите приложение:

Вы можете запустить следующие ссылки в браузере, здесь есть ссылки на источники, которые не существуют на вашем WebApp, но они все находятся под влиянием LogFilter.

Информация Log записывается на экране Console:

Следующий код позволяет запросу пройти фильтр (Filter) чтобы продолжить до цели (желаемой страницы).
// Разрешить request продвигаться дальше. // Может прийти к следующему Filter или к цели. chain.doFilter(request, response);
Когда пользователь посылает запрос, цель (target) может быть источником данных (resource) или servlet. Запрос должен пройти через Filter и, наконец дойти до цели. Filter и цели сцеплены (chained) вместе как в изображении ниже:

Используйте chain.doFilter(request,response), чтобы переместить запрос к следующей ссылке. Если в filter chain.doFilter (request, response) не вызывается, запрос пользователя не достигнет цели, он останавливается в этом фильтре.
Как и с Servlet, вы можете инициализировать параметры для Filter. В примере ниже, Filter имеет обязанность записи log в файл, вы можете настроить конфигурацию в web.xml имя файла для записи.
Log2Filter.java
package org.o7planning.tutorial.servletfilter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class Log2Filter implements Filter { private String logFile; public Log2Filter() { } @Override public void init(FilterConfig fConfig) throws ServletException { this.logFile = fConfig.getInitParameter("logFile"); System.out.println("Log File " + logFile); } @Override public void destroy() { System.out.println("Log2Filter destroy!"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (this.logFile != null) { // Записать информацию Log в File. this.logToFile(this.logFile); } // Разрешить данный request пройти дальше. (Пройти этот Filter). chain.doFilter(request, response); } private void logToFile(String fileName) { // Записать log в file.. System.out.println("Write log to file " + fileName); } }
Добавьте конфигурацию в web.xml:
<filter> <filter-name>log2Filter</filter-name> <filter-class>org.o7planning.tutorial.servletfilter.Log2Filter</filter-class> <init-param> <param-name>logFile</param-name> <param-value>AppLog.log</param-value> </init-param> </filter> <filter-mapping> <filter-name>log2Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletFilterTutorial</display-name> <filter> <filter-name>logFilter</filter-name> <filter-class>org.o7planning.tutorial.servletfilter.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>logFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>log2Filter</filter-name> <filter-class>org.o7planning.tutorial.servletfilter.Log2Filter</filter-class> <init-param> <param-name>logFile</param-name> <param-value>AppLog.log</param-value> </init-param> </filter> <filter-mapping> <filter-name>log2Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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> </web-app>
Существуют 3 способа как вы можете конфигурировать url-pattern для Filter:
URL Pattern | Example |
/* | http://example.com/contextPath |
http://example.com/contextPath/status/abc | |
/status/abc/* | http://example.com/contextPath/status/abc |
http://example.com/contextPath/status/abc/mnp | |
http://example.com/contextPath/status/abc/mnp?date=today | |
*.map | http://example.com/contextPath/status/abc.map |
http://example.com/contextPath/status.map?date=today | |
В примерах выше Filter конфигурируется в web.xlm, однако с WebApp версии 3 и далее, вы можете использовать Annotation для конфигурации Filter.
Этот пример иллюстрирует, когда пользователь запрашивает просмотр файла изображения (JPG, PNG или GIF), filter будет проверять, существует изображение или нет, при отсутствии изображения, Filter перенаправит запрос на файл изображения по умолчанию.
Этот пример иллюстрирует, когда пользователь запрашивает просмотр файла изображения (JPG, PNG или GIF), filter будет проверять, существует изображение или нет, при отсутствии изображения, Filter перенаправит запрос на файл изображения по умолчанию.
Сначала скопируйте 2 изображения flower.png & image-not-found.png в папках images на вашем WebApp.

ImageFilter.java
package org.o7planning.tutorial.servletfilter; import java.io.File; import java.io.IOException; 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.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebFilter(urlPatterns = { "*.png", "*.jpg", "*.gif" }, initParams = { @WebInitParam(name = "notFoundImage", value = "/images/image-not-found.png") }) public class ImageFilter implements Filter { private String notFoundImage; public ImageFilter() { } @Override public void init(FilterConfig fConfig) throws ServletException { // ==> /images/image-not-found.png notFoundImage = fConfig.getInitParameter("notFoundImage"); } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; // ==> /images/path/my-image.png // ==> /path1/path2/image.pngs String servletPath = req.getServletPath(); // Абсолютная ссылка исходной папки WebApp (WebContent). String realRootPath = request.getServletContext().getRealPath(""); // Абсолютная ссылка к файлу изображения. String imageRealPath = realRootPath + servletPath; System.out.println("imageRealPath = " + imageRealPath); File file = new File(imageRealPath); // Проверить, существуют ли изображения. if (file.exists()) { // Разрешить request продвинуться далее. (Пройти этот Filter). // (Чтобы пройти дальше к запрошенному файлу изображений). chain.doFilter(request, response); } else if (!servletPath.equals(this.notFoundImage)) { // Redirect (Перенаправить) к файлу изображения 'image not found'. HttpServletResponse resp = (HttpServletResponse) response; // ==> /ServletFilterTutorial + /images/image-not-found.png resp.sendRedirect(req.getContextPath() + this.notFoundImage); } } }
Перезапустите ваше приложение и запустите следующие URL:

С ссылкой запроса изображения, а изображение не существует, то она будет перенаправлена к изображению по умолчанию.

В приведенном выше примере вы можете также использовать пересылка (Forward) вместо того, чтобы перенаправить (Redirect) запрос на изображение по умолчанию в случае, если запрошенное изображение, не существует.
// Redirect: // ==> /ServletFilterTutorial + /images/image-not-found.png response.sendRedirect(request.getContextPath()+ this.notFoundImage); // Forward: request.getServletContext().getRequestDispatcher(this.notFoundImage).forward(request, response);
Вы можете создать объект Connection соединить с JDBC в Servlet для обработки с Database. Но вы также можете создать объект Connection соединить с JDBC в Filter, и он будет работать с разными Servlet. И вы можете использовать этот Connection на протяжении всего пути запроса. Чтобы легче было понять, вы можете посмотреть на иллюсстрацию ниже:

ConnectionUtils это класс, который создает объект Connection, соединяя к database, в данной статье я буду детально знакомить со способом, как вы получаете объект Connection.
Вы можете просмотреть статью JDBC по ссылке:
ConnectionUtils.java
package org.o7planning.tutorial.servletfilter.conn; import java.sql.Connection; public class ConnectionUtils { public static Connection getConnection() { // Создать Connection (соединение) к Database. Connection conn = null; // ..... return conn; } public static void closeQuietly(Connection conn) { try { conn.close(); } catch (Exception e) { } } public static void rollbackQuietly(Connection conn) { try { conn.rollback(); } catch (Exception e) { } } }
MyUtils.java
package org.o7planning.tutorial.servletfilter.conn; import java.sql.Connection; import javax.servlet.ServletRequest; public class MyUtils { public static final String ATT_NAME = "MY_CONNECTION_ATTRIBUTE"; // Сохранить объект Connection в атрибут (attribute) в request. // Сохраненная информация существует только во время запроса (request) // до тех пор, когда данные возвращаются приложению пользователя. public static void storeConnection(ServletRequest request, Connection conn) { request.setAttribute(ATT_NAME, conn); } // Получить объект Connection сохраненный в атрибуте request. public static Connection getStoredConnection(ServletRequest request) { Connection conn = (Connection) request.getAttribute(ATT_NAME); return conn; } }
Я объявляю URL-pattern для JDBCFilter это /*, этот filter будет работать со всеми запросами пользователей.
JDBCFilter.java
package org.o7planning.tutorial.servletfilter.conn; import java.io.IOException; import java.sql.Connection; 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.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; @WebFilter(urlPatterns = { "/*" }) public class JDBCFilter implements Filter { public JDBCFilter() { } @Override public void init(FilterConfig fConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; // String servletPath = req.getServletPath(); // Открыть Connection (соединение) только для request со специальной ссылкой // (Например ссылка к servlet, jsp, ..) // Избегать открытие Connection для обычноых запросов // (Например image, css, javascript,... ) if (servletPath.contains("/specialPath1") || servletPath.contains("/specialPath2")) { Connection conn = null; try { // Создать объект Connection подключенный к database. conn = ConnectionUtils.getConnection(); // Настроить автоматически commit = false, чтобы активно контролировать. conn.setAutoCommit(false); // Сохранить в атрибут (attribute) в request. MyUtils.storeConnection(request, conn); // Разрешить request продвигаться дальше (Пройти этот Filter). chain.doFilter(request, response); // Вызвать commit() чтобы завершить транзакцию (transaction) с DB. conn.commit(); } catch (Exception e) { ConnectionUtils.rollbackQuietly(conn); throw new ServletException(); } finally { ConnectionUtils.closeQuietly(conn); } } // Для обычных request. else { // Разрешить request продвигаться дальше (Пройти этот Filter). chain.doFilter(request, response); } } }
В следующем Filter или в servlet или JSP-странице (в одном запросе), вы можете получить объект Connection, который сохранился в атрибуте (attribute) запроса:
Connection conn = (Connection) request.getAttribute(ATT_NAME); // Или Connection conn = MyUtils.getStoredConnection();
Далее вы можете изучить про JSP: