├── .gitignore ├── Application reactive ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── svalero │ │ └── amazonapplication │ │ ├── AmazonApplication.java │ │ ├── api │ │ └── Constants.java │ │ ├── controller │ │ └── ApplicationController.java │ │ ├── domain │ │ └── User.java │ │ └── util │ │ └── Resources.java │ └── resources │ └── ui │ └── AmazonApplication.fxml ├── README.md ├── amazonapi ├── HELP.md ├── amazonapi.postman_collection.json ├── amazonapi.yaml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codeandcoke │ │ │ └── amazonapi │ │ │ ├── AmazonapiApplication.java │ │ │ ├── config │ │ │ └── AmazonConfig.java │ │ │ ├── controller │ │ │ ├── OrderController.java │ │ │ ├── ProductController.java │ │ │ └── UserController.java │ │ │ ├── domain │ │ │ ├── Order.java │ │ │ ├── Product.java │ │ │ └── User.java │ │ │ ├── dto │ │ │ ├── ErrorResponse.java │ │ │ ├── OrderInDTO.java │ │ │ ├── OrderOutDTO.java │ │ │ ├── ProductDTO.java │ │ │ └── ProductPatchDTO.java │ │ │ ├── exception │ │ │ ├── ProductNotFoundException.java │ │ │ └── UserNotFoundException.java │ │ │ ├── repository │ │ │ ├── OrderRepository.java │ │ │ ├── ProductRepository.java │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ ├── OrderService.java │ │ │ ├── OrderServiceImpl.java │ │ │ ├── ProductService.java │ │ │ ├── ProductServiceImpl.java │ │ │ ├── UserService.java │ │ │ └── UserServiceImpl.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── codeandcoke │ └── amazonapi │ └── AmazonapiApplicationTests.java ├── bikesapi_reactive ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── bikesapi.yaml ├── bikesapi_reactive.postman_collection.json ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── svalero │ │ │ └── bikesapi │ │ │ ├── BikesapiApplication.java │ │ │ ├── WebClientTest.java │ │ │ ├── controller │ │ │ ├── BikeController.java │ │ │ ├── RouteController.java │ │ │ └── UserController.java │ │ │ ├── domain │ │ │ ├── Bike.java │ │ │ ├── Route.java │ │ │ ├── User.java │ │ │ └── dto │ │ │ │ └── RouteDTO.java │ │ │ ├── exception │ │ │ ├── BikeNotFoundException.java │ │ │ ├── Constants.java │ │ │ ├── ErrorResponse.java │ │ │ ├── RouteNotFoundException.java │ │ │ └── UserNotFoundException.java │ │ │ ├── repository │ │ │ ├── BikeRepository.java │ │ │ ├── RouteRepository.java │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ ├── BikeService.java │ │ │ ├── BikeServiceImpl.java │ │ │ ├── RouteService.java │ │ │ ├── RouteServiceImpl.java │ │ │ ├── UserService.java │ │ │ └── UserServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── logback.xml │ └── test │ └── java │ └── com │ └── svalero │ └── bikesapi │ └── BikesapiApplicationTests.java ├── helloapi ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── helloapi.yaml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── svalero │ │ │ └── helloapi │ │ │ ├── HelloapiApplication.java │ │ │ ├── config │ │ │ └── ApplicationConfig.java │ │ │ ├── controller │ │ │ ├── OrderController.java │ │ │ ├── ProductController.java │ │ │ └── UserController.java │ │ │ ├── domain │ │ │ ├── ErrorResponse.java │ │ │ ├── Order.java │ │ │ ├── Product.java │ │ │ └── User.java │ │ │ ├── dto │ │ │ ├── OrderInDto.java │ │ │ ├── OrderOutDto.java │ │ │ ├── ProductInDto.java │ │ │ └── ProductOutDto.java │ │ │ ├── exception │ │ │ ├── ProductNotFoundException.java │ │ │ └── UserNotFoundException.java │ │ │ ├── repository │ │ │ ├── OrderRepository.java │ │ │ ├── ProductRepository.java │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ ├── OrderService.java │ │ │ ├── ProductService.java │ │ │ └── UserService.java │ └── resources │ │ ├── application.properties │ │ └── logback-spring.xml │ └── test │ └── java │ └── com │ └── svalero │ └── helloapi │ └── HelloapiApplicationTests.java ├── library-api-sec ├── .gitignore ├── library-api-sec.postman_collection.json ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── codeandcoke │ │ └── library │ │ ├── LibraryApplication.java │ │ ├── config │ │ └── LibraryConfig.java │ │ ├── controller │ │ ├── BookController.java │ │ └── TokenController.java │ │ ├── domain │ │ ├── Book.java │ │ ├── Role.java │ │ ├── User.java │ │ └── UserDTO.java │ │ ├── exception │ │ ├── BookNotFoundException.java │ │ ├── ErrorResponse.java │ │ └── UserRegistrationException.java │ │ ├── repository │ │ ├── BookRepository.java │ │ ├── RoleRepository.java │ │ └── UserRepository.java │ │ ├── security │ │ ├── AuthEntryPointJwt.java │ │ ├── AuthTokenFilter.java │ │ ├── JwtResponse.java │ │ ├── JwtUtils.java │ │ └── LibraryUserDetailsService.java │ │ └── service │ │ ├── BookService.java │ │ ├── BookServiceImpl.java │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ └── resources │ ├── app.key │ ├── app.pub │ ├── application.properties │ └── logback-spring.xml ├── library-web ├── .gitignore ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── sanvalero │ │ └── libraryweb │ │ ├── MyshopApplication.java │ │ ├── controller │ │ └── WebController.java │ │ ├── domain │ │ └── Book.java │ │ └── service │ │ ├── BookService.java │ │ └── BookServiceImpl.java │ └── resources │ ├── application.properties │ └── templates │ ├── book.html │ ├── catalog.html │ └── index.html ├── mockapi ├── __files │ ├── defaultResponse.json │ ├── getProduct-ok.json │ ├── getProducts-ok.json │ ├── internalServerError.json │ ├── postProducts-ok.json │ └── productNotFound.json ├── mappings │ ├── defaultRequest.json │ ├── deleteProduct-404.json │ ├── deleteProduct-500.json │ ├── deleteProduct-ok.json │ ├── getProduct-404.json │ ├── getProduct-ok.json │ ├── getProducts-ok.json │ └── postProducts-ok.json └── wiremock-standalone-3.3.1.jar ├── myshop-ws-swagger ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sanvalero │ │ │ └── myshop │ │ │ ├── MyshopApplication.java │ │ │ ├── config │ │ │ └── ShopConfig.java │ │ │ ├── controller │ │ │ ├── ProductController.java │ │ │ └── Response.java │ │ │ ├── domain │ │ │ └── Product.java │ │ │ ├── exception │ │ │ └── ProductNotFoundException.java │ │ │ ├── repository │ │ │ └── ProductRepository.java │ │ │ └── service │ │ │ ├── ProductService.java │ │ │ └── ProductServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── logback-spring.xml │ └── test │ └── java │ └── com │ └── sanvalero │ └── myshop │ └── MyshopApplicationTests.java ├── myshop-ws-swagger2 ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sanvalero │ │ │ └── myshop │ │ │ ├── MyshopApplication.java │ │ │ ├── config │ │ │ └── ShopConfig.java │ │ │ ├── controller │ │ │ ├── OrderController.java │ │ │ ├── ProductController.java │ │ │ └── Response.java │ │ │ ├── domain │ │ │ ├── Order.java │ │ │ ├── OrderDetail.java │ │ │ ├── Product.java │ │ │ └── dto │ │ │ │ └── OrderDTO.java │ │ │ ├── exception │ │ │ └── ProductNotFoundException.java │ │ │ ├── repository │ │ │ ├── OrderDetailRepository.java │ │ │ ├── OrderRepository.java │ │ │ └── ProductRepository.java │ │ │ └── service │ │ │ ├── OrderService.java │ │ │ ├── OrderServiceImpl.java │ │ │ ├── ProductService.java │ │ │ └── ProductServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── logback-spring.xml │ └── test │ └── java │ └── com │ └── sanvalero │ └── myshop │ └── MyshopApplicationTests.java ├── myshop-ws ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sanvalero │ │ │ └── myshop │ │ │ ├── MyshopApplication.java │ │ │ ├── controller │ │ │ ├── ProductController.java │ │ │ └── Response.java │ │ │ ├── domain │ │ │ └── Product.java │ │ │ ├── exception │ │ │ └── ProductNotFoundException.java │ │ │ ├── repository │ │ │ └── ProductRepository.java │ │ │ └── service │ │ │ ├── ProductService.java │ │ │ └── ProductServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── logback-spring.xml │ └── test │ └── java │ └── com │ └── sanvalero │ └── myshop │ └── MyshopApplicationTests.java ├── myshop ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sanvalero │ │ │ └── myshop │ │ │ ├── MyshopApplication.java │ │ │ ├── controller │ │ │ └── WebController.java │ │ │ ├── domain │ │ │ └── Product.java │ │ │ ├── repository │ │ │ └── ProductRepository.java │ │ │ └── service │ │ │ ├── ProductService.java │ │ │ └── ProductServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── catalog.html │ │ └── index.html │ └── test │ └── java │ └── com │ └── sanvalero │ └── myshop │ └── MyshopApplicationTests.java ├── reactive-client ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── svalero │ └── reactiveclient │ ├── Main.java │ └── domain │ └── Bus.java ├── reactive-functional-api ├── .env ├── Dockerfile ├── docker-compose.yaml ├── pom.xml ├── reactive-functional-api.postman_collection.json └── src │ └── main │ ├── java │ └── com │ │ └── svalero │ │ ├── ReactiveApi.java │ │ ├── domain │ │ └── Product.java │ │ ├── handler │ │ └── ProductHandler.java │ │ ├── repository │ │ └── ProductRepository.java │ │ ├── router │ │ └── ProductRouter.java │ │ ├── service │ │ └── ProductService.java │ │ ├── util │ │ └── ErrorResponse.java │ │ └── validator │ │ └── ProductValidator.java │ └── resources │ └── application.properties └── todoapi_v1 ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src ├── main │ ├── java │ │ └── com │ │ │ └── svalero │ │ │ └── todoapi │ │ │ ├── TodoApiApplication.java │ │ │ ├── controller │ │ │ └── TaskController.java │ │ │ ├── domain │ │ │ └── Task.java │ │ │ ├── dto │ │ │ └── ErrorResponse.java │ │ │ ├── exception │ │ │ └── TaskNotFoundException.java │ │ │ ├── repository │ │ │ └── TaskRepository.java │ │ │ └── service │ │ │ ├── TaskService.java │ │ │ └── TaskServiceImpl.java │ └── resources │ │ └── application.properties └── test │ └── java │ └── com │ └── svalero │ └── todoapi │ └── TodoApiApplicationTests.java └── todoapi.postman_collection.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | 4 | # Compiled class file 5 | *.class 6 | 7 | # Log file 8 | *.log 9 | 10 | # BlueJ files 11 | *.ctxt 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.nar 20 | *.ear 21 | *.zip 22 | *.tar.gz 23 | *.rar 24 | 25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 26 | hs_err_pid* 27 | 28 | target 29 | .DS_Store 30 | -------------------------------------------------------------------------------- /Application reactive/src/main/java/com/svalero/amazonapplication/AmazonApplication.java: -------------------------------------------------------------------------------- 1 | package com.svalero.amazonapplication; 2 | 3 | import com.svalero.amazonapplication.controller.ApplicationController; 4 | import com.svalero.amazonapplication.domain.User; 5 | import com.svalero.amazonapplication.util.Resources; 6 | import javafx.application.Application; 7 | import javafx.fxml.FXMLLoader; 8 | import javafx.scene.Scene; 9 | import javafx.scene.layout.BorderPane; 10 | import javafx.stage.Stage; 11 | import org.springframework.web.reactive.function.client.WebClient; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.scheduler.Schedulers; 14 | 15 | import java.util.concurrent.Executors; 16 | 17 | import static com.svalero.amazonapplication.api.Constants.API_BASE_URL; 18 | 19 | public class AmazonApplication extends Application { 20 | 21 | @Override 22 | public void init() throws Exception { 23 | super.init(); 24 | } 25 | 26 | @Override 27 | public void start(Stage stage) throws Exception { 28 | FXMLLoader loader = new FXMLLoader(); 29 | loader.setLocation(Resources.getUI("AmazonApplication.fxml")); 30 | loader.setController(new ApplicationController()); 31 | BorderPane pane = loader.load(); 32 | 33 | Scene scene = new Scene(pane); 34 | stage.setScene(scene); 35 | stage.setTitle("BikesAPI Application"); 36 | stage.show(); 37 | } 38 | 39 | @Override 40 | public void stop() throws Exception { 41 | super.stop(); 42 | } 43 | 44 | public static void main(String[] args) { 45 | launch(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Application reactive/src/main/java/com/svalero/amazonapplication/api/Constants.java: -------------------------------------------------------------------------------- 1 | package com.svalero.amazonapplication.api; 2 | 3 | public class Constants { 4 | 5 | public static final String API_BASE_URL = "http://localhost:8080"; 6 | } 7 | -------------------------------------------------------------------------------- /Application reactive/src/main/java/com/svalero/amazonapplication/controller/ApplicationController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.amazonapplication.controller; 2 | 3 | import com.svalero.amazonapplication.domain.User; 4 | import javafx.event.ActionEvent; 5 | import javafx.fxml.FXML; 6 | import javafx.fxml.Initializable; 7 | import javafx.scene.control.*; 8 | import javafx.scene.control.cell.PropertyValueFactory; 9 | import org.springframework.web.reactive.function.client.WebClient; 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.scheduler.Schedulers; 12 | 13 | import java.net.URL; 14 | import java.util.ResourceBundle; 15 | import java.util.concurrent.Executors; 16 | 17 | import static com.svalero.amazonapplication.api.Constants.API_BASE_URL; 18 | 19 | public class ApplicationController implements Initializable { 20 | 21 | public TextField productSearchTextField; 22 | public Button searchButton; 23 | public TableView dataTable; 24 | public Label statusLabel; 25 | public ProgressBar progressBar; 26 | 27 | @Override 28 | public void initialize(URL url, ResourceBundle resourceBundle) { 29 | prepareTableView(); 30 | listAllUsers(); 31 | } 32 | 33 | private void prepareTableView() { 34 | TableColumn nameColumn = new TableColumn<>("Name"); 35 | nameColumn.setCellValueFactory(new PropertyValueFactory<>("name")); 36 | TableColumn descriptionColumn = new TableColumn<>("Surname"); 37 | descriptionColumn.setCellValueFactory(new PropertyValueFactory<>("surname")); 38 | TableColumn categoryColumn = new TableColumn<>("Email"); 39 | categoryColumn.setCellValueFactory(new PropertyValueFactory<>("email")); 40 | TableColumn priceColumn = new TableColumn<>("DNI"); 41 | priceColumn.setCellValueFactory(new PropertyValueFactory<>("dni")); 42 | 43 | dataTable.getColumns().add(nameColumn); 44 | dataTable.getColumns().add(descriptionColumn); 45 | dataTable.getColumns().add(categoryColumn); 46 | dataTable.getColumns().add(priceColumn); 47 | } 48 | 49 | private void listAllUsers() { 50 | WebClient webClient = WebClient.create(API_BASE_URL); 51 | Flux usersFlux = webClient.get() 52 | .uri("/users") 53 | .retrieve() 54 | .bodyToFlux(User.class); 55 | 56 | usersFlux 57 | .subscribeOn(Schedulers.fromExecutor(Executors.newCachedThreadPool())) 58 | .subscribe(dataTable.getItems()::add); 59 | } 60 | 61 | @FXML 62 | public void searchProduct(ActionEvent event) { 63 | 64 | } 65 | 66 | @FXML 67 | public void closeApp(ActionEvent event) { 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Application reactive/src/main/java/com/svalero/amazonapplication/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.svalero.amazonapplication.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDate; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class User { 13 | 14 | private String id; 15 | private String dni; 16 | private String name; 17 | private String surname; 18 | private LocalDate birthDate; 19 | private String email; 20 | } 21 | -------------------------------------------------------------------------------- /Application reactive/src/main/java/com/svalero/amazonapplication/util/Resources.java: -------------------------------------------------------------------------------- 1 | package com.svalero.amazonapplication.util; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | 6 | public class Resources { 7 | 8 | public static URL getUI(String name) { 9 | return Thread.currentThread().getContextClassLoader().getResource("ui" + File.separator + name); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-web 2 | Proyectos de ejemplo de aplicaciones web con Spring Boot 3 | 4 | - **Application_reactive**: Ejemplo de aplicación JavaFx con RxJava que consume la API **bikesapi_reactive** y muestra la lista de usuarios en una TableView 5 | - **amazonapi**: Ejemplo de API con CRUD, DTOs, ModelMapper y definición OpenAPI 3.0 6 | - **bikesapi_reactive**: Ejemplo de API reactiva con un breve ejemplo de cliente que lo consume con WebClient (incluye colección de prueba y definición OpenAPI 3) 7 | - **helloapi**: API Spring Boot de ejemplo 8 | - **library-api-sec**: Ejemplo de proyecto API con seguridad (token JWT y certs público/privado) 9 | - **library-web**: Ejemplo de proyecto web que consume una API (library-api) 10 | - **mockapi**: Ejemplo de API Mock utilizando Wiremock 11 | - **myshop-ws-swagger**: API documentada con SpringDoc, OpenAPI 3 y Swagger UI 12 | - **myshop-ws-swagger2**: Incluye ejemplos de relaciones entre clases y DTOs 13 | - **myshop-ws**: Aplicación Spring Boot con servicios web 14 | - **myshop**: Aplicación web Spring Boot tienda virtual 15 | - **reactive-client**: Ejemplo de uso de WebClient para consumir una API reactiva 16 | - **reactive-funcional-api**: Ejemplo de API reactiva siguiendo el modelo funcional 17 | - **todoapi_v1**: API muy sencilla que sirve de ejemplo para el proyecto de Android TODOList sobre cómo consumir una API desde Android con Retrofit 18 | -------------------------------------------------------------------------------- /amazonapi/HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 7 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.3/maven-plugin/reference/html/) 8 | * [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.3/maven-plugin/reference/html/#build-image) 9 | * [Spring Web](https://docs.spring.io/spring-boot/docs/2.6.3/reference/htmlsingle/#boot-features-developing-web-applications) 10 | 11 | ### Guides 12 | The following guides illustrate how to use some features concretely: 13 | 14 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 15 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 16 | * [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) 17 | 18 | -------------------------------------------------------------------------------- /amazonapi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.4 9 | 10 | 11 | 12 | com.codeandcoke 13 | amazonapi 14 | 0.0.1-SNAPSHOT 15 | amazonapi 16 | Amazon API 17 | 18 | 19 | 17 20 | 21 | 22 | 23 | 24 | org.modelmapper 25 | modelmapper 26 | 3.1.0 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-data-jpa 37 | 38 | 39 | 40 | com.h2database 41 | h2 42 | runtime 43 | 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | true 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-test 53 | test 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | org.projectlombok 66 | lombok 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/AmazonapiApplication.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AmazonapiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AmazonapiApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/config/AmazonConfig.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.config; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class AmazonConfig { 9 | 10 | @Bean 11 | public ModelMapper modelMapper() { 12 | return new ModelMapper(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.controller; 2 | 3 | import com.codeandcoke.amazonapi.domain.Product; 4 | import com.codeandcoke.amazonapi.domain.User; 5 | import com.codeandcoke.amazonapi.dto.ErrorResponse; 6 | import com.codeandcoke.amazonapi.dto.OrderInDTO; 7 | import com.codeandcoke.amazonapi.dto.OrderOutDTO; 8 | import com.codeandcoke.amazonapi.exception.ProductNotFoundException; 9 | import com.codeandcoke.amazonapi.service.OrderService; 10 | import com.codeandcoke.amazonapi.service.ProductService; 11 | import com.codeandcoke.amazonapi.service.UserService; 12 | import com.codeandcoke.amazonapi.exception.UserNotFoundException; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.http.HttpStatus; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import java.util.List; 19 | 20 | @RestController 21 | public class OrderController { 22 | 23 | @Autowired 24 | private UserService userService; 25 | @Autowired 26 | private ProductService productService; 27 | @Autowired 28 | private OrderService orderService; 29 | 30 | @PostMapping(value = "/user/{userId}/orders") 31 | public ResponseEntity addOrder(@PathVariable long userId, @RequestBody OrderInDTO orderDTO) 32 | throws ProductNotFoundException, UserNotFoundException { 33 | User user = userService.findUser(userId); 34 | Product product = productService.findProduct(orderDTO.getProductId()); 35 | OrderOutDTO orderOutDTO = orderService.addOrder(orderDTO, product, user); 36 | return new ResponseEntity<>(orderOutDTO, HttpStatus.CREATED); 37 | } 38 | 39 | @GetMapping(value = "/user/{userId}/orders") 40 | public ResponseEntity> getOrders(@PathVariable long userId) { 41 | return null; 42 | } 43 | 44 | // TODO Delete order 45 | 46 | // TODO Modify order 47 | 48 | // TODO Deliver order 49 | 50 | @ExceptionHandler(ProductNotFoundException.class) 51 | public ResponseEntity handleException(ProductNotFoundException pnfe) { 52 | ErrorResponse errorResponse = new ErrorResponse(101, pnfe.getMessage()); 53 | return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); 54 | } 55 | 56 | @ExceptionHandler(UserNotFoundException.class) 57 | public ResponseEntity handleException(UserNotFoundException unfe) { 58 | ErrorResponse errorResponse = new ErrorResponse(101, unfe.getMessage()); 59 | return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.controller; 2 | 3 | import com.codeandcoke.amazonapi.domain.User; 4 | import com.codeandcoke.amazonapi.service.UserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | public class UserController { 14 | 15 | @Autowired 16 | private UserService userService; 17 | 18 | // Register user 19 | @PostMapping(value = "/users") 20 | public ResponseEntity addUser(@RequestBody User user) { 21 | User newUser = userService.addUser(user); 22 | return ResponseEntity.status(HttpStatus.CREATED).body(newUser); 23 | } 24 | 25 | // TODO Iniciar sesión (seguridad) 26 | 27 | // TODO Cerrar sesión (seguridad) 28 | } 29 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Entity(name = "orders") 14 | public class Order { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private long id; 19 | @Column 20 | private LocalDate date; 21 | @Column 22 | private int quantity; 23 | 24 | @ManyToOne 25 | @JoinColumn(name = "user_id") 26 | private User user; 27 | 28 | @ManyToOne 29 | @JoinColumn(name = "product_id") 30 | private Product product; 31 | } 32 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonBackReference; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.*; 9 | import java.time.LocalDate; 10 | import java.util.List; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Entity(name = "products") 16 | public class Product { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private long id; 21 | @Column 22 | private String name; 23 | @Column 24 | private String description; 25 | @Column 26 | private String category; 27 | @Column 28 | private float price; 29 | @Column(name = "creation_date") 30 | private LocalDate creationDate; 31 | @Column 32 | private String observations; 33 | @Column 34 | private int quantity; 35 | 36 | @OneToMany(mappedBy = "product") 37 | @JsonBackReference(value = "product-orders") 38 | private List orders; 39 | } 40 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import javax.persistence.*; 9 | import java.time.LocalDate; 10 | import java.util.List; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Entity(name = "users") 16 | public class User { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private long id; 21 | @Column 22 | private String username; 23 | @Column 24 | private String password; 25 | @Column 26 | private String name; 27 | @Column 28 | private String email; 29 | @Column(name = "birth_date") 30 | @DateTimeFormat(pattern = "yyyy-MM-dd") 31 | private LocalDate birthDate; 32 | 33 | @OneToMany(mappedBy = "user") 34 | private List orders; 35 | } 36 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/dto/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class ErrorResponse { 11 | 12 | private int errorCode; 13 | private String message; 14 | } 15 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/dto/OrderInDTO.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class OrderInDTO { 11 | 12 | private int quantity; 13 | private long productId; 14 | } 15 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/dto/OrderOutDTO.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDate; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class OrderOutDTO { 13 | 14 | private long id; 15 | private LocalDate date; 16 | private int quantity; 17 | private ProductDTO product; 18 | // TODO Add user information 19 | } 20 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/dto/ProductDTO.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDate; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class ProductDTO { 13 | 14 | private String name; 15 | private String description; 16 | private String category; 17 | private float price; 18 | private LocalDate creationDate; 19 | private String observations; 20 | private int quantity; 21 | } 22 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/dto/ProductPatchDTO.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class ProductPatchDTO { 11 | 12 | private String field; 13 | private String value; 14 | } 15 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.exception; 2 | 3 | public class ProductNotFoundException extends Exception { 4 | 5 | public ProductNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public ProductNotFoundException(long productId) { 10 | super("Product " + productId + " not found"); 11 | } 12 | 13 | public ProductNotFoundException() { 14 | super("Product not found"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/exception/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.exception; 2 | 3 | public class UserNotFoundException extends Exception { 4 | 5 | public UserNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public UserNotFoundException(long userId) { 10 | super("User " + userId + " not found"); 11 | } 12 | 13 | public UserNotFoundException() { 14 | super("User not found"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.repository; 2 | 3 | import com.codeandcoke.amazonapi.domain.Order; 4 | import com.codeandcoke.amazonapi.domain.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface OrderRepository extends CrudRepository { 12 | 13 | List findAll(); 14 | List findByUser(User user); 15 | } 16 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.repository; 2 | 3 | import com.codeandcoke.amazonapi.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface ProductRepository extends CrudRepository { 11 | 12 | List findAll(); 13 | Product findByName(String name); 14 | List findByPrice(float price); 15 | List findByCategory(String category); 16 | List findByPriceAndCategory(float price, String category); 17 | } 18 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.repository; 2 | 3 | import com.codeandcoke.amazonapi.domain.User; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface UserRepository extends CrudRepository { 11 | 12 | List findAll(); 13 | User findByUsername(String username); 14 | } 15 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.service; 2 | 3 | import com.codeandcoke.amazonapi.domain.Order; 4 | import com.codeandcoke.amazonapi.domain.Product; 5 | import com.codeandcoke.amazonapi.domain.User; 6 | import com.codeandcoke.amazonapi.dto.OrderInDTO; 7 | import com.codeandcoke.amazonapi.dto.OrderOutDTO; 8 | 9 | import java.util.List; 10 | 11 | public interface OrderService { 12 | 13 | OrderOutDTO addOrder(OrderInDTO orderDTO, Product product, User user); 14 | List findOrders(User user); 15 | } 16 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/service/OrderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.service; 2 | 3 | import com.codeandcoke.amazonapi.domain.Order; 4 | import com.codeandcoke.amazonapi.domain.Product; 5 | import com.codeandcoke.amazonapi.domain.User; 6 | import com.codeandcoke.amazonapi.dto.OrderInDTO; 7 | import com.codeandcoke.amazonapi.dto.OrderOutDTO; 8 | import com.codeandcoke.amazonapi.repository.OrderRepository; 9 | import org.modelmapper.ModelMapper; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.time.LocalDate; 14 | import java.util.List; 15 | 16 | @Service 17 | public class OrderServiceImpl implements OrderService { 18 | 19 | @Autowired 20 | private OrderRepository orderRepository; 21 | @Autowired 22 | private ModelMapper modelMapper; 23 | 24 | @Override 25 | public OrderOutDTO addOrder(OrderInDTO orderDTO, Product product, User user) { 26 | Order order = new Order(); 27 | order.setDate(LocalDate.now()); 28 | order.setProduct(product); 29 | order.setUser(user); 30 | modelMapper.map(orderDTO, order); 31 | Order newOrder = orderRepository.save(order); 32 | 33 | OrderOutDTO orderOutDTO = new OrderOutDTO(); 34 | modelMapper.map(newOrder, orderOutDTO); 35 | return orderOutDTO; 36 | } 37 | 38 | @Override 39 | public List findOrders(User user) { 40 | return orderRepository.findByUser(user); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.service; 2 | 3 | import com.codeandcoke.amazonapi.domain.Product; 4 | import com.codeandcoke.amazonapi.dto.ProductPatchDTO; 5 | import com.codeandcoke.amazonapi.exception.ProductNotFoundException; 6 | 7 | import java.util.List; 8 | 9 | public interface ProductService { 10 | 11 | List findAllProducts(); 12 | Product findProduct(long id) throws ProductNotFoundException; 13 | List findByCategory(String categoryName); 14 | List findByPrice(float price); 15 | List findByPriceAndCategory(float price, String category); 16 | 17 | Product addProduct(Product product); 18 | void deleteProductById(long productId) throws ProductNotFoundException; 19 | Product modifyProduct(long productId, Product product) throws ProductNotFoundException; 20 | void patchProduct(long productId, ProductPatchDTO productPatchDTO) throws ProductNotFoundException; 21 | } 22 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.service; 2 | 3 | import com.codeandcoke.amazonapi.domain.User; 4 | import com.codeandcoke.amazonapi.exception.UserNotFoundException; 5 | 6 | public interface UserService { 7 | 8 | User addUser(User user); 9 | User findUser(long id) throws UserNotFoundException; 10 | } 11 | -------------------------------------------------------------------------------- /amazonapi/src/main/java/com/codeandcoke/amazonapi/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi.service; 2 | 3 | import com.codeandcoke.amazonapi.domain.User; 4 | import com.codeandcoke.amazonapi.exception.UserNotFoundException; 5 | import com.codeandcoke.amazonapi.repository.UserRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class UserServiceImpl implements UserService { 11 | 12 | @Autowired 13 | private UserRepository userRepository; 14 | 15 | @Override 16 | public User addUser(User user) { 17 | return userRepository.save(user); 18 | } 19 | 20 | // TODO Modificar cuando se implemente la seguridad 21 | @Override 22 | public User findUser(long id) throws UserNotFoundException { 23 | return userRepository.findById(id) 24 | .orElseThrow(UserNotFoundException::new); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /amazonapi/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.hibernate.ddl-auto=update 2 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 3 | 4 | server.port=8080 5 | 6 | # FIXME 7 | spring.datasource.url=jdbc:h2:file:/Users/santi/amazonapi.db 8 | spring.datasource.driverClassName=org.h2.Driver 9 | spring.datasource.username=sa 10 | spring.datasource.password=password 11 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 12 | spring.h2.console.enabled=true 13 | -------------------------------------------------------------------------------- /amazonapi/src/test/java/com/codeandcoke/amazonapi/AmazonapiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.amazonapi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class AmazonapiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /bikesapi_reactive/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /bikesapi_reactive/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandcoke/spring-web/4746107fb1e7abfb6b3ea76d338119000d7346c5/bikesapi_reactive/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /bikesapi_reactive/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /bikesapi_reactive/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.5 9 | 10 | 11 | com.svalero 12 | bikesapi 13 | 0.0.1-SNAPSHOT 14 | bikesapi 15 | Proyecto de prueba con Spring Boot 16 | 17 | 17 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-validation 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-webflux 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-data-mongodb-reactive 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-data-jpa 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | 44 | com.h2database 45 | h2 46 | runtime 47 | 48 | 49 | org.projectlombok 50 | lombok 51 | true 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | org.modelmapper 60 | modelmapper 61 | 2.4.2 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | org.projectlombok 74 | lombok 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/BikesapiApplication.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class BikesapiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(BikesapiApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/WebClientTest.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.domain.User; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | import java.util.concurrent.Executors; 10 | 11 | public class WebClientTest { 12 | public static void main(String[] args) { 13 | WebClient webClient = WebClient.create("http://localhost:8080"); 14 | Flux productsFlux = webClient.get() 15 | .uri("/users") 16 | .retrieve() 17 | .bodyToFlux(User.class); 18 | 19 | productsFlux.doOnError((System.out::println)) 20 | .subscribeOn(Schedulers.fromExecutor(Executors.newCachedThreadPool())) 21 | .doOnComplete(() -> System.out.println("Terminado")) 22 | .subscribe((user) -> { 23 | System.out.println("Haciendo algo con " + user.getName() + " . . ."); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/controller/RouteController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.controller; 2 | 3 | import com.svalero.bikesapi.domain.Route; 4 | import com.svalero.bikesapi.domain.User; 5 | import com.svalero.bikesapi.domain.dto.RouteDTO; 6 | import com.svalero.bikesapi.exception.BikeNotFoundException; 7 | import com.svalero.bikesapi.exception.ErrorResponse; 8 | import com.svalero.bikesapi.exception.UserNotFoundException; 9 | import com.svalero.bikesapi.service.RouteService; 10 | import com.svalero.bikesapi.service.UserService; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.web.bind.annotation.*; 16 | import reactor.core.publisher.Mono; 17 | 18 | import javax.validation.Valid; 19 | 20 | @RestController 21 | public class RouteController { 22 | 23 | private final Logger logger = LoggerFactory.getLogger(RouteController.class); 24 | 25 | @Autowired 26 | private RouteService routeService; 27 | 28 | @PostMapping("/routes") 29 | public ResponseEntity addRoute(@Valid @RequestBody RouteDTO routeDto) throws UserNotFoundException, 30 | BikeNotFoundException { 31 | Mono route = routeService.addRoute(routeDto); 32 | return ResponseEntity.ok(route); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.controller; 2 | 3 | import com.svalero.bikesapi.domain.User; 4 | import com.svalero.bikesapi.exception.ErrorResponse; 5 | import com.svalero.bikesapi.service.UserService; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.validation.FieldError; 13 | import org.springframework.web.bind.MethodArgumentNotValidException; 14 | import org.springframework.web.bind.annotation.*; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | 18 | import javax.validation.Valid; 19 | import java.time.Duration; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | @RestController 25 | public class UserController { 26 | 27 | private final Logger logger = LoggerFactory.getLogger(UserController.class); 28 | 29 | @Autowired 30 | private UserService userService; 31 | 32 | @PostMapping("/users") 33 | public ResponseEntity> addUser(@Valid @RequestBody User user) { 34 | Mono newUser = userService.addUser(user); 35 | return ResponseEntity.ok(newUser); 36 | } 37 | 38 | @GetMapping(value = "/users", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 39 | public Flux getUsers() { 40 | return userService.findAllUsers().delayElements(Duration.ofSeconds(1)); 41 | } 42 | 43 | @ExceptionHandler(MethodArgumentNotValidException.class) 44 | public ResponseEntity handleException(MethodArgumentNotValidException manve) { 45 | Map errors = new HashMap<>(); 46 | manve.getBindingResult().getAllErrors().forEach(error -> { 47 | String fieldName = ((FieldError) error).getField(); 48 | String message = error.getDefaultMessage(); 49 | errors.put(fieldName, message); 50 | }); 51 | 52 | return ResponseEntity.badRequest().body(ErrorResponse.validationError(errors)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/domain/Bike.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.data.mongodb.core.mapping.Document; 7 | import org.springframework.data.mongodb.core.mapping.Field; 8 | 9 | import javax.persistence.*; 10 | import javax.validation.constraints.NotNull; 11 | import javax.validation.constraints.Positive; 12 | import javax.validation.constraints.PositiveOrZero; 13 | import java.util.List; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @Document(value = "bikes") 19 | public class Bike { 20 | 21 | @Id 22 | private String id; 23 | @Field 24 | private boolean available; 25 | @Field 26 | @NotNull 27 | @PositiveOrZero 28 | private int kilometers; 29 | @Field 30 | @NotNull 31 | private int battery; 32 | @Field(name = "baby_chair") 33 | private boolean babyChair; 34 | @Field(name = "station_id") 35 | @Positive 36 | private int stationId; 37 | 38 | @OneToMany(mappedBy = "bike") 39 | private List routes; 40 | } 41 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/domain/Route.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonBackReference; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | import org.springframework.data.mongodb.core.mapping.Field; 9 | import org.springframework.format.annotation.DateTimeFormat; 10 | 11 | import javax.persistence.*; 12 | import javax.validation.constraints.PositiveOrZero; 13 | import java.time.LocalDate; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @Document(value = "routes") 19 | public class Route { 20 | 21 | @Id 22 | private String id; 23 | @Field(name = "start_date") 24 | @DateTimeFormat(pattern="dd-MM-yyyy") 25 | private LocalDate startDate; 26 | @Field(name = "end_date") 27 | @DateTimeFormat(pattern="dd-MM-yyyy") 28 | private LocalDate endDate; 29 | @Field 30 | @PositiveOrZero 31 | private int kilometers; 32 | 33 | @ManyToOne 34 | @JoinColumn(name = "bike_id") 35 | @JsonBackReference(value = "bike-route") 36 | private Bike bike; 37 | @ManyToOne 38 | @JoinColumn(name = "user_id") 39 | @JsonBackReference(value = "user-route") 40 | private User user; 41 | } 42 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.data.mongodb.core.mapping.Document; 7 | import org.springframework.data.mongodb.core.mapping.Field; 8 | 9 | import javax.persistence.Id; 10 | import javax.persistence.OneToMany; 11 | import javax.validation.constraints.Email; 12 | import javax.validation.constraints.NotEmpty; 13 | import javax.validation.constraints.NotNull; 14 | import javax.validation.constraints.Pattern; 15 | import java.time.LocalDate; 16 | import java.util.List; 17 | 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @Document(value = "users") 22 | public class User { 23 | 24 | @Id 25 | private String id; 26 | @Field 27 | @NotNull 28 | @Pattern(regexp = "[0-9]{8}[A-Z]") 29 | private String dni; 30 | @Field 31 | @NotNull 32 | private String name; 33 | @Field 34 | @NotNull 35 | private String surname; 36 | @Field(name = "birth_date") 37 | private LocalDate birthDate; 38 | @Field 39 | @NotEmpty 40 | @Email 41 | private String email; 42 | 43 | @OneToMany(mappedBy = "user") 44 | private List routes; 45 | } 46 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/domain/dto/RouteDTO.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.domain.dto; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.validation.constraints.NotNull; 8 | import javax.validation.constraints.PositiveOrZero; 9 | import java.time.LocalDate; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | public class RouteDTO { 14 | 15 | @JsonFormat(pattern="dd-MM-yyyy") 16 | private LocalDate startDate; 17 | @JsonFormat(pattern="dd-MM-yyyy") 18 | private LocalDate endDate; 19 | @PositiveOrZero 20 | private int kilometers; 21 | @NotNull 22 | private String userId; 23 | @NotNull 24 | private String bikeId; 25 | } 26 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/exception/BikeNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.exception; 2 | 3 | public class BikeNotFoundException extends Exception { 4 | 5 | private static final String DEFAULT_ERROR_MESSAGE = "Bike not found"; 6 | 7 | public BikeNotFoundException(String message) { 8 | super(message); 9 | } 10 | 11 | public BikeNotFoundException() { 12 | super(DEFAULT_ERROR_MESSAGE); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/exception/Constants.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.exception; 2 | 3 | public class Constants { 4 | 5 | public static final int MANDATORY_FIELD_ERROR_CODE = 102; 6 | } 7 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/exception/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.exception; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import static com.svalero.bikesapi.exception.Constants.MANDATORY_FIELD_ERROR_CODE; 10 | 11 | @Data 12 | public class ErrorResponse { 13 | 14 | private int code; 15 | private String message; 16 | private Map errors; 17 | 18 | private ErrorResponse(int errorCode, String errorMessage) { 19 | code = errorCode; 20 | message = errorMessage; 21 | errors = new HashMap<>(); 22 | } 23 | 24 | private ErrorResponse(int code, String message, Map errors) { 25 | this.code = code; 26 | this.message = message; 27 | this.errors = errors; 28 | } 29 | 30 | public static ErrorResponse generalError(int code, String message) { 31 | return new ErrorResponse(code, message); 32 | } 33 | 34 | public static ErrorResponse validationError(Map errors) { 35 | return new ErrorResponse(104, "Validation error", errors); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/exception/RouteNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.exception; 2 | 3 | public class RouteNotFoundException extends Exception { 4 | 5 | private static final String DEFAULT_ERROR_MESSAGE = "Route not found"; 6 | 7 | public RouteNotFoundException(String message) { 8 | super(message); 9 | } 10 | 11 | public RouteNotFoundException() { 12 | super(DEFAULT_ERROR_MESSAGE); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/exception/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.exception; 2 | 3 | public class UserNotFoundException extends Exception { 4 | 5 | private static final String DEFAULT_ERROR_MESSAGE = "User not found"; 6 | 7 | public UserNotFoundException(String message) { 8 | super(message); 9 | } 10 | 11 | public UserNotFoundException() { 12 | super(DEFAULT_ERROR_MESSAGE); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/repository/BikeRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.repository; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | import reactor.core.publisher.Flux; 7 | 8 | @Repository 9 | public interface BikeRepository extends ReactiveMongoRepository { 10 | 11 | Flux findAll(); 12 | Flux findByStationId(int stationId); 13 | Flux findByBabyChair(boolean babyChair); 14 | Flux findByBatteryGreaterThan(int battery); 15 | } 16 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/repository/RouteRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.repository; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.domain.Route; 5 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 6 | import org.springframework.stereotype.Repository; 7 | import reactor.core.publisher.Flux; 8 | 9 | @Repository 10 | public interface RouteRepository extends ReactiveMongoRepository { 11 | 12 | Flux findAll(); 13 | Flux findByBike(Bike bike); 14 | Flux findByBikeAndKilometers(Bike bike, int kilometers); 15 | } 16 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.repository; 2 | 3 | import com.svalero.bikesapi.domain.User; 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | import reactor.core.publisher.Flux; 7 | 8 | @Repository 9 | public interface UserRepository extends ReactiveMongoRepository { 10 | 11 | Flux findAll(); 12 | } 13 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/BikeService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.exception.BikeNotFoundException; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | 8 | public interface BikeService { 9 | 10 | Flux findAllBikes(); 11 | Flux findAllBikes(int stationId); 12 | Mono findBike(String id) throws BikeNotFoundException; 13 | void repairBike(Bike bike); 14 | 15 | Mono addBike(Bike bike); 16 | Mono deleteBike(String id) throws BikeNotFoundException; 17 | Mono modifyBike(String id, Bike bike) throws BikeNotFoundException; 18 | } 19 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/BikeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.exception.BikeNotFoundException; 5 | import com.svalero.bikesapi.repository.BikeRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Service 12 | public class BikeServiceImpl implements BikeService { 13 | 14 | @Autowired 15 | private BikeRepository bikeRepository; 16 | 17 | @Override 18 | public Flux findAllBikes() { 19 | return bikeRepository.findAll(); 20 | } 21 | 22 | @Override 23 | public Flux findAllBikes(int stationId) { 24 | return bikeRepository.findByStationId(stationId); 25 | } 26 | 27 | @Override 28 | public Mono findBike(String id) throws BikeNotFoundException { 29 | return bikeRepository.findById(id).onErrorReturn(new Bike()); 30 | } 31 | 32 | @Override 33 | public void repairBike(Bike bike) { 34 | 35 | } 36 | 37 | @Override 38 | public Mono addBike(Bike bike) { 39 | return bikeRepository.save(bike); 40 | } 41 | 42 | @Override 43 | public Mono deleteBike(String id) throws BikeNotFoundException { 44 | Mono bike = bikeRepository.findById(id).onErrorReturn(new Bike()); 45 | bikeRepository.delete(bike.block()); 46 | return bike; 47 | } 48 | 49 | @Override 50 | public Mono modifyBike(String id, Bike newBike) throws BikeNotFoundException { 51 | Mono monoBike = bikeRepository.findById(id).onErrorReturn(new Bike()); 52 | 53 | Bike bike = monoBike.block(); 54 | bike.setAvailable(newBike.isAvailable()); 55 | bike.setBabyChair(newBike.isBabyChair()); 56 | bike.setBattery(newBike.getBattery()); 57 | bike.setKilometers(newBike.getKilometers()); 58 | bike.setStationId(newBike.getStationId()); 59 | 60 | return bikeRepository.save(bike); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/RouteService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.domain.Route; 5 | import com.svalero.bikesapi.domain.dto.RouteDTO; 6 | import com.svalero.bikesapi.exception.BikeNotFoundException; 7 | import com.svalero.bikesapi.exception.UserNotFoundException; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | 11 | public interface RouteService { 12 | 13 | Flux findAllRoutes(); 14 | 15 | Mono addRoute(RouteDTO routeDto) throws UserNotFoundException, BikeNotFoundException; 16 | Flux findRoutes(Bike bike, int distance); 17 | Flux findRoutes(Bike bike); 18 | } 19 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/RouteServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.Bike; 4 | import com.svalero.bikesapi.domain.Route; 5 | import com.svalero.bikesapi.domain.User; 6 | import com.svalero.bikesapi.domain.dto.RouteDTO; 7 | import com.svalero.bikesapi.exception.BikeNotFoundException; 8 | import com.svalero.bikesapi.exception.UserNotFoundException; 9 | import com.svalero.bikesapi.repository.BikeRepository; 10 | import com.svalero.bikesapi.repository.RouteRepository; 11 | import com.svalero.bikesapi.repository.UserRepository; 12 | import org.modelmapper.ModelMapper; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Service; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | 18 | @Service 19 | public class RouteServiceImpl implements RouteService { 20 | 21 | @Autowired 22 | private RouteRepository routeRepository; 23 | @Autowired 24 | private UserRepository userRepository; 25 | @Autowired 26 | private BikeRepository bikeRepository; 27 | 28 | @Override 29 | public Flux findAllRoutes() { 30 | return null; 31 | } 32 | 33 | @Override 34 | public Mono addRoute(RouteDTO routeDto) throws UserNotFoundException, 35 | BikeNotFoundException { 36 | Mono monoUser = userRepository.findById(routeDto.getUserId()).onErrorReturn(new User()); 37 | Mono monoBike = bikeRepository.findById(routeDto.getBikeId()).onErrorReturn(new Bike()); 38 | 39 | User user = monoUser.block(); 40 | Bike bike = monoBike.block(); 41 | 42 | ModelMapper mapper = new ModelMapper(); 43 | Route route = mapper.map(routeDto, Route.class); 44 | route.setBike(bike); 45 | route.setUser(user); 46 | return routeRepository.save(route); 47 | } 48 | 49 | @Override 50 | public Flux findRoutes(Bike bike, int distance) { 51 | return routeRepository.findByBikeAndKilometers(bike, distance); 52 | } 53 | 54 | @Override 55 | public Flux findRoutes(Bike bike) { 56 | return routeRepository.findByBike(bike); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.User; 4 | import com.svalero.bikesapi.exception.UserNotFoundException; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | 8 | public interface UserService { 9 | 10 | Flux findAllUsers(); 11 | Mono findUser(long id) throws UserNotFoundException; 12 | 13 | Mono addUser(User user); 14 | } 15 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/java/com/svalero/bikesapi/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi.service; 2 | 3 | import com.svalero.bikesapi.domain.User; 4 | import com.svalero.bikesapi.exception.UserNotFoundException; 5 | import com.svalero.bikesapi.repository.UserRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | 11 | @Service 12 | public class UserServiceImpl implements UserService { 13 | 14 | @Autowired 15 | private UserRepository userRepository; 16 | 17 | @Override 18 | public Flux findAllUsers() { 19 | return userRepository.findAll(); 20 | } 21 | 22 | @Override 23 | public Mono findUser(long id) throws UserNotFoundException { 24 | return null; 25 | } 26 | 27 | @Override 28 | public Mono addUser(User user) { 29 | return userRepository.save(user); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuracion para el acceso a la Base de Datos 2 | spring.data.mongodb.host=localhost 3 | spring.data.mongodb.port=27017 4 | spring.data.mongodb.database=bikesapi 5 | 6 | # Puerto donde escucha el servidor una vez se inicie 7 | server.port=8080 -------------------------------------------------------------------------------- /bikesapi_reactive/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1.} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /bikesapi_reactive/src/test/java/com/svalero/bikesapi/BikesapiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.svalero.bikesapi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class BikesapiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /helloapi/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /helloapi/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandcoke/spring-web/4746107fb1e7abfb6b3ea76d338119000d7346c5/helloapi/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /helloapi/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 3 | -------------------------------------------------------------------------------- /helloapi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.1.4 9 | 10 | 11 | 12 | com.svalero 13 | helloapi 14 | API de ejemplo para Acceso a Datos 15 | 16 | apiproducts 17 | 0.1 18 | 19 | 20 | 17 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-jpa 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | com.h2database 35 | h2 36 | runtime 37 | 38 | 39 | com.mysql 40 | mysql-connector-j 41 | runtime 42 | 43 | 44 | org.projectlombok 45 | lombok 46 | true 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | org.modelmapper 55 | modelmapper 56 | 3.1.1 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-validation 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-maven-plugin 69 | 70 | 71 | 72 | org.projectlombok 73 | lombok 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/HelloapiApplication.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class HelloapiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(HelloapiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/config/ApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.config; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class ApplicationConfig { 9 | 10 | @Bean 11 | public ModelMapper modelMapper() { 12 | return new ModelMapper(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.controller; 2 | 3 | import com.svalero.helloapi.domain.ErrorResponse; 4 | import com.svalero.helloapi.domain.Order; 5 | import com.svalero.helloapi.dto.OrderInDto; 6 | import com.svalero.helloapi.exception.ProductNotFoundException; 7 | import com.svalero.helloapi.exception.UserNotFoundException; 8 | import com.svalero.helloapi.service.OrderService; 9 | import com.svalero.helloapi.service.ProductService; 10 | import com.svalero.helloapi.service.UserService; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import java.util.List; 17 | 18 | @RestController 19 | public class OrderController { 20 | 21 | @Autowired 22 | private UserService userService; 23 | @Autowired 24 | private OrderService orderService; 25 | @Autowired 26 | private ProductService productService; 27 | 28 | @GetMapping("/orders") 29 | public List getOrders() { 30 | return orderService.findAll(); 31 | } 32 | 33 | @GetMapping("/user/{userId}/orders") 34 | public List getUserOrders(@PathVariable long userId) throws UserNotFoundException { 35 | return orderService.findByUser(userId); 36 | } 37 | 38 | @PostMapping("/user/{userId}/orders") 39 | public void addOrder(@RequestBody OrderInDto orderInDto, @PathVariable long userId) throws UserNotFoundException, ProductNotFoundException { 40 | orderService.addOrder(orderInDto, userId); 41 | } 42 | 43 | // TODO Hacer el resto de operaciones hasta el CRUD 44 | 45 | @ExceptionHandler(UserNotFoundException.class) 46 | public ResponseEntity userNotFoundException(UserNotFoundException unfe) { 47 | ErrorResponse errorResponse = ErrorResponse.generalError(404, unfe.getMessage()); 48 | return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); 49 | } 50 | 51 | @ExceptionHandler(ProductNotFoundException.class) 52 | public ResponseEntity productNotFoundException(ProductNotFoundException pnfe) { 53 | ErrorResponse errorResponse = ErrorResponse.generalError(404, pnfe.getMessage()); 54 | return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.controller; 2 | 3 | import com.svalero.helloapi.domain.User; 4 | import com.svalero.helloapi.service.UserService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | public class UserController { 14 | 15 | @Autowired 16 | private UserService userService; 17 | 18 | @GetMapping("/users") 19 | public List getUsers() { 20 | return userService.findAll(); 21 | } 22 | 23 | @PostMapping("/users") 24 | public void addUser(@RequestBody User user) { 25 | userService.addUser(user); 26 | } 27 | 28 | @PutMapping("/user/{userId}") 29 | public void modifyUser(@RequestBody User user, @PathVariable long userId) { 30 | 31 | } 32 | 33 | // TODO Hacer el resto de operaciones hasta el CRUD 34 | } 35 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/domain/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | @Data 11 | public class ErrorResponse { 12 | 13 | private int code; 14 | private String message; 15 | private Map errors; 16 | 17 | private ErrorResponse(int errorCode, String errorMessage) { 18 | code = errorCode; 19 | message = errorMessage; 20 | errors = new HashMap<>(); 21 | } 22 | 23 | private ErrorResponse(int code, String message, Map errors) { 24 | this.code = code; 25 | this.message = message; 26 | this.errors = errors; 27 | } 28 | 29 | public static ErrorResponse generalError(int code, String message) { 30 | return new ErrorResponse(code, message); 31 | } 32 | 33 | public static ErrorResponse validationError(Map errors) { 34 | return new ErrorResponse(400, "Validation error", errors); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonBackReference; 4 | import jakarta.persistence.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.time.LocalDate; 10 | import java.util.List; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Entity(name = "orders") 16 | public class Order { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private long id; 21 | @Column 22 | private String number; 23 | @Column(name = "creation_date") 24 | private LocalDate creationDate; 25 | 26 | @JsonBackReference("order_user") 27 | @ManyToOne 28 | @JoinColumn(name = "user_id") 29 | private User user; 30 | 31 | @JsonBackReference("order_product") 32 | @ManyToMany 33 | @JoinTable(name = "products_orders", 34 | joinColumns = @JoinColumn(name = "product_id"), 35 | inverseJoinColumns = @JoinColumn(name = "order_id")) 36 | private List products; 37 | } 38 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.domain; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDate; 9 | import java.util.List; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Entity(name = "products") 15 | public class Product { 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private long id; 20 | @Column 21 | private String name; 22 | @Column 23 | private String description; 24 | @Column 25 | private float price; 26 | @Column(name = "registration_date") 27 | private LocalDate registrationDate; 28 | 29 | @ManyToMany(mappedBy = "products") 30 | private List orders; 31 | } 32 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.domain; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDate; 9 | import java.util.List; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Entity(name = "users") 15 | public class User { 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private long id; 20 | @Column 21 | private String username; 22 | @Column 23 | private String password; 24 | @Column 25 | private String name; 26 | @Column 27 | private String surname; 28 | @Column(name = "email_address") 29 | private String emailAddress; 30 | @Column(name = "birth_date") 31 | private LocalDate birthDate; 32 | @Column(name = "registration_date") 33 | private LocalDate registrationDate; 34 | 35 | @OneToMany(mappedBy = "user") 36 | private List orders; 37 | } 38 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/dto/OrderInDto.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class OrderInDto { 13 | 14 | private List productIds; 15 | } 16 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/dto/OrderOutDto.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDate; 8 | import java.util.List; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class OrderOutDto { 14 | 15 | private long id; 16 | private String number; 17 | private LocalDate creationDate; 18 | private List productIds; 19 | } 20 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/dto/ProductInDto.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.dto; 2 | 3 | import jakarta.validation.constraints.Min; 4 | import jakarta.validation.constraints.NotNull; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.time.LocalDate; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class ProductInDto { 15 | 16 | @NotNull(message = "El nombre es obligatorio") 17 | private String name; 18 | private String description; 19 | @Min(value = 0, message = "El precio debe ser mayor que cero") 20 | private float price; 21 | } 22 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/dto/ProductOutDto.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.dto; 2 | 3 | import jakarta.persistence.Column; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class ProductOutDto { 14 | 15 | private long id; 16 | private String name; 17 | private String description; 18 | private float price; 19 | private LocalDate registrationDate; 20 | } 21 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.exception; 2 | 3 | import com.svalero.helloapi.repository.ProductRepository; 4 | 5 | public class ProductNotFoundException extends Exception { 6 | 7 | public ProductNotFoundException() { 8 | super(); 9 | } 10 | 11 | public ProductNotFoundException(String message) { 12 | super(message); 13 | } 14 | 15 | public ProductNotFoundException(long id) { 16 | super("The product " + id + " doesn't exist"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/exception/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.exception; 2 | 3 | public class UserNotFoundException extends Exception { 4 | 5 | public UserNotFoundException() { 6 | super(); 7 | } 8 | 9 | public UserNotFoundException(String message) { 10 | super(message); 11 | } 12 | 13 | public UserNotFoundException(long id) { 14 | super("The user " + id + " doesn't exist"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.repository; 2 | 3 | import com.svalero.helloapi.domain.Order; 4 | import com.svalero.helloapi.domain.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface OrderRepository extends CrudRepository { 12 | List findAll(); 13 | List findByUser(User user); 14 | Order findByNumber(String number); 15 | } 16 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.repository; 2 | 3 | import com.svalero.helloapi.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface ProductRepository extends CrudRepository { 11 | List findAll(); 12 | List findByName(String name); 13 | List findByNameAndPrice(String name, float price); 14 | } 15 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.repository; 2 | 3 | import com.svalero.helloapi.domain.Product; 4 | import com.svalero.helloapi.domain.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface UserRepository extends CrudRepository { 12 | List findAll(); 13 | User findByUsername(String username); 14 | } 15 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.service; 2 | 3 | import com.svalero.helloapi.domain.Order; 4 | import com.svalero.helloapi.domain.Product; 5 | import com.svalero.helloapi.domain.User; 6 | import com.svalero.helloapi.dto.OrderInDto; 7 | import com.svalero.helloapi.exception.ProductNotFoundException; 8 | import com.svalero.helloapi.exception.UserNotFoundException; 9 | import com.svalero.helloapi.repository.OrderRepository; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.time.LocalDate; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.UUID; 17 | 18 | @Service 19 | public class OrderService { 20 | 21 | @Autowired 22 | private OrderRepository orderRepository; 23 | @Autowired 24 | private ProductService productService; 25 | @Autowired 26 | private UserService userService; 27 | 28 | public List findAll() { 29 | return orderRepository.findAll(); 30 | } 31 | 32 | public List findByUser(long userId) throws UserNotFoundException { 33 | User user = userService.findById(userId); 34 | return orderRepository.findByUser(user); 35 | } 36 | 37 | public void addOrder(OrderInDto orderInDto, long userId) throws UserNotFoundException, ProductNotFoundException { 38 | Order order = new Order(); 39 | 40 | User user = userService.findById(userId); 41 | order.setUser(user); 42 | 43 | List products = new ArrayList<>(); 44 | for (long productId: orderInDto.getProductIds()) { 45 | Product product = productService.findById(productId).orElseThrow(() -> new ProductNotFoundException(productId)); 46 | products.add(product); 47 | } 48 | order.setProducts(products); 49 | 50 | order.setNumber(UUID.randomUUID().toString()); 51 | order.setCreationDate(LocalDate.now()); 52 | orderRepository.save(order); 53 | } 54 | 55 | // TODO hacer el resto de métodos hasta el CRUD 56 | } 57 | -------------------------------------------------------------------------------- /helloapi/src/main/java/com/svalero/helloapi/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi.service; 2 | 3 | import com.svalero.helloapi.domain.User; 4 | import com.svalero.helloapi.exception.UserNotFoundException; 5 | import com.svalero.helloapi.repository.UserRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class UserService { 13 | 14 | @Autowired 15 | private UserRepository userRepository; 16 | 17 | public List findAll() { 18 | return userRepository.findAll(); 19 | } 20 | 21 | public User findById(long id) throws UserNotFoundException { 22 | return userRepository.findById(id).orElseThrow(() -> new UserNotFoundException(id)); 23 | } 24 | 25 | public void addUser(User user) { 26 | userRepository.save(user); 27 | } 28 | 29 | // TODO Hacer el resto de métodos hasta el CRUD 30 | } 31 | -------------------------------------------------------------------------------- /helloapi/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuracion para el acceso a la Base de Datos 2 | spring.jpa.hibernate.ddl-auto=update 3 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 4 | 5 | # Puerto donde escucha el servidor una vez se inicie 6 | server.port=8080 7 | 8 | # Datos de conexion con la base de datos H2 9 | spring.datasource.url=jdbc:h2:file:~/helloapi.db 10 | spring.datasource.driverClassName=org.h2.Driver 11 | spring.datasource.username=sa 12 | spring.datasource.password=password 13 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 14 | spring.h2.console.enabled=true 15 | 16 | logging.level.org.springframework=DEBUG 17 | logging.level.org.hibernate=DEBUG 18 | -------------------------------------------------------------------------------- /helloapi/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /helloapi/src/test/java/com/svalero/helloapi/HelloapiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.svalero.helloapi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class HelloapiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /library-api-sec/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/LibraryApplication.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LibraryApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LibraryApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/controller/BookController.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.controller; 2 | 3 | import com.codeandcoke.library.exception.BookNotFoundException; 4 | import com.codeandcoke.library.exception.ErrorResponse; 5 | import com.codeandcoke.library.domain.Book; 6 | import com.codeandcoke.library.service.BookService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.security.access.prepost.PreAuthorize; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | import java.util.List; 14 | 15 | @RestController 16 | public class BookController { 17 | 18 | @Autowired 19 | private BookService bookService; 20 | 21 | @GetMapping("/books") 22 | // @PreAuthorize("hasRole('user')") 23 | public ResponseEntity> getBooks() { 24 | List books = bookService.findAll(); 25 | return ResponseEntity.ok(books); 26 | } 27 | 28 | @GetMapping("/books/{id}") 29 | public Book getBook(@PathVariable long id) throws BookNotFoundException { 30 | return bookService.findById(id); 31 | } 32 | 33 | @GetMapping(value = {"/books/{bookId}/authors"}) 34 | public String getAuthors(@PathVariable(required = false) String bookId) { 35 | if (bookId == null) 36 | return "no bookId"; 37 | 38 | return "authors"; 39 | } 40 | 41 | @PostMapping("/books") 42 | public ResponseEntity addBook(@RequestBody Book book) { 43 | return new ResponseEntity<>(bookService.addBook(book), HttpStatus.CREATED); 44 | } 45 | 46 | @PutMapping("/books/{id}") 47 | public ResponseEntity modifyBook(@PathVariable long id, @RequestBody Book book) throws BookNotFoundException { 48 | Book newBook = bookService.editBook(id, book); 49 | return ResponseEntity.ok(newBook); 50 | } 51 | 52 | @DeleteMapping("/books/{id}") 53 | public ResponseEntity deleteBook(@PathVariable long id) throws BookNotFoundException { 54 | bookService.removeBook(id); 55 | return ResponseEntity.noContent().build(); 56 | } 57 | 58 | @ExceptionHandler 59 | public ResponseEntity handleBooktNotFoundException(BookNotFoundException bnfe) { 60 | ErrorResponse errorResponse = new ErrorResponse(100, bnfe.getMessage()); 61 | return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.controller; 2 | 3 | import com.codeandcoke.library.domain.UserDTO; 4 | import com.codeandcoke.library.security.JwtResponse; 5 | import com.codeandcoke.library.security.JwtUtils; 6 | import com.codeandcoke.library.service.UserService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.security.authentication.AuthenticationManager; 10 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 11 | import org.springframework.security.core.Authentication; 12 | import org.springframework.security.core.GrantedAuthority; 13 | import org.springframework.security.core.context.SecurityContextHolder; 14 | import org.springframework.security.core.userdetails.User; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import javax.validation.Valid; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | 21 | @RestController 22 | public class TokenController { 23 | 24 | @Autowired 25 | private UserService userService; 26 | 27 | @Autowired 28 | private AuthenticationManager authenticationManager; 29 | 30 | @Autowired 31 | private JwtUtils jwtUtils; 32 | 33 | @PostMapping("/token") 34 | public ResponseEntity authenticateUser(@Valid @RequestBody UserDTO userDTO) { 35 | Authentication authentication = authenticationManager.authenticate( 36 | new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword())); 37 | 38 | SecurityContextHolder.getContext().setAuthentication(authentication); 39 | String jwt = jwtUtils.generateJwtToken(authentication); 40 | 41 | User userDetails = (User) authentication.getPrincipal(); 42 | List roles = userDetails.getAuthorities().stream() 43 | .map(GrantedAuthority::getAuthority) 44 | .collect(Collectors.toList()); 45 | 46 | return ResponseEntity.ok(new JwtResponse(jwt, 47 | userDetails.getUsername(), 48 | roles)); 49 | } 50 | 51 | @RequestMapping(value = "/register", method = RequestMethod.POST) 52 | public ResponseEntity saveUser(@RequestBody UserDTO user) throws Exception { 53 | return ResponseEntity.ok(userService.addUser(user)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/domain/Book.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | import javax.validation.constraints.NotBlank; 9 | import javax.validation.constraints.NotNull; 10 | import javax.validation.constraints.Positive; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Entity(name = "books") 16 | public class Book { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private long id; 21 | @Column 22 | @NotNull 23 | @NotBlank 24 | private String title; 25 | @Column 26 | private String author; 27 | @Column 28 | private String category; 29 | @Column(name = "page_count") 30 | @Positive 31 | private int pageCount; 32 | @Column 33 | private double latitude; 34 | @Column 35 | private double longitude; 36 | } 37 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/domain/Role.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Entity(name = "roles") 13 | public class Role { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private long id; 18 | @Column 19 | private String name; 20 | } 21 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | import java.time.LocalDate; 9 | import java.time.LocalDateTime; 10 | import java.util.Set; 11 | 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Entity(name = "users") 16 | public class User { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private long id; 21 | @Column(nullable = false, unique = true) 22 | private String username; 23 | @Column(nullable = false) 24 | private String password; 25 | @Column 26 | private String nif; 27 | @Column 28 | private String name; 29 | @Column 30 | private String surname; 31 | @Column(nullable = false) 32 | private String email; 33 | @Column 34 | private String address; 35 | @Column 36 | private String city; 37 | @Column(name = "postal_code") 38 | private String postalCode; 39 | @Column 40 | private String province; 41 | @Column 42 | private String country; 43 | @Column 44 | private String image; 45 | @Column(name = "creation_date") 46 | private LocalDate creationDate; 47 | @Column(name = "last_login") 48 | private LocalDateTime lastLogin; 49 | @Column(name = "active") 50 | private boolean active = true; 51 | @Transient 52 | private int age; 53 | 54 | @ManyToMany 55 | @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) 56 | private Set roles; 57 | 58 | @Override 59 | public String toString() { 60 | return "User{" + 61 | "username='" + username + '\'' + 62 | '}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/domain/UserDTO.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.domain; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class UserDTO { 7 | 8 | private String username; 9 | private String password; 10 | } 11 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/exception/BookNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.exception; 2 | 3 | public class BookNotFoundException extends Exception { 4 | 5 | public BookNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public BookNotFoundException() { 10 | super("Book not found"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/exception/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.exception; 2 | 3 | public record ErrorResponse (int internalErrorCode, String message) {} 4 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/exception/UserRegistrationException.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.exception; 2 | 3 | public class UserRegistrationException extends Exception { 4 | 5 | public UserRegistrationException() { 6 | super(); 7 | } 8 | 9 | public UserRegistrationException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/repository/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.repository; 2 | 3 | import com.codeandcoke.library.domain.Book; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface BookRepository extends CrudRepository { 11 | 12 | List findAll(); 13 | Book findByTitle(String title); 14 | List findByAuthor(String author); 15 | } 16 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/repository/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.repository; 2 | 3 | import com.codeandcoke.library.domain.Role; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface RoleRepository extends CrudRepository { 9 | 10 | Role findByName(String name); 11 | } 12 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.repository; 2 | 3 | import com.codeandcoke.library.domain.User; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | @Repository 10 | public interface UserRepository extends CrudRepository { 11 | 12 | User findByEmail(String email); 13 | User findByUsername(String username); 14 | Set findByCity(String city); 15 | Set findByPostalCode(String postalCode); 16 | } 17 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/security/AuthEntryPointJwt.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.security; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.security.core.AuthenticationException; 6 | import org.springframework.security.web.AuthenticationEntryPoint; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | @Component 15 | public class AuthEntryPointJwt implements AuthenticationEntryPoint { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class); 18 | 19 | @Override 20 | public void commence(HttpServletRequest request, HttpServletResponse response, 21 | AuthenticationException authException) throws IOException, ServletException { 22 | logger.error("Unauthorized error: {}", authException.getMessage()); 23 | response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/security/AuthTokenFilter.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.security; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.context.SecurityContextHolder; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; 10 | import org.springframework.util.StringUtils; 11 | import org.springframework.web.filter.OncePerRequestFilter; 12 | 13 | import javax.servlet.FilterChain; 14 | import javax.servlet.ServletException; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | public class AuthTokenFilter extends OncePerRequestFilter { 20 | 21 | @Autowired 22 | private JwtUtils jwtUtils; 23 | 24 | @Autowired 25 | private LibraryUserDetailsService userDetailsService; 26 | 27 | private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class); 28 | 29 | @Override 30 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 31 | throws ServletException, IOException { 32 | try { 33 | String jwt = parseJwt(request); 34 | if (jwt != null && jwtUtils.validateJwtToken(jwt)) { 35 | String username = jwtUtils.getUserNameFromJwtToken(jwt); 36 | 37 | UserDetails userDetails = userDetailsService.loadUserByUsername(username); 38 | UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( 39 | userDetails, null, userDetails.getAuthorities()); 40 | authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); 41 | 42 | SecurityContextHolder.getContext().setAuthentication(authentication); 43 | } 44 | } catch (Exception exception) { 45 | logger.error("Cannot set user authentication: {}", exception); 46 | } 47 | 48 | filterChain.doFilter(request, response); 49 | } 50 | 51 | private String parseJwt(HttpServletRequest request) { 52 | String headerAuth = request.getHeader("Authorization"); 53 | 54 | if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { 55 | return headerAuth.substring(7); 56 | } 57 | 58 | return null; 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/security/JwtResponse.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.security; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class JwtResponse { 13 | 14 | private String token; 15 | private String username; 16 | private List roles; 17 | } 18 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/security/JwtUtils.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.security; 2 | 3 | import io.jsonwebtoken.*; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.oauth2.jwt.*; 13 | import org.springframework.security.oauth2.jwt.Jwt; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.security.PrivateKey; 17 | import java.security.interfaces.RSAPrivateKey; 18 | import java.time.Instant; 19 | import java.time.temporal.ChronoUnit; 20 | import java.util.Date; 21 | import java.util.stream.Collectors; 22 | 23 | @Component 24 | @Configuration 25 | public class JwtUtils { 26 | private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); 27 | 28 | @Autowired 29 | private JwtEncoder jwtEncoder; 30 | 31 | @Autowired 32 | private JwtDecoder jwtDecoder; 33 | 34 | public String generateJwtToken(Authentication authentication) { 35 | Instant now = Instant.now(); 36 | 37 | String scope = authentication.getAuthorities().stream() 38 | .map(GrantedAuthority::getAuthority) 39 | .collect(Collectors.joining(" ")); 40 | 41 | JwtClaimsSet claims = JwtClaimsSet.builder() 42 | .issuer("self") 43 | .issuedAt(now) 44 | .expiresAt(now.plus(1, ChronoUnit.HOURS)) 45 | .subject(authentication.getName()) 46 | .claim("scope", scope) 47 | .build(); 48 | return jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue(); 49 | } 50 | 51 | public String getUserNameFromJwtToken(String token) { 52 | return jwtDecoder.decode(token).getSubject(); 53 | } 54 | 55 | public boolean validateJwtToken(String authToken) { 56 | try { 57 | Jwt jwt = jwtDecoder.decode(authToken); 58 | return true; 59 | } catch (SignatureException e) { 60 | logger.error("Invalid JWT signature: {}", e.getMessage()); 61 | } catch (MalformedJwtException e) { 62 | logger.error("Invalid JWT token: {}", e.getMessage()); 63 | } catch (ExpiredJwtException e) { 64 | logger.error("JWT token is expired: {}", e.getMessage()); 65 | } catch (UnsupportedJwtException e) { 66 | logger.error("JWT token is unsupported: {}", e.getMessage()); 67 | } catch (IllegalArgumentException e) { 68 | logger.error("JWT claims string is empty: {}", e.getMessage()); 69 | } 70 | 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/security/LibraryUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.security; 2 | 3 | import com.codeandcoke.library.domain.Role; 4 | import com.codeandcoke.library.domain.User; 5 | import com.codeandcoke.library.service.UserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.transaction.Transactional; 15 | import java.util.ArrayList; 16 | import java.util.HashSet; 17 | import java.util.List; 18 | import java.util.Set; 19 | 20 | @Service 21 | public class LibraryUserDetailsService implements UserDetailsService { 22 | 23 | @Autowired 24 | private UserService userService; 25 | 26 | @Override 27 | @Transactional 28 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 29 | User user = userService.findByUsername(username); 30 | if (user == null) 31 | throw new UsernameNotFoundException("Invalid username/password"); 32 | 33 | List authorities = getUserAuthority(user.getRoles()); 34 | return buildUserForAuthentication(user, authorities); 35 | } 36 | 37 | private List getUserAuthority(Set userRoles) { 38 | Set roles = new HashSet<>(); 39 | userRoles.forEach(role -> roles.add(new SimpleGrantedAuthority(role.getName()))); 40 | return new ArrayList<>(roles); 41 | } 42 | 43 | private UserDetails buildUserForAuthentication(User user, List authorities) { 44 | return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), 45 | user.isActive(), true, true, true, authorities); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/service/BookService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.service; 2 | 3 | import com.codeandcoke.library.domain.Book; 4 | import com.codeandcoke.library.exception.BookNotFoundException; 5 | 6 | import java.util.List; 7 | 8 | public interface BookService { 9 | 10 | List findAll(); 11 | Book findById(long id) throws BookNotFoundException; 12 | Book findByTitle(String title); 13 | List findByAuthor(String author); 14 | 15 | Book addBook(Book book); 16 | Book editBook(long id, Book book); 17 | void removeBook(long id) throws BookNotFoundException; 18 | } 19 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/service/BookServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.service; 2 | 3 | import com.codeandcoke.library.domain.Book; 4 | import com.codeandcoke.library.exception.BookNotFoundException; 5 | import com.codeandcoke.library.repository.BookRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class BookServiceImpl implements BookService { 13 | 14 | @Autowired 15 | private BookRepository bookRepository; 16 | 17 | @Override 18 | public List findAll() { 19 | return bookRepository.findAll(); 20 | } 21 | 22 | @Override 23 | public Book findById(long id) throws BookNotFoundException { 24 | return bookRepository.findById(id) 25 | .orElseThrow(() -> new BookNotFoundException("Book not found")); 26 | } 27 | 28 | @Override 29 | public Book findByTitle(String title) { 30 | return bookRepository.findByTitle(title); 31 | } 32 | 33 | @Override 34 | public List findByAuthor(String author) { 35 | return bookRepository.findByAuthor(author); 36 | } 37 | 38 | @Override 39 | public Book addBook(Book book) { 40 | return bookRepository.save(book); 41 | } 42 | 43 | @Override 44 | public Book editBook(long id, Book book) { 45 | return null; 46 | } 47 | 48 | @Override 49 | public void removeBook(long id) throws BookNotFoundException { 50 | Book book = bookRepository.findById(id) 51 | .orElseThrow(() -> new BookNotFoundException("Book not found")); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.service; 2 | 3 | import com.codeandcoke.library.domain.User; 4 | import com.codeandcoke.library.domain.UserDTO; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * Service para gestión de usuarios 10 | */ 11 | public interface UserService { 12 | 13 | Set findAll(); 14 | User findByUsername(String username); 15 | Set findByCity(String city); 16 | 17 | User addUser(UserDTO user); 18 | void remove(User user); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /library-api-sec/src/main/java/com/codeandcoke/library/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.codeandcoke.library.service; 2 | 3 | import com.codeandcoke.library.domain.Role; 4 | import com.codeandcoke.library.domain.User; 5 | import com.codeandcoke.library.domain.UserDTO; 6 | import com.codeandcoke.library.repository.RoleRepository; 7 | import com.codeandcoke.library.repository.UserRepository; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.time.LocalDate; 13 | import java.util.Collections; 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | 17 | @Service 18 | public class UserServiceImpl implements UserService { 19 | 20 | @Autowired 21 | private UserRepository userRepository; 22 | 23 | @Autowired 24 | private RoleRepository roleRepository; 25 | 26 | // @Override 27 | // public boolean add(User user) { 28 | // BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); 29 | // user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); 30 | // user.setCreationDate(LocalDate.now()); 31 | // user.setActive(true); 32 | // Role userRole = roleRepository.findByName("user"); 33 | // user.setRoles(new HashSet<>(Collections.singletonList(userRole))); 34 | // userRepository.save(user); 35 | // 36 | // return true; 37 | // } 38 | 39 | @Override 40 | public void remove(User user) { 41 | userRepository.delete(user); 42 | } 43 | 44 | @Override 45 | public Set findAll() { 46 | return null; 47 | } 48 | 49 | @Override 50 | public User findByUsername(String username) { 51 | return userRepository.findByUsername(username); 52 | } 53 | 54 | @Override 55 | public Set findByCity(String city) { 56 | return null; 57 | } 58 | 59 | @Override 60 | public User addUser(UserDTO userDTO) { 61 | BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); 62 | 63 | User user = new User(); 64 | user.setUsername(userDTO.getUsername()); 65 | user.setPassword(bCryptPasswordEncoder.encode(userDTO.getPassword())); 66 | user.setEmail("default@email.com"); 67 | 68 | return userRepository.save(user); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /library-api-sec/src/main/resources/app.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA 3 | iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM 4 | g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK 5 | LhSHGHqIjyo0wlBf58t+qFt9h/EFBVE/LAGQBsg/jHUQCxsLoVI2aSELGIw2oSDF 6 | oiljwLaQl0n9khX5ZbiegN3OkqodzCYHwWyu6aVVj8M1W9RIMiKmKr09s/gf31Nc 7 | 3WjvjqhFo1rTuurWGgKAxJLL7zlJqAKjGWbIT4P6h/1Kwxjw6X23St3OmhsG6HIn 8 | +jl1++MrAgMBAAECggEBAMf820wop3pyUOwI3aLcaH7YFx5VZMzvqJdNlvpg1jbE 9 | E2Sn66b1zPLNfOIxLcBG8x8r9Ody1Bi2Vsqc0/5o3KKfdgHvnxAB3Z3dPh2WCDek 10 | lCOVClEVoLzziTuuTdGO5/CWJXdWHcVzIjPxmK34eJXioiLaTYqN3XKqKMdpD0ZG 11 | mtNTGvGf+9fQ4i94t0WqIxpMpGt7NM4RHy3+Onggev0zLiDANC23mWrTsUgect/7 12 | 62TYg8g1bKwLAb9wCBT+BiOuCc2wrArRLOJgUkj/F4/gtrR9ima34SvWUyoUaKA0 13 | bi4YBX9l8oJwFGHbU9uFGEMnH0T/V0KtIB7qetReywkCgYEA9cFyfBIQrYISV/OA 14 | +Z0bo3vh2aL0QgKrSXZ924cLt7itQAHNZ2ya+e3JRlTczi5mnWfjPWZ6eJB/8MlH 15 | Gpn12o/POEkU+XjZZSPe1RWGt5g0S3lWqyx9toCS9ACXcN9tGbaqcFSVI73zVTRA 16 | 8J9grR0fbGn7jaTlTX2tnlOTQ60CgYEA5YjYpEq4L8UUMFkuj+BsS3u0oEBnzuHd 17 | I9LEHmN+CMPosvabQu5wkJXLuqo2TxRnAznsA8R3pCLkdPGoWMCiWRAsCn979TdY 18 | QbqO2qvBAD2Q19GtY7lIu6C35/enQWzJUMQE3WW0OvjLzZ0l/9mA2FBRR+3F9A1d 19 | rBdnmv0c3TcCgYEAi2i+ggVZcqPbtgrLOk5WVGo9F1GqUBvlgNn30WWNTx4zIaEk 20 | HSxtyaOLTxtq2odV7Kr3LGiKxwPpn/T+Ief+oIp92YcTn+VfJVGw4Z3BezqbR8lA 21 | Uf/+HF5ZfpMrVXtZD4Igs3I33Duv4sCuqhEvLWTc44pHifVloozNxYfRfU0CgYBN 22 | HXa7a6cJ1Yp829l62QlJKtx6Ymj95oAnQu5Ez2ROiZMqXRO4nucOjGUP55Orac1a 23 | FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF 24 | snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H 25 | c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM 26 | TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR 27 | 47jndeyIaMTNETEmOnms+as17g== 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /library-api-sec/src/main/resources/app.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd 3 | 7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv 4 | c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6 5 | iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2 6 | kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o 7 | RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj 8 | KwIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /library-api-sec/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.hibernate.ddl-auto=update 2 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 3 | 4 | server.port=8080 5 | 6 | spring.datasource.url=jdbc:h2:file:/Users/santi/library_sec.db 7 | spring.datasource.username=sa 8 | spring.datasource.password=password 9 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 10 | spring.h2.console.enabled=true 11 | 12 | key.private=classpath:app.key 13 | key.public=classpath:app.pub -------------------------------------------------------------------------------- /library-api-sec/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1.} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /library-web/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /library-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.3 9 | 10 | 11 | 12 | com.sanvalero 13 | library-web 14 | 0.1 15 | library-web 16 | Proyecto web que consume datos de una API 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-thymeleaf 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /library-web/src/main/java/com/sanvalero/libraryweb/MyshopApplication.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.libraryweb; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MyshopApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MyshopApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /library-web/src/main/java/com/sanvalero/libraryweb/controller/WebController.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.libraryweb.controller; 2 | 3 | import com.sanvalero.libraryweb.domain.Book; 4 | import com.sanvalero.libraryweb.service.BookService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | 11 | import java.util.List; 12 | 13 | import static org.springframework.web.bind.annotation.RequestMethod.GET; 14 | 15 | @Controller 16 | public class WebController { 17 | 18 | @Autowired 19 | private BookService bookService; 20 | 21 | @RequestMapping(value = "/") 22 | public String index(Model model) { 23 | return "index"; 24 | } 25 | 26 | @RequestMapping(value = "/catalog", method = GET) 27 | public String catalog(Model model) { 28 | List books = bookService.findAllBooks(); 29 | model.addAttribute("books", books); 30 | return "catalog"; 31 | } 32 | 33 | @RequestMapping(value = "/book/{id}", method = GET) 34 | public String book(Model model, @PathVariable("id") long id) { 35 | Book book = bookService.findBook(id); 36 | model.addAttribute("book", book); 37 | return "book"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /library-web/src/main/java/com/sanvalero/libraryweb/domain/Book.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.libraryweb.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class Book { 11 | 12 | private long id; 13 | private String title; 14 | private String author; 15 | private String category; 16 | private int pageCount; 17 | private double latitude; 18 | private double longitude; 19 | } 20 | -------------------------------------------------------------------------------- /library-web/src/main/java/com/sanvalero/libraryweb/service/BookService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.libraryweb.service; 2 | 3 | import com.sanvalero.libraryweb.domain.Book; 4 | 5 | import java.util.List; 6 | 7 | public interface BookService { 8 | 9 | Book findBook(long id); 10 | List findAllBooks(); 11 | List findAllBooks(String category); 12 | } 13 | -------------------------------------------------------------------------------- /library-web/src/main/java/com/sanvalero/libraryweb/service/BookServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.libraryweb.service; 2 | 3 | import com.sanvalero.libraryweb.domain.Book; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | @Service 13 | public class BookServiceImpl implements BookService { 14 | 15 | @Override 16 | public Book findBook(long id) { 17 | RestTemplate restTemplate = new RestTemplate(); 18 | ResponseEntity response = restTemplate.getForEntity("http://localhost:8081/books/" + id, Book.class); 19 | return response.getBody(); 20 | } 21 | 22 | @Override 23 | public List findAllBooks() { 24 | RestTemplate restTemplate = new RestTemplate(); 25 | Book[] arrayBooks = restTemplate.getForObject("http://localhost:8081/books", Book[].class); 26 | if (arrayBooks == null) 27 | return Collections.emptyList(); 28 | 29 | List books = Arrays.asList(arrayBooks); 30 | return books; 31 | } 32 | 33 | @Override 34 | public List findAllBooks(String category) { 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /library-web/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Puerto donde escucha el servidor una vez se inicie 2 | server.port=8080 -------------------------------------------------------------------------------- /library-web/src/main/resources/templates/book.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Libro - Detalles 6 | 7 | 8 |

9 |

Autor:

10 | 11 | -------------------------------------------------------------------------------- /library-web/src/main/resources/templates/catalog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Catálogo 6 | 7 | 8 |

Catálogo de libros

9 | 12 | 13 | -------------------------------------------------------------------------------- /library-web/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Inicio 6 | 7 | 8 |

Bienvenidos a mi tienda

9 |

Visita el catálogo de libros

10 | 11 | -------------------------------------------------------------------------------- /mockapi/__files/defaultResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 404, 3 | "message": "Route not found" 4 | } -------------------------------------------------------------------------------- /mockapi/__files/getProduct-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ratón", 3 | "description": "Ratón Bluetooth", 4 | "price": 12, 5 | "id": 3, 6 | "registrationDate": "2023-02-14" 7 | } -------------------------------------------------------------------------------- /mockapi/__files/getProducts-ok.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "portatil", 4 | "description": "Portatil Dell", 5 | "price": 750, 6 | "id": 1, 7 | "registrationDate": "2023-02-14" 8 | }, 9 | { 10 | "name": "pantalla", 11 | "description": "Pantalla LG", 12 | "price": 120, 13 | "id": 2, 14 | "registrationDate": "2021-02-14" 15 | }, 16 | { 17 | "name": "ratón", 18 | "description": "Ratón Bluetooth", 19 | "price": 12, 20 | "id": 3, 21 | "registrationDate": "2023-02-14" 22 | } 23 | ] -------------------------------------------------------------------------------- /mockapi/__files/internalServerError.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 500, 3 | "message": "Internal Server Error" 4 | } -------------------------------------------------------------------------------- /mockapi/__files/postProducts-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ratón", 3 | "description": "Ratón Bluetooth", 4 | "price": 12, 5 | "id": 3, 6 | "registrationDate": "2023-02-14" 7 | } -------------------------------------------------------------------------------- /mockapi/__files/productNotFound.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 404, 3 | "message": "Product not found" 4 | } -------------------------------------------------------------------------------- /mockapi/mappings/defaultRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "priority": 99, 3 | "request": { 4 | "method": "ANY", 5 | "urlPattern": ".*" 6 | }, 7 | "response": { 8 | "status": 404, 9 | "headers":{ 10 | "Content-Type": "application/json" 11 | }, 12 | "bodyFileName": "defaultResponse.json" 13 | } 14 | } -------------------------------------------------------------------------------- /mockapi/mappings/deleteProduct-404.json: -------------------------------------------------------------------------------- 1 | { 2 | "priority": 1, 3 | "request": { 4 | "method": "DELETE", 5 | "url": "/product/5" 6 | }, 7 | "response": { 8 | "status": 404, 9 | "headers":{ 10 | "Content-Type": "application/json" 11 | }, 12 | "bodyFileName": "productNotFound.json" 13 | } 14 | } -------------------------------------------------------------------------------- /mockapi/mappings/deleteProduct-500.json: -------------------------------------------------------------------------------- 1 | { 2 | "priority": 1, 3 | "request": { 4 | "method": "DELETE", 5 | "url": "/product/1" 6 | }, 7 | "response": { 8 | "status": 500, 9 | "headers":{ 10 | "Content-Type": "application/json" 11 | }, 12 | "bodyFileName": "internalServerError.json" 13 | } 14 | } -------------------------------------------------------------------------------- /mockapi/mappings/deleteProduct-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "DELETE", 4 | "urlPattern": "/product/.*" 5 | }, 6 | "response": { 7 | "status": 204, 8 | "headers":{ 9 | "Content-Type": "application/json" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /mockapi/mappings/getProduct-404.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "GET", 4 | "url": "/product/4" 5 | }, 6 | "response": { 7 | "status": 404, 8 | "headers":{ 9 | "Content-Type": "application/json" 10 | }, 11 | "bodyFileName": "productNotFound.json" 12 | } 13 | } -------------------------------------------------------------------------------- /mockapi/mappings/getProduct-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "GET", 4 | "url": "/product/3" 5 | }, 6 | "response": { 7 | "status": 200, 8 | "headers":{ 9 | "Content-Type": "application/json" 10 | }, 11 | "bodyFileName": "getProduct-ok.json" 12 | } 13 | } -------------------------------------------------------------------------------- /mockapi/mappings/getProducts-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "GET", 4 | "url": "/products" 5 | }, 6 | "response": { 7 | "status": 200, 8 | "headers": { 9 | "Content-Type": "application/json" 10 | }, 11 | "bodyFileName": "getProducts-ok.json" 12 | } 13 | } -------------------------------------------------------------------------------- /mockapi/mappings/postProducts-ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "POST", 4 | "url": "/products" 5 | }, 6 | "response": { 7 | "status": 201, 8 | "headers": { 9 | "Content-Type": "application/json" 10 | }, 11 | "bodyFileName": "postProducts-ok.json" 12 | } 13 | } -------------------------------------------------------------------------------- /mockapi/wiremock-standalone-3.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandcoke/spring-web/4746107fb1e7abfb6b3ea76d338119000d7346c5/mockapi/wiremock-standalone-3.3.1.jar -------------------------------------------------------------------------------- /myshop-ws-swagger/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /myshop-ws-swagger/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.3 9 | 10 | 11 | 12 | com.sanvalero 13 | myshop 14 | 0.0.1-SNAPSHOT 15 | myshop 16 | Proyecto de tienda como ejemplo de aplicación web 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-jpa 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | 33 | mysql 34 | mysql-connector-java 35 | runtime 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | 49 | org.springdoc 50 | springdoc-openapi-ui 51 | 1.5.2 52 | 53 | 54 | org.springdoc 55 | springdoc-openapi-ui 56 | 1.5.2 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | org.projectlombok 69 | lombok 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/MyshopApplication.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MyshopApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MyshopApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/config/ShopConfig.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.config; 2 | 3 | import io.swagger.v3.oas.models.Components; 4 | import io.swagger.v3.oas.models.OpenAPI; 5 | import io.swagger.v3.oas.models.info.Contact; 6 | import io.swagger.v3.oas.models.info.Info; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class ShopConfig { 12 | 13 | @Bean 14 | public OpenAPI customOpenAPI() { 15 | return new OpenAPI() 16 | .components(new Components()) 17 | .info(new Info().title("MyShop API") 18 | .description("Ejemplo de API REST") 19 | .contact(new Contact() 20 | .name("Santiago Faci") 21 | .email("santi@codeandcoke.com") 22 | .url("https://datos.codeandcoke.com")) 23 | .version("1.0")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/controller/Response.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.controller; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | /** 8 | * Modelo de respuesta 9 | * @author Santiago Faci 10 | * @version Curso 2020-2021 11 | */ 12 | @Data 13 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 14 | public class Response { 15 | 16 | public static final int NO_ERROR = 0; 17 | public static final int NOT_FOUND = 101; 18 | 19 | public static final String NO_MESSAGE = ""; 20 | 21 | private Error error; 22 | 23 | @Data 24 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 25 | static class Error { 26 | private long errorCode; 27 | private String message; 28 | } 29 | 30 | public static Response noErrorResponse() { 31 | return new Response(new Error(NO_ERROR, NO_MESSAGE)); 32 | } 33 | 34 | public static Response errorResonse(int errorCode, String errorMessage) { 35 | return new Response(new Error(errorCode, errorMessage)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import com.sun.istack.NotNull; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import lombok.*; 6 | 7 | import javax.persistence.*; 8 | import javax.validation.constraints.Min; 9 | import javax.validation.constraints.NotBlank; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | * Un producto del catálogo 14 | * @author Santiago Faci 15 | * @version Curso 2020-2021 16 | */ 17 | @Data 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @Entity(name = "products") 21 | public class Product { 22 | 23 | @Schema(description = "Identificador del producto", example = "1", required = true) 24 | @Id 25 | @GeneratedValue(strategy = GenerationType.IDENTITY) 26 | private long id; 27 | 28 | @Schema(description = "Nombre del producto", example = "Donuts", required = true) 29 | @NotBlank 30 | @Column 31 | private String name; 32 | 33 | @Schema(description = "Descripción del producto", example = "El mejor producto") 34 | @Column 35 | private String description; 36 | 37 | @Schema(description = "Nombre del producto", example = "Alimentación", required = true) 38 | @NotBlank 39 | @Column 40 | private String category; 41 | 42 | @Schema(description = "Precio del producto", example = "3.50", defaultValue = "0.00") 43 | @Column 44 | @Min(value = 0) 45 | private float price; 46 | 47 | @Schema(description = "Fecha de registro del producto", example = "2021-03-01") 48 | @Column(name = "creation_date") 49 | private LocalDateTime creationDate; 50 | } 51 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.exception; 2 | 3 | /** 4 | * Excepción de producto no encontrado 5 | * @author Santiago Faci 6 | * @version Curso 2020-2021 7 | */ 8 | public class ProductNotFoundException extends RuntimeException { 9 | 10 | public ProductNotFoundException() { 11 | super(); 12 | } 13 | 14 | public ProductNotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | public ProductNotFoundException(long id) { 19 | super("Product not found: " + id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Repositorio de productos 11 | * @author Santiago Faci 12 | * @version Curso 2020-2021 13 | */ 14 | @Repository 15 | public interface ProductRepository extends CrudRepository { 16 | 17 | Set findAll(); 18 | Product findByName(String name); 19 | Set findByCategory(String category); 20 | Set findByNameAndPrice(String name, float price); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | /** 9 | * Service de productos 10 | * @author Santiago Faci 11 | * @version Curso 2020-2021 12 | */ 13 | public interface ProductService { 14 | 15 | Set findAll(); 16 | Set findByCategory(String category); 17 | Optional findById(long id); 18 | Product addProduct(Product product); 19 | Product modifyProduct(long id, Product newProduct); 20 | void deleteProduct(long id); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/java/com/sanvalero/myshop/service/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import com.sanvalero.myshop.exception.ProductNotFoundException; 5 | import com.sanvalero.myshop.repository.ProductRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Optional; 10 | import java.util.Set; 11 | 12 | /** 13 | * Implementación del Service de productos 14 | * @author Santiago Faci 15 | * @version Curso 2020-2021 16 | */ 17 | @Service 18 | public class ProductServiceImpl implements ProductService { 19 | 20 | @Autowired 21 | private ProductRepository productRepository; 22 | 23 | @Override 24 | public Set findAll() { 25 | return productRepository.findAll(); 26 | } 27 | 28 | @Override 29 | public Set findByCategory(String category) { 30 | return productRepository.findByCategory(category); 31 | } 32 | 33 | @Override 34 | public Optional findById(long id) { 35 | return productRepository.findById(id); 36 | } 37 | 38 | @Override 39 | public Product addProduct(Product product) { 40 | return productRepository.save(product); 41 | } 42 | 43 | @Override 44 | public Product modifyProduct(long id, Product newProduct) { 45 | Product product = productRepository.findById(id) 46 | .orElseThrow(() -> new ProductNotFoundException(id)); 47 | newProduct.setId(product.getId()); 48 | return productRepository.save(newProduct); 49 | } 50 | 51 | @Override 52 | public void deleteProduct(long id) { 53 | productRepository.findById(id) 54 | .orElseThrow(() -> new ProductNotFoundException(id)); 55 | productRepository.deleteById(id); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuración para el acceso a la Base de Datos 2 | spring.jpa.hibernate.ddl-auto=update 3 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 4 | 5 | # Puerto donde escucha el servidor una vez se inicie 6 | server.port=8081 7 | 8 | # Datos de conexion con la base de datos MySQL 9 | spring.datasource.url=jdbc:mysql://localhost:3306/myshoponline 10 | spring.datasource.username=myshopuser 11 | spring.datasource.password=shop1234 12 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 13 | 14 | # Documentación con spring-doc 15 | #springdoc.api-docs.path=/api-docs 16 | #springdoc.swagger-ui.path=apidocs.html 17 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1.} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /myshop-ws-swagger/src/test/java/com/sanvalero/myshop/MyshopApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MyshopApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.3 9 | 10 | 11 | 12 | com.sanvalero 13 | myshop 14 | 0.0.1-SNAPSHOT 15 | myshop 16 | Proyecto de tienda como ejemplo de aplicación web 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-jpa 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | 33 | mysql 34 | mysql-connector-java 35 | runtime 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | 49 | org.springdoc 50 | springdoc-openapi-ui 51 | 1.5.2 52 | 53 | 54 | org.springdoc 55 | springdoc-openapi-ui 56 | 1.5.2 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | org.projectlombok 69 | lombok 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/MyshopApplication.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MyshopApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MyshopApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/config/ShopConfig.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.config; 2 | 3 | import io.swagger.v3.oas.models.Components; 4 | import io.swagger.v3.oas.models.OpenAPI; 5 | import io.swagger.v3.oas.models.info.Contact; 6 | import io.swagger.v3.oas.models.info.Info; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class ShopConfig { 12 | 13 | @Bean 14 | public OpenAPI customOpenAPI() { 15 | return new OpenAPI() 16 | .components(new Components()) 17 | .info(new Info().title("MyShop API") 18 | .description("Ejemplo de API REST") 19 | .contact(new Contact() 20 | .name("Santiago Faci") 21 | .email("santi@codeandcoke.com") 22 | .url("https://datos.codeandcoke.com")) 23 | .version("1.0")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.controller; 2 | 3 | import com.sanvalero.myshop.domain.Order; 4 | import com.sanvalero.myshop.domain.dto.OrderDTO; 5 | import com.sanvalero.myshop.service.OrderService; 6 | import com.sanvalero.myshop.service.ProductService; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | /** 15 | * Controlador para pedidos 16 | * @author Santiago Faci 17 | * @version Curso 2020-2021 18 | */ 19 | @RestController 20 | public class OrderController { 21 | 22 | private final Logger logger = LoggerFactory.getLogger(OrderController.class); 23 | 24 | @Autowired 25 | private OrderService orderService; 26 | 27 | @PostMapping(value = "/orders", produces = "application/json", consumes = "application/json") 28 | public ResponseEntity addOrder(@RequestBody OrderDTO orderDTO) { 29 | Order order = orderService.addOrder(orderDTO); 30 | return ResponseEntity.status(HttpStatus.CREATED).body(order); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/controller/Response.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.controller; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | /** 8 | * Modelo de respuesta 9 | * @author Santiago Faci 10 | * @version Curso 2020-2021 11 | */ 12 | @Data 13 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 14 | public class Response { 15 | 16 | public static final int NO_ERROR = 0; 17 | public static final int NOT_FOUND = 101; 18 | 19 | public static final String NO_MESSAGE = ""; 20 | 21 | private Error error; 22 | 23 | @Data 24 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 25 | static class Error { 26 | private long errorCode; 27 | private String message; 28 | } 29 | 30 | public static Response noErrorResponse() { 31 | return new Response(new Error(NO_ERROR, NO_MESSAGE)); 32 | } 33 | 34 | public static Response errorResonse(int errorCode, String errorMessage) { 35 | return new Response(new Error(errorCode, errorMessage)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | import javax.persistence.*; 7 | import java.time.LocalDate; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @Data 12 | @Entity(name = "orders") 13 | public class Order { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private long id; 18 | @Column 19 | private String number; 20 | @Column 21 | private LocalDate date; 22 | @Column 23 | private float price; 24 | 25 | @OneToMany(mappedBy = "order") 26 | private List details; 27 | 28 | public Order() { 29 | details = new ArrayList<>(); 30 | } 31 | 32 | public void addDetail(OrderDetail detail) { 33 | details.add(detail); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/domain/OrderDetail.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonBackReference; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @Entity(name = "order_details") 12 | public class OrderDetail { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private long id; 17 | @Column 18 | private int quantity; 19 | @Column 20 | private float price; 21 | 22 | @ManyToOne 23 | @JoinColumn(name = "product_id") 24 | private Product product; 25 | 26 | @ManyToOne 27 | @JoinColumn(name = "order_id") 28 | @JsonBackReference 29 | private Order order; 30 | } 31 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.persistence.*; 10 | import javax.validation.constraints.Min; 11 | import javax.validation.constraints.NotBlank; 12 | import java.time.LocalDateTime; 13 | 14 | /** 15 | * Un producto del catálogo 16 | * @author Santiago Faci 17 | * @version Curso 2020-2021 18 | */ 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @Entity(name = "products") 23 | public class Product { 24 | 25 | @Schema(description = "Identificador del producto", example = "1", required = true) 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.IDENTITY) 28 | private long id; 29 | 30 | @Schema(description = "Nombre del producto", example = "Donuts", required = true) 31 | @NotBlank 32 | @Column 33 | private String name; 34 | 35 | @Schema(description = "Descripción del producto", example = "El mejor producto") 36 | @Column 37 | private String description; 38 | 39 | @Schema(description = "Nombre del producto", example = "Alimentación", required = true) 40 | @NotBlank 41 | @Column 42 | private String category; 43 | 44 | @Schema(description = "Precio del producto", example = "3.50", defaultValue = "0.00") 45 | @Column 46 | @Min(value = 0) 47 | private float price; 48 | 49 | @Schema(description = "Fecha de registro del producto", example = "01-03-2021") 50 | @Column(name = "creation_date") 51 | @JsonFormat(pattern = "dd/MM/yyyy HH:mm:ss") 52 | private LocalDateTime creationDate; 53 | } 54 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/domain/dto/OrderDTO.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class OrderDTO { 11 | 12 | private List products; 13 | private float subtotal; 14 | private float price; 15 | } 16 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.exception; 2 | 3 | /** 4 | * Excepción de producto no encontrado 5 | * @author Santiago Faci 6 | * @version Curso 2020-2021 7 | */ 8 | public class ProductNotFoundException extends RuntimeException { 9 | 10 | public ProductNotFoundException() { 11 | super(); 12 | } 13 | 14 | public ProductNotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | public ProductNotFoundException(long id) { 19 | super("Product not found: " + id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/repository/OrderDetailRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.OrderDetail; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Repositorio de lineas de detalle 11 | * @author Santiago Faci 12 | * @version Curso 2020-2021 13 | */ 14 | @Repository 15 | public interface OrderDetailRepository extends CrudRepository { 16 | 17 | Set findAll(); 18 | } 19 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.Order; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Repositorio de pedidos 11 | * @author Santiago Faci 12 | * @version Curso 2020-2021 13 | */ 14 | @Repository 15 | public interface OrderRepository extends CrudRepository { 16 | 17 | Set findAll(); 18 | } 19 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Repositorio de productos 11 | * @author Santiago Faci 12 | * @version Curso 2020-2021 13 | */ 14 | @Repository 15 | public interface ProductRepository extends CrudRepository { 16 | 17 | Set findAll(); 18 | Product findByName(String name); 19 | Set findByCategory(String category); 20 | Set findByNameAndPrice(String name, float price); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Order; 4 | import com.sanvalero.myshop.domain.dto.OrderDTO; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * Service de pedidos 10 | * @author Santiago Faci 11 | * @version Curso 2020-2021 12 | */ 13 | public interface OrderService { 14 | 15 | Set findAll(); 16 | Order addOrder(OrderDTO orderDTO); 17 | } 18 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/service/OrderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Order; 4 | import com.sanvalero.myshop.domain.OrderDetail; 5 | import com.sanvalero.myshop.domain.Product; 6 | import com.sanvalero.myshop.domain.dto.OrderDTO; 7 | import com.sanvalero.myshop.repository.OrderDetailRepository; 8 | import com.sanvalero.myshop.repository.OrderRepository; 9 | import com.sanvalero.myshop.repository.ProductRepository; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.time.LocalDate; 14 | import java.util.Set; 15 | import java.util.UUID; 16 | 17 | /** 18 | * Implementación del Service de pedidos 19 | * @author Santiago Faci 20 | * @version Curso 2020-2021 21 | */ 22 | @Service 23 | public class OrderServiceImpl implements OrderService { 24 | 25 | @Autowired 26 | private OrderRepository orderRepository; 27 | 28 | @Autowired 29 | private ProductRepository productRepository; 30 | 31 | @Autowired 32 | private OrderDetailRepository orderDetailRepository; 33 | 34 | @Override 35 | public Set findAll() { 36 | return orderRepository.findAll(); 37 | } 38 | 39 | @Override 40 | public Order addOrder(OrderDTO orderDTO) { 41 | String number = UUID.randomUUID().toString(); 42 | Order newOrder = new Order(); 43 | newOrder.setNumber(number); 44 | newOrder.setDate(LocalDate.now()); 45 | newOrder.setPrice(orderDTO.getPrice()); 46 | newOrder = orderRepository.save(newOrder); 47 | 48 | for (String productName : orderDTO.getProducts()) { 49 | Product product = productRepository.findByName(productName); 50 | OrderDetail detail = new OrderDetail(); 51 | detail.setPrice(product.getPrice()); 52 | detail.setQuantity(1); 53 | detail.setOrder(newOrder); 54 | detail.setProduct(product); 55 | newOrder.addDetail(detail); 56 | orderDetailRepository.save(detail); 57 | } 58 | 59 | return newOrder; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | /** 9 | * Service de productos 10 | * @author Santiago Faci 11 | * @version Curso 2020-2021 12 | */ 13 | public interface ProductService { 14 | 15 | Set findAll(); 16 | Set findByCategory(String category); 17 | Optional findById(long id); 18 | Product addProduct(Product product); 19 | Product modifyProduct(long id, Product newProduct); 20 | void deleteProduct(long id); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/java/com/sanvalero/myshop/service/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import com.sanvalero.myshop.exception.ProductNotFoundException; 5 | import com.sanvalero.myshop.repository.ProductRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Optional; 10 | import java.util.Set; 11 | 12 | /** 13 | * Implementación del Service de productos 14 | * @author Santiago Faci 15 | * @version Curso 2020-2021 16 | */ 17 | @Service 18 | public class ProductServiceImpl implements ProductService { 19 | 20 | @Autowired 21 | private ProductRepository productRepository; 22 | 23 | @Override 24 | public Set findAll() { 25 | return productRepository.findAll(); 26 | } 27 | 28 | @Override 29 | public Set findByCategory(String category) { 30 | return productRepository.findByCategory(category); 31 | } 32 | 33 | @Override 34 | public Optional findById(long id) { 35 | return productRepository.findById(id); 36 | } 37 | 38 | @Override 39 | public Product addProduct(Product product) { 40 | return productRepository.save(product); 41 | } 42 | 43 | @Override 44 | public Product modifyProduct(long id, Product newProduct) { 45 | Product product = productRepository.findById(id) 46 | .orElseThrow(() -> new ProductNotFoundException(id)); 47 | newProduct.setId(product.getId()); 48 | return productRepository.save(newProduct); 49 | } 50 | 51 | @Override 52 | public void deleteProduct(long id) { 53 | productRepository.findById(id) 54 | .orElseThrow(() -> new ProductNotFoundException(id)); 55 | productRepository.deleteById(id); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuración para el acceso a la Base de Datos 2 | spring.jpa.hibernate.ddl-auto=update 3 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 4 | 5 | # Puerto donde escucha el servidor una vez se inicie 6 | server.port=8081 7 | 8 | # Datos de conexion con la base de datos MySQL 9 | spring.datasource.url=jdbc:mysql://localhost:3306/myshoponline 10 | spring.datasource.username=myshopuser 11 | spring.datasource.password=shop1234 12 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 13 | 14 | # Documentación con spring-doc 15 | #springdoc.api-docs.path=/api-docs 16 | #springdoc.swagger-ui.path=apidocs.html 17 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1.} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /myshop-ws-swagger2/src/test/java/com/sanvalero/myshop/MyshopApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MyshopApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /myshop-ws/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /myshop-ws/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.3 9 | 10 | 11 | 12 | com.sanvalero 13 | myshop 14 | 0.0.1-SNAPSHOT 15 | myshop 16 | Proyecto de tienda como ejemplo de aplicación web 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-jpa 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-thymeleaf 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | mysql 38 | mysql-connector-java 39 | runtime 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | org.projectlombok 62 | lombok 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/MyshopApplication.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MyshopApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MyshopApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/controller/Response.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.controller; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | /** 8 | * Modelo de respuesta 9 | * @author Santiago Faci 10 | * @version Curso 2020-2021 11 | */ 12 | @Data 13 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 14 | public class Response { 15 | 16 | public static final int NO_ERROR = 0; 17 | public static final int NOT_FOUND = 101; 18 | 19 | public static final String NO_MESSAGE = ""; 20 | 21 | private Error error; 22 | 23 | @Data 24 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 25 | static class Error { 26 | private long errorCode; 27 | private String message; 28 | } 29 | 30 | public static Response noErrorResponse() { 31 | return new Response(new Error(NO_ERROR, NO_MESSAGE)); 32 | } 33 | 34 | public static Response errorResonse(int errorCode, String errorMessage) { 35 | return new Response(new Error(errorCode, errorMessage)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import lombok.*; 4 | 5 | import javax.persistence.*; 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * Producto 10 | * @author Santiago Faci 11 | * @version Curso 2020-2021 12 | */ 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Entity(name = "products") 17 | public class Product { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private long id; 22 | @Column 23 | private String name; 24 | @Column 25 | private String description; 26 | @Column 27 | private String category; 28 | @Column 29 | private float price; 30 | @Column(name = "creation_date") 31 | private LocalDateTime creationDate; 32 | } 33 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.exception; 2 | 3 | /** 4 | * Excepción de producto no encontrado 5 | * @author Santiago Faci 6 | * @version Curso 2020-2021 7 | */ 8 | public class ProductNotFoundException extends RuntimeException { 9 | 10 | public ProductNotFoundException() { 11 | super(); 12 | } 13 | 14 | public ProductNotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | public ProductNotFoundException(long id) { 19 | super("Product not found: " + id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Repositorio de productos 11 | * @author Santiago Faci 12 | * @version Curso 2020-2021 13 | */ 14 | @Repository 15 | public interface ProductRepository extends CrudRepository { 16 | 17 | Set findAll(); 18 | Product findByName(String name); 19 | Set findByCategory(String category); 20 | Set findByNameAndPrice(String name, float price); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | 5 | import java.util.Optional; 6 | import java.util.Set; 7 | 8 | /** 9 | * Service de productos 10 | * @author Santiago Faci 11 | * @version Curso 2020-2021 12 | */ 13 | public interface ProductService { 14 | 15 | Set findAll(); 16 | Set findByCategory(String category); 17 | Optional findById(long id); 18 | Product addProduct(Product product); 19 | Product modifyProduct(long id, Product newProduct); 20 | void deleteProduct(long id); 21 | } 22 | -------------------------------------------------------------------------------- /myshop-ws/src/main/java/com/sanvalero/myshop/service/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import com.sanvalero.myshop.exception.ProductNotFoundException; 5 | import com.sanvalero.myshop.repository.ProductRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Optional; 10 | import java.util.Set; 11 | 12 | /** 13 | * Implementación del Service de productos 14 | * @author Santiago Faci 15 | * @version Curso 2020-2021 16 | */ 17 | @Service 18 | public class ProductServiceImpl implements ProductService { 19 | 20 | @Autowired 21 | private ProductRepository productRepository; 22 | 23 | @Override 24 | public Set findAll() { 25 | return productRepository.findAll(); 26 | } 27 | 28 | @Override 29 | public Set findByCategory(String category) { 30 | return productRepository.findByCategory(category); 31 | } 32 | 33 | @Override 34 | public Optional findById(long id) { 35 | return productRepository.findById(id); 36 | } 37 | 38 | @Override 39 | public Product addProduct(Product product) { 40 | return productRepository.save(product); 41 | } 42 | 43 | @Override 44 | public Product modifyProduct(long id, Product newProduct) { 45 | Product product = productRepository.findById(id) 46 | .orElseThrow(() -> new ProductNotFoundException(id)); 47 | newProduct.setId(product.getId()); 48 | return productRepository.save(newProduct); 49 | } 50 | 51 | @Override 52 | public void deleteProduct(long id) { 53 | productRepository.findById(id) 54 | .orElseThrow(() -> new ProductNotFoundException(id)); 55 | productRepository.deleteById(id); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /myshop-ws/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuración para el acceso a la Base de Datos 2 | spring.jpa.hibernate.ddl-auto=update 3 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 4 | 5 | # Puerto donde escucha el servidor una vez se inicie 6 | server.port=8081 7 | 8 | # Datos de conexion con la base de datos MySQL 9 | spring.datasource.url=jdbc:mysql://localhost:3306/myshoponline 10 | spring.datasource.username=myshopuser 11 | spring.datasource.password=shop1234 12 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver -------------------------------------------------------------------------------- /myshop-ws/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | %white(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %-60.60yellow(%C{20}): %msg%n%throwable 14 | 15 | 16 | 17 | 18 | 19 | 21 | ${LOG_DIR}/${LOG_NAME}.log 22 | 24 | %d %p %C{1.} [%t] %m%n 25 | 26 | 27 | 28 | 30 | ${LOG_DIR}/${LOG_NAME}-%d{yyyy-MM-dd}.%i.log 31 | 33 | 10MB 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /myshop-ws/src/test/java/com/sanvalero/myshop/MyshopApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MyshopApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /myshop/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /myshop/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandcoke/spring-web/4746107fb1e7abfb6b3ea76d338119000d7346c5/myshop/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /myshop/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /myshop/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.3 9 | 10 | 11 | 12 | com.sanvalero 13 | myshop 14 | 0.0.1-SNAPSHOT 15 | myshop 16 | Proyecto de tienda como ejemplo de aplicación web 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-jpa 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-thymeleaf 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | mysql 38 | mysql-connector-java 39 | runtime 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | org.projectlombok 62 | lombok 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/MyshopApplication.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MyshopApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MyshopApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/controller/WebController.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.controller; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import com.sanvalero.myshop.service.ProductService; 5 | import com.sanvalero.myshop.service.ProductServiceImpl; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.Mapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | 12 | import java.util.Set; 13 | 14 | @Controller 15 | public class WebController { 16 | 17 | @Autowired 18 | private ProductService productService; 19 | 20 | @RequestMapping(value = "/") 21 | public String index(Model model) { 22 | return "index"; 23 | } 24 | 25 | @RequestMapping(value = "/catalog") 26 | public String catalog(Model model) { 27 | Set products = productService.findAllProducts(); 28 | model.addAttribute("products", products); 29 | return "catalog"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.domain; 2 | 3 | import lombok.*; 4 | 5 | import javax.persistence.*; 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Entity(name = "products") 12 | public class Product { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private long id; 17 | @Column 18 | private String name; 19 | @Column 20 | private String description; 21 | @Column 22 | private String category; 23 | @Column 24 | private float price; 25 | @Column(name = "creation_date") 26 | private LocalDateTime creationDate; 27 | } 28 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.repository; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.lang.annotation.Native; 8 | import java.util.Set; 9 | 10 | @Repository 11 | public interface ProductRepository extends CrudRepository { 12 | 13 | Set findAll(); 14 | Product findByName(String name); 15 | Set findByNameAndPrice(String name, float price); 16 | } 17 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | 5 | import java.util.Set; 6 | 7 | public interface ProductService { 8 | 9 | Set findAllProducts(); 10 | Set findAllProducts(String category); 11 | void increasePrice(Product product); 12 | } 13 | -------------------------------------------------------------------------------- /myshop/src/main/java/com/sanvalero/myshop/service/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop.service; 2 | 3 | import com.sanvalero.myshop.domain.Product; 4 | import com.sanvalero.myshop.repository.ProductRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.Set; 9 | 10 | @Service 11 | public class ProductServiceImpl implements ProductService { 12 | 13 | @Autowired 14 | private ProductRepository productRepository; 15 | 16 | @Override 17 | public Set findAllProducts() { 18 | return productRepository.findAll(); 19 | } 20 | 21 | @Override 22 | public Set findAllProducts(String category) { 23 | return null; 24 | } 25 | 26 | @Override 27 | public void increasePrice(Product product) { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /myshop/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Configuración para el acceso a la Base de Datos 2 | spring.jpa.hibernate.ddl-auto=update 3 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 4 | 5 | # Puerto donde escucha el servidor una vez se inicie 6 | server.port=8081 7 | 8 | # Datos de conexion con la base de datos MySQL 9 | spring.datasource.url=jdbc:mysql://localhost:3306/myshoponline 10 | spring.datasource.username=root 11 | spring.datasource.password=mysql1234 12 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver -------------------------------------------------------------------------------- /myshop/src/main/resources/templates/catalog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Catálogo 6 | 7 | 8 |

Catálogo de productos

9 |
    10 |
  • 11 |
12 | 13 | -------------------------------------------------------------------------------- /myshop/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Inicio 6 | 7 | 8 |

Bienvenidos a mi tienda

9 |

Visita el catálogo de productos

10 | 11 | -------------------------------------------------------------------------------- /myshop/src/test/java/com/sanvalero/myshop/MyshopApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sanvalero.myshop; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MyshopApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /reactive-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.svalero 8 | reactive-client 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 17 13 | 17 14 | UTF-8 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-webflux 21 | 3.2.4 22 | 23 | 24 | 25 | org.projectlombok 26 | lombok 27 | 1.18.30 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /reactive-client/src/main/java/com/svalero/reactiveclient/Main.java: -------------------------------------------------------------------------------- 1 | package com.svalero.reactiveclient; 2 | 3 | import com.svalero.reactiveclient.domain.Bus; 4 | import org.springframework.web.reactive.function.client.WebClient; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.scheduler.Schedulers; 7 | 8 | import java.util.concurrent.Executors; 9 | 10 | public class Main { 11 | public static void main(String[] args) { 12 | WebClient webClient = WebClient.create("http://localhost:8080"); 13 | 14 | Flux busFlux = webClient.get() 15 | .uri("/buses") 16 | .retrieve() 17 | .bodyToFlux(Bus.class); 18 | 19 | busFlux 20 | .subscribeOn(Schedulers.fromExecutor(Executors.newCachedThreadPool())) 21 | .doOnComplete(() -> System.out.println("Fin")) 22 | .doOnError(throwable -> System.out.println("Se ha producido un error: " + throwable.getMessage())) 23 | .subscribe(bus -> { 24 | System.out.println(bus.getCode()); 25 | // Añadir aqui lo que se necesite 26 | }); 27 | 28 | System.out.println("Sigo aqui"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /reactive-client/src/main/java/com/svalero/reactiveclient/domain/Bus.java: -------------------------------------------------------------------------------- 1 | package com.svalero.reactiveclient.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class Bus { 11 | 12 | private String id; 13 | private String code; 14 | private int maxSpeed; 15 | } 16 | -------------------------------------------------------------------------------- /reactive-functional-api/.env: -------------------------------------------------------------------------------- 1 | MONGODB_DATABASE=reactiveapi 2 | MONGODB_PORT=27017 3 | 4 | SPRING_PORT=8080 5 | -------------------------------------------------------------------------------- /reactive-functional-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:17-jdk-alpine 2 | VOLUME /tmp 3 | COPY target/reactive-api-0.1.jar app.jar 4 | ENTRYPOINT ["java","-jar","app.jar"] -------------------------------------------------------------------------------- /reactive-functional-api/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.4" 2 | name: reactive-api-mongodb 3 | services: 4 | mongodb: 5 | image: mongo:7.0.7 6 | container_name: mongodb 7 | restart: unless-stopped 8 | env_file: ./.env 9 | ports: 10 | - $MONGODB_PORT:$MONGODB_PORT 11 | volumes: 12 | - db:/data/db 13 | app: 14 | image: reactive-api 15 | container_name: reactive-api 16 | env_file: ./.env 17 | ports: 18 | - $SPRING_PORT:$SPRING_PORT 19 | environment: 20 | SPRING_APPLICATION_JSON: '{ 21 | "spring.data.mongodb.uri" : "mongodb://mongodb:$MONGODB_PORT/$MONGODB_DATABASE?authSource=admin" 22 | }' 23 | depends_on: 24 | - mongodb 25 | restart: on-failure 26 | volumes: 27 | db: 28 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/ReactiveApi.java: -------------------------------------------------------------------------------- 1 | package com.svalero; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ReactiveApi { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ReactiveApi.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.svalero.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | import org.springframework.data.mongodb.core.mapping.Field; 9 | 10 | import java.io.Serializable; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Document("products") 16 | public class Product implements Serializable { 17 | @Id 18 | private String id; 19 | @Field 20 | private String name; 21 | } 22 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.repository; 2 | 3 | import com.svalero.domain.Product; 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ProductRepository extends ReactiveMongoRepository { 9 | } 10 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/router/ProductRouter.java: -------------------------------------------------------------------------------- 1 | package com.svalero.router; 2 | 3 | import com.svalero.handler.ProductHandler; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.web.reactive.function.server.RouterFunction; 8 | import org.springframework.web.reactive.function.server.RouterFunctions; 9 | import org.springframework.web.reactive.function.server.ServerResponse; 10 | 11 | import static org.springframework.web.reactive.function.server.RequestPredicates.*; 12 | import static org.springframework.web.reactive.function.server.RequestPredicates.accept; 13 | 14 | @Configuration 15 | public class ProductRouter { 16 | 17 | @Bean 18 | public RouterFunction productsRoute(ProductHandler productHandler){ 19 | return RouterFunctions 20 | .route(GET("/products").and(accept(MediaType.APPLICATION_JSON)), productHandler::getAllProducts) 21 | .andRoute(GET("/product/{id}").and(accept(MediaType.APPLICATION_JSON)), productHandler::getProduct) 22 | .andRoute(POST("/products").and(accept(MediaType.APPLICATION_JSON)), productHandler::createProduct) 23 | .andRoute(DELETE("/product/{id}").and(accept(MediaType.APPLICATION_JSON)), productHandler::deleteProduct) 24 | .andRoute(PUT("/product/{id}").and(accept(MediaType.APPLICATION_JSON)), productHandler::updateProduct); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.service; 2 | 3 | import com.svalero.domain.Product; 4 | import com.svalero.repository.ProductRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | 10 | @Service 11 | public class ProductService { 12 | 13 | @Autowired 14 | private ProductRepository productRepository; 15 | 16 | public Flux getAllProducts() { 17 | return productRepository.findAll(); 18 | } 19 | 20 | public Mono getProduct(String id) { 21 | return productRepository.findById(id); 22 | } 23 | 24 | public Mono save(Product product) { 25 | Product newProduct = new Product(); 26 | newProduct.setName(product.getName()); 27 | return productRepository.save(newProduct); 28 | } 29 | 30 | public Mono deleteProduct(String id) { 31 | return productRepository.deleteById(id); 32 | } 33 | 34 | public Mono update(Mono product) { 35 | return product 36 | .flatMap((p) -> productRepository.findById(p.getId()) 37 | .flatMap(product1 -> { 38 | product1.setName(p.getName()); 39 | return productRepository.save(product1); 40 | })); 41 | } 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/util/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.svalero.util; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class ErrorResponse { 11 | private int code; 12 | private String message; 13 | } 14 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/java/com/svalero/validator/ProductValidator.java: -------------------------------------------------------------------------------- 1 | package com.svalero.validator; 2 | 3 | import com.svalero.domain.Product; 4 | import org.springframework.validation.Errors; 5 | import org.springframework.validation.ValidationUtils; 6 | import org.springframework.validation.Validator; 7 | 8 | public class ProductValidator implements Validator { 9 | 10 | @Override 11 | public boolean supports(Class clazz) { 12 | return Product.class.isAssignableFrom(clazz); 13 | } 14 | 15 | @Override 16 | public void validate(Object target, Errors errors) { 17 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "field.required"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /reactive-functional-api/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | 3 | spring.data.mongodb.host=localhost 4 | spring.data.mongodb.port=27017 5 | spring.data.mongodb.database=reactive-api 6 | 7 | server.error.include-message=always -------------------------------------------------------------------------------- /todoapi_v1/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /todoapi_v1/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandcoke/spring-web/4746107fb1e7abfb6b3ea76d338119000d7346c5/todoapi_v1/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /todoapi_v1/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /todoapi_v1/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.4 9 | 10 | 11 | 12 | com.svalero 13 | todoapi 14 | 0.0.1-SNAPSHOT 15 | todoapi 16 | TODO API 17 | 18 | 19 | 17 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | 34 | com.h2database 35 | h2 36 | 2.2.224 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | org.projectlombok 59 | lombok 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/TodoApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TodoApiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TodoApiApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/controller/TaskController.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.controller; 2 | 3 | import com.svalero.todoapi.dto.ErrorResponse; 4 | import com.svalero.todoapi.service.TaskService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | import com.svalero.todoapi.domain.Task; 10 | 11 | import java.util.List; 12 | 13 | @RestController 14 | public class TaskController { 15 | 16 | @Autowired 17 | private TaskService taskService; 18 | 19 | @GetMapping(value = "/tasks") 20 | public ResponseEntity> getTasks() { 21 | List tasks = taskService.findAllTasks(); 22 | return new ResponseEntity<>(tasks, HttpStatus.OK); 23 | } 24 | 25 | @PostMapping(value = "/tasks") 26 | public ResponseEntity addTask(@RequestBody Task task) { 27 | Task newTask = taskService.addTask(task); 28 | return new ResponseEntity<>(newTask, HttpStatus.CREATED); 29 | } 30 | 31 | @DeleteMapping(value = "/task/{taskId}") 32 | public ResponseEntity deleteTask(@PathVariable long taskId) { 33 | taskService.deleteTask(taskId); 34 | return ResponseEntity.noContent().build(); 35 | } 36 | 37 | @ExceptionHandler(Exception.class) 38 | public ResponseEntity handleException(Exception e) { 39 | e.printStackTrace(); 40 | ErrorResponse errorResponse = new ErrorResponse(999, "Internal server error"); 41 | return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); 42 | } 43 | } -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/domain/Task.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.*; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Entity(name = "tasks") 13 | public class Task { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private long id; 18 | @Column 19 | private String name; 20 | @Column 21 | private String description; 22 | @Column 23 | private String owner; 24 | @Column 25 | private boolean done; 26 | @Column 27 | private double latitude; 28 | @Column 29 | private double longitude; 30 | } 31 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/dto/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class ErrorResponse { 11 | 12 | private int errorCode; 13 | private String message; 14 | } 15 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/exception/TaskNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.exception; 2 | 3 | public class TaskNotFoundException extends Exception { 4 | 5 | public TaskNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public TaskNotFoundException(long taskId) { 10 | super("Task " + taskId + " not found"); 11 | } 12 | 13 | public TaskNotFoundException() { 14 | super("Task not found"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/repository/TaskRepository.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.repository; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | import org.springframework.stereotype.Repository; 5 | import com.svalero.todoapi.domain.Task; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface TaskRepository extends CrudRepository { 11 | 12 | List findAll(); 13 | } 14 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/service/TaskService.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.service; 2 | 3 | import com.svalero.todoapi.domain.Task; 4 | 5 | import java.util.List; 6 | 7 | public interface TaskService { 8 | 9 | List findAllTasks(); 10 | Task addTask(Task task); 11 | void deleteTask(long taskId); 12 | } 13 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/java/com/svalero/todoapi/service/TaskServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import com.svalero.todoapi.domain.Task; 6 | import com.svalero.todoapi.repository.TaskRepository; 7 | 8 | import java.util.List; 9 | 10 | @Service 11 | public class TaskServiceImpl implements TaskService { 12 | 13 | @Autowired 14 | private TaskRepository taskRepository; 15 | 16 | @Override 17 | public List findAllTasks() { 18 | return taskRepository.findAll(); 19 | } 20 | 21 | @Override 22 | public Task addTask(Task task) { 23 | return taskRepository.save(task); 24 | } 25 | 26 | @Override 27 | public void deleteTask(long taskId) { 28 | taskRepository.deleteById(taskId); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /todoapi_v1/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Listening port 2 | server.port=8080 3 | 4 | # Database configuration 5 | spring.jpa.hibernate.ddl-auto=update 6 | spring.jpa.properties.hibernate.globally_quoted_identifiers=true 7 | 8 | # FIXME Put a valid url 9 | spring.datasource.url=jdbc:h2:file:/home/astable/todoapi.db 10 | spring.datasource.driverClassName=org.h2.Driver 11 | spring.datasource.username=sa 12 | spring.datasource.password=password 13 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 14 | spring.h2.console.enabled=true 15 | -------------------------------------------------------------------------------- /todoapi_v1/src/test/java/com/svalero/todoapi/TodoApiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.svalero.todoapi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class TodoApiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /todoapi_v1/todoapi.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "4e1e33aa-50f5-4efd-bfe3-4c2c73b66974", 4 | "name": "todoapi", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", 6 | "_exporter_id": "3720353" 7 | }, 8 | "item": [ 9 | { 10 | "name": "tasks", 11 | "request": { 12 | "method": "GET", 13 | "header": [], 14 | "url": { 15 | "raw": "http://localhost:8080/tasks", 16 | "protocol": "http", 17 | "host": [ 18 | "localhost" 19 | ], 20 | "port": "8080", 21 | "path": [ 22 | "tasks" 23 | ] 24 | } 25 | }, 26 | "response": [] 27 | }, 28 | { 29 | "name": "tasks", 30 | "request": { 31 | "method": "POST", 32 | "header": [], 33 | "body": { 34 | "mode": "raw", 35 | "raw": "{\n \"name\": \"Comprar el pan\",\n \"description\": \"Comprar el pan por la mañana\",\n \"owner\": \"yo\",\n \"done\": false,\n \"latitude\": 0.8457575,\n \"longitude\": -40.384834\n}", 36 | "options": { 37 | "raw": { 38 | "language": "json" 39 | } 40 | } 41 | }, 42 | "url": { 43 | "raw": "http://localhost:8080/tasks", 44 | "protocol": "http", 45 | "host": [ 46 | "localhost" 47 | ], 48 | "port": "8080", 49 | "path": [ 50 | "tasks" 51 | ] 52 | } 53 | }, 54 | "response": [] 55 | }, 56 | { 57 | "name": "tasks/:taskId", 58 | "request": { 59 | "method": "DELETE", 60 | "header": [], 61 | "url": { 62 | "raw": "http://localhost:8080/task/:taskId", 63 | "protocol": "http", 64 | "host": [ 65 | "localhost" 66 | ], 67 | "port": "8080", 68 | "path": [ 69 | "task", 70 | ":taskId" 71 | ], 72 | "variable": [ 73 | { 74 | "key": "taskId", 75 | "value": "1" 76 | } 77 | ] 78 | } 79 | }, 80 | "response": [] 81 | } 82 | ] 83 | } --------------------------------------------------------------------------------