Groovy: различия между версиями
Byzantine (обсуждение | вклад) орфография |
|||
Строка 128: | Строка 128: | ||
someMap.a = 2 // Изменение элемента, как поля</source> |
someMap.a = 2 // Изменение элемента, как поля</source> |
||
Для хранения |
Для хранения объектов в качестве ключа можно использовать скобки (): |
||
<source lang="groovy"> |
<source lang="groovy"> |
||
Строка 240: | Строка 240: | ||
println "user: $user.first" |
println "user: $user.first" |
||
} |
} |
||
//создаем |
//создаем объект класса Person с параметрами |
||
def tempPerson = new Person(first: 'Adam', last: 'Smith') |
def tempPerson = new Person(first: 'Adam', last: 'Smith') |
||
// вызов функции разными способами |
// вызов функции разными способами |
||
Строка 271: | Строка 271: | ||
= Closures = |
= Closures = |
||
Closure - это замыкание и представляет из себя некую анонимную функцию со свойствами |
Closure - это замыкание и представляет из себя некую анонимную функцию со свойствами объекта. |
||
Синтаксис замыкания : { [closureArguments->] statements } |
Синтаксис замыкания : { [closureArguments->] statements } |
||
Строка 327: | Строка 327: | ||
</source> |
</source> |
||
Специальный класс [http://groovy.codehaus.org/gapi/groovy/util/Expando.html Expando] для создания динамических |
Специальный класс [http://groovy.codehaus.org/gapi/groovy/util/Expando.html Expando] для создания динамических объектов и методов (как замыкания) которые можно вызывать: |
||
<source lang="groovy"> |
<source lang="groovy"> |
||
Строка 758: | Строка 758: | ||
println new Manager2().doWork() |
println new Manager2().doWork() |
||
// Аннотация @Immutable делает |
// Аннотация @Immutable делает объект этого класса неизменяемым |
||
// свойства |
// свойства объекта становятся readonly |
||
@Immutable |
@Immutable |
||
class Person{ |
class Person{ |
||
Строка 937: | Строка 937: | ||
import groovy.json.JsonSlurper |
import groovy.json.JsonSlurper |
||
import groovy.json.JsonOutput |
import groovy.json.JsonOutput |
||
// Создание JSON |
// Создание JSON объекта |
||
def json = new JsonBuilder() |
def json = new JsonBuilder() |
||
json.person { |
json.person { |
||
Строка 945: | Строка 945: | ||
} |
} |
||
println json.toString() // вывод в строку полученного |
println json.toString() // вывод в строку полученного объекта |
||
// Парсинг строки в JSON формате |
// Парсинг строки в JSON формате |
||
def someJSONString = '{"person":{"username":"Guillaume","age":33,"pets":["Hector","Felix"]}}' |
def someJSONString = '{"person":{"username":"Guillaume","age":33,"pets":["Hector","Felix"]}}' |
||
println JsonOutput.prettyPrint(someJSONString) // форматированный вывод |
println JsonOutput.prettyPrint(someJSONString) // форматированный вывод объекта |
||
def slurper = new JsonSlurper() |
def slurper = new JsonSlurper() |
||
Строка 960: | Строка 960: | ||
== Работа с XML == |
== Работа с XML == |
||
Создание XML документа из |
Создание XML документа из объекта: |
||
<source lang="groovy"> |
<source lang="groovy"> |
Версия от 13:10, 26 декабря 2018
Первая программа
Откройте редактор и напишите программу. По традиции, первая программа должна просто выводить приветствие миру:
println "Hello World!"
Сохраните её в файл helloworld.groovy
и запустите.
groovy helloworld.groovy
На экране появится надпись:
Hello World!
На этом традиционную часть можно считать выполненной.
Комментарии и демонстрация результата
Комментарием называется часть программного кода, пропускаемая при обработке (интерпретации или компиляции).
В Groovy знаком начала комментария служит //
. Всё, что между ним и концом строки пропускается.
Также комментарий можно расположить между /*
и */
. Пример:
println 2 + 2 // это комментарий
println "Привет!" /* это тоже комментарий */
/* А это - многострочный
комментарий */
Результат иллюстрируемого кода будет располагаться после последовательности //=>
. Пример:
println 2 + 2 //=> 4
println "Привет" //=> Привет
Переменные
Переменная в Groovy определяется ключевым словом def
(это аналогично типу Object в Java):
def a = 1 // объявление "безтиповой" переменной, присвоение ей значения типа int
a = "String" /* так как мы не указали тип при объявлении этой переменной,
то можно присваивать этой переменной значение другого типа */
int b = 2 // объявление переменной типа int
b = "String for type int?" // так как тип переменной указан,
// то когда мы пытаемся присвоить String, получаем ошибку (GroovyCastException)
Строки
В Groovy есть 2 типа строк:
- Java Strings — строки в одинарных кавычках
- Groovy Strings, известны как GStrings — в двойных кавычках; используя
${имя_переменной}
можно "вставить" внутрь строки значение переменной
javaString = 'java' // Java String
groovyString = "Hello ${javaString}!" // GString
println javaString // => java
println groovyString // => Hello java!
bigGroovyString = """
long
long
string
""" // Длинная строка с отступами
def a = "a"
println a
println a + "12" // конкатенация
println a * 3 // умножение
Списки
Groovy содержит встроенную поддержку списков. Списки объявляются путем перечисления элементов в квадратных скобках:
def someList = [1,2,3,4] // Создание списка
def emptyList = [] // Создание пустого списка
Обращение к элементам списка осуществляется по индексу, как к массиву в Java:
someList[0] // Обращение к элементу по индексу
Новые элементы могут быть добавлены в список различными способами:
someList[5] = 6 // Добавление элемента в список
someList << 7 << 8 // Добавление элементов в конец списка
someList += [ 9, 10 ] // "Приклеивание" списка
Теперь, совместное использование списков и ranges:
someList[1..3] // "Срезка" списка - получение подсписка
someList[2..4] = [ 12, 13, 14 ] // Изменение подсписка
Также, для индексирования можно использовать и списки:
someList[1,3,5..7,9] // Получение подсписка
Также, Groovy предоставляет встроенный цикл, для перебора элементов списка, или элементов любого объекта, реализующего интерфейс java.lang.Iterable:
for ( e in someList ) {
println e // Распечатываем все элементы списка someList
}
Maps (Отображения)
Аналогично спискам, Groovy поддерживает прозрачный синтаксис для работы с maps (ассоциативными массивами). Объявление выглядит следующим образом:
def someMap = [ 'a' : 1, 'b' : 2 ] // Объявление
Также, существует специальный синтаксис для объявления пустых отображений:
// Объявление пустого отображения
def emptyMap = [:]
def otherEmptyMap = [:] as HashMap
Доступ к элементам осуществляется по ключу, с использованием оператора [], или же с ключом как полем:
someMap['a'] // Доступ к элементу
someMap.a // Доступ к элементу как к полю
Аналогично производится и изменение элементов:
someMap['a'] = 2 // Изменение элемент
someMap.a = 2 // Изменение элемента, как поля
Для хранения объектов в качестве ключа можно использовать скобки ():
def map = [(new String("username")):"james", nickname:"jcameron", (new Integer(22)):1234]
println map.get(new Integer(22))
Условное исполнение
Одним из наиболее важных особенностей любого языка программирования является возможность выполнять различные коды в разных условиях.Простейший способ сделать это состоит в использовании IF конструкции. Например:
def amPM = Calendar.getInstance().get(Calendar.AM_PM)
if (amPM == Calendar.AM){
println("Good morning")
} else {
println("Good evening")
}
Не беспокойтесь о длинной первой строке, это просто какой-то код, чтобы определить, сейчас утро или вечер. Остальная часть кода выполняется следующим образом: сначала оценивается выражение в круглых скобках и в зависимости от результата true (истинно) или false (ложно) выполняется первый или второй блок кода. Смотрите ниже раздел логические выражения.
Обратите внимание, что блок else не требуется, в отличии от первого блока:
amPM = Calendar.getInstance().get(Calendar.AM_PM)
if (amPM == Calendar.AM){
println("Have another cup of coffee.")
}
Логические выражения
Существует специальный тип данных в большинстве языков программирования, который используется для представления значений истинности,true (истина) и false (ложь). Простейшие логические выражения - это просто слова. Логические значения могут быть сохранены в переменных, как и любой другой тип данных:
def myBooleanVariable = true
Более сложные логические выражения использует один из булевых операторов:
- ==
- !=
- >
- >=
- <
- <=
Большинство из них, довольно интуитивны. Оператор равенства ==, не путайте с оператором присваивания =. Оператор не равенство !=, то есть "не равно".
Некоторые примеры:
def titanicBoxOffice = 1234600000
def titanicDirector = "James Cameron"
def trueLiesBoxOffice = 219000000
def trueLiesDirector = "James Cameron"
def returnOfTheKingBoxOffice = 752200000
def returnOfTheKingDirector = "Peter Jackson"
def theTwoTowersBoxOffice = 581200000
def theTwoTowersDirector = "PeterJackson"
titanicBoxOffice > returnOfTheKingBoxOffice // вычисляется как истина
titanicBoxOffice >= returnOfTheKingBoxOffice // вычисляется как истина
titanicBoxOffice >= titanicBoxOffice // вычисляется как истина
titanicBoxOffice > titanicBoxOffice // оценивается как ложное
titanicBoxOffice + trueLiesBoxOffice < returnOfTheKingBoxOffice + theTwoTowersBoxOffice // оценивается как ложное
titanicDirector > returnOfTheKingDirector // оценивается как ложное, потому что "J" находится перед "Р"
titanicDirector < returnOfTheKingDirector // вычисляется как истина
titanicDirector >= "James Cameron" // вычисляется как истина
titanicDirector == "James Cameron" // вычисляется как истина
Логические выражения особенно полезны при использовании совместно с if-конструкциями. Например:
if (titanicBoxOffice + trueLiesBoxOffice > returnOfTheKingBoxOffice + theTwoTowersBoxOffice){
println(titanicDirector + " is a better director than " + returnOfTheKingDirector)
}
Особенно полезна проверка на наличие значения. К примеру, определён ли данный ключ в карте:
def suvMap = ["Acura MDX":"\$36,700", "Ford Explorer":"\$26,845"]
if (suvMap["Hummer H3"] != null){
println("A Hummer H3 will set you back "+suvMap["Hummer H3"]);
}
Вообще null используется для указания на отсутствие значения выражения или переменной.
Функции
Функции и методы всегда возвращают, как результат, последнее выражение.
//класс пользователя
class Person{
String first, last
}
//функции без типизированных параметров
def printInfo(first, second){
println "first name: $first, second name: $second"
}
def printFirstName(user){
println "user: $user.first"
}
//создаем объект класса Person с параметрами
def tempPerson = new Person(first: 'Adam', last: 'Smith')
// вызов функции разными способами
printInfo tempPerson.first, tempPerson.last
printFirstName(tempPerson)
printFirstName tempPerson
//типизированный параметр
def functionA(String str){
println str
}
functionA 'String'// все ок
functionA 1 // вернётся исключение
int functionB(int argB) {
argB + 2
}
String functionC() {
"Hello World"
}
println functionB(1)
def hw = functionC()
println hw
Closures
Closure - это замыкание и представляет из себя некую анонимную функцию со свойствами объекта.
Синтаксис замыкания : { [closureArguments->] statements }
def closureFunction = {a, b ->
println a
println b
}
closureFunction(1, 2)
В замыканиях по умолчанию присутствует переменная it и ссылается на первый параметр в замыкании:
def closureA = { it }
assert closureA() == null
assert closureA(1) == 1
Вызов замыкания:
def c = { it, arg-> println "${it} ${arg}" }
c.call("A", "B") // первый тип вызова
c("C", "D") // второй тип вызова
Определение замыкания в классе и его вызов:
public class ClassWithClosure {
private int member = 20;
private String method()
{
return "hello";
}
def publicMethodWithClosure(String name_)
{
def localVar = member + 5;
def localVar2 = "Parameter: ${name_}";
return {
println "${member} ${name_} ${localVar} ${localVar2} ${method()}"
}
}
}
ClassWithClosure sample = new ClassWithClosure();
def closureVar = sample.publicMethodWithClosure("Xavier");
closureVar();
Специальный класс Expando для создания динамических объектов и методов (как замыкания) которые можно вызывать:
def player = new Expando()
player.name = "Alec"
player.greeting = { "Hello, my name is $name" }
println player.greeting()
player.name = "Max"
println player.greeting()
Работа с файлами
def out= new File('File1.txt')
// если файл не существует, то создаем файл
if(!out.exists()) {
out.createNewFile()
out << 'aaa\nbbb\nccc' // пишем текст в файл
}
list= [] // создаем список для строк
out.eachLine { list<< it } // и заполняем его
println list.size() // выводим размер списка строк
println out.text // выводим весь текст
out.write('\nnew string') // пишем текст в файл
out.eachLine { println it}
out.append('\nappend string') // добавляем текст в файл
//выводим информацию о файле
println out.name
println out.isAbsolute()
println out.path
println out.parent
println out.absolutePath
println out.absoluteFile.toString()
println out.canonicalPath
println out.canonicalFile.toString()
println out.toURI().toString()
// Создаем директории
def dir= new File('Directory1')
dir.mkdir() //make directory, if it doesn't already exist
def dir2= new File('Directory2/SubDir1')
dir2.mkdirs()
Работа со строками
lst = /This is my new string./
println lst
def b = "abcde" // также строка представляет собой и список символов
println b[2] // напечатает c
println b[1..3] // напечатает bcd
println "reverse me".reverse()
println "This is the end, my only friend!".tokenize(' ').reverse().join(' ')
Classes and Objects
Описание и создание класса(по умолчанию класс имеет тип доступа public, а переменные класса имеют тип доступа private, но компилятор groovy сам сделает для этих полей геттеры и сеттеры с доступом public):
class Human {
String name
int age
}
def man = new Human();
man.name = "Adam"
man.age = 25;
def woman = new Human(name: "Eva", age: 22 )
Для обновления поля или полей можно использовать такой подход:
man.with{
name = "Adam"
age = 34
}
Классы:
// Классы могут не иметь конструктора
class ClassWithoutConstructor { }
class Bird {
static startDate = new Date()
private name
def getName() { name }
def setName(name) { this.name = name }
static getStartDate() {
startDate
}
}
println Bird.startDate
def myBird = new Bird()
myBird.name = "Chack"
println myBird.name
// и иметь разные правила для генерации методов для полей
class Cat {
def startDate = new Date() // getter и setter
final String name = "Empty"
final age // только getter
Cat(date, name) {
startDate = date
this.name = name
this.age = 1
}
}
Cat catty = new Cat(new Date(), "Pussy Cat")
println catty.name
println catty.age
println catty.startDate
Интерфейсы:
// Объявление интерфейса
interface Voice{
void voice();
String getAnimalName();
}
// его реализация
class Dog implements Voice{
@Override
void voice() {
println "Gav"
}
@Override
String getAnimalName() {
return Dog.class.getSimpleName()
}
void goMethod(){
}
}
// и использование
def dog = new Dog() as Voice
// или можно привести к интерфейсу таким способом:
def dog = new Dog().asType(Voice.class)
dog.voice()
println "my name is: " + dog.getAnimalName()
// Реализация интерфейса как замыкания
def mainRunnable = {
run:{
try {
int i = 5
while (i>0) {
sleep(1000)
println "${i--}"
}
} catch (InterruptedException ex) {
// error
}
}
} as Runnable
new Thread(mainRunnable).start()
Наследование:
class PersonA implements Comparable {
def firstname, initial, surname
PersonA(f,i,s) { firstname = f; initial = i; surname = s }
int compareTo(other) { firstname <=> other.firstname }
}
def a = new PersonA('James', 'T', 'Kirk')
def b = new PersonA('Samuel', 'L', 'Jackson')
println a <=> b
// => -1
class PersonB extends PersonA {
PersonB(f,i,s) { super(f,i,s) }
int compareTo(other) { initial <=> other.initial }
}
a = new PersonB('James', 'T', 'Kirk')
b = new PersonB('Samuel', 'L', 'Jackson')
println a <=> b
// => 1
class Parent {
private name // my child's name
def setChildName(value) { name = value }
def getChildName() { name }
}
class GrandParent extends Parent {
private name // my grandchild's name
def setgrandChildName(value) { name = value }
def getGrandChildName() { name }
}
g = new GrandParent()
g.childName = 'Jason'
g.grandChildName = 'Rachel'
println g.childName // => Jason
println g.grandChildName // => Rachel
Абстрактные классы:
abstract class Shape {
final name
Shape(name) { this.name = name }
abstract printName()
}
class Circle extends Shape {
final radius
Circle(radius) {
super('circle')
this.radius = radius
}
def area() { Math.PI * radius * radius }
def printName() {
println "I am a $name."
}
}
class Rectangle extends Shape {
final length, breadth
def Rectangle(length, breadth) {
super("rectangle")
this.length = length
this.breadth = breadth
}
def printName() {
println "I am a $name."
}
}
shapes = [new Circle(4.2), new Rectangle(5, 7)]
shapes.each { shape -> shape.printName() }
Статические внутренние классы:
class OuterClass {
static class StaticInnerClass {
public int getAge(){
int a = 35
}
}
}
OuterClass.StaticInnerClass myInstance = new OuterClass.StaticInnerClass()
println myInstance.getAge()
Анонимные внутренние классы:
new Thread([run: {
try {
int i = 5
while (i>0) {
sleep(1000)
println "${i--}"
}
} catch (InterruptedException ex) {
// error
}
}] as Runnable).start();
Enum:
enum Color{
RED, GREEN, BLUE
}
def redColor = "RED" as Color
Color blueColor = "BLUE"
println blueColor
Расширенные возможности
Импорт и переопределение
Импортируемые пакеты по умолчанию которые добавляются компилятором в каждый сценарий:
- java.io.*
- java.lang.*
- java.math.BigDecimal
- java.math.BigInteger
- java.net.*
- java.util.*
- groovy.lang.*
- groovy.util.*
Можно импортировать пакеты в статическом контексте, а также назначать алиасы/псевдонимы:
import static java.awt.Color.BLUE
import static Boolean.FALSE as F // назначаем алиас с именем F
import static Calendar.getInstance as now // назначаем алиас с именем now
import static java.lang.Integer.*
println BLUE
// напечатает java.awt.Color[r=0,g=0,b=255]
println !F
// напечатает true
println now().time
// напечатает Fri Jun 08 06:37:20 EEST 2011
def a = parseInt("123")
println a
// напечатает 123
// представление списка как интерфейса Set
def contacts = ['a', 'b', 'c'] as Set
println contacts.size() // напечатает 3
// представление списка как интерфейса Map
def contacts = ['a':10, 'b':20, 'c':30] as Map
println contacts['a'] // напечатает 10
Работа с данными
// множественное присвоение
def (a, b, c) = [1,2,5]
println c
def (int myint, String mystring) = [5, "hello"]
println mystring
//диапазоны значений
def list = [3, 'Some string' , new Date()]
println list[0]
println list[1]
def letters = 'a'..'z'
def numbers = 0..<10
println numbers.size()
// работа с замыканиями
3.times { println 'Hi'}
[1,2,3].each {it -> println it}
(10..1).each {println it}
[ 'a' : 1, 'b' : 2 ].each {key, value -> println key}
Дата и время
import java.util.GregorianCalendar as D
import static java.util.Calendar.getInstance as now
println new D(2011, 11, 25).time
println now().time
println new Date() + 1
dateStr = "2011-06-03"
date = Date.parse("yyyy-MM-dd", dateStr)
println 'Date was '+date.format("MM/dd/yyyy")
Аннотации
// Эта аннотация которая генерирует из данного класса синглетон
@Singleton(lazy=true)
class MySingleton {
def getHello(){
"hello world"
}
}
println MySingleton.instance.hello
// Эта аннотация позволяет внедрить в класс Manager поведение метода из класса Employee
class Employee {
def doWork() { 'my work' }
}
class Manager {
@Delegate
Employee slave = new Employee()
}
def worker = new Manager()
println worker.doWork()
// либо можно сделать то же самое с помощью mixin
class Employee2 { def doWork() { 'my work' } }
class Manager2 {}
Manager2.mixin Employee2
println new Manager2().doWork()
// Аннотация @Immutable делает объект этого класса неизменяемым
// свойства объекта становятся readonly
@Immutable
class Person{
String first, last
}
Regular Expressions
Оператор Pattern
Оператор pattern (~) обеспечивает простой способ создать java.util.regex.Pattern.
Пример:
def p = ~/foo/
assert p instanceof Pattern
В основном оператор pattern используется со слеш-строками (строки обрамлённых слешами), тем не менее этот оператор может использоваться с любыми видами строк Groovy:
p = ~'foo' /*1*/
p = ~"foo" /*2*/
p = ~$/dollar/slashy $ string/$ /*3*/
p = ~"${pattern}" /*4*/
- использование строк в одинарных кавычках
- использование строк в двойных кавычках
- использование строки обрамлённой доллар-слешем, позволяет использовать слеш и доллар без их экранирования
- использование GString
Find operator
Alternatively to building a pattern, you can directly use the find operator =~ to build a java.util.regex.Matcher instance:
def text = "some text to match"
def m = text =~ /match/ /*1*/
assert m instanceof Matcher /*2*/
if (!m) { /*3*/
throw new RuntimeException("Oops, text not found!")
}
- =~ creates a matcher against the text variable, using the pattern on the right hand side
- the return type of =~ is a Matcher
- equivalent to calling if (!m.find())
Since a Matcher coerces to a boolean by calling its find method, the =~ operator is consistent with the simple use of Perl’s =~ operator, when it appears as a predicate (in if, while, etc.).
Match operator
The match operator (==~) is a slight variation of the find operator, that does not return a Matcher but a boolean and requires a strict match of the input string:
m = text ==~ /match/ /*1*/
assert m instanceof Boolean /*2*/
if (!m) { /*3*/
throw new RuntimeException("Should not reach that point!")
}
- ==~ matches the subject with the regular expression, but match must be strict
- the return type of ==~ is therefore a boolean
- equivalent to calling if (text ==~ /match/)
The operators
Capture groups
Non-matching Groups
Replacement
Reluctant Operators
Groovy SQL
Подключение к базе данных и запрос SELECT(необходимо подключить драйвер JDBC для MySQL или другой базы):
import groovy.sql.Sql
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/testdatabase", "user", "password", "com.mysql.jdbc.Driver")
// создаем таблицу
sql.execute('''create table users (
id int(11) not null primary key auto_increment,
username varchar(255),
age int(11)
)''')
Выполнение простого sql-запроса
Вставка новой записи:
def age = 25
def name = "Adam"
sql.execute("insert into users (username, age) values (${name}, ${age})")
// or
sql.executeInsert("insert into users (username, age) values (${name}, ${age})")
Выборка первой записи из результата запроса:
def rowFirst = sql.firstRow('select username, age from users')
println "Row: Name = ${rowFirst.username} and Age = ${rowFirst.age}"
Выборка всех записей:
sql.eachRow("select * from users"){ row -> println row.username }
Удаление записи:
int id = 2
sql.execute('delete from users where id = ?' , [id])
Обновление записи:
def newUsername = 'New Name'
int rowsAffected = sql.executeUpdate('update users set username = ? where id=2', [newUsername])
println "updated: ${rowsAffected}";
Выполнение более сложных запросов
import groovy.sql.Sql
import groovy.sql.DataSet
DataSet users
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/testdatabase", "user", "password", "com.mysql.jdbc.Driver")
// таблица users должна быть создана
users = sql.dataSet("USERS")
users.add(username: "James", age: 55) //вставка новой записи в таблицу
DataSet findedUsers = users.findAll() // получение всех записей и их вывод
findedUsers.each{ println it.username}
Добавление записей в транзакции:
import groovy.sql.Sql
DataSet users
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/testdatabase", "user", "password", "com.mysql.jdbc.Driver")
// таблица users должна быть создана
users = sql.dataSet("USERS")
sql.withTransaction {
users.add(username: "Alec", age: 25)
users.add(username: "Alec 2", age: 25)
}
Блочное добавление записей:
import groovy.sql.Sql
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/testdatabase", "user", "password", "com.mysql.jdbc.Driver")
def updateCounts = sql.withBatch('insert into users(username, age) values (?, ?)') { ps ->
ps.addBatch("New Name", 22) // varargs style
ps.addBatch(["New Name", 18]) // list
ps.addBatch(["New Name", 31])
}
Call Procedure
Вызов процедур:
import groovy.sql.Sql
Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/testdatabase", "user", "password", "com.mysql.jdbc.Driver")
sql.call("{? = call MyProcedure(?)}", [Sql.VARCHAR, 'Sam']) { name ->
assert name == 'Adam'
}
// or with GString
def first = 'Sam'
sql.call("{$Sql.VARCHAR = call MyProcedure($first)}") { name ->
assert name == 'Adam'
}
Прочие советы
Работа с JSON
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
// Создание JSON объекта
def json = new JsonBuilder()
json.person {
username "Guillaume"
age 33
pets "Hector", "Felix"
}
println json.toString() // вывод в строку полученного объекта
// Парсинг строки в JSON формате
def someJSONString = '{"person":{"username":"Guillaume","age":33,"pets":["Hector","Felix"]}}'
println JsonOutput.prettyPrint(someJSONString) // форматированный вывод объекта
def slurper = new JsonSlurper()
def doc = slurper.parseText(someJSONString)
println doc.person.username // вывод имени
doc.person.pets.each {println it} // вывод животных
Работа с XML
Создание XML документа из объекта:
import groovy.xml.MarkupBuilder
writer = new StringWriter()
builder = new MarkupBuilder(writer)
petsList = [ "Hector", "Felix"]
builder.person() {
username("Guillaume")
age("33")
gender("female")
pets(){
for (e in petsList){pet(e)}
}
}
println writer.toString()
Работа с HTML:
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.html() {
head() {
title("This is the title")
}
body() {
div("class" : "main") {
p("this is the body")
}
}
}
println writer.toString()
Парсинг XML документа
def xmlString = """
<person>
<username>Guillaume</username>
<age>33</age>
<gender>female</gender>
<pets>
<pet>Hector</pet>
<pet>Felix</pet>
</pets>
</person>
"""
def person = new XmlSlurper().parseText(xmlString)
println person.username
person.pets.pet.each {println "pet's name:"+it}
Потоки и асинхронная работа
//эта аннотация скачивает и устанавливает библиотеку в classpath
@Grab(group='org.codehaus.gpars', module='gpars', version='0.12')
import static groovyx.gpars.GParsExecutorsPool.withPool
//запуск в новом потоке
Thread.start {
println Thread.currentThread().getId()
}
//50 раз сделать асинхронную загрузку страницы(и распечатать ответ)
//по url в отдельных потоках
int count = 50
withPool(count) {
count.times {
Closure callUrl = {"http://google.com".toURL().withReader {
reader -> println reader.readLines()
}}
callUrl.callAsync();
}
}