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

Создание простого веб-приложения с помощью Spring Boot и Groovy

· 6 мин. чтения

1. Обзор

Groovy имеет ряд возможностей, которые мы могли бы захотеть использовать в наших веб-приложениях Spring.

Итак, в этом руководстве мы создадим простое приложение todo с помощью Spring Boot и Groovy. Кроме того, мы изучим их точки интеграции.

2. Приложение Todo

Наше приложение будет иметь следующие функции:

  • Создать задачу
  • Изменить задачу
  • Удалить задачу
  • Посмотреть конкретную задачу
  • Посмотреть все задачи

Это будет приложение на основе REST, и мы будем использовать Maven в качестве инструмента сборки .

2.1. Зависимости Maven

Давайте включим все необходимые зависимости в наш файл pom.xml :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
<scope>runtime</scope>
</dependency>

Здесь мы включаем spring -boot-starter-web для создания конечных точек REST и импортируем зависимость groovy , чтобы обеспечить поддержку Groovy для нашего проекта .

Для уровня сохраняемости мы используем spring-boot-starter-data-jpa , а h2 — это встроенная база данных .

Кроме того, мы должны включить gmavenplus-plugin со всеми целями в pom.xml:

<build>
<plugins>
//...
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.9.0</version>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>addTestSources</goal>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>compileTests</goal>
<goal>removeStubs</goal>
<goal>removeTestStubs</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

2.2. Класс сущности JPA

Давайте напишем простой класс Todo Groovy с тремя полями — id , task и isCompleted :

@Entity
@Table(name = 'todo')
class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id

@Column
String task

@Column
Boolean isCompleted
}

Здесь поле id — это уникальный идентификатор задачи. task содержит сведения о задаче, а isCompleted показывает, завершена задача или нет.

Обратите внимание, что если мы не предоставляем модификаторы доступа к полю, компилятор Groovy сделает это поле закрытым, а также сгенерирует для него методы получения и установки .

2.3. Уровень сохранения

Давайте создадим интерфейс Groovy — TodoRepository , который реализует JpaRepository . Он позаботится обо всех операциях CRUD в нашем приложении:

@Repository
interface TodoRepository extends JpaRepository<Todo, Integer> {}

2.4. Сервисный уровень

Интерфейс TodoService содержит все абстрактные методы, необходимые для нашей операции CRUD :

interface TodoService {

List<Todo> findAll()

Todo findById(Integer todoId)

Todo saveTodo(Todo todo)

Todo updateTodo(Todo todo)

Todo deleteTodo(Integer todoId)
}

TodoServiceImpl — это класс реализации, который реализует все методы TodoService:

@Service
class TodoServiceImpl implements TodoService {

//...

@Override
List<Todo> findAll() {
todoRepository.findAll()
}

@Override
Todo findById(Integer todoId) {
todoRepository.findById todoId get()
}

@Override
Todo saveTodo(Todo todo){
todoRepository.save todo
}

@Override
Todo updateTodo(Todo todo){
todoRepository.save todo
}

@Override
Todo deleteTodo(Integer todoId){
todoRepository.deleteById todoId
}
}

2.5. Уровень контроллера

Теперь давайте определим все REST API в TodoController , который является нашим @RestController :

@RestController
@RequestMapping('todo')
public class TodoController {

@Autowired
TodoService todoService

@GetMapping
List<Todo> getAllTodoList(){
todoService.findAll()
}

@PostMapping
Todo saveTodo(@RequestBody Todo todo){
todoService.saveTodo todo
}

@PutMapping
Todo updateTodo(@RequestBody Todo todo){
todoService.updateTodo todo
}

@DeleteMapping('/{todoId}')
deleteTodo(@PathVariable Integer todoId){
todoService.deleteTodo todoId
}

@GetMapping('/{todoId}')
Todo getTodoById(@PathVariable Integer todoId){
todoService.findById todoId
}
}

Здесь мы определили пять конечных точек, которые пользователь может вызывать для выполнения операций CRUD.

2.6. Начальная загрузка приложения Spring Boot

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

@SpringBootApplication
class SpringBootGroovyApplication {
static void main(String[] args) {
SpringApplication.run SpringBootGroovyApplication, args
}
}

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

Кроме того, суффикс .class не нужен ни для одного класса в Groovy , поэтому мы используем SpringBootGroovyApplication напрямую.

Теперь давайте определим этот класс в pom.xml как начальный класс :

<properties>
<start-class>com.foreach.app.SpringBootGroovyApplication</start-class>
</properties>

3. Запуск приложения

Наконец, наше приложение готово к запуску. Мы должны просто запустить класс SpringBootGroovyApplication как приложение Java или запустить сборку Maven:

spring-boot:run

Это должно запустить приложение на http://localhost:8080 , и мы сможем получить доступ к его конечным точкам.

4. Тестирование приложения

Наше приложение готово к тестированию. Давайте создадим класс Groovy — TodoAppTest для тестирования нашего приложения.

4.1. Начальная настройка

Давайте определим три статические переменные — API_ROOT , readTodoId и writeTodoId в нашем классе:

static API_ROOT = "http://localhost:8080/todo"
static readingTodoId
static writingTodoId

Здесь API_ROOT содержит корневой URL нашего приложения. « readingTodoId » и « writingTodoId» — это первичные ключи наших тестовых данных, которые мы будем использовать позже для выполнения тестирования.

Теперь давайте создадим еще один метод — populateDummyData () , используя аннотацию @BeforeClass для заполнения тестовых данных:

@BeforeClass
static void populateDummyData() {
Todo readingTodo = new Todo(task: 'Reading', isCompleted: false)
Todo writingTodo = new Todo(task: 'Writing', isCompleted: false)

final Response readingResponse =
RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(readingTodo).post(API_ROOT)

Todo cookingTodoResponse = readingResponse.as Todo.class
readingTodoId = cookingTodoResponse.getId()

final Response writingResponse =
RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(writingTodo).post(API_ROOT)

Todo writingTodoResponse = writingResponse.as Todo.class
writingTodoId = writingTodoResponse.getId()
}

Мы также заполним переменные — readTodoId и writeTodoId в одном и том же методе, чтобы сохранить первичный ключ записей, которые мы сохраняем.

Обратите внимание, что в Groovy мы также можем инициализировать bean-компоненты, используя именованные параметры и конструктор по умолчанию , как мы делаем для bean-компонентов, таких как readTodo и writeTodo в приведенном выше фрагменте.

4.2. Тестирование операций CRUD

Далее найдем все задачи из todo list:

@Test
void whenGetAllTodoList_thenOk(){
final Response response = RestAssured.get(API_ROOT)

assertEquals HttpStatus.OK.value(),response.getStatusCode()
assertTrue response.as(List.class).size() > 0
}

Затем давайте найдем конкретную задачу, передав readTodoId , который мы заполнили ранее:

@Test
void whenGetTodoById_thenOk(){
final Response response =
RestAssured.get("$API_ROOT/$readingTodoId")

assertEquals HttpStatus.OK.value(),response.getStatusCode()
Todo todoResponse = response.as Todo.class
assertEquals readingTodoId,todoResponse.getId()
}

Здесь мы использовали интерполяцию для объединения строки URL.

Кроме того, давайте попробуем обновить задачу в списке задач с помощью readTodoId :

@Test
void whenUpdateTodoById_thenOk(){
Todo todo = new Todo(id:readingTodoId, isCompleted: true)
final Response response =
RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(todo).put(API_ROOT)

assertEquals HttpStatus.OK.value(),response.getStatusCode()
Todo todoResponse = response.as Todo.class
assertTrue todoResponse.getIsCompleted()
}

А затем удалите задачу из списка задач с помощью writeTodoId :

@Test
void whenDeleteTodoById_thenOk(){
final Response response =
RestAssured.given()
.delete("$API_ROOT/$writingTodoId")

assertEquals HttpStatus.OK.value(),response.getStatusCode()
}

Наконец, мы можем сохранить новую задачу:

@Test
void whenSaveTodo_thenOk(){
Todo todo = new Todo(task: 'Blogging', isCompleted: false)
final Response response =
RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(todo).post(API_ROOT)

assertEquals HttpStatus.OK.value(),response.getStatusCode()
}

5. Вывод

В этой статье мы использовали Groovy и Spring Boot для создания простого приложения. Мы также увидели, как их можно интегрировать вместе, и продемонстрировали некоторые интересные функции Groovy на примерах.

Как всегда, полный исходный код примера доступен на GitHub .