Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: zenbook14
ports:
- "5555:5556"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

redis:
image: redis:7
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5

volumes:
postgres_data:
redis_data:
145 changes: 136 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,43 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.emobile</groupId>
<artifactId>SpringToDo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringToDo</name>
<description>Spring Boot ToDo Application</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath/>
</parent>
<groupId>com.emobile</groupId>
<artifactId>SpringToDo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringToDo</name>
<description>SpringToDo</description>

<properties>
<java.version>21</java.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<springdoc.version>2.5.0</springdoc.version>
<testcontainers.version>1.20.2</testcontainers.version>

<!-- Кодировки -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<dependencies>
<!-- Web + Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<!-- JPA/Hibernate -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

<!-- Flyway миграции -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>

<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

<!-- Swagger/OpenAPI аннотации + UI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>

<!-- MapStruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>

<!-- Lombok (опционально) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>

<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>

<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<systemPropertyVariables>

<spring.profiles.active>test,hibernate</spring.profiles.active>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
@SpringBootApplication
public class SpringToDoApplication {

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/emobile/springtodo/config/HibernateConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.emobile.springtodo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("hibernate")
public class HibernateConfig {
// пусто — убрали SessionFactory- бин, чтобы не было циклов
}
22 changes: 22 additions & 0 deletions src/main/java/com/emobile/springtodo/config/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.emobile.springtodo.config;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

@Configuration
@Profile("redis")
public class RedisConfig {

@Bean
public RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
48 changes: 48 additions & 0 deletions src/main/java/com/emobile/springtodo/controller/ToDoAPI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.emobile.springtodo.controller;

import com.emobile.springtodo.dto.ToDoDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.responses.ApiResponse;

import java.util.List;

@Tag(name = "ToDoAPI", description = "API for managing TODO items")
public interface ToDoAPI {

@Operation(summary = "Create a new TODO item")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "TODO created"),
@ApiResponse(responseCode = "404", description = "invalid input")
})
ToDoDto create(ToDoDto dto);

@Operation(summary = "Get TODO item by ID")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "TODO found"),
@ApiResponse(responseCode = "404", description = "TODO not found")
})
ToDoDto getById(Long id);

@Operation(summary = "Get all TODO items with pagination")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "List of TODOs")
})
List<ToDoDto> getAll(int limit, int offset);

@Operation(summary = "Update TODO item")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "TODO updated"),
@ApiResponse(responseCode = "404", description = "TODO not found"),
@ApiResponse(responseCode = "400", description = "Invalid input")
})
ToDoDto update(Long id, ToDoDto dto);

@Operation(summary = "Delete TODO item")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "TODO deleted"),
@ApiResponse(responseCode = "404", description = "TODO not found")
})
void delete(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.emobile.springtodo.controller;

import com.emobile.springtodo.dto.ToDoDto;
import com.emobile.springtodo.service.ToDoService;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("api/todos")
public class ToDoController implements ToDoAPI {

private final ToDoService service;

public ToDoController(ToDoService service) {
this.service = service;
}

@PostMapping
public ToDoDto create(@Valid @RequestBody ToDoDto dto){
return service.create(dto);
}

@GetMapping("/{id}")
public ToDoDto getById(@PathVariable Long id){
return service.findById(id);
}

@GetMapping
public List<ToDoDto> getAll(@RequestParam(defaultValue = "10") int limit,
@RequestParam(defaultValue = "0") int offset){
return service.findAll(limit, offset);
}

@PutMapping("/{id}")
public ToDoDto update(@PathVariable Long id, @Valid @RequestBody ToDoDto dto){
return service.update(id, dto);
}

@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
service.delete(id);
}
}
Loading