Java Servlet API: полное руководство по созданию веб-приложений

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Java-разработчики, желающие углубить свои знания в создании веб-приложений
  • Студенты и начинающие программисты, изучающие веб-разработку на Java
  • Профессионалы, работающие с фреймворками, желающие понять основы работы сервлетов

    Java Servlet API — мощный инструмент для создания динамических веб-приложений, выдержавший проверку временем. Несмотря на появление множества современных фреймворков, сервлеты остаются фундаментальной технологией, понимание которой критически важно для Java-разработчика. В этом руководстве мы шаг за шагом разберём, как работать с Java Servlet API — от базовых концепций до написания функционального кода. Вы получите практические примеры, которые можно сразу применить в реальных проектах. 🚀

Хотите быстро освоить Java Servlet API и другие ключевые технологии веб-разработки? Курс Java-разработки от Skypro предлагает структурированную программу с акцентом на практику. Вы не просто изучите теорию сервлетов, но создадите полноценные веб-приложения под руководством опытных менторов. Курс включает реальные проекты для портфолио и поддержку в трудоустройстве после обучения.

Что такое Java Servlet API: основные концепции и применение

Java Servlet API представляет собой набор классов и интерфейсов, предназначенных для создания динамических веб-приложений на языке Java. По сути, сервлет — это Java-класс, который обрабатывает HTTP-запросы и генерирует соответствующие ответы.

Сервлеты выступают как связующее звено между клиентом (обычно веб-браузером) и базами данных или другими приложениями на стороне сервера. Основное преимущество сервлетов — их независимость от платформы и возможность использовать всю мощь Java.

Андрей Петров, тимлид отдела веб-разработки Когда я пришёл в компанию, наше старое веб-приложение было написано на чистых сервлетах без использования фреймворков. Сначала это казалось архаичным, но именно этот проект дал мне глубокое понимание работы веб-приложений на Java. Я увидел, как запрос проходит через фильтры, обрабатывается сервлетом, взаимодействует с бизнес-логикой и возвращается клиенту. Спустя год, когда мы начали миграцию на Spring MVC, я был единственным в команде, кто мог отлаживать проблемы на низком уровне, понимая, что происходит "под капотом" фреймворка. Знание сервлетов стало моим конкурентным преимуществом и ускорило мой карьерный рост.

Основные компоненты Java Servlet API включают:

  • Servlet: интерфейс, определяющий основные методы, которые должен реализовать каждый сервлет
  • ServletConfig: используется для передачи информации о конфигурации сервлету
  • ServletContext: предоставляет информацию о среде, в которой работает сервлет
  • ServletRequest и ServletResponse: обрабатывают запросы и ответы соответственно
  • HttpServlet: расширение для обработки HTTP-запросов

Главные области применения Java Servlet API:

Область применения Описание Преимущества
Веб-приложения Создание динамических веб-сайтов с генерацией HTML-контента Полный контроль над генерируемым HTML, интеграция с Java-экосистемой
RESTful API Разработка API для взаимодействия с фронтендом или другими системами Простая обработка HTTP-методов, гибкость в работе с данными
Корпоративные приложения Построение серверной части для бизнес-приложений Интеграция с корпоративными системами, высокая производительность
Шлюзы и прокси Обработка и перенаправление запросов между системами Возможность трансформации и валидации данных

Несмотря на появление множества фреймворков высокого уровня (Spring, Jakarta EE), понимание работы сервлетов остается критически важным, поскольку эти фреймворки построены поверх Servlet API. Можно сказать, что изучение сервлетов — это как изучение анатомии для врача: без понимания базовых структур невозможно стать настоящим экспертом. 🧠

Пошаговый план для смены профессии

Настройка рабочей среды для разработки Java сервлетов

Для разработки приложений с использованием Java Servlet API требуется правильно настроенная среда. Рассмотрим последовательные шаги по созданию рабочего окружения, в котором вы сможете эффективно разрабатывать и тестировать сервлеты.

Прежде всего, вам потребуются следующие компоненты:

  • Java Development Kit (JDK) 8 или выше
  • Интегрированная среда разработки (IDE): IntelliJ IDEA, Eclipse или NetBeans
  • Сервер приложений: Apache Tomcat, Jetty или WildFly
  • Система сборки проекта: Maven или Gradle

Установка JDK — первый и самый важный шаг. После загрузки и установки JDK необходимо настроить переменные окружения JAVA_HOME и PATH.

Далее следует настроить сервер приложений. Apache Tomcat — наиболее популярный выбор для начинающих разработчиков. После установки Tomcat необходимо выполнить базовую настройку:

# Для Linux/Mac
export CATALINA_HOME=/path/to/tomcat
export PATH=$PATH:$CATALINA_HOME/bin

# Для Windows (PowerShell)
$env:CATALINA_HOME = "C:\path\to\tomcat"
$env:PATH += ";$env:CATALINA_HOME\bin"

Для создания проекта с сервлетами рекомендуется использовать Maven. Вот пример базовой структуры pom.xml:

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

Также требуется создать файл web.xml в директории WEB-INF для конфигурации веб-приложения:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>My Servlet Application</display-name>
</web-app>

Сравнение популярных IDE для разработки сервлетов:

IDE Преимущества Недостатки Встроенная поддержка сервлетов
IntelliJ IDEA Мощный редактор, интеграция с серверами, умная автодополнение Платная версия для всех возможностей, высокие требования к ресурсам Отличная (шаблоны, интеграция с Tomcat, отладка)
Eclipse Бесплатный, богатая экосистема плагинов, стабильность Сложная настройка, местами устаревший интерфейс Хорошая (требуется установка WTP)
NetBeans Простая настройка, интуитивно понятный интерфейс Более медленная работа, меньше плагинов Средняя (базовые функции доступны)
VS Code Лёгкий, быстрый, современный Ограниченная встроенная поддержка Java и сервлетов Слабая (требуются дополнительные расширения)

После настройки среды разработки, рекомендуется создать простой проект-заготовку, который можно использовать как шаблон для будущих проектов. Включите в него базовый сервлет, страницу JSP и структуру директорий, соответствующую стандартам Java-веб-приложений. 📝

Также важно настроить отладку (debugging) в вашей IDE. Это позволит отслеживать выполнение кода сервлетов в реальном времени и значительно упростит разработку. В IntelliJ IDEA и Eclipse эта функциональность настраивается через конфигурации запуска сервера в режиме отладки.

Жизненный цикл сервлета: от создания до уничтожения

Понимание жизненного цикла сервлета — ключ к созданию эффективных и надёжных веб-приложений. Сервлет проходит через строго определённые этапы, каждый из которых имеет своё назначение и особенности.

Мария Соколова, Java-архитектор В начале моей карьеры я создала сервлет, который устанавливал соединение с базой данных в методе doGet(). Приложение работало, но было катастрофически медленным при большой нагрузке. Руководитель указал мне на фундаментальную ошибку: я не понимала жизненный цикл сервлета. После его объяснения я перенесла инициализацию соединения в метод init(), а закрытие — в destroy(). Производительность выросла в 5 раз. Вместо создания нового соединения для каждого запроса, сервлет использовал одно соединение на весь жизненный цикл. Это научило меня тому, что знание жизненного цикла сервлета — не теоретическая абстракция, а практический инструмент оптимизации.

Жизненный цикл сервлета состоит из трёх основных фаз:

  1. Инициализация — сервлет-контейнер загружает класс сервлета и создаёт его экземпляр
  2. Обслуживание — сервлет обрабатывает запросы от клиентов
  3. Уничтожение — сервлет завершает работу и освобождает ресурсы

Рассмотрим эти фазы подробнее:

Фаза 1: Инициализация

Когда сервлет-контейнер (например, Tomcat) запускается или получает первый запрос к сервлету, он выполняет следующие действия:

  • Загружает класс сервлета через ClassLoader
  • Создаёт единственный экземпляр сервлета
  • Вызывает метод init(ServletConfig) для инициализации сервлета

Метод init() вызывается только один раз за всё время существования сервлета. Это идеальное место для:

  • Чтения параметров инициализации из web.xml
  • Установления соединений с базами данных
  • Загрузки конфигурационных файлов
  • Инициализации ресурсоёмких объектов
Java
Скопировать код
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// Получение параметра инициализации
String databaseURL = config.getInitParameter("database-url");
// Инициализация соединения с БД
dbConnection = DatabaseManager.connect(databaseURL);
System.out.println("Servlet initialized");
}

Фаза 2: Обслуживание

После инициализации сервлет готов обрабатывать запросы. Для каждого запроса контейнер:

  1. Создаёт объекты HttpServletRequest и HttpServletResponse
  2. Вызывает метод service()
  3. Метод service() определяет тип HTTP-запроса и вызывает соответствующий метод (doGet(), doPost() и т.д.)

Важно понимать, что в отличие от init(), методы обслуживания вызываются для каждого запроса, часто параллельно в многопоточной среде. Это значит, что они должны быть потокобезопасными.

Java
Скопировать код
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
try (PrintWriter out = response.getWriter()) {
out.println("<html><body>");
out.println("<h1>Servlet Response</h1>");
out.println("</body></html>");
}
}

Фаза 3: Уничтожение

Сервлет уничтожается, когда:

  • Контейнер сервлетов завершает работу
  • Веб-приложение выгружается из контейнера
  • Контейнер решает освободить ресурсы

При уничтожении контейнер вызывает метод destroy(). Это последний шанс для сервлета закрыть соединения, записать данные и выполнить другие операции очистки.

Java
Скопировать код
@Override
public void destroy() {
// Закрытие соединения с БД
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("Servlet destroyed");
super.destroy();
}

Вот сравнительная таблица методов жизненного цикла:

Метод Когда вызывается Частота вызовов Использование
init() При создании экземпляра сервлета Один раз Инициализация ресурсов и загрузка конфигурации
service() При каждом запросе к сервлету Многократно Распределение запросов по методам doXxx()
doGet() При HTTP GET-запросе Многократно Обработка запросов на получение данных
doPost() При HTTP POST-запросе Многократно Обработка запросов на изменение данных
destroy() При уничтожении сервлета Один раз Освобождение ресурсов

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

Обработка HTTP-запросов в сервлетах: GET и POST методы

Обработка HTTP-запросов — основная задача сервлетов. Большинство веб-приложений активно используют методы GET и POST для различных операций. Каждый из этих методов имеет свои особенности и сценарии применения.

Обработка GET-запросов

GET-запросы преимущественно используются для получения данных. Параметры передаются в URL и видны пользователю. Рассмотрим стандартную структуру метода doGet():

Java
Скопировать код
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Установка типа содержимого и кодировки
response.setContentType("text/html;charset=UTF-8");

// Получение параметров запроса
String name = request.getParameter("name");
String id = request.getParameter("id");

// Формирование ответа
try (PrintWriter out = response.getWriter()) {
out.println("<html>");
out.println("<head><title>Get Response</title></head>");
out.println("<body>");
out.println("<h1>Hello, " + (name != null ? name : "Guest") + "!</h1>");
if (id != null) {
out.println("<p>Your ID: " + id + "</p>");
}
out.println("</body></html>");
}
}

Ключевые моменты при обработке GET-запросов:

  • Параметры запроса извлекаются с помощью метода request.getParameter()
  • Размер URL с параметрами ограничен (обычно 2048 символов)
  • GET-запросы могут кэшироваться браузерами и серверами
  • Не рекомендуется использовать GET для передачи конфиденциальных данных

Обработка POST-запросов

POST-запросы используются для отправки данных на сервер, особенно когда эти данные изменяют состояние приложения. Параметры передаются в теле запроса, что делает их невидимыми в URL.

Java
Скопировать код
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Установка типа содержимого и кодировки
response.setContentType("text/html;charset=UTF-8");

// Установка кодировки для правильного чтения параметров
request.setCharacterEncoding("UTF-8");

// Получение параметров формы
String username = request.getParameter("username");
String email = request.getParameter("email");
String password = request.getParameter("password");

// Проверка данных (очень простая)
boolean isValid = username != null && !username.trim().isEmpty() &&
email != null && email.contains("@") &&
password != null && password.length() >= 6;

// Формирование ответа
try (PrintWriter out = response.getWriter()) {
out.println("<html>");
out.println("<head><title>Registration Result</title></head>");
out.println("<body>");
if (isValid) {
// В реальном приложении здесь был бы код сохранения данных
out.println("<h1>Registration Successful!</h1>");
out.println("<p>Welcome, " + username + "!</p>");
} else {
out.println("<h1>Registration Failed</h1>");
out.println("<p>Please check your input and try again.</p>");
}
out.println("</body></html>");
}
}

Особенности обработки POST-запросов:

  • Необходимо устанавливать кодировку с помощью request.setCharacterEncoding() перед чтением параметров
  • POST-запросы не кэшируются и не могут быть добавлены в закладки
  • Размер передаваемых данных практически не ограничен
  • POST-запросы безопаснее для передачи конфиденциальной информации (но всё равно требуют HTTPS)
  • После обработки POST-запроса рекомендуется выполнить перенаправление (PRG-паттерн) для предотвращения повторной отправки формы

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

Существует два основных способа перехода к другому ресурсу после обработки запроса:

Java
Скопировать код
// Перенаправление (клиент получает код 302 и новый URL)
response.sendRedirect("success.jsp");

// Переадресация (происходит на сервере, клиент "не видит" изменения URL)
request.getRequestDispatcher("success.jsp").forward(request, response);

Обработка загрузки файлов

Для обработки загружаемых файлов требуется специальный подход:

  1. В HTML-форме должен быть указан атрибут enctype="multipart/form-data"
  2. Для обработки необходима библиотека, например Apache Commons FileUpload

Обработка ошибок

Профессиональный подход к обработке запросов включает правильную обработку ошибок:

Java
Скопировать код
try {
// Код, который может вызвать исключение
processBusinessLogic(request);
} catch (SQLException e) {
// Логирование ошибки
logger.error("Database error", e);
// Установка кода ошибки
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
// Отправка сообщения об ошибке
response.getWriter().write("Database error occurred: " + e.getMessage());
}

Поддержка правильных HTTP-статусов помогает клиентам корректно обрабатывать ответы:

  • 200 OK — запрос успешно обработан
  • 400 Bad Request — некорректный запрос
  • 401 Unauthorized — требуется аутентификация
  • 404 Not Found — ресурс не найден
  • 500 Internal Server Error — ошибка на сервере

Эффективная обработка HTTP-запросов в сервлетах требует понимания не только синтаксиса Java, но и принципов работы протокола HTTP. Владение этими навыками позволяет создавать надёжные и безопасные веб-приложения. 🔒

Практические примеры кода сервлетов для веб-приложений

Теперь применим полученные знания на практике. Ниже представлены готовые к использованию примеры сервлетов для различных сценариев веб-разработки. Эти примеры можно скопировать, адаптировать под свои нужды и использовать как отправную точку для ваших проектов.

1. Простой сервлет "Hello World"

Начнём с базового примера — сервлета, который выводит приветствие:

Java
Скопировать код
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

try (PrintWriter out = response.getWriter()) {
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Hello Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello, World from Servlet!</h1>");
out.println("</body>");
out.println("</html>");
}
}
}

Обратите внимание на аннотацию @WebServlet, которая заменяет конфигурацию в web.xml. Это современный способ маппинга URL к сервлетам.

2. Сервлет для обработки формы регистрации

Этот сервлет демонстрирует работу с данными формы и реализацию базовой валидации:

Java
Скопировать код
import java.io.IOException;
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;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/register")
public class RegistrationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

// Имитация базы данных пользователей
private final Map<String, String> users = new HashMap<>();

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
// Отобразить форму регистрации
request.getRequestDispatcher("/WEB-INF/views/register.jsp").forward(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
// Получение и валидация данных
String username = request.getParameter("username");
String email = request.getParameter("email");
String password = request.getParameter("password");
String confirmPassword = request.getParameter("confirmPassword");

// Проверка данных
Map<String, String> errors = new HashMap<>();

if (username == null || username.trim().isEmpty()) {
errors.put("username", "Username is required");
} else if (users.containsKey(username)) {
errors.put("username", "Username already exists");
}

if (email == null || !email.contains("@")) {
errors.put("email", "Valid email is required");
}

if (password == null || password.length() < 6) {
errors.put("password", "Password must be at least 6 characters");
} else if (!password.equals(confirmPassword)) {
errors.put("confirmPassword", "Passwords do not match");
}

if (!errors.isEmpty()) {
// Если есть ошибки – возвращаемся к форме
request.setAttribute("errors", errors);
request.setAttribute("username", username);
request.setAttribute("email", email);
request.getRequestDispatcher("/WEB-INF/views/register.jsp").forward(request, response);
return;
}

// Сохранение пользователя (в реальном приложении – в БД)
users.put(username, password);

// Создание сессии для пользователя
HttpSession session = request.getSession();
session.setAttribute("username", username);

// Перенаправление на домашнюю страницу
response.sendRedirect(request.getContextPath() + "/home");
}
}

3. Сервлет для работы с сессиями и cookies

Демонстрирует управление сессией и cookies для отслеживания пользователя:

Java
Скопировать код
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/session-demo")
public class SessionDemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

// Получаем сессию (создаём новую, если не существует)
HttpSession session = request.getSession();

// Получаем счётчик посещений или устанавливаем в 0
Integer visitCount = (Integer) session.getAttribute("visitCount");
if (visitCount == null) {
visitCount = 0;
}

// Увеличиваем и сохраняем счётчик
visitCount++;
session.setAttribute("visitCount", visitCount);

// Устанавливаем cookie с именем пользователя
String username = request.getParameter("username");
if (username != null && !username.isEmpty()) {
Cookie userCookie = new Cookie("username", username);
userCookie.setMaxAge(60 * 60 * 24 * 30); // 30 дней
response.addCookie(userCookie);
}

// Получаем имя пользователя из cookie
String savedUsername = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("username".equals(cookie.getName())) {
savedUsername = cookie.getValue();
break;
}
}
}

// Выводим информацию
try (PrintWriter out = response.getWriter()) {
out.println("<!DOCTYPE html>");
out.println("<html><head><title>Session Demo</title></head><body>");
out.println("<h1>Session and Cookie Demo</h1>");

out.println("<h2>Session Info:</h2>");
out.println("<p>Session ID: " + session.getId() + "</p>");
out.println("<p>Visit Count: " + visitCount + "</p>");

out.println("<h2>Cookie Info:</h2>");
if (savedUsername != null) {
out.println("<p>Welcome back, " + savedUsername + "!</p>");
} else {
out.println("<p>No username cookie found.</p>");
}

out.println("<h2>Set Your Name:</h2>");
out.println("<form method='get'>");
out.println("Username: <input type='text' name='username'>");
out.println("<input type='submit' value='Save'>");
out.println("</form>");

out.println("</body></html>");
}
}
}

4. Сервлет для работы с базой данных (JDBC)

Демонстрирует взаимодействие с базой данных:

Java
Скопировать код
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/users")
public class UserListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

// JDBC URL, username и password следует настроить для вашей БД
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/userdb";
private static final String JDBC_USER = "root";
private static final String JDBC_PASSWORD = "password";

private Connection getConnection() throws SQLException {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
} catch (ClassNotFoundException e) {
throw new SQLException("JDBC Driver not found", e);
}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");

try (PrintWriter out = response.getWriter();
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {

out.println("<!DOCTYPE html>");
out.println("<html><head><title>User List</title></head><body>");
out.println("<h1>User List</h1>");

out.println("<table border='1'>");
out.println("<tr><th>ID</th><th>Username</th><th>Email</th></tr>");

while (rs.next()) {
out.println("<tr>");
out.println("<td>" + rs.getInt("id") + "</td>");
out.println("<td>" + rs.getString("username") + "</td>");
out.println("<td>" + rs.getString("email") + "</td>");
out.println("</tr>");
}

out.println("</table>");
out.println("</body></html>");

} catch (SQLException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().println("Database error: " + e.getMessage());
e.printStackTrace();
}
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");

String username = request.getParameter("username");
String email = request.getParameter("email");

if (username == null || username.trim().isEmpty() || email == null || email.trim().isEmpty()) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Username and email are required");
return;
}

try (Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO users (username, email) VALUES (?, ?)")) {

pstmt.setString(1, username);
pstmt.setString(2, email);
int rowsAffected = pstmt.executeUpdate();

if (rowsAffected > 0) {
response.sendRedirect(request.getContextPath() + "/users");
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Insert failed");
}

} catch (SQLException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().println("Database error: " + e.getMessage());
e.printStackTrace();
}
}
}

5. Сервлет для загрузки и скачивания файлов

Демонстрирует работу с файлами:

Java
Скопировать код
import java.io.*;
import java.nio.file.Paths;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet("/file")
@MultipartConfig
public class FileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

// Директория для хранения загруженных файлов
private static final String UPLOAD_DIRECTORY = "uploads";

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
// Отображаем форму для загрузки файла или скачиваем файл, если указан параметр download
String fileName = request.getParameter("download");

if (fileName != null && !fileName.isEmpty()) {
// Скачивание файла
File file = new File(getUploadPath() + File.separator + fileName);

if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "File not found");
return;
}

response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setContentLength((int) file.length());

try (FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream()) {

byte[] buffer = new byte[4096];
int bytesRead;

while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
} else {
// Отображаем форму для загрузки
response.setContentType("text/html;charset=UTF-8");

try (PrintWriter out = response.getWriter()) {
out.println("<!DOCTYPE html>");
out.println("<html><head><title>File Upload/Download</title></head><body>");
out.println("<h1>File Upload</h1>");

out.println("<form method='post' enctype='multipart/form-data'>");
out.println("Select file: <input type='file' name='file'><br><br>");
out.println("<input type='submit' value='Upload'>");
out.println("</form>");

// Список загруженных файлов
out.println("<h2>Uploaded Files:</h2>");

File uploadDir = new File(getUploadPath());
if (uploadDir.exists() && uploadDir.isDirectory()) {
File[] files = uploadDir.listFiles();
if (files != null && files.length > 0) {
out.println("<ul>");
for (File f : files) {
if (f.isFile()) {
out.println("<li><a href='?download=" + f.getName() + "'>" + 
f.getName() + "</a> (" + f.length() + " bytes)</li>");
}
}
out.println("</ul>");
} else {
out.println("<p>No files uploaded yet.</p>");
}
}

out.println("</body></html>");
}
}
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
// Создаём директорию, если она не существует
File uploadDir = new File(getUploadPath());
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}

// Получаем файл из запроса
Part filePart = request.getPart("file");
if (filePart == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No file uploaded");
return;
}

// Получаем имя файла
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();

// Сохраняем файл
filePart.write(getUploadPath() + File.separator + fileName);

// Перенаправляем обратно на страницу
response.sendRedirect(request.getContextPath() + "/file");
}

private String getUploadPath() {
return getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY;
}
}

Эти примеры демонстрируют основные сценарии использования сервлетов. Обратите внимание, что в реальных приложениях необходимо реализовывать дополнительные меры безопасности, такие как защита от SQL-инъекций, XSS-атак, CSRF и других уязвимостей. Также рекомендуется использовать пулы соединений для работы с базой данных и разделять код на слои (MVC-архитектура). 🛡️

Овладение Java Servlet API открывает широкие возможности для разработки серверных приложений. Несмотря на появление множества фреймворков высокого уровня, понимание сервлетов остаётся фундаментальным навыком для каждого Java-разработчика. Начните с простых примеров, постепенно внедряйте изученные концепции в свои проекты и помните: знание жизненного цикла сервлетов и правильная обработка HTTP-запросов — залог создания надёжных и производительных веб-приложений.

Загрузка...