Как написать скрипт на java

Скрипты написаны полностью на языке Java, поэтому могут иметь доступ ко всем ресурсам сервера, на котором запущен AggreGate Server, включая:

  • Любые объекты в оперативной памяти
  • Файловую систему
  • Сетевой и последовательный интерфейсы ввода/вывода
  • Консоли, журналирование и даже графический интерфейс пользователя
  • Многопоточную обработку

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

Интерфейс скрипта

Скрипты написаны на языке Java. Каждый скрипт — это отдельный Java класс, который должен реализовать интерфейс скрипта:

public interface Script

{

  public DataTable execute(ScriptExecutionEnvironment environment, DataTable parameters) throws ScriptException;

}

Этот интерфейс объявляет единственный метод execute(), который вызывается  AggreGate Server при выполнении скрипта.

Среда выполнения

У каждого скрипта есть доступ к объекту, описыващему интерфейс ScriptExecutionEnvironment, который передается в качестве аргумента методу execute(). Ниже описан интерфейс ScriptExecutionEnvironment:

public interface ScriptExecutionEnvironment

{

  public abstract CallerController getCallerController();

  public abstract Context getScriptContext();

}

Экземпляр ScriptExecutionEnvironment предоставляет доступ к объекту, описывающему интерфейс CallerController (он получен в результате вызова метода getCallerController()). Этот объект включает в себя права доступа пользователя, который инициировал выполнение скрипта. Объект CallerController передается в качестве аргумента большинству контекстных операций (Get Context, Get/Set Variable, Call Function, Add/Remove Event Listener и т.д.)

Когда скрипт запускается автоматически при запуске сервера, его среда выполнения включает в себя систему CallerController, которая подавляет все проверки прав доступа.

Context, возвращаемый методом getScriptContext(), позволяет получить доступ к дереву контекстов и всем его объектам.

Разработка скриптов

Изучите руководство по программированию, чтобы получить общую информацию о разработке скриптов AggreGate.

Шаблон скрипта

Когда создается новый скрипт, он содержит автоматически сгенерированную заглушку класса реализации интерфейса Скрипта с пустым методом execute(). Ниже представлен текст скрипта по умолчанию:

import com.tibbo.aggregate.common.context.*;

import com.tibbo.aggregate.common.datatable.*;

import com.tibbo.aggregate.common.script.*;

import com.tibbo.linkserver.*;

import com.tibbo.linkserver.context.*;

import com.tibbo.linkserver.script.*;

public class %ScriptClassNamePattern% implements Script

{

  public DataTable execute(ScriptExecutionEnvironment environment, DataTable parameters) throws ScriptException

  {

  }

}

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

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

Пример скрипта

Пример Java скрипта, который меняет IP адрес аппаратного Device Server:

import com.tibbo.aggregate.common.context.*;

import com.tibbo.aggregate.common.datatable.*;

import com.tibbo.aggregate.common.script.*;

import com.tibbo.linkserver.*;

import com.tibbo.linkserver.context.*;

import com.tibbo.linkserver.script.*;

public class %ScriptClassNamePattern% implements Script

{

  public DataTable execute(ScriptExecutionEnvironment environment, DataTable parameters) throws ScriptException

  {

try

{

       // Getting context of a Device Server

       Context con = environment.getScriptContext().getContextManager().get("users.admin.deviceservers.c1", environment.getCallerController());

       if (con == null)

       {

               throw new ScriptException("Device Server not available");

       }

       // Getting IP address variable

       DataTable val = con.getVariable("IP_setting", environment.getCallerController());

       // Changing IP address

       val.rec().setValue("IP_setting", "192.168.1.235");

       // Writing new value of variable

       con.setVariable("IP_setting", environment.getCallerController(), val);

       // Rebooting Device Server

       con.callFunction("reboot", environment.getCallerController());

       return null;

}

catch (ScriptException ex)

{

       throw ex;

}

catch (Exception ex)

{

       throw new ScriptException(ex);

}

  }

}

  • Назад
  • Обзор: Getting started with the web
  • Далее

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

Что такое JavaScript на самом деле?

JavaScript («JS» для краткости) — это полноценный динамический язык программирования, который применяется к HTML документу, и может обеспечить динамическую интерактивность на веб-сайтах. Его разработал Brendan Eich, сооснователь проекта Mozilla, Mozilla Foundation и Mozilla Corporation.

JavaScript невероятно универсален и дружелюбен к новичкам. Обладая большим опытом, вы сможете создавать игры, анимированную 2D и 3D графику, полномасштабные приложения с базами данных и многое другое!

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

  • Программные интерфейсы приложения (API), встроенные в браузеры, обеспечивающие различные функциональные возможности, такие как динамическое создание HTML и установку CSS стилей, захват и манипуляция видеопотоком, работа с веб-камерой пользователя или генерация 3D графики и аудио сэмплов.
  • Сторонние API позволяют разработчикам внедрять функциональность в свои сайты от других разработчиков, таких как Twitter или Facebook.
  • Также вы можете применить к вашему HTML сторонние фреймворки и библиотеки, что позволит вам ускорить создание сайтов и приложений.

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

Ниже мы познакомим вас с некоторыми аспектами основного языка, и вы также будете играть с несколькими функциями API браузера. Веселитесь!

Пример «hello world»

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

Тем не менее, с JavaScript немного более сложно освоиться, чем с HTML и CSS. Вам придётся начать с малого, продолжая изучение небольшими шагами. Для начала мы покажем вам, как добавить некоторые основы JavaScript на вашу страницу, чтобы создать «hello world!» пример (стандарт в начальных примерах программирования).

Предупреждение: Важно: Если вы не следили за остальным нашим курсом, скачайте этот пример кода и используйте его в качестве стартовой точки.

  1. Для начала перейдите на ваш тестовый сайт и создайте папку с именем ‘scripts’ (без кавычек). Затем, в новой папке скриптов, которую вы только что создали, создайте новый файл с именем main.js. Сохраните его в вашей папке scripts.
  2. Далее перейдите в ваш index.html файл и введите следующий элемент на новой строке прямо перед закрывающим тегом </body>:
    <script src="scripts/main.js"></script>
    
  3. В основном этот код выполняет ту же работу, что и элемент <link> для CSS — добавляет JavaScript на страницу, позволяя ему взаимодействовать с HTML (и CSS, и чем-нибудь ещё на странице).
  4. Теперь добавьте следующий код в файл main.js:
    var myHeading = document.querySelector('h1');
    myHeading.textContent = 'Hello world!';
    
  5. Теперь убедитесь, что HTML и JavaScript файлы сохранены, и загрузите index.html в браузере. Вы должны увидеть что-то вроде этого:

Примечание: Причиной, по которой мы поставили элемент <script> в нижней части HTML файла, является то, что HTML-элементы загружаются браузером в том порядке, в котором они расположены в файле. Поэтому, если JavaScript загружается первым и ему нужно взаимодействовать с HTML ниже его, он не сможет работать, так как JavaScript будет загружен раньше, чем HTML, с которым нужно работать. Поэтому, располагать JavaScript в нижней части HTML страницы считается лучшей стратегией.

Что произошло?

Итак, ваш заголовок текста был изменён на «Hello world!» с помощью JavaScript. Мы сделали это с помощью вызова функции querySelector(), захватив ссылку на наш заголовок и сохранив её в переменной, названной myHeading. Это очень похоже на то, что мы делали в CSS с помощью селекторов. Если вы хотите что-то сделать с элементом, то для начала вам нужно его выбрать.

После этого, вы устанавливаете значение переменной myHeading в textContent свойство (которое представляет собой контент заголовка) «Hello world!».

Ускоренный курс по основам языка

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

Предупреждение: Важно: В этой статье попробуйте вводить примеры строк кода в вашей JavaScript консоли, чтобы увидеть, что происходит. Для более подробной информации о JavaScript консоли смотрите статью Откройте для себя браузерные инструменты разработчика.

Переменные

Переменные — это контейнеры, внутри которых вы можете хранить значения. Вы начинаете с того, что объявляете переменную с помощью ключевого слова var (не рекомендуется, продолжайте читать, чтобы получить объяснения) или let, за которым следует любое имя, которым вы захотите её назвать:

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

Примечание: JavaScript чувствителен к регистру — myVariable отличается от переменной myvariable. Если у вас возникают проблемы в вашем коде, проверьте регистр!

**Примечание:**Для получения более подробной информации о разнице между var и let, смотрите: Разница между var и let.

После объявления переменной вы можете присвоить ей значение:

Вы можете сделать обе эти операции на одной и той же строке, если вы захотите:

Вы можете получить значение, просто вызвав переменную по имени:

После установки значения переменной вы можете изменить его позже:

var myVariable = 'Bob';
myVariable = 'Steve';

Обратите внимание, что переменные имеют разные типы данных:

Переменная Пояснение Пример
String Последовательность текста, называемая строкой. Чтобы указать, что это значение является строкой, вы должны заключить его в кавычки. var myVariable = 'Bob';
Number Числа. Числа не имеют кавычек вокруг них. var myVariable = 10;
Boolean Значение True(Правда)/False(Ложь). Слова true и false специальные ключевые слова в JS, и не нуждаются в кавычках. var myVariable = true;
Array Массив, который позволяет хранить несколько значений в одной ссылке. var myVariable = [1,'Bob','Steve',10]; Обратиться к каждому элементу массива можно так: myVariable[0], myVariable[1], и т.д.
Object В принципе, что угодно. Все в JavaScript является объектом, и может храниться в переменной. Имейте это в виду, пока вы учитесь. var myVariable = document.querySelector('h1'); Все это из вышеприведённых примеров.

Так для чего нам нужны переменные? Что ж, переменные должны были сделать что-нибудь интересное в программировании. Если значения не могли бы изменяться, то вы не могли бы ничего сделать динамическим, например, персонализировать приветственное сообщение или сменить изображение, отображаемое в галерее изображений.

Комментарии

Комментарии — это, по сути, короткие фрагменты текста, которые могут быть добавлены в код, и которые игнорируются браузером. Вы можете поместить комментарии в JavaScript-код, так же как вы делали это в CSS:

/*
Всё, что находится тут - комментарий.
*/

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

Операторы

operator (en-US) — это математический символ, который производит результат, основанный на двух значениях (или переменных). В приведённой ниже таблице вы можете увидеть некоторые из наиболее простых операторов, наряду с некоторыми примерами, которые опробуете в JavaScript консоли.

Оператор Пояснение Символ(ы) Пример
Сложение (Конкатенация) Используется для сложения двух чисел или склеивания двух строк вместе. + 6 + 9; "Hello " + "world!";
Вычитание, Умножение, Деление Они делают то, чего вы от них ожидаете в математике. -, *, / 9 - 3; 8 * 2; // умножение в JS это звёздочка 9 / 3;
Присваивание Вы уже это видели: он присваивает значение переменной. = var myVariable = 'Bob';
Равенство (Тождество) Делает проверку, если увидит, что два значения равны друг другу, то возвращает результат true/false (Boolean). === var myVariable = 3; myVariable === 4;
Отрицание (Неравенство) Возвращает логически противоположное значение, которое ему предшествует; превращает true в false, и т.д. Когда используется вместе с оператором равенства, оператор отрицания проверяет, являются ли два значения не равными. !, !== Основное выражение true, но сравнение возвращает false, потому что мы отрицаем его: var myVariable = 3; !(myVariable === 3);Здесь мы проверяем «myVariable НЕ равно 3″. Это возвращает false, потому что myVariable равно 3. var myVariable = 3; myVariable !== 3;

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

Примечание: Смешивание типов данных может привести к некоторым неожиданным результатам при выполнении вычислений, поэтому будьте осторожны, правильно ссылайтесь на ваши переменные, чтобы получать ожидаемые результаты. Например, введите "35" + "25" в вашу консоль. Почему вы не получили результат, который вы ожидали? Потому, что кавычки превратили числа в строки, так что у вас в итоге получилась конкатенация строк, а не сложение чисел. Если вы введёте, 35 + 25, то получите правильный результат.

Условия

Условия — это конструкции в коде, которые позволяют проверить истинность или ложность выражения и выполнить другой код в зависимости от полученного результата. Самая распространённая форма условия — инструкция if ... else. Например:

var iceCream = 'chocolate';
if (iceCream === 'chocolate') {
  alert('Yay, I love chocolate ice cream!');
} else {
  alert('Awwww, but chocolate is my favorite...');
}

Выражение внутри if ( ... ) — это проверка, которая использует тождественный оператор (как описано выше), чтобы сравнить переменную iceCream со строкой chocolate и увидеть равны ли они. Если это сравнение возвращает true, выполнится первый блок кода. Если нет, этот код пропустится и выполнится второй блок кода, после инструкции else.

Функции

Функции — способ упаковки функциональности, которую вы хотите использовать повторно. Всякий раз, когда вам нужна определённая процедура, вы можете просто вызвать функцию по её имени, а не переписывать весь код каждый раз. Вы уже видели некоторые функции, описанные выше, например:

var myVariable = document.querySelector('h1');

Эти функции, document.querySelector и alert, встроены в браузер для того, чтобы вы использовали их всякий раз, когда вам это необходимо.

Если вы видите что-то, что выглядит как имя переменной, но имеет после него скобки — (), скорее всего, это функция. Функции часто принимают аргументы — биты данных, которые им необходимы для выполнения своей работы. Они находятся в скобках, и разделяются запятыми, если присутствует более одного аргумента.

Например, функция alert() вызывает всплывающий блок, появляющийся в окне браузера, но мы должны дать ему строку в качестве аргумента, чтобы сказать функции, что писать во всплывающем блоке.

Хорошая новость заключается в том, что вы можете определить свои собственные функции — в следующем примере мы напишем простую функцию, которая принимает два числа в качестве аргументов и умножает их:

function multiply(num1,num2) {
  var result = num1 * num2;
  return result;
}

Попробуйте запустить вышеупомянутую функцию в консоли, затем попробуйте изменить аргументы, например:

multiply(4,7);
multiply(20,20);
multiply(0.5,3);

Примечание: Инструкция return сообщает браузеру, что нужно вернуть переменную result из функции, которую можно будет использовать. Это необходимо потому, что переменные, определённые внутри функций, доступны только внутри этих функций. Это называется областью видимости (en-US) переменной. (Читайте больше об области видимости переменных.)

События

Для создания действительной интерактивности на веб-сайте вам необходимы события. События — это структура, которая следит за тем, что происходит в браузере, а затем позволяет вам запускать код в ответ на это. Наиболее очевидным является событие клика (en-US), которое вызывается браузером, когда мы щёлкаем по чему-то мышью. Для демонстрации этого события введите следующую команду в вашу консоль, а затем щёлкните по текущей веб-странице:

document.querySelector('html').onclick = function() {
    alert('Ouch! Stop poking me!');
}

Существуют множество способов прикрепить событие к элементу. Здесь мы выбираем <html> элемент и устанавливаем ему обработчик свойства onclick (en-US) анонимной функцией (т.е. безымянной) которая содержит код, который мы хотим запустить для события клика.

Обратите внимание, что

document.querySelector('html').onclick = function() {};

эквивалентно

var myHTML = document.querySelector('html');
myHTML.onclick = function() {};

Просто так короче.

Прокачаем пример нашего веб-сайта

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

Добавление смены изображения

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

  1. В первую очередь найдите другое изображение, которые вы хотели бы показать на вашем сайте. Убедитесь что оно такого же размера, как ваше первое изображение или максимально близкое к нему.
  2. Сохраните изображение в вашу папку images.
  3. Переименуйте это изображение в ‘firefox2.png’ (без кавычек).
  4. Перейдите в ваш файл main.js и введите следующий JavaScript. (Если ваш «hello world» JavaScript по-прежнему существует, удалите его.)
    var myImage = document.querySelector('img');
    
    myImage.onclick = function() {
        var mySrc = myImage.getAttribute('src');
        if(mySrc === 'images/firefox-icon.png') {
          myImage.setAttribute ('src','images/firefox2.png');
        } else {
          myImage.setAttribute ('src','images/firefox-icon.png');
        }
    }
    
  5. Сохраните все файлы и загрузите index.html в браузере. Теперь, когда вы щёлкните по изображению, оно должно измениться на другое!

Итак, мы сохраняем ссылку на наш элемент <img> в переменной myImage. Далее, мы создаём этой переменной обработчик события onclick с анонимной функцией. Теперь, каждый раз, когда на этот элемент изображения щёлкнут:

  1. Мы получаем значение из атрибута src изображения.
  2. Мы используем условие для проверки значения src, равен ли путь к исходному изображению:
    1. Если это так, мы меняем значение src на путь ко 2-му изображению, заставляя другое изображение загружаться внутри элемента <image>.
    2. Если это не так (значит, оно должно было уже измениться), мы меняем значение src, возвращаясь к первоначальному пути изображения, каким он был изначально.

Добавление персонального приветственного сообщения

Далее мы добавим немного другого кода, чтобы изменить заголовок страницы на персонализированное приветственное сообщение, когда пользователь впервые зайдёт на сайт. Это приветственное сообщение будет сохраняться, когда пользователь покинет сайт, а позже вернётся — мы сохраним его с помощью Web Storage API. Мы также включим возможность изменить пользователя и, следовательно, приветственное сообщение, в любое время, когда это будет необходимо.

  1. В index.html, добавьте следующую строку перед элементом <script>:
    <button>Change user</button>
    
  2. В main.js, добавьте следующий код в конец файла, точно так, как написано — он захватит ссылки на новую кнопку и заголовок, и сохранит их в переменные:
    var myButton = document.querySelector('button');
    var myHeading = document.querySelector('h1');
    
  3. Теперь добавьте следующую функцию для установки персонализированного приветствия — она ничего не будет делать, но мы будем использовать её позже:
    function setUserName() {
      var myName = prompt('Please enter your name.');
      localStorage.setItem('name', myName);
      myHeading.textContent = 'Mozilla is cool, ' + myName;
    }
    

    Эта функция содержит функцию prompt() (en-US), которая вызывает диалоговое окно, немного похожее на alert() кроме того, что prompt() просит пользователя ввести некоторые данные, и сохраняет эти данные в переменной, после того как пользователь нажимает OK. В данном случае, мы просим пользователя ввести его имя. Далее, мы вызываем API под названием localStorage, который позволяет нам хранить данные в браузере и извлекать их позднее. Мы используем функцию setItem() из localStorage для создания и хранения данных в свойстве под названием 'name', и устанавливаем это значение в переменную myName, которая содержит имя введённое пользователем. В конце мы устанавливаем textContent заголовку в виде строки и имени пользователя.

  4. Затем добавьте блок if ... else — мы могли бы назвать это кодом инициализации, поскольку он структурирует приложение при его первой загрузке:
    if(!localStorage.getItem('name')) {
      setUserName();
    } else {
      var storedName = localStorage.getItem('name');
      myHeading.textContent = 'Mozilla is cool, ' + storedName;
    }
    

    Этот блок сначала использует оператор отрицания (логическое НЕ, представленное в виде !) чтобы проверить, существуют ли данные в пункте name. Если нет, то функция setUserName() запускается для их создания. Если данные существуют (то есть, пользователь установил его во время предыдущего посещения), мы извлекаем сохранённое имя, с помощью getItem() и устанавливаем textContent заголовку в виде строки плюс имя пользователя, так же, как мы делали внутри setUserName().

  5. Наконец, установите обработчик события onclick на кнопку. При нажатии кнопки запускается функция setUserName(). Это позволяет пользователю установить новое имя, всякий раз, когда он захочет, нажатием кнопки:
    myButton.onclick = function() {
      setUserName();
    }
    

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

Заключение

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

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

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

  • Назад
  • Обзор: Getting started with the web
  • Далее

В этом модуле

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

Java Script является языком программирования, который обрабатывается браузером при отображении содержимого веб-сайта. Файл JS представляет собой обыкновенный текстовый документ, который может быть создан и отредактирован стандартными средствами системы.

Как создать java скрипт

Создание файла

Создать файл JS можно несколькими способами. Код программы хранится в документе и не требует дополнительной обработки программой-компилятором. Чтобы создать документ, который будет читаться в системе как файл скрипта, кликните правой клавишей мыши на свободной области в «Проводнике» Windows или на рабочем столе. В появившемся контекстном меню выберите параметр «Создать» — «Текстовый документ». Далее вам будет предложено задать имя для будущего файла и его расширение. Если вы хотите, чтобы документ корректно подключался к HTML-странице, желательно задать скрипту имя с использованием латинских букв. После указания имени переместите курсор вправо за точку, которая шла сразу после названия. Измените предложенное Windows расширение «.txt» на «.js» и нажмите Enter. Подтвердите выполнение операции и изменение расширения. Создание документа JS завершено.

Редактирование

Кликните правой клавишей мыши на вновь созданном файле. В появившемся меню выберите опцию «Открыть с помощью». В списке предложенных параметров выберите программу, через которую вам будет легче всего производить ввод программного кода. Например, вы можете выбрать стандартное приложение «Блокнот» или Wordpad. Если у вас имеются другие редакторы, способные открывать файлы JS, они также будут отображены в списке. После открытия вы можете начать вводить код.

Закончив написание скрипта, сохраните изменения в файле при помощи команды «Файл» — «Сохранить».

Вы также можете создать файл JS при помощи «Блокнота». Для этого откройте программу, перейдя в меню «Пуск» — «Все программы» — «Стандартные» — «Блокнот». После этого начните вводить программный код. После окончания ввода нажмите на кнопку «Сохранить как» и выберите папку, в которой вы бы хотели сохранить ваш будущий файл Java Script. Задайте имя для файла а после него поставьте расширение «.js». Таким образом вы укажите все необходимые параметры для идентификации файла Java Script в системе.

Таким образом файл Java Script может исполняться как самостоятельно, так и в окне браузера через загрузку на HTML странице сайта.

После создания документа вы можете его запустить как в Windows, так и в установленном на компьютере браузере через меню «Открыть с помощью». Файл JS может быть подключен в HTML при помощи специальной директивы <script type = “text/javascript” href = “путь_до_файла_JS”>. При этом код <script> должен быть указан в секции <head></head> файла HTML.

Понравилась статья? Поделить с друзьями:
  • Как написать скрипт для установки программ
  • Как написать скрипт для трейдингвью
  • Как написать скрипт для сайта на python
  • Как написать скрипт для роблокс студио
  • Как написать скрипт для отдела продаж