Пишем Java веб-приложение на современном стеке. С нуля до микросервисной архитектуры. Часть 1
Постараюсь описать шаги разработки приложения на Java, возникающие проблемы и пути их решения. Наращивать функциональность будем постепенно.
На сегодняшний день в мире разработки на Java существует огромное количество библиотек и технологий, в которых новичку очень легко запутаться. В этом руководстве я постараюсь простым языком описать все шаги, возникающие проблемы и пути их решения. Начинать будем с самого простого и постепенно наращивать функциональность.
Spring Boot
Spring Boot — один из самых популярных универсальных фреймворков для построения веб-приложений на Java. Создадим в среде разработки Gradle Project. Для облегчения работы воспользуемся сайтом https://start.spring.io, который поможет сформировать build.gradle.
Для начала нам необходимо выбрать следующие зависимости:
- Spring Web — необходим для создания веб-приложения;
- Spring Data JPA — для работы с базами данных;
- PostgreSQL Driver — драйвер для работы с PostgreSQL;
- Lombok — библиотека, позволяющая уменьшить количество повторяющегося кода.
В результате генерации build.gradle должно получиться что-то похожее:
plugins < id 'org.springframework.boot' version '2.4.3' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' >group 'org.example' version '1.0-SNAPSHOT' configurations < compileOnly < extendsFrom annotationProcessor >> repositories < mavenCentral() >dependencies < implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok:1.18.22' annotationProcessor 'org.projectlombok:lombok:1.18.22' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' runtimeOnly 'org.postgresql:postgresql' >test
Тот же результат можно получить и в самой IntelliJ Idea: File → New → Project → Spring Initializr.
@SpringBootApplication public class SpringDemoApplication < public static void main(String[] args) < SpringApplication.run(SpringDemoApplication.class, args); >>
Опишем самый простой контроллер, чтобы удостовериться, что проект работает:
@RestController public class HelloController < @GetMapping("/hello") public String hello(@RequestParam(required = false) String name) < return "Hello, " + name; >>
Запустим проект в среде разработки или через терминал: ./gradlew bootRun .
Результат работы можно проверить в браузере перейдя по адресу http://localhost:8080/hello?name=World или с помощью консольной утилиты curl:
curl "http://localhost:8080/hello?name=World" Hello, World
Наш сервис запускается и работает, пора переходить к следующему шагу.
Представим, что нам требуется разработать некий сервис для интернет-магазина по продаже книг. Это будет rest-сервис, который будет позволять добавлять, редактировать, получать описание книги. Хранить данные будем в БД Postgres.
Docker
Для хранения данных нам потребуется база данных. Проще всего запустить инстанс БД с помощью Docker. Docker позволяет запускать приложение в изолированной среде выполнения — контейнере. Поддерживается всеми операционными системами.
Выкачиваем образ БД и запускаем контейнер:
docker pull postgres:12-alpine docker run -d -p 5432:5432 --name db -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=password -e POSTGRES_DB=demo postgres:12-alpine
Lombok
Создадим data-класс «книга». Он будет иметь несколько полей, которые должны иметь getters, конструктор и должна быть неизменяемой (immutable). Среда разработки позволяет автоматически генерировать конструктор и методы доступа к полям, но чтобы уменьшить количество однотипного кода, будем использовать Lombok.
Аннотация @Value при компиляции исходного кода добавит в наш класс getters, конструктор, пометит все поля класса private final , добавит методы hashCode , equals и toString .
@Value public class Book
После сборки проекта можно посмотреть, как выглядит класс после компиляции. Воспользуемся стандартной утилитой, входящей в состав JDK:
javap -private build/classes/java/main/com/example/BookStore/model/Book public final class com.example.bookstore.model.Book
Lombok очень упрощает читаемость подобного рода классов и очень широко используется в современной разработке.
Spring Data JPA
Для работы с БД нам потребуется Spring Data JPA, который мы уже добавили в зависимости проекта. Дальше нам нужно описать классы Entity и Repository. Первый соответствует таблице в БД, второй необходим для загрузки и сохранения записей в эту таблицу.
@Data @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "books") public class BookEntity
Мы также используем аннотации Lombok: @Data добавляет getters и setters, @NoArgsConstructor и @AllArgsConstructor — конструкторы без параметров и со всеми параметрами, соответственно. @Entity , @Table , @Id , @GeneratedValue — аннотации относящиеся к JPA. Здесь мы указываем, что это объект БД, название таблицы, первичный ключ и стратегию его генерации (в нашем случае автоматическую).
Класс Repository будет выглядеть совсем просто — достаточно объявить интерфейс и наследоваться от CrudRepository:
public interface BookRepository extends CrudRepository
Никакой реализации не требуется. Spring всё сделает за нас. В данном случае мы сразу получим функциональность CRUD — create, read, update, delete. Функционал можно наращивать — чуть позже мы это увидим. Мы описали DAO-слой.
Теперь нам нужен некий сервис, который будет иметь примерно следующий интерфейс:
public interface BookService < Book getBookById(Long id);// получить книгу по id ListgetAllBooks();// получить список всех книг void addBook(Book book);// добавить книгу >
Это так называемый сервисный слой. Реализуем этот интерфейс:
@Service @RequiredArgsConstructor public class DefaultBookService implements BookService < private final BookRepository bookRepository; @Override public Book getBookById(Long id) < BookEntity bookEntity = bookRepository .findById(id) .orElseThrow(() ->new BookNotFoundException("Book not found: + id)); return new Book(bookEntity.getId(), bookEntity.getAuthor(), bookEntity.getTitle(), bookEntity.getPrice()); > @Override public List getAllBooks() < Iterableiterable = bookRepository.findAll(); ArrayList books = new ArrayList<>(); for (BookEntity bookEntity : iterable) < books.add(new Book(bookEntity.getId(), bookEntity.getAuthor(), bookEntity.getTitle(), bookEntity.getPrice())); >return books; > @Override public void addBook(Book book) < BookEntity bookEntity = new BookEntity(null, book.getAuthor(), book.getTitle(), book.getPrice()); bookRepository.save(bookEntity); >>
Аннотацией @Service мы возлагаем на Spring создание объекта этого класса. @RequiredArgsConstructor — уже знакомая нам аннотация, которая генерирует конструктор с необходимыми аргументами. В нашем случае класс имеет final-поле bookRepository , которое необходимо проинициализировать. Добавив эту аннотацию, мы получим следующую реализацию:
public DefaultBookService(BookRepository bookRepository)
При создании объекта класса Spring опять всё возьмёт на себя — сам создаст объект BookRepository и передаст его в конструктор. Имея объект репозитория мы можем выполнять операции с БД:
bookRepository.findById(id); //прочитать запись из БД по первичному ключу id bookRepository.findAll(); //прочитать все записи из БД и вернуть их в виде списка bookRepository.save(bookEntity); //сохранить объект в БД
Метод findById возвращает объект типа Optional . Это такой специальный тип который может содержать, а может и не содержать значение. Альтернативный способ проверки на null , но позволяющий более изящно написать код. Метод orElseThrow извлекает значение из Optional , и, если оно отсутствует, бросает исключение, которое создается в переданном в качестве аргумента лямбда-выражении. То есть объект исключения будет создаваться только в случае отсутствия значения в Optional .
MapStruct
Смотря на код может показаться, что класс Book не нужен, и достаточно только BookEntity, но это не так. Book — это класс сервисного слоя, а BookEntity — DAO. В нашем простом случае они действительно повторяют друг друга, но бывают и более сложные случаи, когда сервисный слой оперирует с несколькими таблицами и соответственно DAO-объектами.
Если присмотреться, то и тут мы видим однотипный код, когда мы перекладываем данные из BookEntity в Book и обратно. Чтобы упростить себе жизнь и сделать код более читаемым, воспользуемся библиотекой MapStruct. Это mapper, который за нас будет выполнять перекладывание данных из одного объекта в другой и обратно. Для этого добавим зависимости в build.gradle:
dependencies
Создадим mapper, для этого необходимо объявить интерфейс, в котором опишем методы для конвертации из BookEntity в Book и обратно:
@Mapper(componentModel = "spring") public interface BookToEntityMapper
Так как имена полей классов соотносятся один к одному, то интерфейс получился таким простым. Если поля имеют отличающиеся имена, то потребуется аннотацией @Mapping указать какие поля соответствуют друг другу. Более подробно можно найти в документации. Чтобы spring смог сам создавать бины этого класса, необходимо указать componentModel = «spring» .
После сборки проекта, в каталоге build/generated/sources/annotationProcessor появится сгенерированный исходный код mapper, избавив нас от необходимости писать однотипные десятки строк кода:
@Component public class BookToEntityMapperImpl implements BookToEntityMapper < @Override public BookEntity bookToBookEntity(Book book) < if ( book == null ) < return null; >BookEntity bookEntity = new BookEntity(); bookEntity.setId( book.getId() ); bookEntity.setAuthor( book.getAuthor() ); bookEntity.setTitle( book.getTitle() ); bookEntity.setPrice( book.getPrice() ); return bookEntity; > @Override public Book bookEntityToBook(BookEntity bookEntity) < if ( bookEntity == null ) < return null; >Long String author = null; String title = null; Double price = null; author = bookEntity.getAuthor(); title = bookEntity.getTitle(); price = bookEntity.getPrice(); Book book = new Book( id, author, title, price ); return book; > >
Воспользуемся мэппером и перепишем DefaultBookService. Для этого нам достаточно добавить добавить final-поле BookMapper, которое Lombok автоматически подставит в аргумент конструктора, а spring сам инстанциирует и передаст параметром в него:
@Service @RequiredArgsConstructor public class DefaultBookService implements BookService < private final BookRepository bookRepository; private final BookToEntityMapper mapper; @Override public Book getBookById(Long id) < BookEntity bookEntity = bookRepository .findById(id) .orElseThrow(() ->new BookNotFoundException("Book not found: + id)); return mapper.bookEntityToBook(bookEntity); > @Override public List getAllBooks() < Iterableiterable = bookRepository.findAll(); ArrayList books = new ArrayList<>(); for (BookEntity bookEntity : iterable) < books.add(mapper.bookEntityToBook(bookEntity)); >return books; > @Override public void addBook(Book book) < BookEntity bookEntity = bookMapper.bookToBookEntity(book); mapper.save(bookEntity); >.
Теперь опишем контроллер, который будет позволять выполнять http-запросы к нашему сервису. Для добавления книги нам потребуется описать класс запроса. Это data transfer object, который относится к своему слою DTO.
@Data public class BookRequest
Нам также потребуется конвертировать объект AddBookRequest в объект Book. Создадим для этого BookToDtoMapper:
@Mapper(componentModel = "spring") public interface BookToDtoMapper
Теперь объявим контроллер, на эндпоинты которого будут приходить запросы на создание и получение книг, добавив зависимости BookService и BookToDtoMapper. При необходимости аналогично объекту AddBookRequest можно описать Response-объект, добавив соответствующий метод в мэппер, который будет конвертировать Book в GetBookResponse. Контроллер будет содержать 3 метода: методом POST мы будем добавлять книгу, методом GET получать список всех книг и книгу по идентификатору, который будем передавать в качестве PathVariable.
@RestController() @RequestMapping("/books") @RequiredArgsConstructor public class BookController < private final BookService bookService; private final BookToDtoMapper mapper; @GetMapping("/") public Book getBookById(@PathVariable Long id) < return bookService.getBookById(id); >@GetMapping public List getAllBooks() < return bookService.getAllBooks(); >@PostMapping public void addBook(@RequestBody AddBookRequest request) < bookService.addBook(mapper.AddBookRequestToBook(request)); >>
Осталось создать файл настроек приложения. Для Spring boot по умолчанию это application.properties или application.yml . Мы будем использовать формат properties. Необходимо указать настройки для соединения с БД (выше мы задавали пользователя и его пароль при старте docker-контейнера):
spring.datasource.url=jdbc:postgresql://localhost:5432/demo spring.datasource.username=admin spring.datasource.password=password spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
Настройка spring.jpa.hibernate.ddl-auto=update указывает hibernate необходимость обновить схему когда это нужно. Так как мы не создавали никаких схем, то приложение сделает это автоматически. В процессе промышленной разработки схемы баз данных постоянно меняются, и часто используются инструменты для версионирования и применения этих изменений, например Liquibase.
Запустим наше приложение и выполним запросы на добавление книг:
curl -X POST --location "http://localhost:8080/books" -H "Content-Type: application/json" -d "< "author" : "Joshua Bloch", "title" : "Effective Java", "price" : 54.99 >" curl -X POST --location "http://localhost:8080/books" -H "Content-Type: application/json" -d "< "author" : "Kathy Sierra", "title" : "Head First Java", "price" : 12.66 >" curl -X POST --location "http://localhost:8080/books" -H "Content-Type: application/json" -d "< "author" : "Benjamin J. Evans", "title" : "Java in a Nutshell: A Desktop Quick Reference", "price" : 28.14 >"
После выполнения запросов в таблице books должны появиться записи. Чтобы удостовериться в этом, можно использовать любой удобный клиент БД. Для примера сделаем это, используя консольный клиент, входящий в состав docker-контейнера. При создании контейнера, мы указали его имя ‘db’ (если имя не задавалось, то можно вывести список всех запущенных контейнеров командой docker container ls , и дальше использовать идентификатор нужного контейнера). Для доступа к шелл-оболочке выполним:
docker exec -ti db sh
Запустим клиент БД и выполним sql-запрос:
psql --username=admin --dbname=demo psql (12.6) Type "help" for help. demo=# SELECT * FROM books; id | author | price | title ----+-------------------+-------+----------------------------------------------- 1 | Joshua Bloch | 54.99 | Effective Java 2 | Kathy Sierra | 12.66 | Head First Java 3 | Benjamin J. Evans | 28.14 | Java in a Nutshell: A Desktop Quick Reference (3 rows)
Получим список всех книг:
curl -X GET --location "http://localhost:8080/books" -H "Accept: application/json" [ < "id": 1, "author": "Joshua Bloch", "title": "Effective Java", "price": 54.99 >, < "id": 2, "author": "Kathy Sierra", "title": "Head First Java", "price": 12.66 >, < "id": 3, "author": "Benjamin J. Evans", "title": "Java in a Nutshell: A Desktop Quick Reference", "price": 28.14 >]
Получим книгу через запрос к api нашего сервиса, указав идентификатор книги:
curl -X GET --location "http://localhost:8080/books/2" -H "Accept: application/json"
Добавим к нашему api более сложную функциональность — поиск по автору книги. Для этого в BookRepository нужно описать метод, который будет делать соответствующий SELECT из БД. Это можно сделать с помощью аннотации @Query , а можно назвать метод в соответствии со специальной нотацией Spring:
List findAllByAuthorContaining(String author);
В документации можно подробнее прочитать об именовании методов. Здесь мы указываем findAll — найти все записи, ByAuthor — параметр обрамляется %. При вызове этого метода (например с аргументом ‘Bloch’) будет сгенерирован следующий запрос:
SELECT * FROM books WHERE author LIKE '%Bloch%';
Далее добавим метод в BookService и DefaultBookService:
@Override public List findByAuthor(String author) < Iterableiterable = bookRepository.findAllByAuthorContaining(author); ArrayList books = new ArrayList<>(); for (BookEntity bookEntity : iterable) < books.add(mapper.bookEntityToBook(bookEntity)); >return books; >
А в контроллере немного модифицируем метод получения списка книг таким образом, что при передаче get-параметра author мы искали по автору, а если параметр не передётся, то используется старая логика и выводится список всех книг:
@GetMapping public List getAllBooks(@RequestParam(required = false) String author)
Теперь можно выполнить поиск:
curl -X GET --location "http://localhost:8080/books?author=Bloch" -H "Accept: application/json" [ < "id": 1, "author": "Joshua Bloch", "title": "Effective Java", "price": 54.99 >]
Итак, мы написали веб-сервис и познакомились с очень распространенными библиотеками. В следующей части продолжим улучшать наше приложение, добавив в него авторизацию, а также напишем отдельный микросервис, который будет выписывать токены доступа.
Код проекта доступен на GitHub.
Разработка на Java

Язык Java был создан в 1995 году Джеймсом Гослингом. Первая сборка «Ява» позиционировалась на рынке IT-продуктов как один из главных компонентов Sun Microsystems. Философия данного языка программирования проста: «Напиши один раз, запускай везде». Высокая востребованность разработки Sun Microsystems обусловлена 7 основными преимуществами:
- отсутствием привязки к платформе;
- простотой в изучении;
- безопасностью;
- портативностью;
- многопоточностью;
- высокой производительностью;
- объектной ориентированности с возможностью расширения дополнений.
На языке Java создаются сайты, программы и приложения, в том числе предназначенные для мобильных устройств.
Компания Soft Media Group – это коллектив талантливых программистов, имеющих большой опыт создания приложений различной сложности. Наши специалисты прекрасно знакомы со всеми тонкостями Java. Позвоните нам прямо сейчас и доверьте разработку приложения профессионалам своего дела!
Создание сайтов на Java
Язык программирования Java представляет собой идеальный инструмент для сайтостроения. Созданные проекты прекрасно работают на Windows и Unix-серверах. Сайт, написанный на Java, состоит из множества приложений, каждое из которых работает и инсталлируется отдельно от остальных компонентов.
Вам необходимо создать площадку, выдерживающую высокую трафиковую нагрузку? Эту проблему позволяет решить разработка сайтов на Java! Технологии Java EE подразумевают использование проверенных шаблонов, которые сами по себе являются высокопроизводительными.
Используя Java, программисты реализуют любые пожелания заказчика к структуре сайта. Наши специалисты имеют большой опыт работы и отлично знают данный язык. Вы можете смело доверить Soft Media Group создание проекта любой сложности!
Разработка программного обеспечения на Java
Вам необходима универсальная программа, которая практически не привязана к аппаратной мощности «железа» и запускается на широком спектре платформ? Разработка программ на Java является одним из ведущих направлений деятельности компании Soft Media Group. Приложения, написанные на «Ява», поддерживают самые популярные платформы:
- Android;
- SOA;
- Open Source;
- OSGI;
- Automation;
- J2EE и другие.
Приложение будет запускаться на компьютере в браузере, на смартфоне, планшете или любом другом устройстве, работающим под одной из вышеупомянутых платформ. Наша компания предлагает:
- разработку программ полного цикла;
- активное взаимодействие с заказчиком на всех стадиях девелопмента;
- услуги по интеграции готового IT-продукта в основную систему;
- передачу клиенту всех прав на исходный код.
В будущем заказчик сможет модернизировать приложение по своему усмотрению, если в этом возникнет необходимость. Наши специалисты реализуют любые пожелания клиента к готовому продукту. Позвоните нам прямо сейчас и доверьте разработку необходимой программы специалистам компании Soft Media Group!
Приложения на Java
Наша компания занимается разработкой корпоративных систем, браузерных и мобильных приложений. К последним относится широкий спектр продуктов:
- игры;
- мультимедиа;
- программы для социальных сетей;
- приложения для работы с финансами;
- рекламное ПО и многое другое.
Как правило, разработка приложений на Java осуществляется по принципу полного цикла. После того как команда программистов закончит работу, клиенту предоставляется отлаженный продукт, позволяющий решать определенные задачи, который исправно работает и уже готов к использованию. Вы можете заказать разработку мобильных приложения различных типов:
- локализационные сервисы;
- распространители медиаконтента;
- программы VOIP-телефонии;
- утилиты для платежей и переводов;
- корпоративные социальные сети.
Возможна разработка и других приложений в соответствии с пожеланиями заказчика. Вам необходим надежный партнер, который в кратчайший срок предоставит стабильную программу, сайт или приложение, написанные на Java? Тогда позвоните в компанию Soft Media Group прямо сейчас!
Разработка сайтов с помощью Java Spring Boot.
В предыдущей статье мы говорили о продвижении сайтов и показателей посещаемости на сайте. В данной статье мы поговорим о том, как можно за короткий промежуток времени разработать веб-приложение на фреймворке Spring с помощью Java Spring.
В современном мире веб-разработки очень сложно представить проект, собранный без применения какого-либо фреймворка на основе языка программирования на котором разрабатывается приложение. Из самых известных, это Laravel для PHP, Django для Python, и Spring для Java. К слову, фреймворки — это такой набор инструментов, который нацелен на решение определенных, часто повторяющихся в разработке приложений, задач. Это такой скелет, который состоит из библиотек, которые облегчают процесс разработки приложения с нуля.

Какую роль играет Spring Boot в создании сайта?
На одном HTML, CSS и JavaScript невозможно написать полноценный проект, потому что у нас есть функционал проекта под капотом, где мы подключаем данные из базы, прописываем функцию для любой кнопочки, берем данные из строки ввода информации и многое другое. Допустим, у Вас есть простая авторизационная страница, где нужно будет вводить и выводить данные о пользователе. Согласитесь, это большая проблема работать с ними только через HTML и JavaScript, для этого существуют языки программирования, которые прописывают всю бэкенд часть (функционал) проекта. В нашем случае, мы используем Java Spring Boot на основе языка программирования Java.
Начнем с того, что Spring Boot — это проект, построенный поверх основного фреймворка Java Spring. Есть много других проектов как Java Spring Data, Spring Batch, каждый из которых имеет свою особенность в работе с ними.
Spring Boot это в первую очередь один из самых быстрых способов создания веб приложений без особо сложных заморочек с поднятием и написанием конфигурации сервера для вашего web-приложения. Как это работает? За счет Spring фреймворка, поверх которого он и был построен, позволяющий нам читать и собирать все необходимые данные из разных мест в проектах и библиотеках, к примеру, через аннотации, они начинаются с символа “@”, вы сразу поймете. Spring Boot — это все, что необходимо для того, чтобы упаковать существующие части фреймворка в пакетик, который мы в будущем будем использовать для разработки веб-приложений и не только с минимальными заморочками для конфигурации.
Практическое применение Java библиотек во фреймворке Spring Boot
Представьте, что будто авторы Spring собрали все самые нужные утилиты, которые автоматизируют процесс настройки сервера, его развертывания и ускоряют это действие до такой степени, что разработчикам больше не надо будет тратить время и нервы на написание специального кода для всего этого. Как раз-таки, теперь у нас есть Spring Boot, а у него есть все самое необходимое для автоматической конфигурации и готовые контейнеры сервлетов. Сервлет — это такой способ/интерфейс взаимодействия с клиентами посредством такого принципа как запрос-ответ, помните слова request, response из веб программирования? Он связывает наш Java класс с ссылкой из адресной строки, проще говоря.
По сути дела, почти всегда, когда разработчик впервые сталкивается с сервлетами, для него это становится чем-то сложным для понятия: как он работает, что это такое и как он действует на сам проект.
Допустим, Вы захотели развернуть свое web-приложение:
✔ Первым делом, Вы загружаете библиотеки из интернета и настраиваете их на наш проект (servlet-api, servlet-jsp-api), которые будут нужны для разработки MVC приложения на Java, закидываете их в папку самого проекта, указываете что, мол, это библиотеки для нашего проекта.
✔ Затем, добавляем наш проект в сервер Tomcat. Не спешите паниковать: Вам просто нужно скачать сервер из интернета, распаковать его, указать путь к нему и задеплоить проект.
Веб-приложение Java для начинающих
Создать сайт можно и со статическими HTML-страницами, но когда нам нужна динамическая информация, необходимо веб-приложение. Java Web Application (веб-приложение Java) используется для создания динамических сайтов. Java обеспечивает поддержку для веб-приложений Servlet (сервлетов) и JSP.
Цель этой статьи — предоставить основные сведения о различных компонентах веб-приложения и показать, как с помощью сервлета и JSP можно создавать приложения Java.
Веб-сервер и клиент
Веб-сервер — это программное обеспечение, которое может обрабатывать запросы клиентов и отправлять ответ обратно. Например, Apache — один из наиболее широко используемых веб-серверов. Он работает на физической машине и прослушивает запросы клиентов на определенном порту. Веб-клиент — программное обеспечение, которое помогает взаимодействовать с сервером. Некоторые из популярных веб-клиентов: Firefox, Google Chrome, Safari и т. д. Когда мы запрашиваем что-то у сервера (через URL), веб-клиент создает запрос и отправляет его на сервер, а затем анализирует ответ сервера и представляет его пользователю.
HTML и HTTP
Веб-сервер и веб-клиент — это два отдельных программных обеспечения, поэтому для взаимодействия между ними должен быть общий язык. HTML (HyperText Markup Language) – это язык гипертекстовой разметки, который используется для описания структуры и содержания веб-страниц, он и является общим языком между сервером и клиентом. Для обеспечения обмена данными между сервером и клиентом используется протокол коммуникации – HTTP (HyperText Transfer Protocol), который работает поверх протокола связи TCP/IP. Важные части HTTP-запроса:
- HTTP-метод — это действие, которое необходимо выполнить, обычно GET, POST, PUT и т. д.
- URL — это адрес страницы, к которой требуется получить доступ.
- Form Parameters (параметры формы) — аналог аргументов в методе java (например, данные пользователя, пароль со страницы входа).
GET /FirstServletProject/jsps/hello.jsp HTTP/1.1 Host: localhost:8080 Cache-Control: no-cache
Важные части HTTP-ответа:
- Код состояния — это целое число, которое показывает, был ли запрос успешным или нет. Распространенные коды состояния: 200 — Success, 404 — Not Found и 403 — Access Forbidden.
- Тип контента — это текст, html, изображение, pdf и т. д. Также известен как MIME-тип.
- Контент — фактические данные, которые рендерит клиент и показывает пользователю.
200 OK Date: Wed, 07 Aug 2013 19:55:50 GMT Server: Apache-Coyote/1.1 Content-Length: 309 Content-Type: text/html;charset=US-ASCIIHello Hi There!
Date=Wed Aug 07 12:57:55 PDT 2013
Обратите внимание, что заголовок ответа HTTP в примере выше содержит тег “Content-Type”. Он также называется MIME-тип, сервер отправляет его клиенту, чтобы сообщить ему тип отправляемых данных. Это помогает клиенту отображать данные для пользователя. Некоторые из наиболее распространенных типов MIME: text/html, text/xml, application/xml и т. д.
Что такое URL?
URL (Universal Resource Locator) — используется для определения сервера и ресурса. У каждого ресурса в сети свой уникальный адрес. Давайте рассмотрим части URL-адреса на таком примере:
https://localhost:8080/FirstServletProject/jsps/hello.jsp
https:// — первая часть URL, в ней указывается протокол связи, который будет использоваться при взаимодействии сервер-клиент. localhost — уникальный адрес сервера, чаще всего это имя хоста сервера, которое соответствует уникальному IP-адресу. Иногда несколько имен хостов указывают на одни и те же IP-адреса, а виртуальный хост веб-сервера заботится об отправке запроса на конкретный экземпляр. 8080 — это порт, на котором прослушивается сервер, он не обязателен и если он не указан в URL, то запрос отправляется на порт протокола по умолчанию. Порты с номерами от 0 до 1023 — это зарезервированные порты для известных сервисов, например, 80 для HTTP, 443 для HTTPS, 21 для FTP и т.д. FirstServletProject/jsps/hello.jsp — запрашиваемый ресурс с сервера. Это может быть статический html, pdf, JSP, сервлеты, PHP и т.д.
Зачем нужны сервлеты и JSP?
Веб-серверы подходят для обслуживания статических HTML-страниц, но без дополнительных инструментов они не могут генерировать динамический контент или сохранять данные в базе, поэтому им нужны сторонние средства, с помощью которых можно создать динамический контент. Есть несколько языков программирования динамического контента: PHP, Python, Ruby on Rails, Java Servlet и JSPs. Java Servlet и JSP — это технологии на стороне сервера, которые расширяют возможности веб-серверов за счет поддержки динамических ответов и сохранения данных.
Разработка на Java
Первое веб-приложение с сервлетом и JSP
Мы создадим сервлет-приложение с помощью “Eclipse IDE for Java EE Developers”. Поскольку сервлет — это серверная технология, нам понадобится веб-контейнер, который поддерживает технологию сервлетов, поэтому мы будем работать с Apache Tomcat. Его очень легко настроить и вы сможете это сделать самостоятельно.
Для удобства разработки можно настроить Tomcat с Eclipse, это упростит развертывание и запуск приложений. Перейдите в “Eclipse Preferences”, выберите “Server Runtime Environments” и укажите версию вашего сервера tomcat, у нас — Tomcat 7.

Чтобы добавить среду выполнения, укажите расположение каталога apache tomcat и информацию о JRE. Теперь перейдите во вкладку “Servers” и создайте новый сервер, как показано на скриншоте ниже, указав добавленную среду выполнения.
Примечание: если вкладка “Servers” не отображается, то выберите Window > Show View > Servers, чтобы она появилась в окне Eclipse. Чтобы убедиться, что сервер работает правильно, остановите и затем запустите его. Если вы уже запустили сервер из терминала, то нужно остановить его, а затем запустить из Eclipse, чтобы избежать возможных конфликтов. Теперь можно перейти к созданию первого сервлета и запуску его на сервере tomcat. Для этого выберите File > New > Dynamic Web Project и с помощью скриншота ниже выберите сервер, который мы добавили на предыдущем этапе, а также версию модуля 3.0 для создания сервлета при помощи спецификаций Servlet 3.0.

Вы можете сразу нажать кнопку “Finish”, чтобы создать проект или “Next” для выбора других опций. Затем выберите File > New > Servlet и по скриншоту ниже создайте свой первый сервлет. Опять же, можно нажать кнопку “Finish” или выбрать другие опции, нажав “Next”.

После нажатия “Finish” будет создан скелет кода сервлета, что сэкономит наше время, так как нам не нужно вводить все методы и импорты в сервлет. Затем добавим HTML-код в метод doGet(), который будет генерировать динамические данные при HTTP-запросе GET. Наш первый сервлет будет выглядеть следующим образом:
package com.journaldev.first; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class FirstServlet */ @WebServlet(description = "My First Servlet", urlPatterns = < "/FirstServlet" , "/FirstServlet.do">, initParams = ) public class FirstServlet extends HttpServlet private static final long serialVersionUID = 1L; public static final String HTML_START=""; public static final String HTML_END=""; /** * @see HttpServlet#HttpServlet() */ public FirstServlet() super(); // TODO Auto-generated constructor stub > /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException PrintWriter out = response.getWriter(); Date date = new Date(); out.println(HTML_START + "Hi There!
Date="+date +"
"+HTML_END); > /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException // TODO Auto-generated method stub > >
До версии Servlet 3 нужно было указывать информацию о URL-шаблонах в дескрипторе развертывания веб-приложения, но в Servlet 3.0 можно использовать аннотации java, что снизит вероятность ошибок. Теперь в окне редактора сервлетов выберите Run > Run on Server, после чего настройте параметры по скриншотам ниже.


После нажатия кнопки “Finish” в Eclipse откроется браузер, где мы увидим HTML-страницу, которая будет выглядеть следующим образом:
Вы можете обновить страницу, чтобы убедиться, что Date динамическая и продолжает меняться. Кроме того, страницу можно открыть в любом другом браузере вне Eclipse. Сервлет используется для генерации HTML и отправки его в ответ. Если посмотреть на реализацию метода doGet(), то можно заметить, что мы фактически создаем HTML документ, записывая его в объект PrintWriter ответа, и добавляем динамическую информацию там, где нам это необходимо. Однако, если ответ является большим и содержит много динамических данных, то он подвержен ошибкам, а еще его трудно читать и поддерживать. Это основная причина введения JSP — это технология на стороне сервера, похожая на HTML, но сразу с дополнительными функциями для добавления динамического контента. JSP подходят для презентаций, потому что их легко писать, так как они похожи на HTML. Вот наша первая программа JSP, которая делает то же самое, что и вышеупомянутый сервлет:
pageEncoding="US-ASCII"%> Hello Hi There!
Date=
Если мы запустим вышеприведенный JSP, мы получим вывод, показанный ниже.

Иерархия проекта в Eclipse показана на следующем скриншоте.

Скачивание проекта FirstServlet
Скачать пример проекта сервлета Hello World можно здесь .
Мы рассмотрим сервлеты и JSP более подробно в следующих статьях, но прежде чем закончить эту, вы должны иметь представление о некоторых аспектах веб-приложений Java.
Веб-контейнер
Tomcat — это веб-контейнер. Когда клиент делает запрос на веб-сервер, он передает запрос в веб-контейнер, и его задача — найти правильный ресурс для обработки запроса (сервлет или JSP), а затем использовать ответ от ресурса для генерации ответа и предоставления его веб-серверу. Затем веб-сервер отправляет ответ обратно клиенту. Когда веб-контейнер получает запрос, предназначенный для сервлета, то контейнер создает два объекта: HTTPServletRequest и HTTPServletResponse. Затем он находит правильный сервлет на базе URL-адреса и создает поток для запроса. Далее он вызывает метод сервлета service(), в зависимости от метода HTTP service() вызывает doGet() или doPost(). Методы сервлетов генерируют динамическую страницу и записывают ее в ответ. После завершения потока сервлета контейнер конвертирует ответ в HTTP-ответ и отправляет его обратно клиенту. Некоторые из важных задач, которые выполняет веб-контейнер:
- Поддержка коммуникации: контейнер обеспечивает простой способ связи между веб-сервером, сервлетами и JSP. Благодаря контейнеру нам не нужно создавать серверный сокет для прослушивания запросов от веб-сервера, анализировать их и генерировать ответ. Контейнер выполняет все эти задачи, а мы можем сосредоточиться на бизнес-логике приложений.
- Управление жизненным циклом и ресурсами: контейнер заботится об управлении жизненным циклом сервлета, загрузке сервлетов в память, их инициализации, вызове методов сервлета и их уничтожении. Контейнер также предоставляет утилиты (например JNDI) для объединения и управления ресурсами.
- Поддержка многопоточности: контейнер создает новый поток для каждого запроса к сервлет; когда он обрабатывается, поток останавливается. Таким образом, сервлеты не инициализируются для каждого запроса, что экономит время и память.
- Поддержка JSP: JSP не похожи на обычные классы Java, а веб-контейнер обеспечивает поддержку JSP. Каждый JSP в приложении компилируется контейнером и конвертируется в сервлет, а затем контейнер управляет ими, как и другими сервлетами.
- Разные задачи: веб-контейнер управляет пулом ресурсов, оптимизирует использование памяти, запускает сборщик мусора, предоставляет конфигурации безопасности, поддерживает несколько приложений, горячее развертывание и ряд других скрытых задач, которые упрощают работу.
Структура каталога веб-приложений
Веб-приложения Java упакованы в виде веб-архива (WAR) и имеют определенную структуру. Вы можете экспортировать вышеупомянутый динамический веб-проект в виде файла WAR и распаковать его, чтобы проверить иерархию. Получится что-то вроде того, что показано на скриншоте ниже.

Дескриптор развертывания
Файл web.xml является дескриптором развертывания веб-приложения и содержит сопоставление сервлетов (до версии 3.0), страницы приветствия, конфигурации безопасности, настройки времени ожидания сеанса и т. д.