Приклад простого серверного додатка на java

Програма UploadServer - приклад найпростішого серверного додатка на мові Java. Наводиться вихідний код з докладними поясненнями роботи кожного фрагмента. Прдставляет інтерес для тих, хто тільки починає освоювати програмування на мові Java.

Програма UploadServer - найпростіший вузькоспеціалізований web-сервер, призначений для закачування файлів на комп'ютер, на якому він запущений. Він був написаний мною на мові Java, причому я переслідував дві мети: зробити програму, якою зручно перекидати файли в локальній (і не тільки) мережі без установки і настройки громіздкого софта, а також зробити простий, але функціональний і багатий різними «фичами» приклад серверного додатки на Java.

Порядок роботи з програмою не менше простий, ніж вона сама. Ви запускаєте програму, вказавши в командному рядку номер порту (він повинен бути дозволений в фаєрвол для доступу зовні), після чого з комп'ютера, де є файли для завантаження, заходите на свій комп'ютер звичайним web-браузером. У формі, що з'явилася вибираєте потрібний файл кнопкою "Browse." І натискаєте кнопку "Upload". Після успішного завантаження файлу буде відображена сторінка з зазначенням розміру і MD5-суми завантаженого файлу.

Для роботи програми потрібно Java Runtime Environment версії не нижче 1.4 (я перевіряв на 1.6, але якщо вірити документації, всі необхідні функції з'явилися не пізніше 1.4). Завантажити останню версію платформу можна з офіційного сайту Java. Якщо ви плануєте не тільки дивитися на програму, але і модифікувати її, то вам буде потрібно ще і Java-компілятор, який разом з іншими корисними в розробці утилітами входить до складу Java Development Kit (JDK), який можна завантажити там же.

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

Програма поставляється у вигляді архіву містить вихідний текст (файл UploadServer.java) і відкомпільований клас (файл UploadServer.class)

Програма UploadServer (архів Zip, 5 k)

Для запуску програми наберіть в каталозі з відкомпільоване файлом UploadServer.class наступний рядок:

Хорошим тоном вважається вставляти ці рядки в кожен файл вихідного коду, хоча в разі великих проектів ліцензію зручніше винести в окремий файл, а в исходниках залишити тільки згадка про цей файл.

Імпорт використовуваних класів

Програма на мові Java складається з класів, які групуються в пакети, утворюючи ієрархічну структуру на зразок файлової системи. При використанні класів з інших пакетів, їх необхідно імпортувати за допомогою директиви import. Як параметр можна вказувати ім'я конкретного класу або зірочку після назви пакунка, що буде означати імпорт всіх класів з пакета.

Тема класу і визначення змінних

конструктор класу

Конструктор - спеціальна функція, що викликається при створенні об'єкта. Тут конструктор отримує в якості аргументу номер порту, на якому буде створено сервер, створює серверний сокет, слухає вказаний порт, і друкує повідомлення про успішний запуск.
При створенні сокета може виникнути виняток, оскільки конструктор і не виконує жодних його самостійно, а передає виключення в викликає код, про що повідомляється в заголовку функції (throws Exception).

Функція, з якої починається виконання потоку

Функція обробки з'єднання з клієнтом - визначення змінних

Читання заголовка клієнтського запиту

Обробка запиту типу "GET"

Якщо перший рядок запиту починається з рядка "GET", клієнту просто відправляється заздалегідь сформований відповідь з HTML-документом, що містить форму для відправки файлу.

Обробка запиту типу "POST", визначення змінних

У разі, якщо тип запиту клієнта починається з рядка "POST", ми припускаємо, що була відправлена ​​форма з завантажуваних файлом. Спочатку по параметру Content-Length з заголовка визначається довжина переданих даних. Далі, оскільки дані передаватимуться клієнтом в форматі MIME, необхідно отримати роздільник з параметра Content-Type і сформувати з нього рядок-роздільник для визначення кінця переданого файлу (додаток А другий частини опису формату MIME). Для пошуку оригінального імені файлу (на клієнтській машині) формується регулярний вираз в змінної fileNamePattern. Для підрахунку контрольної суми прийнятого файлу створюється об'єкт MessageDigest з використанням алгоритму хешування MD5. Також визначаються змінні для записувача (writer), імені файлу, створюється буфер для читання файлу buffer.

Цикл читання тіла запиту, обробка заголовка форми

При відправці форми по HTTP в форматі multipart / form-data для кожного поля file в формі створюється блок, розділений рядками-обмежувачами, який складається з текстових полів з ім'ям файлу, а також відокремленим від них символом нового рядка блоком двійкових даних самого файлу. У цій частині коду ми Новомосковськ текстові поля і шукаємо в них ім'я файлу за допомогою регулярного виразу. Оскільки в даному випадку регулярний вираз охоплює не всю рядок, а тільки її частину, для перевірки наявності підрядка використовується метод find () замість методу matches () в розборі заголовка запиту.
Після читання порожнього рядка виробляється створення об'єктів для читання самого надісланого файлу. Якщо ім'я файлу не було знайдено, створюється виключення типу RuntimeException з пояснювальним текстовим рядком. Якщо ж ім'я було знайдено, створюється вихідний файловий потік в файл з вказаним ім'ям в поточному каталозі. Також створюється прозорий потік DigestOutputStream, який під час запису в нього надсилає копію даних в об'єкт digest для підрахунку «на льоту» контрольної суми прийнятого файлу. Для перетворення символів в байти для запису створюється записувача з використанням того ж Charset, що і при читанні.

Читання даних відправленого файлу і запис їх на диск

Завершення прийому файлу, відправка відповіді клієнту

Після завершення циклу читання закривається записувача і виводиться діагностичне повідомлення. Потім обчислюється контрольна сума MD5, отриманий масив байт перетвориться в шістнадцяткову рядок і формується відповідь клієнтові про успішну завантаженні файлу.

Службова функція перекладу байта в шістнадцяткову рядок

Функція використовується для друку MD5-суми у відповіді клієнту. Вона отримує байт, перетворює його в ціле з відкиданням старших байтів (оскільки байт - знаковий тип, то в разі негативних значень у цілого старші байти будуть мати значення 0xFF). Потім використовується статичний метод toHexString класу Integer, який перетворює ціле в шістнадцяткову рядок. Цей метод друкує тільки значущі цифри, тому для чисел, менших 16, необхідно доповнити отриману рядок символом "0" зліва.

функція main

Виконання програми на мові Java починається з функції main класу, який вказаний в якості стартового в командному рядку. Це статична функція, вона викликається, коли жодного об'єкта даного класу ще не створено. Функція повинна бути описана саме так, як в даному прикладі, інакше при запуску програми виникне помилка java.lang.NoSuchMethodError (не найден метод).
Функція main отримує параметри командного рядка у вигляді масиву рядків. У нашому випадку функція main перевіряє кількість аргументів, порівнюючи довжину масиву з одиницею, якщо немає жодного аргументу, то в консоль друкується інформація про формат командного рядка і програма завершується. Якщо ж користувач вказав хоча б один аргумент, то створюється об'єкт класу UploadServer, причому конструктору передається перший аргумент, перетворений в число, а потім у створеного об'єкту викликається метод start. Це метод базового класу Thread, який створює новий потік, викликає в ньому метод run і повертає управління. Таким чином перший потік, в якому була викликана функція main, завершується, але програма продовжує працювати в новому потоці до завершення функції run.