diff --git a/DSList.postman_collection.json b/DSList.postman_collection.json new file mode 100644 index 0000000..18e8e6f --- /dev/null +++ b/DSList.postman_collection.json @@ -0,0 +1,140 @@ +{ + "info": { + "_postman_id": "014fa714-5c7b-44ca-a052-6900518a07ee", + "name": "DSList", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "1242165", + "_collection_link": "https://devsuperior-oficial.postman.co/workspace/Aula~cea0855a-8350-42de-9c9d-0c360fac7d27/collection/1242165-014fa714-5c7b-44ca-a052-6900518a07ee?action=share&creator=1242165&source=collection_link" + }, + "item": [ + { + "name": "Games", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/games", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "games" + ] + } + }, + "response": [] + }, + { + "name": "Game by id", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/games/1", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "games", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Game lists", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/lists", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "lists" + ] + } + }, + "response": [] + }, + { + "name": "Games by lists", + "protocolProfileBehavior": { + "disabledSystemHeaders": {} + }, + "request": { + "method": "GET", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "http://localhost:8080/lists/2/games", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "lists", + "2", + "games" + ] + } + }, + "response": [] + }, + { + "name": "List replacement", + "protocolProfileBehavior": { + "disabledSystemHeaders": {} + }, + "request": { + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"sourceIndex\": 3,\r\n \"destinationIndex\": 1\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8080/lists/2/replacement", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "lists", + "2", + "replacement" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 9edc1d3..d5c98c3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **1. Perdeu alguma aula ou material de apoio?** -Inscreva-se para receber no seu email: +Inscreva-se para receber os conteúdos no seu email: https://devsuperior.com.br @@ -14,18 +14,17 @@ Envie uma mensagem pra gente no email que chegou pra você no ato da sua inscri ## Calendário -Os conteúdos ficarão temporariamente disponíveis no nosso canal de eventos. Ative o lembrete: +Os conteúdos ficarão temporariamente disponíveis no nosso website. -https://www.youtube.com/@DevsuperiorJavaSpring +Horário: cada aula será liberada por volta das 9h, somente para quem estiver inscrito no treinamento. Fica de olho no seu email, Whatsapp ou Telegram. | Dia / horário | Conteúdo | | ------------- | ------------- | -| Segunda-feira 20h30 | Aula 1: Projeto estruturado | -| Terça-feira 20h30 | Aula 2: Modelo de domínio | -| Quarta-feira 20h30 | Aula 3: Deploy e caso de uso | -| Quinta-feira 20h30 | Aula 4: Endpoint especial | -| Sexta-feira 20h30 | Aula 5: Resumão e reforço do aprendizado | -| Domingo 16h00 | Oficina: Avançando na modelagem de dados | +| Segunda-feira 9h | Aula 1: Projeto estruturado | +| Terça-feira 9h | Aula 2: Domínio e consultas | +| Quarta-feira 9h | Aula 3: Homologação e CORS | +| Quinta-feira 9h | Aula 4: Endpoint especial | +| Sexta-feira 9h | Aula 5: Resumão e reforço do aprendizado ## Modelo de domínio DSList @@ -69,6 +68,39 @@ spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true ``` +### application-dev.properties + +``` +#spring.jpa.properties.jakarta.persistence.schema-generation.create-source=metadata +#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.action=create +#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.create-target=create.sql +#spring.jpa.properties.hibernate.hbm2ddl.delimiter=; + +spring.datasource.url=jdbc:postgresql://localhost:5432/dscatalog +spring.datasource.username=postgres +spring.datasource.password=1234567 + +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.jpa.hibernate.ddl-auto=none +``` + +### application-prod.properties +``` +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} + +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.jpa.hibernate.ddl-auto=none +``` + +### system.properties +``` +java.runtime.version=17 +``` + ### WebConfig ```java @@ -142,3 +174,7 @@ INSERT INTO tb_belonging (list_id, game_id, position) VALUES (2, 8, 2); INSERT INTO tb_belonging (list_id, game_id, position) VALUES (2, 9, 3); INSERT INTO tb_belonging (list_id, game_id, position) VALUES (2, 10, 4); ``` + +### Script Docker Compose + +https://gist.github.com/acenelio/5e40b27cfc40151e36beec1e27c4ff71 diff --git a/pom.xml b/pom.xml index 33b020e..38f1408 100644 --- a/pom.xml +++ b/pom.xml @@ -1,20 +1,34 @@ - 4.0.0 org.springframework.boot spring-boot-starter-parent - 3.0.6 - + 3.4.1 + com.devsuperior dslist 0.0.1-SNAPSHOT dslist Intensivão Java Spring + + + + + + + + + + + + + - 17 + 21 @@ -25,7 +39,6 @@ org.springframework.boot spring-boot-starter-web - com.h2database h2 @@ -50,7 +63,7 @@ maven-resources-plugin 3.1.0 - + org.springframework.boot spring-boot-maven-plugin diff --git a/src/main/java/com/devsuperior/dslist/config/WebConfig.java b/src/main/java/com/devsuperior/dslist/config/WebConfig.java new file mode 100644 index 0000000..7b3a752 --- /dev/null +++ b/src/main/java/com/devsuperior/dslist/config/WebConfig.java @@ -0,0 +1,25 @@ +package com.devsuperior.dslist.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig { + + @Value("${cors.origins}") + private String corsOrigins; + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**").allowedMethods("*").allowedOrigins(corsOrigins); + } + }; + } + +} diff --git a/src/main/java/com/devsuperior/dslist/controllers/GameListController.java b/src/main/java/com/devsuperior/dslist/controllers/GameListController.java index 94254ff..e8cdda1 100644 --- a/src/main/java/com/devsuperior/dslist/controllers/GameListController.java +++ b/src/main/java/com/devsuperior/dslist/controllers/GameListController.java @@ -5,11 +5,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.devsuperior.dslist.dto.GameListDTO; import com.devsuperior.dslist.dto.GameMinDTO; +import com.devsuperior.dslist.dto.ReplacementDTO; import com.devsuperior.dslist.services.GameListService; import com.devsuperior.dslist.services.GameService; @@ -23,6 +26,12 @@ public class GameListController { @Autowired private GameService gameService; + @GetMapping(value = "/{id}") + public GameListDTO findById(@PathVariable Long id) { + GameListDTO result = gameListService.findById(id); + return result; + } + @GetMapping public List findAll() { List result = gameListService.findAll(); @@ -34,4 +43,9 @@ public List findGames(@PathVariable Long listId) { List result = gameService.findByGameList(listId); return result; } + + @PostMapping(value = "/{listId}/replacement") + public void move(@PathVariable Long listId, @RequestBody ReplacementDTO body) { + gameListService.move(listId, body.getSourceIndex(), body.getDestinationIndex()); + } } diff --git a/src/main/java/com/devsuperior/dslist/dto/GameMinDTO.java b/src/main/java/com/devsuperior/dslist/dto/GameMinDTO.java index aac53c0..9952996 100644 --- a/src/main/java/com/devsuperior/dslist/dto/GameMinDTO.java +++ b/src/main/java/com/devsuperior/dslist/dto/GameMinDTO.java @@ -22,7 +22,7 @@ public GameMinDTO(Game entity) { public GameMinDTO(GameMinProjection projection) { id = projection.getId(); title = projection.getTitle(); - year = projection.getYear(); + year = projection.getGameYear(); imgUrl = projection.getImgUrl(); shortDescription = projection.getShortDescription(); } diff --git a/src/main/java/com/devsuperior/dslist/dto/ReplacementDTO.java b/src/main/java/com/devsuperior/dslist/dto/ReplacementDTO.java new file mode 100644 index 0000000..88b3e89 --- /dev/null +++ b/src/main/java/com/devsuperior/dslist/dto/ReplacementDTO.java @@ -0,0 +1,23 @@ +package com.devsuperior.dslist.dto; + +public class ReplacementDTO { + + private Integer sourceIndex; + private Integer destinationIndex; + + public Integer getSourceIndex() { + return sourceIndex; + } + + public void setSourceIndex(Integer sourceIndex) { + this.sourceIndex = sourceIndex; + } + + public Integer getDestinationIndex() { + return destinationIndex; + } + + public void setDestinationIndex(Integer destinationIndex) { + this.destinationIndex = destinationIndex; + } +} diff --git a/src/main/java/com/devsuperior/dslist/projections/GameMinProjection.java b/src/main/java/com/devsuperior/dslist/projections/GameMinProjection.java index dc51ea6..1beed94 100644 --- a/src/main/java/com/devsuperior/dslist/projections/GameMinProjection.java +++ b/src/main/java/com/devsuperior/dslist/projections/GameMinProjection.java @@ -4,7 +4,7 @@ public interface GameMinProjection { Long getId(); String getTitle(); - Integer getYear(); + Integer getGameYear(); String getImgUrl(); String getShortDescription(); Integer getPosition(); diff --git a/src/main/java/com/devsuperior/dslist/repositories/GameListRepository.java b/src/main/java/com/devsuperior/dslist/repositories/GameListRepository.java index a72033a..e95509e 100644 --- a/src/main/java/com/devsuperior/dslist/repositories/GameListRepository.java +++ b/src/main/java/com/devsuperior/dslist/repositories/GameListRepository.java @@ -1,9 +1,15 @@ package com.devsuperior.dslist.repositories; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import com.devsuperior.dslist.entities.GameList; public interface GameListRepository extends JpaRepository { + @Modifying + @Query(nativeQuery = true, + value = "UPDATE tb_belonging SET position = :newPosition WHERE list_id = :listId AND game_id = :gameId") + void updateBelongingPosition(Long listId, Long gameId, Integer newPosition); } diff --git a/src/main/java/com/devsuperior/dslist/repositories/GameRepository.java b/src/main/java/com/devsuperior/dslist/repositories/GameRepository.java index 40ab535..ac22176 100644 --- a/src/main/java/com/devsuperior/dslist/repositories/GameRepository.java +++ b/src/main/java/com/devsuperior/dslist/repositories/GameRepository.java @@ -11,7 +11,7 @@ public interface GameRepository extends JpaRepository { @Query(nativeQuery = true, value = """ - SELECT tb_game.id, tb_game.title, tb_game.game_year AS `year`, tb_game.img_url AS imgUrl, + SELECT tb_game.id, tb_game.title, tb_game.game_year AS gameYear, tb_game.img_url AS imgUrl, tb_game.short_description AS shortDescription, tb_belonging.position FROM tb_game INNER JOIN tb_belonging ON tb_game.id = tb_belonging.game_id diff --git a/src/main/java/com/devsuperior/dslist/services/GameListService.java b/src/main/java/com/devsuperior/dslist/services/GameListService.java index ded372c..07c6aa3 100644 --- a/src/main/java/com/devsuperior/dslist/services/GameListService.java +++ b/src/main/java/com/devsuperior/dslist/services/GameListService.java @@ -8,7 +8,9 @@ import com.devsuperior.dslist.dto.GameListDTO; import com.devsuperior.dslist.entities.GameList; +import com.devsuperior.dslist.projections.GameMinProjection; import com.devsuperior.dslist.repositories.GameListRepository; +import com.devsuperior.dslist.repositories.GameRepository; @Service public class GameListService { @@ -16,9 +18,35 @@ public class GameListService { @Autowired private GameListRepository gameListRepository; + @Autowired + private GameRepository gameRepository; + @Transactional(readOnly = true) public List findAll() { List result = gameListRepository.findAll(); return result.stream().map(GameListDTO::new).toList(); } + + @Transactional + public void move(Long listId, int sourceIndex, int destinationIndex) { + + List list = gameRepository.searchByList(listId); + + GameMinProjection obj = list.remove(sourceIndex); + list.add(destinationIndex, obj); + + int min = sourceIndex < destinationIndex ? sourceIndex : destinationIndex; + int max = sourceIndex < destinationIndex ? destinationIndex : sourceIndex; + + for (int i = min; i <= max; i++) { + gameListRepository.updateBelongingPosition(listId, list.get(i).getId(), i); + } + } + + @Transactional(readOnly = true) + public GameListDTO findById(Long id) { + GameList entity = gameListRepository.findById(id).get(); + return new GameListDTO(entity); + } } + diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties new file mode 100644 index 0000000..18a88b7 --- /dev/null +++ b/src/main/resources/application-dev.properties @@ -0,0 +1,12 @@ +#spring.jpa.properties.jakarta.persistence.schema-generation.create-source=metadata +#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.action=create +#spring.jpa.properties.jakarta.persistence.schema-generation.scripts.create-target=create.sql +#spring.jpa.properties.hibernate.hbm2ddl.delimiter=; + +spring.datasource.url=jdbc:postgresql://localhost:5433/dslist +spring.datasource.username=postgres +spring.datasource.password=1234567 + +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.jpa.hibernate.ddl-auto=none diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties new file mode 100644 index 0000000..d1beb75 --- /dev/null +++ b/src/main/resources/application-prod.properties @@ -0,0 +1,7 @@ +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} + +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true +spring.jpa.hibernate.ddl-auto=none diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 9e61b4b..497e585 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,7 +1,7 @@ # H2 Connection spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.username=sa -spring.datasource.password= +spring.datasource.password=1234567; # H2 Client spring.h2.console.enabled=true diff --git a/system.properties b/system.properties new file mode 100644 index 0000000..eafd676 --- /dev/null +++ b/system.properties @@ -0,0 +1 @@ +java.runtime.version=17