Перейти к основному содержимому

Простые приложения на Groovy

Разработчику Архитектору

Простые приложения на Groovy

Groovy — динамический язык на JVM — лаконичный синтаксис, GString, встроенный JSON (JsonSlurper), удобные File API. Запуск: groovy script.groovy.


Как запускать примеры из главы

  1. Команда: groovy имя.groovy
  2. Нужно: JDK + Groovy (groovy -version).

Генератор паролей

Как запустить

  • Файл: password.groovy
  • Команда: groovy password.groovy

import java.security.SecureRandom

def generatePassword(int len = 16) {
def chars = ('a'..'z') + ('A'..'Z') + ('0'..'9') + '!@#$%^&*'
def rnd = new SecureRandom()
(1..len).collect { chars[rnd.nextInt(chars.size())] }.join()
}

println generatePassword()

Разбор:

  • import java.security.SecureRandom подключает криптографически стойкий генератор случайных чисел, который лучше обычного Random для паролей.
  • Функция generatePassword(int len = 16) объявляет параметр длины с дефолтным значением 16, поэтому её можно вызывать без аргументов.
  • Выражение ('a'..'z') + ('A'..'Z') + ('0'..'9') + '!@#$%^&*' формирует пул допустимых символов: диапазоны букв и цифр плюс спецсимволы.
  • new SecureRandom() создаёт источник случайности, а rnd.nextInt(chars.size()) выбирает индекс внутри пула.
  • Конструкция (1..len).collect { ... }.join() делает len итераций, на каждой выбирает символ, затем склеивает список символов в итоговую строку.
  • println generatePassword() выводит готовый пароль в консоль; при каждом запуске результат будет новым.

Сортировщик файла

def sortFile(input, output) {
def lines = new File(input).readLines('UTF-8')
.collect { it.trim() }
.findAll { it }
.sort()
new File(output).text = lines.join('\n') + '\n'
}

Разбор:

  • Функция sortFile(input, output) принимает путь к исходному и итоговому файлу.
  • new File(input).readLines('UTF-8') читает файл построчно в кодировке UTF-8, чтобы корректно обрабатывать кириллицу и спецсимволы.
  • .collect { it.trim() } убирает пробелы по краям строк, а .findAll { it } отфильтровывает пустые строки.
  • .sort() сортирует строки по возрастанию (лексикографически).
  • lines.join('\n') + '\n' собирает отсортированный текст и добавляет перевод строки в конце файла.
  • new File(output).text = ... перезаписывает целевой файл новым содержимым.

Калькулятор

def calc(a, b, op) {
switch (op) {
case '+': return a + b
case '-': return a - b
case '*': return a * b
case '/': return b ? a / b : null
default: return null
}
}

Разбор:

  • Функция calc(a, b, op) реализует простой калькулятор: два операнда и символ операции.
  • switch (op) выбирает ветку по значению оператора (+, -, *, /).
  • return a + b и аналогичные выражения сразу возвращают результат выбранной операции.
  • В ветке деления используется тернарный оператор b ? a / b — null — если b не ноль (truthy), выполняется деление, иначе возвращается null.
  • default: return null обрабатывает неизвестные операции и защищает от непредусмотренного ввода.

JSON-трекер


import groovy.json.JsonSlurper
import groovy.json.JsonOutput

def db = new File('tasks.json')
def load() { db.exists() ? new JsonSlurper().parse(db) : [] }
def save(tasks) { db.text = JsonOutput.prettyPrint(JsonOutput.toJson(tasks)) }

def tasks = load()
tasks << [id: System.currentTimeMillis(), title: 'Изучить Groovy', done: false]
save(tasks)

Разбор:

  • JsonSlurper нужен для чтения JSON в структуры Groovy (Map/List), а JsonOutput — для сериализации обратно в JSON.
  • def db = new File('tasks.json') задаёт файл-хранилище рядом со скриптом.
  • load() проверяет db.exists(): если файл есть, парсит его; если нет, возвращает пустой список [].
  • save(tasks) преобразует список задач в JSON и форматирует его через prettyPrint для читаемости.
  • tasks << [...] добавляет новую задачу в конец списка; System.currentTimeMillis() используется как простой уникальный id.
  • save(tasks) сохраняет обновлённое состояние на диск, превращая скрипт в минимальный трекер задач.

HTTP (HttpURLConnection)

def url = new URL('https://example.com')
def conn = url.openConnection()
conn.requestMethod = 'GET'
println conn.inputStream.text.take(200)

Разбор:

  • new URL('https://example.com') создаёт объект адреса, к которому будет выполняться запрос.
  • url.openConnection() открывает соединение и возвращает URLConnection (на HTTP это обычно HttpURLConnection).
  • conn.requestMethod = 'GET' явно задаёт HTTP-метод запроса.
  • conn.inputStream.text читает тело ответа целиком как текст.
  • .take(200) берёт только первые 200 символов, чтобы не выводить слишком большой объём данных в консоль.
  • println ... печатает результат и помогает быстро проверить, что соединение работает.

Полноценный desktop API-тестер (Swing, JMeter как HTTP-движок, заголовки, JSON, smoke-тест) — пошагово в Практикум — API-тестер на Groovy и JMeter.


Характерный пример — GString и замыкания

def greet = { name -> "Привет, $name!" }
['Анна', 'Борис'].each { println greet(it) }

Разбор:

  • def greet = { name -> ... } объявляет замыкание (closure) и сохраняет его в переменной greet.
  • Параметр name подставляется в GString через $name, поэтому возвращается персонализированная строка приветствия.
  • Список ['Анна', 'Борис'] перебирается методом each, который принимает замыкание-обработчик.
  • Внутри each переменная it — текущий элемент списка; greet(it) вызывает ранее объявленное замыкание.
  • println выводит результат для каждого элемента, демонстрируя типичный функциональный стиль обработки коллекций в Groovy.

GString и each — типичный "скриптовый" стиль Groovy на JVM.


Дополнительные сниппеты

Аргументы командной строки

В скрипте без класса доступен массив args — как String[] в main у Java.

if (args.length == 0) {
println 'Использование: groovy sort-lines.groovy input.txt output.txt'
return
}
println "Входной файл: ${args[0]}"

Разбор:

  • args — встроенная переменная скрипта; элементы приходят из командной строки после имени файла.
  • args.length == 0 проверяет, что пользователь передал хотя бы один аргумент.
  • return в script mode завершает выполнение скрипта без явного System.exit.
  • GString "${args[0]}" подставляет первый переданный путь или имя файла.

Запуск: groovy sort-lines.groovy data.txt sorted.txt.

Построчный разбор лога

def logFile = new File('app.log')
def errors = logFile.readLines('UTF-8').findAll { it.contains('ERROR') }
errors.each { println it }

Разбор:

  • new File('app.log') ссылается на файл относительно текущей рабочей директории.
  • readLines('UTF-8') читает все строки сразу в List<String>.
  • findAll { it.contains('ERROR') } оставляет только строки с маркером ошибки.
  • each { println it } выводит каждую подходящую строку; it — текущая строка списка.

Фильтр незавершённых задач (JSON-трекер)

def openTasks = load().findAll { !it.done }
println "Открыто: ${openTasks.size()}"
openTasks.each { println "- ${it.title}" }

Разбор:

  • load() (из примера выше) возвращает список карт с полями id, title, done.
  • findAll { !it.done } отбирает задачи, у которых done ложно (false или отсутствует).
  • openTasks.size() — число элементов в отфильтрованном списке.
  • В each обращение it.title использует property-стиль Groovy для ключей map.

Проверка калькулятора

assert calc(10, 2, '+') == 12
assert calc(10, 2, '-') == 8
assert calc(4, 2, '*') == 8
assert calc(10, 0, '/') == null
assert calc(1, 2, '%') == null

Разбор:

  • assert прерывает выполнение, если условие ложно — удобно для быстрой самопроверки скрипта.
  • Сложение, вычитание и умножение проверяют обычные ветки switch.
  • calc(10, 0, '/') должен вернуть null, потому что деление на ноль в примере запрещено.
  • Неизвестный оператор % попадает в default и тоже даёт null.

Дата в строке лога (регулярное выражение)

def line = '2026-05-28 14:02 ERROR payment failed'
def matcher = line =~ /\d{4}-\d{2}-\d{2}/
if (matcher) {
println "Дата в логе: ${matcher[0]}"
}

Разбор:

  • Оператор =~ создаёт Matcher для поиска подстроки по шаблону.
  • Шаблон \d{4}-\d{2}-\d{2} означает дату в формате ГГГГ-ММ-ДД.
  • В условии if (matcher) matcher приводится к boolean: true, если совпадение найдено.
  • matcher[0] — первое полное совпадение в строке.

Копирование файла одной строкой

def src = new File('input.txt')
def dst = new File('backup.txt')
dst.bytes = src.bytes
println "Скопировано ${src.length()} байт"

Разбор:

  • Свойство bytes у File читает или записывает содержимое файла как массив байтов.
  • Присваивание dst.bytes = src.bytes копирует файл целиком без ручного потока.
  • src.length() возвращает размер исходного файла в байтах.
  • Подход годится для небольших файлов; для очень больших лучше потоковое копирование.

См. также: Gradle · Java — простые приложения

Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций. Сборка своего HTTP-клиента на Groovy — Практикум — API-тестер.