diff --git a/.assets/openapi.png b/.assets/openapi.png new file mode 100644 index 0000000..d687b0f --- /dev/null +++ b/.assets/openapi.png Binary files differ diff --git a/README.MD b/README.MD index f3d7c57..569a995 100644 --- a/README.MD +++ b/README.MD @@ -1,3 +1,15 @@ +# Доступ к Swagger UI + +После запуска приложения: + + Swagger UI: http://localhost:8080/swagger-ui.html + + OpenAPI JSON: http://localhost:8080/api-docs + + OpenAPI YAML: http://localhost:8080/api-docs.yaml + +![img.png](.assets/openapi.png) + # Примеры вызовов (cURL) ## Получить все объекты организации @@ -37,15 +49,7 @@ bash curl -X GET "http://localhost:8080/api/data/Contact?orgId=1" ``` -# Доступ к Swagger UI -После запуска приложения: - - Swagger UI: http://localhost:8080/swagger-ui.html - - OpenAPI JSON: http://localhost:8080/api-docs - - OpenAPI YAML: http://localhost:8080/api-docs.yaml # UML/ERD схема базы данных Pivot Multitenancy diff --git a/build.gradle b/build.gradle index 2cbf500..a395cd2 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,7 @@ annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" implementation "net.datafaker:datafaker:${datafakerVersion}" implementation "org.apache.commons:commons-lang3:${commonsLangVersion}" + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate6' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-testcontainers' testImplementation "org.testcontainers:postgresql:${testcontainersVersion}" diff --git a/src/main/java/ru/mcs/config/JacksonConfig.java b/src/main/java/ru/mcs/config/JacksonConfig.java new file mode 100644 index 0000000..5180fa5 --- /dev/null +++ b/src/main/java/ru/mcs/config/JacksonConfig.java @@ -0,0 +1,28 @@ +package ru.mcs.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JacksonConfig { + + @Bean + public ObjectMapper objectMapper() { + ObjectMapper mapper = new ObjectMapper(); + + // Поддержка Hibernate lazy loading + Hibernate6Module hibernateModule = new Hibernate6Module(); + hibernateModule.configure(Hibernate6Module.Feature.FORCE_LAZY_LOADING, false); + mapper.registerModule(hibernateModule); + + // Поддержка Java 8 Date/Time + mapper.registerModule(new JavaTimeModule()); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + return mapper; + } +} diff --git a/src/main/java/ru/mcs/controller/MetadataController.java b/src/main/java/ru/mcs/controller/MetadataController.java index 045f1b8..21b77b3 100644 --- a/src/main/java/ru/mcs/controller/MetadataController.java +++ b/src/main/java/ru/mcs/controller/MetadataController.java @@ -2,10 +2,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -14,10 +10,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import ru.mcs.dto.FieldDto; import ru.mcs.dto.ObjectDto; import ru.mcs.entity.MtField; import ru.mcs.entity.MtObject; +import ru.mcs.mapper.ObjectMapper; import ru.mcs.service.MetadataService; import java.util.List; @@ -29,34 +25,21 @@ public class MetadataController { private final MetadataService metadataService; + private final ObjectMapper objectMapper; - @Operation( - summary = "Получить все объекты организации", - description = "Возвращает список всех объектов (таблиц) для указанной организации" - ) - @ApiResponse( - responseCode = "200", - description = "Список объектов", - content = @Content( - mediaType = "application/json", - array = @ArraySchema(schema = @Schema(implementation = ObjectDto.class)) - ) - ) + @Operation(summary = "Получить все объекты организации") @GetMapping("/objects") - public ResponseEntity> getObjects( + public ResponseEntity> getObjects( @Parameter(description = "ID организации", example = "1") @RequestParam(defaultValue = "1") Integer orgId) { List objects = metadataService.getObjectsByOrg(orgId); - return ResponseEntity.ok(objects); + return ResponseEntity.ok(objectMapper.toDtoList(objects)); } - @Operation( - summary = "Получить объект по имени", - description = "Возвращает метаданные конкретного объекта" - ) + @Operation(summary = "Получить объект по имени") @GetMapping("/objects/{objectName}") - public ResponseEntity getObject( + public ResponseEntity getObject( @Parameter(description = "ID организации", example = "1") @RequestParam(defaultValue = "1") Integer orgId, @@ -64,13 +47,10 @@ @PathVariable String objectName) { MtObject object = metadataService.getObjectByName(orgId, objectName); - return ResponseEntity.ok(object); + return ResponseEntity.ok(objectMapper.toDto(object)); } - @Operation( - summary = "Получить поля объекта", - description = "Возвращает список всех полей (колонок) для указанного объекта" - ) + @Operation(summary = "Получить поля объекта") @GetMapping("/objects/{objectName}/fields") public ResponseEntity> getFields( @Parameter(description = "ID организации", example = "1") diff --git a/src/main/java/ru/mcs/dto/ObjectDto.java b/src/main/java/ru/mcs/dto/ObjectDto.java index 7c211ee..05d2601 100644 --- a/src/main/java/ru/mcs/dto/ObjectDto.java +++ b/src/main/java/ru/mcs/dto/ObjectDto.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.time.OffsetDateTime; + @Data @Builder @NoArgsConstructor @@ -19,7 +21,7 @@ @Schema(description = "ID организации", example = "1") private Integer orgId; - @Schema(description = "Системное имя объекта", example = "Contact") + @Schema(description = "Системное имя", example = "Contact") private String objName; @Schema(description = "Отображаемое имя", example = "Contact") @@ -28,9 +30,18 @@ @Schema(description = "Множественное имя", example = "Contacts") private String pluralLabel; + @Schema(description = "Описание") + private String description; + @Schema(description = "Кастомный объект", example = "false") private Boolean isCustom; @Schema(description = "Активен", example = "true") private Boolean isActive; + + @Schema(description = "Дата создания") + private OffsetDateTime createdAt; + + @Schema(description = "Дата изменения") + private OffsetDateTime modifiedAt; } diff --git a/src/main/java/ru/mcs/mapper/ObjectMapper.java b/src/main/java/ru/mcs/mapper/ObjectMapper.java new file mode 100644 index 0000000..909ad63 --- /dev/null +++ b/src/main/java/ru/mcs/mapper/ObjectMapper.java @@ -0,0 +1,15 @@ +package ru.mcs.mapper; + +import org.mapstruct.Mapper; +import ru.mcs.dto.ObjectDto; +import ru.mcs.entity.MtObject; + +import java.util.List; + +@Mapper(componentModel = "spring") +public interface ObjectMapper { + + ObjectDto toDto(MtObject entity); + + List toDtoList(List entities); +}