1. Метод init()

І ще пара корисних дрібниць. Звісно, я про ініціалізацію сервлета. Як ти вже знаєш, після того, як веб-сервер створив об'єкт сервлета та помістив його в контейнер, він викликає у сервлета метод init(). Ти можеш перевизначити цей метод та ініціалізувати у ньому все, що тобі потрібно.

А чому б не використати конструктор?

Тому що процес створення сервлету відбувається приблизно так:

  • Створюємо об'єкт, успадкований від HttpServlet
  • Створюємо об'єкт ServletContext, додаємо його змінну сервлета
  • Створюємо об'єкт ServletConfig, додаємо його змінну сервлета
  • Веб-сервер приєднує сервлет до контейнера
  • Викликаємо метод init()

У конструкторі твого сервлета ще багато його внутрішніх змінних не ініціалізовано. Контейнер нічого не знає про твій сервлет, твій сервлет нічого не знає про його контекст. Думаю, тут і так зрозуміло.

Давай напишемо сервлет, який при ініціалізації знаходить properties-файл з налаштуваннями:


public class PropertiesServlet extends HttpServlet {
    public init() {
         try (InputStream input = new FileInputStream("c:/path/to/config.properties")) {

             Properties prop = new Properties();
             prop.load(input);

             String databaseURL = prop.getProperty("db.url");
             String databaseUser = prop.getProperty("db.user ");
             String databasePassword = prop.getProperty("db.password");
	 }
  }
}

Тут ми створюємо об'єктProperties і завантажуємо в нього дані із файлу config.properties. Ну і надалі можна діставати з об'єкту Properties різні параметри, такі як дані для доступу до бази даних, наприклад.

2. Як правильно завантажити properties-файл

До речі, а що робити, якщо твій сервлет виконується не на комп'ютері?

Скажімо, написали його тут, а він виконується на сервері десь в іншій частині світу. Або на кількох серверах. Як правильно завантажити properties-файл у цьому випадку?

Гарне питання. Зазвичай у процесі роботи сервлет знає лише відносний шлях своїх properties-файлів, але не знає їхнього абсолютного шляху, оскільки war-файли з сервлетами можуть зберігатися будь-де.

Отже, нам потрібно дізнатися шлях, де зберігається наш сервлет (сервлет вже проініціалізовано) і додати до нього відносний шлях :)

Виглядає це приблизно так:


String path = absoluteServletPath + "относительный путь";

І, як завжди, таке елементарне завдання часто має своє невелике “але”. Твій сервлет та його properties-файл зберігаються всередині архіву :) Не обов'язково, звичайно, але й таке буває. properties-файл часто зберігається всередині jar-або war-файлів.

Тобто фізичного шляху на диску твій файл може й не мати. Але оскільки контейнеру вдалося завантажити твій сервлет, він, швидше за все, зможе завантажити і твій properties-файл.

Для цього тобі потрібно отримати об'єкт завантажувача класу (ClassLoader) та попросити його завантажити твій файл. Ось як це виглядатиме:


ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream stream = loader.getResourceAsStream("/config.properties");

Properties prop = new Properties();
prop.load(stream);

3. Метод getConfig()

До речі, не всі параметри можна передавати до сервлета у properties-файлах. Наприклад, твій сервлет взаємодіє з іншими сервлетами в розподіленому вебзастосунку.

Тоді потрібно зробити так, щоб контейнер передав твоєму сервлету всю необхідну інформацію, коли він буде викликати його метод init(). Ба більше, він саме так і робить.

У твого сервлета (адже ти пам'ятаєш, що він успадкований від класу HttpServlet) є метод getServletConfig(), який повертає об'єкт ServletConfig, що створено та ініціалізовано контейнером. Цей об'єкт має такі методи:

getInitParameterNames() Повертає список імен параметрів сервлету
getInitParameter(String name) Повертає параметр сервлета за його ім'ям
getServletName() Повертає власне ім'я сервлета
getServletContext() Повертає об'єкт ServletContext

Давай напишемо сервлет, який повертає список своїх параметрів з ServletConfig. Класти їх туди будемо через файл web.xml:

	<web-app> 
 	
        <servlet> 
            <servlet-name>Print-Servlet</servlet-name> 
            <servlet-class>PrintServlet</servlet-class> 
            <init-param> 
                <param-name>jdbc-driver</param-name> 
    	        <param-value>sun.jdbc.odbc.JdbcOdbcDriver</param-value> 
	        </init-param> 
        </servlet> 
  	
        <servlet-mapping> 
            <servlet-name>Print-Servlet</servlet-name> 
            <url-pattern>/print</url-pattern> 
        </servlet-mapping> 
  	
    </web-app>

Отримати свої параметри сервлет може за допомогою коду:


public class PrintServlet extends HttpServlet {
    public void init() {
        ServletConfig config = this.getServletConfig();
        Enumeration<String> initParameterNames = config.getInitParameterNames();

        while (initParameterNames.hasMoreElements()){
       	     String key = initParameterNames.nextElement();
             System.out.println("%s: %s\n", key, config.getInitParameter(key));
    	}
  }
}