Skip to content

Commit

Permalink
Java template simplified and updated
Browse files Browse the repository at this point in the history
  • Loading branch information
GoodforGod committed Oct 27, 2024
1 parent c9c27ce commit 1e10ccd
Show file tree
Hide file tree
Showing 22 changed files with 123 additions and 267 deletions.
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

# Шаблон приложения Kora Java CRUD

Пример сервиса реализованного на Kora с HTTP [CRUD](https://github.com/swagger-api/swagger-petstore) API,
в качестве базы данных выступает Postgres, используется кэш Caffeine, а также другие модули которые использовались бы в реальном приложении в бою.
Шаблон для быстрого старта нового проекта на Java и Kora с базовым настроенным HTTP [CRUD](https://github.com/swagger-api/swagger-petstore) API для одной сущности.
В качестве базы данных выступает Postgres, используется кэш Caffeine,
а также другие модули которые использовались бы в реальном приложении в бою.

В примере использовались модули:
В шаблоне используются модули:
- [HTTP сервер](https://kora-projects.github.io/kora-docs/ru/documentation/http-server/)
- [OpenAPI HTTP серверная генерация](https://kora-projects.github.io/kora-docs/ru/documentation/openapi-codegen/)
- [Пробы](https://kora-projects.github.io/kora-docs/ru/documentation/probes/)
Expand All @@ -31,13 +32,27 @@
./gradlew openApiGenerateHttpServer
```

### Image

Собрать образ приложения:
```shell
docker build -t kora-java-crud .
```

## Run

Запустить локально:
```shell
./gradlew run
```

## Migration

Миграции вызываются с помощью Flyway Gradle Plugin:
```shell
./gradlew flywayMigrate
```

## Test

Тесты используют [Testcontainers](https://java.testcontainers.org/), требуется [Docker](https://docs.docker.com/engine/install/) окружение для запуска тестов или аналогичные контейнерные окружения ([colima](https://github.com/abiosoft/colima) / итп)
Expand Down
91 changes: 40 additions & 51 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ plugins {
id "com.diffplug.spotless" version "6.19.0"
}

applicationName = "application"
mainClassName = "ru.tinkoff.kora.java.crud.Application"

group = groupId
version = koraVersion

Expand All @@ -27,13 +24,14 @@ targetCompatibility = JavaVersion.VERSION_21

repositories {
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}

configurations {
koraBom
implementation.extendsFrom(koraBom)
annotationProcessor.extendsFrom(koraBom)
compileOnly.extendsFrom(koraBom)
implementation.extendsFrom(koraBom)
api.extendsFrom(koraBom)
}

dependencies {
Expand All @@ -58,22 +56,32 @@ dependencies {
testImplementation "org.json:json:20231013"
testImplementation "org.skyscreamer:jsonassert:1.5.1"

testImplementation "org.mockito:mockito-core:5.6.0"
testImplementation "org.mockito:mockito-core:5.7.0"
testImplementation "ru.tinkoff.kora:test-junit5"
testImplementation "io.goodforgod:testcontainers-extensions-postgres:0.11.0"
testImplementation "org.testcontainers:junit-jupiter:1.17.6"
testImplementation "io.goodforgod:testcontainers-extensions-postgres:0.12.0"
testImplementation "org.testcontainers:junit-jupiter:1.19.8"
}

// for snapshot dependencies
configurations {
configureEach {
resolutionStrategy {
cacheChangingModulesFor 0, "seconds" // check for updates every build
}
}
application {
applicationName = "application"
mainClassName = "ru.tinkoff.kora.java.crud.Application"
applicationDefaultJvmArgs = ["-Dfile.encoding=UTF-8"]
}

distTar {
archiveFileName = "application.tar"
}

//noinspection GroovyAssignabilityCheck
run {
environment([
"POSTGRES_JDBC_URL": "jdbc:postgresql://$postgresHost:$postgresPort/$postgresDatabase",
"POSTGRES_USER" : "$postgresUser",
"POSTGRES_PASS" : "$postgresPassword",
])
}

openApiGenerate {
tasks.register("openApiGenerateHttpServer", GenerateTask) {
generatorName = "kora"
group = "openapi tools"
inputSpec = "$projectDir/src/main/resources/openapi/http-server.yaml"
Expand All @@ -87,21 +95,12 @@ openApiGenerate {
]
}

compileJava.dependsOn tasks.openApiGenerate
test.dependsOn tasks.distTar

application {
applicationDefaultJvmArgs = ["-Dfile.encoding=UTF-8"]
sourceSets.main {
java.srcDirs += "$buildDir/generated/openapi"
}

//noinspection GroovyAssignabilityCheck
run {
environment([
"POSTGRES_JDBC_URL": "jdbc:postgresql://$postgresHost:$postgresPort/$postgresDatabase",
"POSTGRES_USER" : "$postgresUser",
"POSTGRES_PASS" : "$postgresPassword",
])
}
compileJava.dependsOn tasks.openApiGenerateHttpServer
test.dependsOn tasks.distTar

test {
jvmArgs += [
Expand Down Expand Up @@ -130,9 +129,11 @@ test {
}
}

sourceSets {
main {
java.srcDirs += "$buildDir/generated/openapi"
check.dependsOn jacocoTestReport
jacocoTestReport {
reports {
xml.required = true
html.outputLocation = layout.buildDirectory.dir("jacocoHtml")
}
}

Expand All @@ -143,16 +144,19 @@ flyway {
locations = ["classpath:db/migration"]
}

distTar {
archiveFileName = "application.tar"
}

compileJava {
options.encoding("UTF-8")
options.incremental(true)
options.fork = false
}

javadoc {
options.encoding = "UTF-8"
if (JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption("html5", true)
}
}

spotless {
java {
encoding("UTF-8")
Expand All @@ -162,18 +166,3 @@ spotless {
targetExclude("**/proto/**", "**/generated/openapi/**", "**/generated/soap/**", "**/generated/grpc/**",)
}
}

check.dependsOn jacocoTestReport
jacocoTestReport {
reports {
xml.required = true
html.outputLocation = layout.buildDirectory.dir("jacocoHtml")
}
}

javadoc {
options.encoding = "UTF-8"
if (JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption("html5", true)
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
groupId=ru.tinkoff.kora
koraVersion=1.1.9
koraVersion=1.1.11


##### GRADLE #####
Expand Down
1 change: 0 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package ru.tinkoff.kora.java.crud.controller;

import io.micrometer.core.instrument.config.validate.ValidationException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeoutException;
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.common.Context;
import ru.tinkoff.kora.common.Tag;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.MessageTO;
import ru.tinkoff.kora.http.common.body.HttpBody;
import ru.tinkoff.kora.http.server.common.*;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.MessageTO;
import ru.tinkoff.kora.json.common.JsonWriter;

import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeoutException;

@Tag(HttpServerModule.class)
@Component
public final class HttpExceptionHandler implements HttpServerInterceptor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.java.crud.model.mapper.PetMapper;
import ru.tinkoff.kora.java.crud.openapi.http.server.api.PetApiDelegate;
import ru.tinkoff.kora.java.crud.service.PetService;
import ru.tinkoff.kora.java.crud.openapi.http.server.api.PetApiResponses;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.MessageTO;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.PetCreateTO;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.PetUpdateTO;
import ru.tinkoff.kora.java.crud.service.PetService;

@Component
public final class PetDelegate implements PetApiDelegate {
Expand Down Expand Up @@ -64,7 +64,8 @@ public PetApiResponses.DeletePetApiResponse deletePet(long petId) {
}

if (petService.delete(petId)) {
return new PetApiResponses.DeletePetApiResponse.DeletePet200ApiResponse(new MessageTO("Successfully deleted pet with ID: " + petId));
return new PetApiResponses.DeletePetApiResponse.DeletePet200ApiResponse(
new MessageTO("Successfully deleted pet with ID: " + petId));
} else {
return new PetApiResponses.DeletePetApiResponse.DeletePet404ApiResponse(notFound(petId));
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/ru/tinkoff/kora/java/crud/model/dao/Pet.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
@Table("pets")
public record Pet(@Id @Column("id") long id,
@Column("name") String name,
@Column("status") Status status,
@Column("category_id") long categoryId) {
@Column("status") Status status) {

public enum Status {

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package ru.tinkoff.kora.java.crud.model.mapper;

import org.mapstruct.Mapper;
import ru.tinkoff.kora.java.crud.model.dao.PetCategory;
import ru.tinkoff.kora.java.crud.model.dao.PetWithCategory;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.CategoryTO;
import ru.tinkoff.kora.java.crud.model.dao.Pet;
import ru.tinkoff.kora.java.crud.openapi.http.server.model.PetTO;

@Mapper
public interface PetMapper {

PetTO asDTO(PetWithCategory pet);

CategoryTO asDTO(PetCategory category);
PetTO asDTO(Pet pet);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
package ru.tinkoff.kora.java.crud.repository;

import java.util.Optional;
import ru.tinkoff.kora.database.common.UpdateCount;
import ru.tinkoff.kora.database.common.annotation.Id;
import ru.tinkoff.kora.database.common.annotation.Query;
import ru.tinkoff.kora.database.common.annotation.Repository;
import ru.tinkoff.kora.database.jdbc.JdbcRepository;
import ru.tinkoff.kora.java.crud.model.dao.Pet;
import ru.tinkoff.kora.java.crud.model.dao.PetWithCategory;

import java.util.Optional;

@Repository
public interface PetRepository extends JdbcRepository {

@Query("""
SELECT p.id, p.name, p.status, p.category_id, c.name as category_name
FROM pets p
JOIN categories c on c.id = p.category_id
WHERE p.id = :id
""")
Optional<PetWithCategory> findById(long id);
@Query("SELECT %{return#selects} FROM %{return#table} WHERE id = :id")
Optional<Pet> findById(long id);

@Id
@Query("INSERT INTO %{entity#inserts -= id}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package ru.tinkoff.kora.java.crud.repository.mapper;

import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.database.jdbc.mapper.parameter.JdbcParameterColumnMapper;
import ru.tinkoff.kora.java.crud.model.dao.Pet;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.database.jdbc.mapper.parameter.JdbcParameterColumnMapper;
import ru.tinkoff.kora.java.crud.model.dao.Pet;

@Component
public final class PetStatusParameterMapper implements JdbcParameterColumnMapper<Pet.Status> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package ru.tinkoff.kora.java.crud.repository.mapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.database.jdbc.mapper.result.JdbcResultColumnMapper;
import ru.tinkoff.kora.java.crud.model.dao.Pet;

import java.sql.ResultSet;
import java.sql.SQLException;

@Component
public final class PetStatusResultMapper implements JdbcResultColumnMapper<Pet.Status> {

Expand Down
Loading

0 comments on commit 1e10ccd

Please sign in to comment.