diff --git a/src/main/java/com/isaacandrade/blog/BlogApplication.java b/src/main/java/com/isaacandrade/blog/BlogApplication.java index 3cf92e4..68a02ba 100644 --- a/src/main/java/com/isaacandrade/blog/BlogApplication.java +++ b/src/main/java/com/isaacandrade/blog/BlogApplication.java @@ -3,9 +3,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @Slf4j +@EnableCaching +@EnableScheduling public class BlogApplication { public static void main(String[] args) { diff --git a/src/main/java/com/isaacandrade/blog/config/CacheManager.java b/src/main/java/com/isaacandrade/blog/config/CacheManager.java new file mode 100644 index 0000000..39df1cf --- /dev/null +++ b/src/main/java/com/isaacandrade/blog/config/CacheManager.java @@ -0,0 +1,26 @@ +package com.isaacandrade.blog.config; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; + +import java.time.Duration; + +public class CacheManager { + + @Bean + public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() // + .prefixCacheNameWith(this.getClass().getPackageName() + ".") // + .entryTtl(Duration.ofSeconds(10)) // + .disableCachingNullValues(); + + return RedisCacheManager.builder(connectionFactory) // + .cacheDefaults(config) // + .build(); + } + +} diff --git a/src/main/java/com/isaacandrade/blog/config/FileStorageConfig.java b/src/main/java/com/isaacandrade/blog/config/FileStorageConfig.java new file mode 100644 index 0000000..d8c9424 --- /dev/null +++ b/src/main/java/com/isaacandrade/blog/config/FileStorageConfig.java @@ -0,0 +1,4 @@ +package com.isaacandrade.blog.config; + +public class FileStorageConfig { +} diff --git a/src/main/java/com/isaacandrade/blog/controller/PostController.java b/src/main/java/com/isaacandrade/blog/controller/PostController.java index 15417e5..2f1a064 100644 --- a/src/main/java/com/isaacandrade/blog/controller/PostController.java +++ b/src/main/java/com/isaacandrade/blog/controller/PostController.java @@ -47,7 +47,7 @@ public class PostController { } ) public ResponseEntity> findAllPosts(){ - List posts = postService.findAllActives(); + List posts = postService.findAllActivesCache(); return ResponseEntity.ok(posts); } diff --git a/src/main/java/com/isaacandrade/blog/domain/post/AuthorWithPostsDTO.java b/src/main/java/com/isaacandrade/blog/domain/post/AuthorWithPostsDTO.java index b54cc7b..ab67079 100644 --- a/src/main/java/com/isaacandrade/blog/domain/post/AuthorWithPostsDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/post/AuthorWithPostsDTO.java @@ -2,7 +2,8 @@ import com.isaacandrade.blog.domain.user.UserDTO; +import java.io.Serializable; import java.util.List; -public record AuthorWithPostsDTO(UserDTO author, List posts) { +public record AuthorWithPostsDTO(UserDTO author, List posts) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/post/CreatePostDTO.java b/src/main/java/com/isaacandrade/blog/domain/post/CreatePostDTO.java index a14f2c5..d9d8e39 100644 --- a/src/main/java/com/isaacandrade/blog/domain/post/CreatePostDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/post/CreatePostDTO.java @@ -1,10 +1,11 @@ package com.isaacandrade.blog.domain.post; +import java.io.Serializable; public record CreatePostDTO( String title, String content, Boolean isActive -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/post/EditPostDTO.java b/src/main/java/com/isaacandrade/blog/domain/post/EditPostDTO.java index 93d0322..23db026 100644 --- a/src/main/java/com/isaacandrade/blog/domain/post/EditPostDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/post/EditPostDTO.java @@ -1,7 +1,9 @@ package com.isaacandrade.blog.domain.post; +import java.io.Serializable; + public record EditPostDTO( String title, String content -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/post/PostDTO.java b/src/main/java/com/isaacandrade/blog/domain/post/PostDTO.java index 4cd11b1..3325343 100644 --- a/src/main/java/com/isaacandrade/blog/domain/post/PostDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/post/PostDTO.java @@ -2,10 +2,13 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.io.Serializable; import java.time.LocalDateTime; @JsonPropertyOrder({"id", "title", "content", "createdAt", "isActive"}) -public record PostDTO(Long id, String title, String content, @JsonFormat(pattern = "dd/MM/yyyy HH:mm") LocalDateTime createdAt, Boolean isActive) { +public record PostDTO(Long id, String title, String content, @JsonFormat(pattern = "dd/MM/yyyy HH:mm") @JsonSerialize(using = LocalDateTimeSerializer.class)LocalDateTime createdAt, Boolean isActive) implements Serializable { } \ No newline at end of file diff --git a/src/main/java/com/isaacandrade/blog/domain/user/AuthenticationDTO.java b/src/main/java/com/isaacandrade/blog/domain/user/AuthenticationDTO.java index 9fd2c46..99e9183 100644 --- a/src/main/java/com/isaacandrade/blog/domain/user/AuthenticationDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/user/AuthenticationDTO.java @@ -2,11 +2,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + public record AuthenticationDTO( @JsonProperty("username") String userName, @JsonProperty("senha") String passWord -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/user/CreateUserDTO.java b/src/main/java/com/isaacandrade/blog/domain/user/CreateUserDTO.java index 728e5d9..3410d35 100644 --- a/src/main/java/com/isaacandrade/blog/domain/user/CreateUserDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/user/CreateUserDTO.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; +import java.io.Serializable; + public record CreateUserDTO( @JsonProperty("username") String userName, @@ -13,5 +15,5 @@ public record CreateUserDTO( String passWord, UserRole role -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/user/EditUserDTO.java b/src/main/java/com/isaacandrade/blog/domain/user/EditUserDTO.java index bdc994d..bb738b9 100644 --- a/src/main/java/com/isaacandrade/blog/domain/user/EditUserDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/user/EditUserDTO.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serializable; + public record EditUserDTO( @JsonProperty("username") String userName, @@ -12,6 +14,6 @@ public record EditUserDTO( @JsonProperty("role") UserRole role -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/user/LoginResponseDTO.java b/src/main/java/com/isaacandrade/blog/domain/user/LoginResponseDTO.java index af048cd..438b22c 100644 --- a/src/main/java/com/isaacandrade/blog/domain/user/LoginResponseDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/user/LoginResponseDTO.java @@ -1,4 +1,6 @@ package com.isaacandrade.blog.domain.user; -public record LoginResponseDTO(String token) { +import java.io.Serializable; + +public record LoginResponseDTO(String token) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/domain/user/UserDTO.java b/src/main/java/com/isaacandrade/blog/domain/user/UserDTO.java index 3b99ead..a9414c0 100644 --- a/src/main/java/com/isaacandrade/blog/domain/user/UserDTO.java +++ b/src/main/java/com/isaacandrade/blog/domain/user/UserDTO.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import jakarta.validation.constraints.Email; +import java.io.Serializable; + @JsonPropertyOrder({"id", "userName", "email"}) public record UserDTO( @@ -19,5 +21,5 @@ public record UserDTO( UserRole role -) { +) implements Serializable { } diff --git a/src/main/java/com/isaacandrade/blog/service/PostService.java b/src/main/java/com/isaacandrade/blog/service/PostService.java index ba73901..805939e 100644 --- a/src/main/java/com/isaacandrade/blog/service/PostService.java +++ b/src/main/java/com/isaacandrade/blog/service/PostService.java @@ -6,13 +6,20 @@ import com.isaacandrade.blog.exception.ConstraintViolationException; import com.isaacandrade.blog.exception.PostNotFoundException; import com.isaacandrade.blog.infra.exceptionhandler.ApplicationExceptionHandler; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +@Slf4j @Service public class PostService { @@ -26,6 +33,12 @@ public class PostService { private ApplicationExceptionHandler exceptionHandler; + // Cacheamento + @Cacheable(value = "posts", key = "'findAllActivesCache'") + public List findAllActivesCache(){ + return findAllActives(); + } + public List findAllActives(){ List posts = postRepository.findByIsActiveTrue(); if (posts.isEmpty()){ @@ -34,6 +47,17 @@ public List findAllActives(){ return posts.stream().map(this::mapToPostDTO).collect(Collectors.toList()); } + + //Sistema de limpeza de cache dos Posts - 12 horas LIMPA + @Scheduled(fixedDelay = 12, timeUnit = TimeUnit.HOURS) + @CacheEvict("posts") + public void limparPostsCache() { + log.info("Cache de Posts Limpado!"); + } + + + + @Cacheable(value = "posts", key = "#authorId", unless = "#result == null") public AuthorWithPostsDTO findPostsWithAuthorId(Long authorId){ UserDTO author = userService.findUserById(authorId); List posts = postRepository.findPostsByAuthorId(authorId); @@ -47,6 +71,9 @@ public AuthorWithPostsDTO findPostsWithAuthorId(Long authorId){ return new AuthorWithPostsDTO(author, postDTOs); } + + + @Cacheable(value = "posts", key = "#title", unless = "#result == null") public PostDTO findByTitle(String title){ Post posts = postRepository.findByTitle(title); if (posts.getTitle().isEmpty()) { @@ -55,6 +82,8 @@ public PostDTO findByTitle(String title){ return mapToPostDTO(posts); } + + public PostDTO createPost(CreatePostDTO data, Long authorId){ Post post = new Post(); UserDTO author = userService.findUserById(authorId); @@ -73,6 +102,8 @@ public PostDTO createPost(CreatePostDTO data, Long authorId){ return mapToPostDTO(savedPost); } + @CachePut(value = "posts", key = "#id") + @CacheEvict(value = "posts", key = "'findAllActivesCache'") public PostDTO updatePost(Long id, EditPostDTO data){ Post post = postRepository.findById(id).orElseThrow(() -> new PostNotFoundException("Post With Id " + id + " Was Not Found")); post.updatePost(data); @@ -81,12 +112,17 @@ public PostDTO updatePost(Long id, EditPostDTO data){ return mapToPostDTO(post); } + + + @CacheEvict(value = "posts", key = "#id") public void deletePost(Long id){ Post post = postRepository.findById(id).orElseThrow(() -> new PostNotFoundException("Post With Id " + id + " Was Not Found")); post.delete(); postRepository.save(post); } + + private User mapToUserEntity(UserDTO userDTO) { User user = new User(); user.setId(userDTO.id()); @@ -95,6 +131,8 @@ private User mapToUserEntity(UserDTO userDTO) { return user; } + + private PostDTO mapToPostDTO(Post post) { UserDTO authorDTO = new UserDTO(post.getAuthor().getId(), post.getAuthor().getEmail(), post.getAuthor().getUsername(), post.getAuthor().getRole()); return new PostDTO( @@ -105,4 +143,4 @@ private PostDTO mapToPostDTO(Post post) { post.getIsActive() ); } -} +} \ No newline at end of file diff --git a/src/main/java/com/isaacandrade/blog/service/ProjectService.java b/src/main/java/com/isaacandrade/blog/service/ProjectService.java index bb6d043..0764df7 100644 --- a/src/main/java/com/isaacandrade/blog/service/ProjectService.java +++ b/src/main/java/com/isaacandrade/blog/service/ProjectService.java @@ -11,6 +11,9 @@ import com.isaacandrade.blog.exception.ConstraintViolationException; import com.isaacandrade.blog.exception.ProjectNotFoundException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.*; @@ -26,6 +29,7 @@ public class ProjectService { TechnologyRepository technologyRepository; // Metodo que para listar todos os projetos + @Cacheable(value = "projects", key = "#id", unless = "#result == null") public List getAllProjects() { List projects = projectRepository.findAll(); if (projects.isEmpty()){ @@ -35,6 +39,7 @@ public List getAllProjects() { } // Metodo para mostrar um projeto pelo id + @Cacheable(value = "projects", key = "#name", unless = "#result.name == null") public ProjectDto getProjectByName(String name) { Project project = projectRepository.findByName(name); @@ -82,6 +87,8 @@ public ProjectDto createProject(CreateProjectDto data) { return mapToProjectDTO(projectRepository.save(project)); } + + @CachePut(value = "projects", key = "#id") public Optional updateProject(Long id, CreateProjectDto data) { projectRepository.findById(id).orElseThrow(() -> @@ -124,6 +131,7 @@ public Optional updateProject(Long id, CreateProjectDto data) { }); } + @CacheEvict(value = "projects", key = "#id") public void deleteProject(Long id) { projectRepository.findById(id).orElseThrow(() -> new ProjectNotFoundException("Project With id " + id + " Was Not Found!")); diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 3e62b18..692c9da 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -23,3 +23,11 @@ spring.flyway.clean-disabled=false springdoc.pathsToMatch=/**/**/** springdoc.swagger-ui.use-root-path=true + +spring.redis.host=redis +spring.redis.port=6379 +spring.cache.type=redis + +spring.data.redis.repositories.enabled=false +logging.level.org.springframework.cache=trace + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 11710b4..7f0e7ec 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,2 @@ -spring.profiles.active=prod +spring.profiles.active=dev