Java как написать web приложение

Время на прочтение
8 мин

Количество просмотров 204K

Опытные разработчики могут не читать дальше, так-как эта статья рассчитана скорее на новичков, но всё-же я был бы очень рад, если бы кто-нибудь оставил конструктивную критику в мой адрес или указал на ошибки.

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

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

Для предпринимателей или начинающих бизнесменов, или владельцев каких-либо площадок будет интересно узнать, что им в начале их бизнеса совсем не обязательно вкладывать большие деньги на «крутой» сайт, а достаточно воспользоваться открытыми библиотеками и единственное за что заплатить — это за то, чтобы взять в аренду виртуальный сервер.

В статье я покажу, как сделать простейший сайт, имеющий простую функциональность. Это скорее статья, посвященная именно тому, чтобы показать общую концепцию и помочь начинающим разработчикам сформировать понимание того, как именно создаются такие известные ресурсы, как Google, Facebook, Вконтакте.

Вы должны понимать, что все интернет-сервисы создаются по одному принципу, отличаются только детали и реализация каких-то уникальных и конкретных вещей, но суть остаётся единой.

Для тех, кто заинтересовался:

Подготовка

Установка того, что нам понадобиться:

Писать наш сервис мы будем на Java, как самом распространённом языке для веб-сервисов.

Проверьте, что на вашем компьютере установлена последняя версия Java, сейчас это 8 версия. Проверить это можно здесь проверить Java. В 97% случаях так оно и есть, но если это не так, то следуя инструкциями на этом сайте вы без труда исправите это, установив и настроив окружение.

Если же всё-таки это не удалось, сразу договоримся с вами так, первым делом вы пытаетесь решить проблему на этих сайтах:

  • www.google.ru
  • toster.ru
  • stackoverflow.com
  • ru.stackoverflow.com

Если даже это не помогло, то закройте эту статью, вам нужен материал для более низкого уровня подготовки.

Вообще, открою вам секрет, в программировании, когда у вас всё заработало с 1 раза — это означает только одно, что что-то не работает. Это неоспоримый факт. Куча ошибок, несовместимость версий, отсутствие в библиотеке классов и прочее — это нормальное явление.

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

Итак, Java стоит — всё хорошо.

Теперь нам нужен инструмент. Да, нам нужна идея. Качаем и ставим отсюда JetBrains.

Только учтите, что вам нужна именно Ultimate — версия. Простая версия не позволяет разрабатывать веб-приложения. Там есть бесплатный пробный период на 30 дней, думаю с этим не будет проблем.

Итак, среда разработки есть, Java есть.

Начнём

Запускаем идею.

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

Часто вижу вопросы от новичков про такие интересные вещи, как Spring и Hibernate (https://spring.io/, hibernate.org). В 96% случаях вам это пока что не надо, и без хорошей подготовки и хорошего скилла «solve problem» вы увязните там очень надолго и выбраться обратно будет очень тяжело.

Ваша альма-матер на первых порах — это 2 технологии:

  • Сервлет
  • JDBC

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

«Application server». Что это такое? А вот, что Application server.

Так, нам нужен этот сервер, будем использовать Tomcat . Качаем его, если скачали то, что надо, а скорее всего скачали какую-нибудь фигню, то проверьте, архив должен называться «apache-tomcat-7.0.67.zip», разархивируем. Не забудьте, куда распаковали, пригодиться он вам ещё.

Концепция веб-ресурсов

Суть такая, сервер. Что такое сервер? Это программный код, который «зацикленно» крутиться в системе и слушает порты. Это тема отдельного разговора. Но в общем, рассмотрим 2 варианта того, что вообще сервер умеет делать, он умеет отдать данные (GET) — просто вернуть число, страницу, или ещё бог знает что. Но, есть ещё и POST — он тоже возвращает данные, но и принимает от клиента их перед этим.

Если ничего не понятно, читаем тут ru.wikipedia.org/wiki/REST.

Статья начинает слишком сильно расти. Теперь буду стараться писать более кратко.

Идём в мой репозиторий. Предполагаем, что человек совершенно не понимает, что такое система контроля версий, поэтому идём путём дилетанта, там есть кнопка («Download ZIP» — качаем и разархивируем).

В окне приветствия идеи есть кнопка «import project» — жмём. Выбираем скачанный и разархивированный проект.

Жмём далее, далее и далее, пока не откроется проект.

Первые сложности

Проект открыт, но вы не запустите сервер и не сможете открыть сайт. Почему? Потому что, идея не знает, что ей делать, она умна, но не настолько.

Объяснение того, как это сделать, заняло бы пару страниц и оказало бы вам «медвежью» услугу. Первые сложности — первые трудности. Это будет вашим «боевым крещением». Программировать — не пирожки печь. Ссылки сверху вам помогут. Потратить 1-2 часа на это — это нормально. Я знаю хороших и опытных программистов, которые сидели несколько дней, но так и не сумели правильно запустить сервер. Это не делает им чести — но факт — есть факт. Вперед. Запустите — возвращайтесь к чтению.

Не забудьте сообщить идее, что используем tomcat (как? ссылки вверху, по ним есть ответ).

Локальное тестирование сервиса

Получиться у вас должно примерно вот это:

Но есть проблема — не работает! Ну что же, этого следовало ожидать. У нас не создана таблица в базе данных. В проекте мы используем базу данных SQLite

Объяснить, что это такое будет с 0 не просто. Попробуйте почитать об этом на специализированных ресурсах.

Могу посоветовать хороший сервис: www.codecademy.com (там есть Java, SQL, Git, JavaScript и другие супер полезные вещи), поэтому милости прошу.

В итоге, нам нужно создать нашу таблицу, делаем это так:

cd Path/apache-tomcat-7.0.64/bin/
sqlite3 SimpleDatabse

CREATE TABLE NAMES(
   ID INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL,
   NAME TEXT NOT NULL
);

Таблица создана. Можно проверить как работает наша система. Добавьте пару имён и посмотрите, как они будут вам возвращены уже из самой базы.

Разбор кода

Начнём смотреть, что же у нас в коде:

Так уж повелось, что в Java все конфигурации пишутся в xml-файлах, тут не исключение — файл web.xml контролирует, то, какой сервлет за что отвечает. Внимательно посмотрите на код и попробуйте поменять ссылку или имя сервлета.

Приложение у нас простое, поэтому у всего 2 класса (SQLiteClass и MainServlet).

Очевидно, думаю, что первый отвечает за работу с базой данных, а второй и есть наш пресловутый сервлет.

А вот и наши, упомянутые выше POST и GET запросы, эти функции являются обработчиками и задают поведение сервлета в ответ на запросы от клиента. Суть одна — данные пришли, данные ушли. Ничего сложного. Попробуйте поиграться с методами.

protected void doGet(HttpServletRequest request, HttpServletResponse response)

protected void doPost(HttpServletRequest request, HttpServletResponse response) 

Переходим к классу, реализующему JDBC:

public static void addName(String name)

public static ArrayList<String> getAllNames()

Здесь тоже всё просто, те же SQL запросы, только завёрнутые в Java-код. Небольшой совет — остерегайтесь всяких надстроек и фреймворков. Они хороши только в больших проектах, когда у вас миллионы записей, и сложные транзакционные операции. Но, настоящий контроль вы получите только, когда пишете именно вручную запрос, без таких вещей как сериализация жить намного проще (особенно поначалу).

Всё, с серверной частью закончим. Тут вам придётся посидеть, почитать специальные статьи и руководства. Без реальной практики тут никак.

Клиентская часть

Вот и пришло время взглянуть на то, что твориться у клиента в браузере. А ничего сверхъестественного. Но, скажу вам прямо, конечно всё зависит от проекта, но, клиентская часть обычно намного сложнее в реализации, чем серверная. И всё в основном из-за JavaScript-а. Очень быстро клиентский код превращается в набор «простыней», заплат, хардкода и прочих веселостей. JavaScript суров и беспощаден. На чистом нём писать очень тяжело. Поэтому мы используем JQuery. Есть куча других фреймворков и другого творения, но их касаться здесь не будем. Есть такая поговорка, что назови любое слово и это будет названием JS-фреймворка. Известен в узких кругах фреймфорк Mocha, я не представляю какие мысли посещали человека, когда он придумывал ему название, ну ладно, это было его право, конечно же.

Итак, что у нас там с клиентом?

Опять дам ссылку на отличнейший ресурс www.codecademy.com. Фронтенд там разобран очень хорошо и даёт необходимую базу для начинающих.

Тут рассмотрим только функцию

function serverConnectFunc(serverUrl, jsonData) {
    $.ajax({
        url: serverUrl + "/",
        type: 'POST',
        data: jsonData,

        dataType: 'json',
        async: true,

        success: function (event) {
            //do somehting
        },
        error: function (xhr, status, error) {
            alert(error);
        }
    });
}

Что она делает? Правильно, шлёт тот самый POST — запрос и разбирает ответ. Всё просто, отдал данные и получил с сервера. По русски он говорит серверу «Дай мне имена всех, кто у тебя в базе» или «Занеси в базу это имя» и даёт ему имя.

Вот и вся клиентская часть.

Отправляем ресурс в настоящий мир

Как можно было заметить, наш сервис крутиться на локальном хосте. Другими словами на нашем же компьютере. Пришло время это исправить.

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

И по традиции сразу несколько ссылок:

nginx
tomcat in real world
nginx config
SSH

Читаем, что там написано, формируем в голове общую концепцию, того, как происходит взаимодействие программиста и удаленного сервера.

Сами сервера можно приобрести на amazone. Ссылку не даю, ибо реклама, можете сами поискать, это не сложно. Есть бесплатный тестовый период. НО! Будьте предельно осторожны, ваш покорный слуга сам слышал истории, как со счетов списывались тысячи долларов без ведома хозяина, ибо система сама умеет докупать себе мощности. Не попадитесь, я сам уже платил несколько раз за непонятные услуги, там всё на английском. Если не уверены, что делаете — лучше вообще не делайте.

Порядок действий таков:

  1. Арендуете облако
  2. Подключаетесь по протоколу ssh
  3. Ставите нужные пакеты и настраиваете систему
  4. Собираете у себя war-пакет и деплоите его на сервер
  5. Решаете кучу ошибок и проблем

Сразу скажу, с первого раза это удалось единицам. Всегда есть что-то, что не хочет ставиться, запускаться или работать. Это нормально. Рано или поздно у вас будет красивый ip-шник вроде 74.125.224.72 и ваш сервер станет доступен в интернете. У меня ушло на это дело несколько месяцев, можно быстрее? Думаю да, попробуйте. Потом не забудьте купить себе красивый домен и передайте другу или знакомому ссылку. Если всё получилось — поздравляю, вы стали на один шаг ближе к тому, чтобы стать профессионалом.

На всякий случай я оставлю тут эти ссылки, вдруг, кто-то застопорился на каком-то моменте и решил спуститься в самый низ статьи, может помогут:

maven.apache.org
git-scm.com

Заключение

Вот мы и добрались до кульминации нашего здесь обсуждения Джавы и веб-разработки на ней. Сложно? Да. Интересно? Да. Все, абсолютно все сервисы, будь то, поисковая система с миллиардами индексов, будь то видео-сервис с миллионами стрим-каналов — всё строиться по одному принципу. Отдать — забрать данные. Понимая эту концепцию вы сможете написать любую систему, сервис или платформу.

Я не стану лукавить и обманывать вас уважаемые читатели. Вряд ли вы за 2 или 3 недели станете супер профессионалами и будете свободно писать код. Этому можно научиться только потом и долгими ночами. Чем дальше вы будете залазить в дебри, тем больше вы будете понимать, что вы так мало знаете. Дорогу осилит идущий, вперед, дерзайте.

Вперед. Пришло время действовать. Стареющим Дурову и Брину пора уйти на покой, время их славы уже прошло, пришло время обновить учебники истории и списки Forbs. И кто знает, может эту статью читает тот, кто в своё время напишет отличнейшую платформу, которая затмит собой таких гигантов как Google, Facebook и других. Удачи, спасибо, что дочитали до конца.

На сегодняшний день в мире разработки на 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 {
    useJUnitPlatform()
}

Тот же результат можно получить и в самой IntelliJ Idea: File → New → Project → Spring Initializr.

Объявим Main-класс:

@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 {
    Long id;
    String author;
    String title;
    Double price;
}

После сборки проекта можно посмотреть, как выглядит класс после компиляции. Воспользуемся стандартной утилитой, входящей в состав JDK:

javap -private build/classes/java/main/com/example/BookStore/model/Book

public final class com.example.bookstore.model.Book {
  private final java.lang.Long id;
  private final java.lang.String author;
  private final java.lang.String title;
  private final java.lang.Double price;
  public com.example.bookstore.model.Book(java.lang.Long, java.lang.String, java.lang.String, java.lang.Double);
  public java.lang.Long getId();
  public java.lang.String getAuthor();
  public java.lang.String getTitle();
  public java.lang.Double getPrice();
  public boolean equals(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
}

Lombok очень упрощает читаемость подобного рода классов и очень широко используется в современной разработке.

Spring Data JPA

Для работы с БД нам потребуется Spring Data JPA, который мы уже добавили в зависимости проекта. Дальше нам нужно описать классы Entity и Repository. Первый соответствует таблице в БД, второй необходим для загрузки и сохранения записей в эту таблицу.

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "books")
public class BookEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String author;

    private String title;

    private Double price;
}

Мы также используем аннотации Lombok: @Data добавляет getters и setters, @NoArgsConstructor и @AllArgsConstructor — конструкторы без параметров и со всеми параметрами, соответственно. @Entity, @Table, @Id, @GeneratedValue — аннотации относящиеся к JPA. Здесь мы указываем, что это объект БД, название таблицы, первичный ключ и стратегию его генерации (в нашем случае автоматическую).

Класс Repository будет выглядеть совсем просто — достаточно объявить интерфейс и наследоваться от CrudRepository:

public interface BookRepository extends CrudRepository<BookEntity, Long> {
    
}

Никакой реализации не требуется. Spring всё сделает за нас. В данном случае мы сразу получим функциональность CRUD — create, read, update, delete. Функционал можно наращивать — чуть позже мы это увидим. Мы описали DAO-слой.

Теперь нам нужен некий сервис, который будет иметь примерно следующий интерфейс:

public interface BookService {
    Book getBookById(Long id);// получить книгу по id
    List<Book> getAllBooks();// получить список всех книг
    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 = " + id));

        return new Book(bookEntity.getId(), 
                        bookEntity.getAuthor(), 
                        bookEntity.getTitle(), 
                        bookEntity.getPrice());
    }

    @Override
    public List<Book> getAllBooks() {
        Iterable<BookEntity> iterable = bookRepository.findAll();
        
        ArrayList<Book> 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) {
    this.bookRepository = bookRepository;
}

При создании объекта класса Spring опять всё возьмёт на себя — сам создаст объект BookRepository и передаст его в конструктор. Имея объект репозитория мы можем выполнять операции с БД:

bookRepository.findById(id); //прочитать запись из БД по первичному ключу id
bookRepository.findAll(); //прочитать все записи из БД и вернуть их в виде списка
bookRepository.save(bookEntity); //сохранить объект в БД

Метод findById возвращает объект типа Optional<BookEntity>. Это такой специальный тип который может содержать, а может и не содержать значение. Альтернативный способ проверки на null, но позволяющий более изящно написать код. Метод orElseThrow извлекает значение из Optional, и, если оно отсутствует, бросает исключение, которое создается в переданном в качестве аргумента лямбда-выражении. То есть объект исключения будет создаваться только в случае отсутствия значения в Optional.

MapStruct

Смотря на код может показаться, что класс Book не нужен, и достаточно только BookEntity, но это не так. Book — это класс сервисного слоя, а BookEntity — DAO. В нашем простом случае они действительно повторяют друг друга, но бывают и более сложные случаи, когда сервисный слой оперирует с несколькими таблицами и соответственно DAO-объектами.

Если присмотреться, то и тут мы видим однотипный код, когда мы перекладываем данные из BookEntity в Book и обратно. Чтобы упростить себе жизнь и сделать код более читаемым, воспользуемся библиотекой MapStruct. Это mapper, который за нас будет выполнять перекладывание данных из одного объекта в другой и обратно. Для этого добавим зависимости в build.gradle:

dependencies {
    ...
    implementation 'org.mapstruct:mapstruct:1.4.2.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}

Создадим mapper, для этого необходимо объявить интерфейс, в котором опишем методы для конвертации из BookEntity в Book и обратно:

@Mapper(componentModel = "spring")
public interface BookToEntityMapper {
    BookEntity bookToBookEntity(Book book);
    Book bookEntityToBook(BookEntity bookEntity);
}

Так как имена полей классов соотносятся один к одному, то интерфейс получился таким простым. Если поля имеют отличающиеся имена, то потребуется аннотацией @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 id = null;
        String author = null;
        String title = null;
        Double price = null;

        id = bookEntity.getId();
        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 = " + id));
        
        return mapper.bookEntityToBook(bookEntity);
    }

    @Override
    public List<Book> getAllBooks() {
        Iterable<BookEntity> iterable = bookRepository.findAll();
        ArrayList<Book> 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 {
    private String author;
    private String title;
    private Double price;
}

Нам также потребуется конвертировать объект AddBookRequest в объект Book. Создадим для этого BookToDtoMapper:

@Mapper(componentModel = "spring")
public interface BookToDtoMapper {
    Book AddBookRequestToBook(BookRequest bookRequest);
}

Теперь объявим контроллер, на эндпоинты которого будут приходить запросы на создание и получение книг, добавив зависимости 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("/{id}")
    public Book getBookById(@PathVariable Long id) {
        return bookService.getBookById(id);
    }

    @GetMapping
    public List<Book> 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"

{
  "id": 2,
  "author": "Kathy Sierra",
  "title": "Head First Java",
  "price": 12.66
}

Добавим к нашему api более сложную функциональность — поиск по автору книги. Для этого в BookRepository нужно описать метод, который будет делать соответствующий SELECT из БД. Это можно сделать с помощью аннотации @Query, а можно назвать метод в соответствии со специальной нотацией Spring:

List<BookEntity> findAllByAuthorContaining(String author);

В документации можно подробнее прочитать об именовании методов. Здесь мы указываем findAll — найти все записи, ByAuthor — параметр обрамляется %. При вызове этого метода (например с аргументом ‘Bloch’) будет сгенерирован следующий запрос:

SELECT * FROM books WHERE author LIKE '%Bloch%';

Далее добавим метод в BookService и DefaultBookService:

@Override
public List<Book> findByAuthor(String author) {
    Iterable<BookEntity> iterable = bookRepository.findAllByAuthorContaining(author);
    ArrayList<Book> books = new ArrayList<>();
    for (BookEntity bookEntity : iterable) {
        books.add(mapper.bookEntityToBook(bookEntity));
    }

    return books;
}

А в контроллере немного модифицируем метод получения списка книг таким образом, что при передаче get-параметра author мы искали по автору, а если параметр не передётся, то используется старая логика и выводится список всех книг:

@GetMapping
public List<Book> getAllBooks(@RequestParam(required = false) String author) {
    if (author != null)
        return bookService.findByAuthor(author);

    return bookService.getAllBooks();
}

Теперь можно выполнить поиск:

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.

Архитектура Web-приложений

Архитектура современных web-приложений

Архитектура современных web-приложений

Архитектура современных приложений состоит из отдельных модулей, как показано на рисунке выше. Эти модули часто называют Frontend и Backend. Frontend – это модуль, который отвечает за юзер-интерфейс и логику, которые предоставляется приложением при использовании. Так, например когда мы заходим в соцсети через браузер, мы взаимодействуем именно с FrontEnd-модулем приложения. То, как отображаются наши посты в виде сторисов или карточек, сообщения и другие активности реализуются именно в FrontEnd-модуле. А все данные, которые мы видим, хранятся и обрабатываются в Backend или серверной части приложения. Эти модули обмениваются между собой посредством разных архитектурных стилей: REST, GRPC и форматов сообщений – JSON и XML.

В этой статье мы напишем примитивную серверную часть социальной сети с использованием Spring Boot, запустим свой сервер, рассмотрим разные типы HTTP запросов и их применение.

Необходимое требование к читателю: умение писать на Java и базовые знания Spring Framework. Данная статья познакомит вас со Spring Boot и даст базовые понятия данного фреймворка.

Инициализация проекта

Чтобы создать Spring Boot проект, перейдем на страницу https://start.spring.io/ и выберем необходимые зависимости: в нашем случае Spring Web. Чтобы запустить проект, необходима минимальная версия Java 17. Скачиваем проект и открываем в любом IDE (в моем случае – Intellij Idea)

Инициализация проекта

Инициализация проекта

Spring Web – зависимость, которая предоставляет контейнер сервлетов Apache Tomcat (является дефолтным веб-сервером). Проще говоря, сервлеты – это классы, которые обрабатывают все входящие запросы.

Открываем проект и запускаем.

Запуск проекта

Запуск проекта

Мы видим, что проект запустился и готов обрабатывать запросы на порту 8080 – Tomcat started on port(s): 8080 (http).

Теперь создадим свой первый класс – GreetingController. Controller-классы ответственны за обработку входящих запросов и возвращают ответ.
Чтобы сделать наш класс Controller, достаточно прописать аннотацию @RestController. @RequestMapping указывает, по какому пути будет находиться определённый ресурс или выполняться логика.

Greeting Controller
        package io.proglib;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/greet")
public class GreetingController {

    @GetMapping
    public String greet() {
        return "Hello";
    }

}

    

Перезапускаем проект, и сервер готов уже обрабатывать наши запросы.
Открываем браузер по адресу http://localhost:8080/greet и получаем следующий вывод.

Ответ сервера

Ответ сервера

Если отправить запрос по адресу http://localhost:8080/ , мы получим ошибку, т. к. по этому пути не определены логика обработки запроса и ресурсы.

Request Params

При отправке запросов мы часто используем переменные в запросе, чтобы передавать дополнительную информацию или же делать запросы гибкими. Параметр в запросе передаётся в конце адреса (=url) сервера и указывается после вопросительного знака (=?).
Например, http://localhost:8080/greet?name=Alice. Параметр запроса является = name cо значением = Alice.

Чтобы обрабатывать переменную запроса, используется аннотация @RequestParam. Параметры запроса могут быть опциональными или же обязательными. @RequestParam("name") означает следующее: взять ту переменную из запроса, название которого равно name.

Метод с параметризированным запросом
        @RestController
@RequestMapping("/greet")
public class GreetingController {

    @GetMapping
    public String greet(@RequestParam("name") String name) {
        return "Hello, " + name;
    }

}

    

☕ Пишем свой первый сервер на Java и Spring Boot

Вдобавок, запрос может содержать несколько параметров.

Например, http://localhost:8080/greet/full?name=John&surname=Smith. Параметры выделяются знаком &. В этом запросе два параметра: name=John и surname=Smith.

Чтобы обработать каждый параметр запроса, нужно пометить каждую переменную @RequestParam.

        package io.proglib;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/greet")
public class GreetingController {

    @GetMapping
    public String greet(@RequestParam("name") String name) {
        return "Hello, " + name;
    }

    @GetMapping("/full")
    public String fullGreeting(@RequestParam("name") String name, 
                               @RequestParam("surname") String surname) {
        return "Nice to meet you, " + name + " " + surname;
    }

}

    

Параметризованный запрос с двумя параметрами

Параметризованный запрос с двумя параметрами

Path Variable

PathVariable по применению похож на @Request Param. @PathVariable также является параметром запроса, но используются внутри адреса запроса. Например,

RequestParamhttp://localhost:8080/greet/full?name=John&surname=Smith
PathVariablehttp://localhost:8080/greet/John. В этом случае John является PathVariable.
В запросе можно указывать несколько PathVariable, как и в случае RequestParam

        package io.proglib;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/greet")
public class GreetingController {

    @GetMapping
    public String greet(@RequestParam("name") String name) {
        return "Hello, " + name;
    }

    @GetMapping("/full")
    public String fullGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname) {
        return "Nice to meet you, " + name + " " + surname;
    }

    @GetMapping("/{name}")
    public String greetWithPathVariable(@PathVariable("name") String name) {
        return "Hello, " + name;
    }

}

    

Чтобы протестировать, открываем браузер и переходим по адресам: http://localhost:8080/greet/John/Smith и http://localhost:8080/greet/John

☕ Пишем свой первый сервер на Java и Spring Boot

Запрос с двумя параметризованными PathVariable.

☕ Пишем свой первый сервер на Java и Spring Boot

HTTP-методы

Когда мы говорим о запросах, мы также подразумеваем HTTP-метод, который используется при отправке этого запроса. Каждый запрос представляет собой некий HTTP-метод. Например, когда мы переходим в браузере по адресу http://localhost:8080/greet/John/Smith, наш браузер отправляет GET-запрос на сервер.

Большая часть информационных систем обмениваются данными посредством HTTP-методов. Основными HTTP-методами являются – POST, GET, PUT, DELETE. Эти четыре запроса также называют CRUD-запросами.

  • POST-метод – используется при создании новых ресурсов или данных. Например, когда мы загружаем новые посты в соцсетях, чаще всего используется POST-запросы. POST-запрос может иметь тело запроса.
  • GET-метод – используется при получении данных. Например, при открытии любого веб-приложения, отправляется именно GET-запрос для получения данных и отображения их на странице. GET-запрос не имеет тела запроса.
  • PUT-метод – используется для обновления данных, а также может иметь тело запроса, как и POST.
  • DELETE-метод – используется для удаления данных.

Реализация основных методов

Давайте создадим сущности и реализуем методы, чтобы наш сервер принимал все четыре запроса. Для этого создадим сущности User и Post, и будем проводить операции над ними.

Для простоты User имеет только два поля: username и список постов posts, а сущность Post имеет поле description и imageUrl.

Сущность User:

        package io.proglib;

import java.util.ArrayList;
import java.util.List;

public class User {
    private String username;
    private List<Post> posts;

    public User() {
        posts = new ArrayList<>();
    }

    public User(String username, List<Post> posts) {
        this.username = username;
        this.posts = posts == null ? new ArrayList<>() : posts;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<Post> getPosts() {
        return posts;
    }

    public void setPosts(List<Post> posts) {
        this.posts = posts;
    }

}

    

Сущность Post:

        package io.proglib;

public record Post(
        String description,
        String imageUrl
) {
}

    

Создаем новый класс контроллер – UserActivityController, который будет обрабатывать наши запросы – POST, GET, PUT, DELETE.

Наш контроллер: UserActivityController.

Будем использовать список – List<User> users в качестве локальной базы данных, где будем хранить все наши данные.

UserActivityController
        package io.proglib;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserActivityController {

      private final static List<User> users = new ArrayList<>();

}

    

POST-запрос: добавление нового пользователя

Чтобы указать, что метод принимает POST-запросы используем аннотацию – @PostMapping. Так как запрос имеет тело запроса, где мы передаем пользователя, нужно пометить переменную user аннотацией @RequestBody.

            @PostMapping("")
    public User addUser(@RequestBody User user) {
        users.add(user);
        return user;
    }
    

GET-запрос: получение пользователей

         @GetMapping("")
    public List<User> getUsers() {
        return users;
    }

    @GetMapping("/{username}")
    public User getUserByUsername(@PathVariable("username") String username) {
        return users.stream().filter(user -> user.getUsername().equals(username))
                .findFirst().get();
    }


    

@Getmapping("") указывает, что методы обрабатывают GET-запросы. Значение, которое передаётся внутри аннотации, является частью url или адреса. Например, запрос http://localhost:8080/users/baggio обработается методом getUserByUsername(), а запрос http://localhost:8080/users/ обработается методом http://localhost:8080/users.

PUT-запрос: обновление данных

            @PutMapping("/{username}")
    public Post update(@PathVariable("username") String username, @RequestBody Post post) {
        users.stream().filter(user ->
                        user.getUsername().equals(username))
                .findAny()
                .ifPresent(user -> user.getPosts().add(post));
        return post;
    }
    

@PutMapping("/{username}") указывает, что метод принимает PUT-запросы. В нашем примере в запросе мы передаем параметр запроса, а также тело запроса – post. Метод принимает – username, ищет юзера из списка с таким username и добавляем новый пост к его списку постов.

Delete-запрос: удаление данных

        @DeleteMapping("/{username}")
    public String deleteUser(@PathVariable("username") String username) {
        users.stream().filter(user ->
                        user.getUsername().equals(username))
                        .findAny()
                                .ifPresent(users::remove);
        return "User with username: " + username + " has been deleted";
    }
    

@DeleteMapping("/{username}") – указывает, что метод принимает DELETE-запросы.
Данный метод получает параметр username из запроса и удаляет из списка пользователя с таким username.

Запуск приложения и тестирование

Чтобы убедиться, что все работает, мы можем отправить каждый вид запроса и протестировать. Для этого нам необходим API-client, который может посылать запросы. В примерах я использую POSTMAN.

Post-запрос: создание нового пользователя.

Тело запроса отправляется в виде JSON.

☕ Пишем свой первый сервер на Java и Spring Boot

GET-запрос: получение пользователей

☕ Пишем свой первый сервер на Java и Spring Boot

PUT-запрос: обновление списка постов пользователя

☕ Пишем свой первый сервер на Java и Spring Boot

DELETE-запрос: удаление пользователя по username

☕ Пишем свой первый сервер на Java и Spring Boot

***

В этой статье мы рассмотрели архитектуру современных web-приложений, а также написали свою серверную часть приложения, получив поверхностные знания по Spring Boot, HTTP запросы и параметры запросов.

Ссылка на репозиторий

Исходный код можно найти по ссылке.

Материалы по теме

  • ☕ Сертификаты и тренинги для Java-разработчика
  • ☕🛣️ Дорожная карта Java-разработчика в 2023 году: путь с нуля до первой работы

Многие современные программисты предпочитают в своей работе пользоваться Java. Несмотря на то, что спросом пользуется Си-семейство, Джава тоже не уступает. Связано это с тем, что данный язык является универсальным. Он удобен, понятен и практичен.

С самого своего возникновения (в 1995 году) стал активно развиваться и совершенствоваться. Сейчас Java удобно использовать как для компьютерных программ, так и для мобильных платформ. Это – полноценный язык, поддерживающий объектно-ориентированное программирование. Ключевая особенность Java – возможность создавать веб-приложения и расширения.

Перед тем, как садиться за написание первых приложений на Джаве, нужно знать, какими особенностями обладает соответствующий         язык. Далеко не все «способы общения» с софтом и «железом» подходят для написания конкретного контента.

У Java следующие особенности:

  • наличие функционала для ООП;
  • понятный и относительно простой синтаксис – освоить его может даже начинающий программист-любитель;
  • хорошая пользовательская поддержка – она дружелюбна к новичкам;
  • достаточное количество документации на всех языках, включая русский;
  • движок и библиотеки для написания игр и всевозможных веб утилит.

Java великолепно «работает» с Сетью. Именно для этой цели изначально планировалось создание оного. Также стоит отметить – упомянутый язык является кроссплатформенным. Перенести программу из одной ОС в другую удается в кратчайшие сроки и без потери качества исходной кодификации.

Понятие веб-приложения

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

В веб-приложении клиент будет взаимодействовать с веб-сервером посредством вспомогательных утилит. Их называют браузерами. Логика распределяется между сервером и клиентом. Хранение информации производится в основном на servers. Обмен данными обеспечивается Сетью.

Основное преимущество подобного контента – это то, что клиенты не будут зависеть от той или иной операционной системы. Не важно, какая ОС установлена на задействованном устройстве. Web-приложения будут работать везде. Это – кроссплатформенный вариант.

Техособенности

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

  1. Функции выполняются независимо от ОС пользователя.
  2. Приложение будет создаваться всего один раз для произвольно выбранной платформе. Именно на ней осуществляется дальнейшее развертывание.
  3. Иногда пользовательские права на редактирование настроек интернет-обозревателя способны доставить немало хлопот. Приложения для работы с сетью будут отображаться некорректно.
  4. Не исключены проблемы при разработке и поддержке утилит из-за разной реализации CSS и DOM.
  5. Возможно использование Java-апплетов и Adobe Flash. Со вторым типом приложений сегодня возникают затруднения. Связано это с тем, что Flash-технологии с 2015 года перестали поддерживаться.

В каком-то смысле веб приложения можно отнести к «толстым» клиентам. Связано это с особенностями архитектуры рассматриваемого контента.

Архитектурный вопрос

Для начала рекомендуется разобраться, какова архитектура у приложений типа «веб». Она включает в себя клиентскую и серверную части. За счет этого в жизнь воплощается технология под названием «клиент-сервер».

Клиент отвечает за реализацию пользовательского interface. Также он формирует серверные запросы и обрабатывает ответы, получаемые от соответствующих «команд».

Серверная часть:

  • получает заданный клиентом (юзером) запрос;
  • производит необходимые вычисления;
  • формирует веб-страничку для дальнейших манипуляций;
  • производит отправку полученной страницы пользователю по Сети, используя протоколы HTTP.

 Веб приложение может являться клиентом иных служб.: баз данных или иных утилит, хранящихся на тех или иных серверах. Пока удается привести один узнаваемый пример – Википедия и ее система управления. Здесь n-количество участников способны принимать участие в разработке сетевой энциклопедии. Работа ведется посредством браузеров. Дополнительные исполняемые модули не загружаются.

Веб-сервер – это…

Перед тем, как писать собственный контент, надо хорошо разбираться в том, какие процессы будут происходить внутри программы. Особенно тогда, когда речь заходит о создании утилит для работы с Сетью.

Web Applications работают по принципу «клиент-сервер». Но не совсем понятно, что такое server, как он реализован. Даже сложные и глобальные проекты будут функционировать по примерно одному и тому же принципу.

Веб-сервер – своеобразный сервер, который принимает HTTP-запросы от клиента, а затем выдает соответствующие ответы. Специальное программное обеспечение, которое выполняет функции веб-server. Может быть выражен «железом» с ПО для взаимодействия с Сетью.

Web Servers, как сказано в Google, обладают дополнительным функционалом. Примеры:

  • автоматизация работы страничек в Сети;
  • авторизация и аутентификация пользователей;
  • поддержка страниц, которые генерируются динамически;
  • возможность поддержки HTTPS для защищенных соединений;
  • ведение журнала пользовательских обращений к тем или иным ресурсам.

Вариантов веб-серверов очень много. Это говорит о том, что данное направление является весьма перспективным. Вот примеры самых популярных веб-серверов:

  • Apache;
  • Nginx;
  • Microsoft IIS.

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

Сервер приложений

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

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

Application Server – утилита, представленная сервером. Последний занимается системной поддержкой программ, а также отвечает за обеспечение жизненных циклов в соответствие с установленными принципами работы. Функционирует или самостоятельно, или выступает в качестве поставщика страниц для иных web-servers. Отвечает за обмен информации между софтом и клиентами. Создает программную среду для итогового приложения, помогает авторизовывать и идентифицировать клиентов, организовывает сессии для каждого «подключившегося».

Вот несколько распространенных серверов утилит на Java:

  • Tomcat Apache;
  • JBoss;
  • IBM WebSphere;
  • Oracle WebLogic.

Веб-сервер имеет отношение преимущественно к способу передачи данных. Если говорить об Application Server, можно сделать вывод о том, что это – более узкое понятие. Относится к способу исполнения программ (удаленная обработка клиентских команд). В одном ряду соответствующие термины не размещаются. Они отвечают за совершенно разные признаки софта.

Серверные технологии

Java, как и любой другой язык программирования, позволяет создавать уникальный контент. Если он относится к типу «веб», предстоит сначала разобраться в технологиях, используемых для запуска софта и обработки информации. У Джавы их несколько. Выбирать стоит в зависимости от того, для чего конкретно пишется программа.

Технология AJAX

AJAX – это асинхронный JavaScript и XML. Технология, которую можно считать относительно новой. При ней утилита не будет перезагружаться полностью. Для обновления информации осуществляется подгрузка недостающих/новых сведений. Это значительно ускоряет работу и упрощает ее.

AJAX в основном используется при интерактивных пользовательских интерфейсах. Обмен данными «браузер-сервер» протекает в фоновом режиме. Описать данный процесс можно так:

  1. Юзер открывает страничку в интернете.
  2. Происходит взаимодействие с тем или иным элементом.
  3. Скрипт JS определяет, какие данные нужны для обновления.
  4. Браузер отправляет соответствующий запрос на веб-сервер.
  5. Последний отвечает за возврат документа, на которую посылался запрос.
  6. Скрипт корректирует страницу с учетом полученных данных.

Вообще, принцип работы базируется на двух вариантах. Каждый обладает своими нюансами.

Динамическое обращение

Первый вариант развития событий – это технология динамического обращения к серверам «на лету» посредством динамического создания:

  • фреймов дочернего характера;
  • тегов <script>;
  • тегов <img>.

После применения данных технологий происходит функционирование без перезагрузки всей страницы целиком. Это – относительно быстрое решение поставленной задачи.

Второй подход – задействование DHTML для динамического корректирования информации на страничке.

Что включает в себя AJAX

При составлении кода утилиты и изучении материалов о принципах работы веб-софта нужно уяснить – AJAX не является самостоятельной технологией. Она включает в себя следующие методы реализации:

  • HTML и CSS – для того, чтобы подавать и стилизировать электронные материалы;
  • DOM-модели – в ответе за динамическое отображение и взаимодействие с соответствующими сведениями через JS;
  • XMLHttpRequest или иные транспорты (Iframe, SCRIPT-теги и так далее) – асинхронизированый обмен материалами с web server;
  • JSON или иной формат соответствующего характера (форматированные HTML, тестовые «вариации», XML) – обмен информацией.

Фактически AJAX – это концепция применения сразу нескольких технологий серверного характера.

Технологии WebSocket

WebSoket – еще один популярный нынче вариант. Стараясь разобраться в теме веб-приложений перед написанием оного, важно осознавать, какие технологии будут применяться в том или ином случае.

WebSoket – протокол полнодуплексной связи, накладываемый поверх TCP-соединения. Он предназначается для того, чтобы сервер обменивался данными с интернет-обозревателем в режиме реального времени, «здесь и сейчас». Комментарии тут излишни.

Достаточно запомнить, что данный вариант предусматривает две URI схема:

  • ws: – нешифрованное соединение;
  • wss: — шифрованный «коннектинг».

Технология не требует постоянных запросов клиент-сервер. В процессе реализации всегда создается двунаправленное соединение. Данные с server могут отправляться к client без запроса от оного.

А что о CGI?

Создавая приложение на Джаве, программист должен предварительно изучить возможные технологии работы веб-утилит. Есть вариант CGI. Это – низкоуровневый вариант. Стандарт, который использует интерфейс. Последний задействуется для связи внешней программы с сервером.

CGI обладает хорошей реализацией. Там можно использовать практически любой язык программирования, а не просто Java или JavaScript. Соответствующий вариант имеет следующие плюсы и минусы:

  • универсален за счет отсутствия требований к платформам;
  • позволяет использовать тот язык программирования, который хотим;
  • CGI – это готовый к запуску файл, что делает затрудненным расширение системы.

Все это заставило программистов развиваться в технологиях работы с серверными каналами. Теперь существуют более совершенные «версии» технологий.

Java Servlet

Сервлет относится к «методикам» Java. Сочетает в себе особенности API и CGI. Помогает разобраться с производительностью, так как все запросы будут выполняться в едином потоке в одном и том же процессе. Сервлеты не имеют никакой зависимости от платформы.

Servlet – это класс Java, который выполняется внутри Джава VM:

  1. Контейнер веб-утилиты вида Tomcat начинает загрузку сервлета. Это происходит при первом обращении или в процессе запуска сервера согласно установленным конфигурационным параметрам.
  2. Servlet загружается и остается в подобном состоянии до тех пор, пока не будет произведена явная выгрузка.
  3. Возможно отключение посредством остановки контейнера.

Java Servlets имеет программный интерфейс, позволяющий вести обработку запросов на низком уровне. Обработка ведется в едином процессе посредством создания потоков внутри. Код предстоит составлять так, чтобы он был безопасным.

JSP – нюансы

Еще один вариант, применяемый для приложений, написанных на Джаве – это JSP. Разработка здесь больше не требует особых временных затрат. Связано это с тем, что программисту предстоит работать с шаблонами.

JSP – шаблоны страничек, похожих на ASP и PHP. Привязки к ПО и аппаратным платформам нет. Производительность ограничена:

  • странички нужно компилировать в сервлеты, но только при первом обращении;
  • servlets обрабатываются в JVM.

Основная нагрузка при реализации за счет кластеризации переходит на аппаратное обеспечение.

PHP – что такое?

PHP – распространенный «формат», который используют многие сервисы и приложения. Обладает высоким уровнем безопасности. Основывается на принципе построения страничек по шаблонам.

PHP-страницы – это обычные HTML, включающие в себя особые тэги. Каждый такой элемент виден сразу. Он имеет форму <?php?>.

Из песочницы, Разработка веб-сайтов, Java


Рекомендация: подборка платных и бесплатных курсов Smm — https://katalog-kursov.ru/

Всем доброго времени суток.

Эта статья рассчитана для новичков в мире Web и Java. Мы рассмотрим стандартную архитектуру веб-приложения и сделаем небольшой проект с нуля.

Будем использовать Spring (Огромный фреймворк для веба), но по минимуму. Если не иметь предыдущего опыта использования и сразу пытаться использовать весь функционал, то не будет базового понимания, так как имеется перечень подводных камней.

Что будет делать приложение

Хочу представить короткий и в то же время полезный пример. Он минимально загружен и по итогу вы сможете использовать его как шаблон.

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

Исходный код вы сможете найти здесь.

Что будем использовать

  • любимую IDE (я использую IntelliJ IDEA)
  • не замутненную голову
  • Maven (сборщик проекта)
  • JDBC (звено между Java и СУБД)

Создание проекта

Создайте простой Maven проект. Делаем все с чистого листа, не добавляя никаких архетипов.
IDE должна сгенерировать такую структуру.

image

И так, что мы видим.

  • java — основное место где будет происходить «магия»
  • resources — место где хранятся наши ресурсы. (Это могут быть файлы, картинки и чего только душа пожелает, зачастую тут хранится front часть приложения)
  • test — место где принято писать тесты к приложению. (Вы можете с чистой совестью удалять эту папку, тестирование мы рассматривать не будем)
  • pom.xml — сердце Maven. В нем содержится информация о проекте, тут прописываются все зависимости, указывается какой тип «упаковки» должен быть у проекта и тд.

Кстати, не пропустите сообщения от IDE, и разрешите авто-импорт для Maven.

image

Архитектура веб-приложения

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

image

На картинке показаны слои веб-приложения, каждый слой может взаимодействовать только со своими соседями, если приложение написано «по-правильному».

И так пробежимся по каждому слою и разберем их назначения.

  1. Browser — это лицо нашего приложения. То что видит пользователь и что называют Frontend. Он может взаимодействовать с Backend — серверной частью, а именно с контроллером. Этот слой должен уметь отправлять и получать данные от контроллера.
  2. Controller — должен контролировать запросы от Frontend, уметь их обрабатывать и возвращать данные. И, конечно же, задачей контролера является общение со следующим слоем.
  3. Service — в этом слое должна быть реализована бизнес-логика приложения. Можно считать этот слой корнем приложения. В нем происходят самые тяжеловесные операции.
  4. DAL(data access layer) — этот слой должен общаться с нашей БД. В нём реализованы все запросы к БД, которые нужны для приложения, а именно запросы на выборку, изменения и тд.
  5. Database — она же БД, структурированная туса данных.

Проектирование базы данных

Один из самых первых этапов разработки веб-приложения является проектирование БД.

Выбор БД предоставляется на ваше усмотрение, но у меня в примере будет использоваться H2.

Так как я хочу чтобы пример вышел небольшой, но чтобы в нем удалось рассмотреть как можно больше скользких моментов и понять всеобщие принципы построения веб-приложений. В примере будет только одна таблица User.

create table DATABASE.USER
(
    ID INT auto_increment,
    NAME VARCHAR not null,
    SURNAME VARCHAR not null,
    LOGIN VARCHAR not null,
    PASSWORD VARCHAR not null,
    constraint USER_PK
        primary key (ID)
);

Добавляем Spring в проект

Вспоминаем про нашу папку java.

Создаем внутри java пакет com.zuk(вы можете называть иначе), в нем класс App с обычной main функцией.

И добавим щепотку магии Spring. Не будем вдаваться сильно в то что здесь происходит, с помощью @SpringBootApplication мы просто говорим Spring, чтобы он делал автоматическую настройку, чтобы он сканировал все что ему нужно. Сейчас рекомендую рассматривать Spring как автономную республику.

//com.zuk.App
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

Не впадаем в панику если все красное и не забываем подключать зависимости в pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.zuk</groupId>
    <artifactId>LoginAndRegistration</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
    </dependencies>

</project>

Если вы все сделали правильно у вас появится возможность сделать билд проекта, и Spring скажет вам привет.

image

Spring говорит что он стартанул сервер на порту 8080. Мы можем сами убедиться в этом, сходив на http://localhost:8080.

Подключаем БД к проекту

И так мы уже создали нашу Базу даных, подключили Spring к проекту, но они ещё не знают о существование друг друга.

Давайте создадим application.properties по пути src.main.resources.

Этот файл служит для хранения конфигурационных параметров в формате ключ-значение.

spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:~/test

spring.datasource.username=sa
spring.datasource.password=

Это стандартные ключи для Spring, и он сам может их прочитать.

Чтобы вы смогли убедиться в соединении, предлагаю проверить сможем ли мы подключиться в БД.
Хочу предупредить, моё решение будет спорным. На мой взгляд для новичка оно будет показательным и не будет вызывать много вопросов, но не стоит сильно опираться на данный подход. В Spring есть интересные реализации для работы с БД.
Советую почитать несколько статей по данной тематике.

По пути java.com.zuk.connection создадим класс ConnectionManager, он должен отдавать нам соединение с БД, и с этим соединением мы в дальнейшем будем работать.
Для этого нам понадобится вытянуть наши properties, сделаем это с помощью FileInputStream.

//ConnectionManager
FileInputStream fis;
Properties property = new Properties();

Проберемся к нашему application.properties, и вытянем с него properties.

//ConnectionManager
fis = new FileInputStream("src/main/resources/application.properties");
property.load(fis);

Создаем метод getConnection.

  //ConnectionManager
  public Connection getConnection() {
            Connection connection = null;
            try {
                connection = DriverManager.getConnection(property.getProperty("spring.datasource.url"),property.getProperty("spring.datasource.username"),property.getProperty("spring.datasource.password"));
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }

Теперь можете проверить есть ли соединение, сделать это можно и в App.

Если у вас все получилось, должно вывести такое.

conn2: url=jdbc:h2:~/test user=SA

Ах да, не забываем добавить зависимость в наш любимый pom.

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.200</version>
</dependency>

POJO (Plain Old Java Objects)

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

Представьте простой класс, который ничего не наследует, в который не должно быть реализованы ничего сложно. Это просто класс, который служит носителем информации, в котором есть некоторые поля, геттеры и сеттеры для них. Максимум, что может быть, это реализация стандартных методов объекта. Это и есть наш POJO.

Для нашего проекта, это будет описание сущности таблицы User.
То есть мы реализуем таблицу в виде класса.

И так создаем пакет java.com.zuk.entity, в нем класс User.
Запишем в поля класса поля таблицы, и реализуем для каждого геттер и сеттер.

User.java

public class User {

    private int id;
    private String name;
    private String surname;
    private String login;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

DAL

Что же, самое время приступить к следующему слою, а именно DAL. Тут будут реализованы все запросы к нашей БД, которые нам понадобятся. Честь этого слоя будет отстаивать DAO (data access object) — интерфейс к какому-либо типу базы данных или механизму хранения.

Создаем пакет java.com.zuk.dao в нем интерфейс UserDao (принято сначала писать имя таблицы). Опишем пока что только два метода findByLogin, save.

public interface UserDao {
    User findByLogin(String login);
    Boolean save(User user);
}

Дальше напишем реализацию для этого интерфейса, создаем пакет java.com.zuk.dao.impl,
в нем класс UserDaoImpl.
Вы можете спросить зачем так сильно разделять все — это будет служить хорошей привычкой, вдруг вам придется работать в большом проекте, там скорее всего будут специфические реализации (например, если используется несколько БД).

public class UserDaoImpl implements UserDao {
    @Override
    public User findByLogin(String login) {
        return null;
    }

    @Override
    public Boolean save(User user) {
        return null;
    }
}

Начнем с findByLogin. Нам нужно сделать такой SQL запрос.

SELECT  * from DATABASE.User where LOGIN=login

Далее нужно вернуть объект класса User.

Проверим есть ли у нас соединение с базой, если же его не будет мы вернем null.

//UserDaoImpl
ConnectionManager cm = new ConnectionManager();
Connection con = cm.getConnection();

@Override
    public User findByLogin(String login) {
        User user = null;
        if (con != null) {
              //..  
        }
        return user;
     }

Если условие в if правильное, мы выполним SQL запрос, и запишем значение в user.

//findByLogin
PreparedStatement pr = con.prepareStatement("SELECT * FROM DATABASE.User where LOGIN=?");
pr.setString(1 , login);
ResultSet resultSet = pr.executeQuery();//return sql result
if(resultSet.next()) {
       user = new User();
       user.setId(resultSet.getInt("ID"));
       user.setName(resultSet.getString("NAME"));
       user.setSurname(resultSet.getString("SURNAME"));
       user.setLogin(login);
       user.setPassword(resultSet.getString("PASSWORD"));
       return user;
}
 pr.close();
 con.close();

Не забываем покрывать возможные исключения.

Попробуйте реализовать save своими руками.
Код оставлю под спойлером.

save

//UserDaoImpl
@Override
    public Boolean save(User user) {
        ConnectionManager cm = new ConnectionManager();
        Connection con = cm.getConnection();
        if (con != null) {
            try {
                PreparedStatement pr = con.prepareStatement("insert into DATABASE.USER (NAME,SURNAME,LOGIN,PASSWORD) values (?,?,?,?)");
                pr.setString(1,user.getName());
                pr.setString(2,user.getSurname());
                pr.setString(3,user.getLogin());
                pr.setString(4, DigestUtils.md5DigestAsHex((user.getPassword()).getBytes()));
                pr.executeUpdate();
                pr.close();
                con.close();
                return true;
            } catch (SQLException e) {
                e.printStackTrace();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

Service

В сервисе будет находится наша бизнес-логика. Создаем пакет java.com.zuk.service, в нем интерфейс UserService с двумя методами: login, registration. И создаем класс UserServiceImpl в java.com.zuk.service.impl, который имплементирует UserService.

public class UserServiceImpl implements UserService {
    @Override
    public String login(User user) {
        return null;
    }

    @Override
    public String registration(User user) {
        return null;
    }
}

Предлагаю начать с login.
Алгоритм будет таким:

  1. Проверим существует ли поле «login» в БД.
  2. Если условие 1 выполняется, проверяем совпадает ли пароль.
  3. Если условие 2 выполняется, скажем «life is beautiful»

//UserServiceImpl
UserDaoImpl userDao = new UserDaoImpl();
    @Override
    public String login(User user) {
        User findUser = userDao.findByLogin(user.getLogin());
        if(findUser!=null){
            if(DigestUtils.md5DigestAsHex((user.getPassword()).getBytes()).equals(findUser.getPassword())){
                return "life is beautiful"  + "your Id: " + findUser.getId();
            }
        }
        return "do not give up";
    }

Попытайтесь сделать регистрацию своими руками.

registration

 @Override
    public String registration(User user) {
        User findUser = userDao.findByLogin(user.getLogin());
        if(findUser==null) {
            userDao.save(user);
            return "life is beautiful";
        }
        return "this login is not available";
    }

Controller

Настала звездный час контроллера, и мы наконец-то сможем увидеть результат наших деяний.
Создаём пакет java.com.zuk.controller в нем класс Controller. Перед классом разместим «магическую» аннотацию RestController, она поможет Spring понять, что этот класс будет служить нам как Rest Controller.
Создаём метод, который возвращает строку и аннотируем его с помощью @RequestMapping(«/»).

@RestController
public class Controller {
    @RequestMapping("/")
    String main() {
        return "Hello from Controller";
    }
}

Делаем билд проекта, и переходим на http://localhost:8080.
Мы должны увидеть «Hello from Controller».

Теперь создаём два html файла. Один будет с формой регистрации, второй с формой логина.
Правильным тоном будет сохранение этих файлы внутри resources, а еще лучше в папку resources.static.

html

<!--loginFrom.html-->
<html>
<title>Login</title>
<body>
<form action="http://localhost:8080/login"  method="post">
    <input type="text" required name="login" placeholder="login" />
    <input type="password" required name="password" placeholder="password" />
    <button>login</button>
</form>
<a href="http://localhost:8080/registrationForm">don't have account</a>
</body>
</html>

<!--registrationForm.html-->
<html>
<title>Registration</title>
<body>
<form action="http://localhost:8080/registration"  method="post">
    <input type="text" required name="name" placeholder="name" />
    <input type="text" required name="surname" placeholder="surname" />
    <input type="text" required name="login" placeholder="login" />
    <input type="password" required name="password" placeholder="password" />
    <button>registration</button>
</form>
<a href="http://localhost:8080/loginForm">already have account</a>
</body>
</html>

Теперь я хочу, чтобы при переходе по ссылке http://localhost:8080/loginForm, или http://localhost:8080/registrationForm выводились наши html файлы с формами.
Возвращаемся к нашему контроллеру, тут мы должны добавить мапинг для /loginForm, /registrationForm и отдавать соответствующую html. В этом нам поможет ModelAndView.

//Controller
 @RequestMapping("/loginForm")
    ModelAndView loginForm() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("loginForm.html");
        return modelAndView;
    }

    @RequestMapping("/registrationForm")
    ModelAndView registrationForm() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("registrationForm.html");
        return modelAndView;
    }

Если вы заметили, то в форме я уже написал action на http://localhost:8080/login и registration, но мы ещё не ловим эти переходы в контроллере.
Пора это исправлять и связаться с нашим service.

//Controller
UserServiceImpl userService = new UserServiceImpl();
//..
 @PostMapping("/login")
    String login(@RequestParam String login,@RequestParam String password) {
        User user = new User();
        user.setLogin(login);
        user.setPassword(password);
        return userService.login(user);
    }

    @PostMapping("/registration")
    String registration(@RequestParam String name,@RequestParam String surname, @RequestParam String login,@RequestParam String password) {
        User user = new User();
        user.setName(name);
        user.setSurname(surname);
        user.setLogin(login);
        user.setPassword(password);
        return userService.registration(user);
    }

Мы видим, что наши методы в Controller начали принимать параметры. Это те параметры, которые мы пишем в наших формах. Их имена должны совпадать с именами input.

Заключение

Надеюсь эта статья смогла ответь на некоторые ваши вопросы, и помогла расширить свои горизонты.

Всем приятного развития.

Вы наверняка слышали о том, что сайты можно делать на PHP, Python и довольно не плохие сайты. Но как же Java? Да на java тоже можно делать очень даже офигенные сайты, а если быть точней то используют java для разработки крупных ресурсов. В этом уроке я покажу как создать простое web-приложение на java.

Что нам потребуется для создания web-приложения?

1) Любой сервер приложений в нашем случае это будет Tomcat 7.0.

2) Верная и надежная Intellij IDEA.

3) Желание создать своё первое WEB-приложение.

Шаг 1

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

Давайте теперь разберем структуру проекта: src/java/servlets – тут будут лежать сервлеты(сервлеты будут рассматриваться в Шаг 2.) src/resources – тут будут лежать все ресурсные файлы которые буду нужны для проекта. src/webapp – тут лежат все файлы которые будут использоваться во view (к примеру img, css).

Шаг 2

Теперь разберем что такое Servlet? Servlet – это Java-интерфейс, реализация которого расширяет функциональные возможности сервера. Servlet взаимодействует с клиентами посредством принципа запрос-ответ за частую это запросы GET, POST по протоколу HTTP/HTTPS. Для создания сервлета нам нужно подключить зависимости в Maven.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>3.0-alpha-1</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javaee</groupId>
    <artifactId>javaee-api</artifactId>
    <version>5</version>
</dependency>

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>6.0</version>
    <scope>provided</scope>
</dependency>

А также не забудьте указать:

<packaging>war</packaging>

это говорит Maven-у что собирать надо в WEB проект, по умолчанию он собирает jar.

Теперь нужно добавить 2 плагина который позволяет откомпилировать и собрать проект в war архив.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.5</source>
        <target>1.5</target>
    </configuration>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

Полный листинг pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>MyFirstWebProject</groupId>
    <artifactId>MyFirstWebProject</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>3.0-alpha-1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javaee</groupId>
            <artifactId>javaee-api</artifactId>
            <version>5</version>
        </dependency>

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Теперь создадим класс MyServlet который унаследуем от HttpServlet.

@WebServlet("/s")
public class MyServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                          throws ServletException, IOException {
        super.doPost(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                         throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        out.println("Hello Word");
    }
}

Как вы видите тут есть два метода doPost и doGet, как я уже упоминал сервлеты взаимодействуют с клиентом по средством запрос-ответ, так вот в основном это GET и POST. Внимание! Главное не допускать такую ошибку, что всего есть два метода GET/POST их на самом деле 9, это OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH. И так рассмотрим эти методы методы: Как вы уже поняли метод doPost принимает и отправляет посредством запроса POST, doGet по средством запроса GET. У обоих методов есть входящие параметры типы которых – HttpServletRequest и HttpServletResponse. HttpServletRequest request – это запрос со стороны клиента; HttpServletResponse response – это ответ со стороны сервера.

Аннотация @WebServlet(“/s”) указывает на то что данный сервлет будет доступен по адресу <URL>/s.

Шаг 3

Не забываем, что метод GET срабатывает когда мы просто заходим по URL на страничку, а пост чаще всего используется при передачи данных с формы, но при условии что метод передачи данных формы указан POST. Создадим “Hello Word”:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                     throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    out.println("Hello Word");
}

response.setContentType("text/html") – в этой строке мы говорим про то что отображать мы будем страничку как html. PrintWriter out = response.getWriter() – тут мы создаем врайтер который поможет нам осуществить ответ с сервера. out.println("Hello Word") – ну и отправляем ответ с сервера клиенту.

Шаг 4

Теперь соберите проект в Maven:

Шаг 5

Установка и настройка Tomcat 7.0.

1. Идем сюда http://tomcat.apache.org/download-70.cgi и качаем Tomcat 7.0.

2. Извлекаем с архива;

3. Настроить Intellij IDEA что бы деплоить приложение на сервер с нее.

Нажимаем плюсик выбираем Tomcat Server -> Local после чего нажимаем Configure… и выбираем корневую папку где лежит Tomcat 7.0.

В Startup Page – указываем стартовую страничку загрузки в нашем случае это localhost:8080/s (где s это наш про аннотированиый сервлет).

Дальше заходим во вкладкуDeployment:

И выбираем ваш собранный проект, лежит он в корне проекта в папке target/<name>.war

4. Запускаем:

Шаг 6

Завяжем на наш сервлет jsp страничку.

Для этого мы должны создать в папке src/main/webapp нашу страничку, в нашем случае это index.jsp.

И теперь с помощью метода GET отправим на нее тот же текст “<h1>Hello World!</h1> <p>It JSP.<p>”

Вот так будет выглядеть наш метод сервлета doGet():

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

        String varTextA = "Hello World!";
        request.setAttribute("textA", varTextA);
        String varTextB = "It JSP.";
        request.setAttribute("textB", varTextB);

        RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
        dispatcher.forward(request, response);
}

С помощью RequestDispatcher мы отправляем наш response request клиенту.

А так будет выглядеть index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title></title>
</head>
<body>
${textA}
${textB}
</body>
</html>

С помощью конструкции ${<var>} мы принимаем данные с сервера.

После этого вы получите ту же по виду страничку, только это уже будет не сервлет отображать а  jsp.

Для получения углубленных знаний по Java проходите наш курс «Программирование на языке Java для начинающих», а также читайте серию статей «Spring Data JPA. Работа с БД»: часть 1, часть 2 и часть 3

    None Found

Понравилась статья? Поделить с друзьями:
  • Is a pen little it как правильно написать
  • Ios или ios как правильно пишется
  • Inshaallah как пишется
  • Info amefir tv как написать письмо
  • Inc как пишется