├── .github └── workflows │ └── maven.yml ├── .gitignore ├── APIs_REST.postman_collection.json ├── cap01 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap01 │ │ │ ├── Cap01Application.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ └── DriverRepository.java │ │ │ └── interfaces │ │ │ └── DriverAPI.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── app │ └── car │ └── cap01 │ └── Cap01ApplicationTests.java ├── cap02 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap02 │ │ │ ├── Cap02Application.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ └── DriverRepository.java │ │ │ └── interfaces │ │ │ └── DriverAPI.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── app │ └── car │ └── cap02 │ └── Cap02ApplicationTests.java ├── cap03 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap03 │ │ │ ├── Cap03Application.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ └── TravelService.java │ │ │ └── interfaces │ │ │ ├── DriverAPI.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── input │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ └── TravelRequestOutput.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── app │ └── car │ └── cap03 │ └── Cap03ApplicationTests.java ├── cap04 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap04 │ │ │ ├── Cap04Application.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ └── TravelService.java │ │ │ └── interfaces │ │ │ ├── incoming │ │ │ ├── DriverAPI.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── input │ │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ │ └── TravelRequestOutput.java │ │ │ └── outcoming │ │ │ └── GMapsService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── app │ └── car │ └── cap04 │ └── Cap04ApplicationTests.java ├── cap05 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap05 │ │ │ ├── Cap05Application.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ └── TravelService.java │ │ │ └── interfaces │ │ │ ├── incoming │ │ │ ├── DriverAPI.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── input │ │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ │ └── TravelRequestOutput.java │ │ │ └── outcoming │ │ │ └── GMapsService.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── app │ │ └── car │ │ └── cap05 │ │ ├── Cap05ApplicationTests.java │ │ ├── infrastructure │ │ └── FileUtils.java │ │ └── interfaces │ │ └── incoming │ │ ├── PassengerAPITestIT.java │ │ └── TravelRequestAPITestIT.java │ └── resources │ ├── application-test.properties │ ├── requests │ ├── passengers_api │ │ └── create_new_passenger.json │ └── travel_requests_api │ │ └── create_new_request.json │ └── responses │ └── gmaps │ └── sample_response.json ├── cap06 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap06 │ │ │ ├── Cap06Application.java │ │ │ ├── config │ │ │ ├── LoadUserConfig.java │ │ │ └── SecurityConfig.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ ├── TravelService.java │ │ │ ├── User.java │ │ │ └── UserRepository.java │ │ │ └── interfaces │ │ │ ├── incoming │ │ │ ├── DriverAPI.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── input │ │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ │ └── TravelRequestOutput.java │ │ │ └── outcoming │ │ │ └── GMapsService.java │ └── resources │ │ ├── application.properties │ │ └── keystore.p12 │ └── test │ ├── java │ └── app │ │ └── car │ │ └── cap06 │ │ ├── Cap06ApplicationTests.java │ │ ├── infrastructure │ │ └── FileUtils.java │ │ └── interfaces │ │ └── incoming │ │ ├── PassengerAPITestIT.java │ │ └── TravelRequestAPITestIT.java │ └── resources │ ├── application-test.properties │ ├── requests │ ├── passengers_api │ │ └── create_new_passenger.json │ └── travel_requests_api │ │ └── create_new_request.json │ └── responses │ └── gmaps │ └── sample_response.json ├── cap07 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap07 │ │ │ ├── Cap07Application.java │ │ │ ├── config │ │ │ ├── AppConfig.java │ │ │ ├── LoadUserConfig.java │ │ │ └── SecurityConfig.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ ├── TravelService.java │ │ │ ├── User.java │ │ │ └── UserRepository.java │ │ │ └── interfaces │ │ │ ├── incoming │ │ │ ├── DriverAPI.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── errorhandling │ │ │ │ ├── DefaultErrorHandler.java │ │ │ │ ├── ErrorData.java │ │ │ │ ├── ErrorResponse.java │ │ │ │ └── LocaleResolver.java │ │ │ ├── input │ │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ │ └── TravelRequestOutput.java │ │ │ └── outcoming │ │ │ └── GMapsService.java │ └── resources │ │ ├── application.properties │ │ ├── i18n │ │ ├── messages_en.properties │ │ └── messages_pt_BR.properties │ │ └── keystore.p12 │ └── test │ ├── java │ └── app │ │ └── car │ │ └── cap07 │ │ ├── Cap07ApplicationTests.java │ │ ├── infrastructure │ │ └── FileUtils.java │ │ └── interfaces │ │ └── incoming │ │ ├── PassengerAPITestIT.java │ │ └── TravelRequestAPITestIT.java │ └── resources │ ├── application-test.properties │ ├── requests │ ├── passengers_api │ │ └── create_new_passenger.json │ └── travel_requests_api │ │ └── create_new_request.json │ └── responses │ └── gmaps │ └── sample_response.json ├── cap08 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── app │ │ │ └── car │ │ │ └── cap08 │ │ │ ├── Cap08Application.java │ │ │ ├── config │ │ │ ├── AppConfig.java │ │ │ ├── LoadUserConfig.java │ │ │ ├── OpenAPIConfig.java │ │ │ └── SecurityConfig.java │ │ │ ├── domain │ │ │ ├── Driver.java │ │ │ ├── DriverRepository.java │ │ │ ├── Passenger.java │ │ │ ├── PassengerRepository.java │ │ │ ├── TravelRequest.java │ │ │ ├── TravelRequestRepository.java │ │ │ ├── TravelRequestStatus.java │ │ │ ├── TravelService.java │ │ │ ├── User.java │ │ │ └── UserRepository.java │ │ │ └── interfaces │ │ │ ├── incoming │ │ │ ├── DriverAPI.java │ │ │ ├── DriverAPIImpl.java │ │ │ ├── PassengerAPI.java │ │ │ ├── TravelRequestAPI.java │ │ │ ├── errorhandling │ │ │ │ ├── DefaultErrorHandler.java │ │ │ │ ├── ErrorData.java │ │ │ │ ├── ErrorResponse.java │ │ │ │ └── LocaleResolver.java │ │ │ ├── input │ │ │ │ └── TravelRequestInput.java │ │ │ ├── mapping │ │ │ │ └── TravelRequestMapper.java │ │ │ └── output │ │ │ │ └── TravelRequestOutput.java │ │ │ └── outcoming │ │ │ └── GMapsService.java │ └── resources │ │ ├── application.properties │ │ ├── i18n │ │ ├── messages_en.properties │ │ └── messages_pt_BR.properties │ │ └── keystore.p12 │ └── test │ ├── java │ └── app │ │ └── car │ │ └── cap08 │ │ ├── Cap08ApplicationTests.java │ │ ├── infrastructure │ │ └── FileUtils.java │ │ └── interfaces │ │ └── incoming │ │ ├── PassengerAPITestIT.java │ │ └── TravelRequestAPITestIT.java │ └── resources │ ├── application-test.properties │ ├── requests │ ├── passengers_api │ │ └── create_new_passenger.json │ └── travel_requests_api │ │ └── create_new_request.json │ └── responses │ └── gmaps │ └── sample_response.json └── cap09 ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── app │ │ └── car │ │ └── cap09 │ │ ├── Cap09Application.java │ │ ├── config │ │ ├── AppConfig.java │ │ ├── LoadUserConfig.java │ │ ├── OpenAPIConfig.java │ │ └── SecurityConfig.java │ │ ├── domain │ │ ├── Driver.java │ │ ├── DriverRepository.java │ │ ├── Passenger.java │ │ ├── PassengerRepository.java │ │ ├── TravelRequest.java │ │ ├── TravelRequestRepository.java │ │ ├── TravelRequestStatus.java │ │ ├── TravelService.java │ │ ├── User.java │ │ └── UserRepository.java │ │ └── interfaces │ │ ├── incoming │ │ ├── DriverAPI.java │ │ ├── DriverAPIImpl.java │ │ ├── PassengerAPI.java │ │ ├── TravelRequestAPI.java │ │ ├── errorhandling │ │ │ ├── DefaultErrorHandler.java │ │ │ ├── ErrorData.java │ │ │ ├── ErrorResponse.java │ │ │ └── LocaleResolver.java │ │ ├── input │ │ │ └── TravelRequestInput.java │ │ ├── mapping │ │ │ └── TravelRequestMapper.java │ │ └── output │ │ │ ├── Drivers.java │ │ │ └── TravelRequestOutput.java │ │ └── outcoming │ │ └── GMapsService.java └── resources │ ├── application.properties │ ├── i18n │ ├── messages_en.properties │ └── messages_pt_BR.properties │ └── keystore.p12 └── test ├── java └── app │ └── car │ └── cap09 │ ├── Cap09ApplicationTests.java │ ├── infrastructure │ └── FileUtils.java │ └── interfaces │ └── incoming │ ├── PassengerAPITestIT.java │ └── TravelRequestAPITestIT.java └── resources ├── application-test.properties ├── requests ├── passengers_api │ └── create_new_passenger.json └── travel_requests_api │ └── create_new_request.json └── responses └── gmaps └── sample_response.json /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 21 20 | uses: actions/setup-java@v1 21 | with: 22 | java-version: 21 23 | - name: Build with Maven 24 | run: mvn -B verify --file cap01/pom.xml ; mvn -B verify --file cap02/pom.xml; mvn -B verify --file cap03/pom.xml; mvn -B verify --file cap04/pom.xml; mvn -B verify --file cap05/pom.xml; mvn -B verify --file cap06/pom.xml; mvn -B verify --file cap07/pom.xml; mvn -B verify --file cap08/pom.xml; mvn -B verify --file cap09/pom.xml 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # Intellij 7 | .idea/ 8 | *.iml 9 | *.iws 10 | 11 | # Mac 12 | .DS_Store 13 | 14 | # Maven 15 | log/ 16 | target/ 17 | 18 | chaveGoogle.txt 19 | -------------------------------------------------------------------------------- /cap01/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap01/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap01/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap01/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap01/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap01 13 | 0.0.1-SNAPSHOT 14 | cap01 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-devtools 38 | true 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.junit.vintage 53 | junit-vintage-engine 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /cap01/src/main/java/app/car/cap01/Cap01Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap01; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap01Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap01Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap01/src/main/java/app/car/cap01/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap01.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import lombok.Data; 6 | 7 | import java.time.LocalDate; 8 | 9 | @Data 10 | @Entity 11 | public class Driver { 12 | 13 | 14 | @Id 15 | Long id; 16 | String name; 17 | LocalDate birthDate; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap01/src/main/java/app/car/cap01/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap01.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap01/src/main/java/app/car/cap01/interfaces/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap01.interfaces; 2 | 3 | import app.car.cap01.domain.Driver; 4 | import app.car.cap01.domain.DriverRepository; 5 | import java.util.List; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @Service 14 | @RestController() 15 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 16 | public class DriverAPI { 17 | 18 | @Autowired 19 | DriverRepository driverRepository; 20 | 21 | @GetMapping("/drivers") 22 | public List listDrivers() { 23 | return driverRepository.findAll(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cap01/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cap01/src/test/java/app/car/cap01/Cap01ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap01; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap01ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap02/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap02/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap02/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap02/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap02/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap02 13 | 0.0.1-SNAPSHOT 14 | cap02 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-devtools 38 | true 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.junit.vintage 53 | junit-vintage-engine 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /cap02/src/main/java/app/car/cap02/Cap02Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap02; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap02Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap02Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap02/src/main/java/app/car/cap02/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap02.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap02/src/main/java/app/car/cap02/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap02.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap02/src/main/java/app/car/cap02/interfaces/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap02.interfaces; 2 | 3 | import app.car.cap02.domain.Driver; 4 | import app.car.cap02.domain.DriverRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.DeleteMapping; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PatchMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.server.ResponseStatusException; 21 | 22 | @Service 23 | @RestController() 24 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class DriverAPI { 26 | 27 | @Autowired 28 | DriverRepository driverRepository; 29 | 30 | @GetMapping("/drivers") 31 | public List listDrivers() { 32 | return driverRepository.findAll(); 33 | } 34 | 35 | 36 | @GetMapping("/drivers/{id}") 37 | public Driver findDriver(@PathVariable("id") Long id){ 38 | //return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 39 | return driverRepository.findById(id).get(); 40 | } 41 | 42 | @PostMapping("/drivers") 43 | public Driver createDriver(@RequestBody Driver driver) { 44 | return driverRepository.save(driver); 45 | } 46 | 47 | @PutMapping("/drivers/{id}") 48 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 49 | Driver foundDriver = findDriver(id); 50 | foundDriver.setBirthDate(driver.getBirthDate()); 51 | foundDriver.setName(driver.getName()); 52 | return driverRepository.save(foundDriver); 53 | } 54 | 55 | @PatchMapping("/drivers/{id}") 56 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 57 | Driver foundDriver = findDriver(id); 58 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 59 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 60 | return driverRepository.save(foundDriver); 61 | } 62 | 63 | @DeleteMapping("/drivers/{id}") 64 | public void deleteDriver(@PathVariable("id") Long id) { 65 | driverRepository.delete(findDriver(id)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cap02/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cap02/src/test/java/app/car/cap02/Cap02ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap02; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap02ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap03/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap03/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap03/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap03/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap03/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap03 13 | 0.0.1-SNAPSHOT 14 | cap03 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-devtools 38 | true 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | 45 | 46 | 47 | org.springframework.hateoas 48 | spring-hateoas 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | org.junit.vintage 58 | junit-vintage-engine 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-maven-plugin 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/Cap03Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap03Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap03Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface TravelRequestRepository extends JpaRepository {} 6 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.domain; 2 | 3 | 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Service 10 | public class TravelService { 11 | 12 | 13 | @Autowired 14 | TravelRequestRepository travelRequestRepository; 15 | 16 | 17 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 18 | travelRequest.setStatus(TravelRequestStatus.CREATED); 19 | travelRequest.setCreationDate(LocalDateTime.now()); 20 | return travelRequestRepository.save(travelRequest); 21 | } 22 | 23 | 24 | 25 | 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces; 2 | 3 | import app.car.cap03.domain.Driver; 4 | import app.car.cap03.domain.DriverRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.DeleteMapping; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PatchMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.server.ResponseStatusException; 21 | 22 | @Service 23 | @RestController() 24 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class DriverAPI { 26 | 27 | @Autowired 28 | DriverRepository driverRepository; 29 | 30 | @GetMapping("/drivers") 31 | public List listDrivers() { 32 | return driverRepository.findAll(); 33 | } 34 | 35 | 36 | @GetMapping("/drivers/{id}") 37 | public Driver findDriver(@PathVariable("id") Long id){ 38 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 39 | } 40 | 41 | @PostMapping("/drivers") 42 | public Driver createDriver(@RequestBody Driver driver) { 43 | return driverRepository.save(driver); 44 | } 45 | 46 | @PutMapping("/drivers/{id}") 47 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 48 | Driver foundDriver = findDriver(id); 49 | foundDriver.setBirthDate(driver.getBirthDate()); 50 | foundDriver.setName(driver.getName()); 51 | return driverRepository.save(foundDriver); 52 | } 53 | 54 | @PatchMapping("/drivers/{id}") 55 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 56 | Driver foundDriver = findDriver(id); 57 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 58 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 59 | return driverRepository.save(foundDriver); 60 | } 61 | 62 | @DeleteMapping("/drivers/{id}") 63 | public void deleteDriver(@PathVariable("id") Long id) { 64 | driverRepository.delete(findDriver(id)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces; 2 | 3 | import app.car.cap03.domain.Passenger; 4 | import app.car.cap03.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.server.ResponseStatusException; 13 | 14 | @Service 15 | @RestController 16 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 17 | public class PassengerAPI { 18 | 19 | @Autowired 20 | PassengerRepository passengerRepository; 21 | 22 | @GetMapping() 23 | public List listPassengers() { 24 | return passengerRepository.findAll(); 25 | } 26 | 27 | @GetMapping("/{id}") 28 | public Passenger findPassenger(@PathVariable("id") Long id) { 29 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 30 | } 31 | 32 | @PostMapping 33 | public Passenger createPassenger(@RequestBody Passenger passenger) { 34 | return passengerRepository.save(passenger); 35 | } 36 | 37 | @PutMapping("/{id}") 38 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 39 | Passenger p = findPassenger(id); 40 | p.setName(passenger.getName()); 41 | return passengerRepository.save(p); 42 | } 43 | 44 | @PatchMapping("/{id}") 45 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 46 | Passenger foundPassenger = findPassenger(id); 47 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 48 | return passengerRepository.save(foundPassenger); 49 | } 50 | 51 | @DeleteMapping("/{id}") 52 | public void deletePassenger(@PathVariable("id") Long id) { 53 | passengerRepository.delete(findPassenger(id)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces; 2 | 3 | 4 | import app.car.cap03.domain.TravelRequest; 5 | import app.car.cap03.domain.TravelService; 6 | import app.car.cap03.interfaces.input.TravelRequestInput; 7 | import app.car.cap03.interfaces.mapping.TravelRequestMapper; 8 | import app.car.cap03.interfaces.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RequestBody; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | @Service 19 | @RestController 20 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 21 | public class TravelRequestAPI { 22 | 23 | @Autowired 24 | TravelService travelService; 25 | 26 | @Autowired 27 | TravelRequestMapper mapper; 28 | 29 | @PostMapping 30 | public EntityModel makeTravelRequest (@RequestBody TravelRequestInput travelRequestInput) { 31 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 32 | TravelRequestOutput output = mapper.map(request); 33 | return mapper.buildOutputModel(request, output); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces.input; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TravelRequestInput { 7 | 8 | Long passengerId; 9 | String origin; 10 | String destination; 11 | } -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces.mapping; 2 | 3 | import app.car.cap03.domain.Passenger; 4 | import app.car.cap03.domain.PassengerRepository; 5 | import app.car.cap03.domain.TravelRequest; 6 | import app.car.cap03.interfaces.PassengerAPI; 7 | import app.car.cap03.interfaces.input.TravelRequestInput; 8 | import app.car.cap03.interfaces.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | @Component 18 | public class TravelRequestMapper { 19 | 20 | @Autowired 21 | private PassengerRepository passengerRepository; 22 | 23 | public TravelRequest map(TravelRequestInput input) { 24 | 25 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 26 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 27 | 28 | TravelRequest travelRequest = new TravelRequest(); 29 | travelRequest.setOrigin(input.getOrigin()); 30 | travelRequest.setDestination(input.getDestination()); 31 | travelRequest.setPassenger(passenger); 32 | 33 | return travelRequest; 34 | } 35 | 36 | public TravelRequestOutput map(TravelRequest travelRequest) { 37 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 38 | 39 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 40 | travelRequestOutput.setDestination(travelRequest.getDestination()); 41 | travelRequestOutput.setId(travelRequest.getId()); 42 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 43 | travelRequestOutput.setStatus(travelRequest.getStatus()); 44 | 45 | return travelRequestOutput; 46 | } 47 | 48 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 49 | EntityModel model = EntityModel.of(output); 50 | 51 | Link passengerLink = WebMvcLinkBuilder 52 | .linkTo(PassengerAPI.class) 53 | .slash(travelRequest.getPassenger().getId()) 54 | .withRel("passenger") 55 | .withTitle(travelRequest.getPassenger().getName()); 56 | model.add(passengerLink); 57 | return model; 58 | } 59 | } -------------------------------------------------------------------------------- /cap03/src/main/java/app/car/cap03/interfaces/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03.interfaces.output; 2 | 3 | import app.car.cap03.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | } -------------------------------------------------------------------------------- /cap03/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap03/src/main/resources/application.properties -------------------------------------------------------------------------------- /cap03/src/test/java/app/car/cap03/Cap03ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap03; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap03ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap04/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap04/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap04/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap04/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap04/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap04 13 | 0.0.1-SNAPSHOT 14 | cap04 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-devtools 38 | true 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | 45 | 46 | 47 | org.springframework.hateoas 48 | spring-hateoas 49 | 50 | 51 | 52 | com.jayway.jsonpath 53 | json-path 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-test 60 | test 61 | 62 | 63 | org.junit.vintage 64 | junit-vintage-engine 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/Cap04Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap04Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap04Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.domain; 2 | 3 | 4 | import app.car.cap04.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming; 2 | 3 | import app.car.cap04.domain.Driver; 4 | import app.car.cap04.domain.DriverRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.DeleteMapping; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PatchMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.server.ResponseStatusException; 21 | 22 | @Service 23 | @RestController() 24 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class DriverAPI { 26 | 27 | @Autowired 28 | DriverRepository driverRepository; 29 | 30 | @GetMapping("/drivers") 31 | public List listDrivers() { 32 | return driverRepository.findAll(); 33 | } 34 | 35 | 36 | @GetMapping("/drivers/{id}") 37 | public Driver findDriver(@PathVariable("id") Long id){ 38 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 39 | } 40 | 41 | @PostMapping("/drivers") 42 | public Driver createDriver(@RequestBody Driver driver) { 43 | return driverRepository.save(driver); 44 | } 45 | 46 | @PutMapping("/drivers/{id}") 47 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 48 | Driver foundDriver = findDriver(id); 49 | foundDriver.setBirthDate(driver.getBirthDate()); 50 | foundDriver.setName(driver.getName()); 51 | return driverRepository.save(foundDriver); 52 | } 53 | 54 | @PatchMapping("/drivers/{id}") 55 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 56 | Driver foundDriver = findDriver(id); 57 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 58 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 59 | return driverRepository.save(foundDriver); 60 | } 61 | 62 | @DeleteMapping("/drivers/{id}") 63 | public void deleteDriver(@PathVariable("id") Long id) { 64 | driverRepository.delete(findDriver(id)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming; 2 | 3 | import app.car.cap04.domain.Passenger; 4 | import app.car.cap04.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.server.ResponseStatusException; 13 | 14 | @Service 15 | @RestController 16 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 17 | public class PassengerAPI { 18 | 19 | @Autowired 20 | PassengerRepository passengerRepository; 21 | 22 | @GetMapping() 23 | public List listPassengers() { 24 | return passengerRepository.findAll(); 25 | } 26 | 27 | @GetMapping("/{id}") 28 | public Passenger findPassenger(@PathVariable("id") Long id) { 29 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 30 | } 31 | 32 | @PostMapping 33 | public Passenger createPassenger(@RequestBody Passenger passenger) { 34 | return passengerRepository.save(passenger); 35 | } 36 | 37 | @PutMapping("/{id}") 38 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 39 | Passenger p = findPassenger(id); 40 | p.setName(passenger.getName()); 41 | return passengerRepository.save(p); 42 | } 43 | 44 | @PatchMapping("/{id}") 45 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 46 | Passenger foundPassenger = findPassenger(id); 47 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 48 | return passengerRepository.save(foundPassenger); 49 | } 50 | 51 | @DeleteMapping("/{id}") 52 | public void deletePassenger(@PathVariable("id") Long id) { 53 | passengerRepository.delete(findPassenger(id)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming; 2 | 3 | 4 | import app.car.cap04.domain.TravelRequest; 5 | import app.car.cap04.domain.TravelService; 6 | import app.car.cap04.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap04.interfaces.incoming.output.TravelRequestOutput; 8 | import app.car.cap04.interfaces.incoming.mapping.TravelRequestMapper; 9 | import java.util.List; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.hateoas.EntityModel; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestParam; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @Service 22 | @RestController 23 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 24 | public class TravelRequestAPI { 25 | 26 | @Autowired 27 | TravelService travelService; 28 | 29 | @Autowired 30 | TravelRequestMapper mapper; 31 | 32 | @PostMapping 33 | public EntityModel makeTravelRequest (@RequestBody TravelRequestInput travelRequestInput) { 34 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 35 | TravelRequestOutput output = mapper.map(request); 36 | return mapper.buildOutputModel(request, output); 37 | } 38 | 39 | 40 | @GetMapping("/nearby") 41 | public List> listNearbyRequests(@RequestParam String currentAddress) { 42 | List requests = travelService.listNearbyTravelRequests(currentAddress); 43 | return mapper.buildOutputModel(requests); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TravelRequestInput { 7 | 8 | Long passengerId; 9 | String origin; 10 | String destination; 11 | } 12 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming.mapping; 2 | 3 | import app.car.cap04.domain.Passenger; 4 | import app.car.cap04.domain.PassengerRepository; 5 | import app.car.cap04.domain.TravelRequest; 6 | import app.car.cap04.interfaces.incoming.PassengerAPI; 7 | import app.car.cap04.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap04.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.List; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.incoming.output; 2 | 3 | import app.car.cap04.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap04/src/main/java/app/car/cap04/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | private static final String GMAPS_TEMPLATE = "https://maps.googleapis.com/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 19 | 20 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 21 | 22 | RestTemplate template = new RestTemplate(); 23 | String jsonResult = template.getForObject(GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 24 | 25 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 26 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 27 | } 28 | 29 | 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cap04/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | -------------------------------------------------------------------------------- /cap04/src/test/java/app/car/cap04/Cap04ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap04; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap04ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap05/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap05/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap05/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap05/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap05/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap05 13 | 0.0.1-SNAPSHOT 14 | cap05 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-devtools 38 | true 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | 45 | 46 | 47 | org.springframework.hateoas 48 | spring-hateoas 49 | 50 | 51 | 52 | com.jayway.jsonpath 53 | json-path 54 | 55 | 56 | 57 | org.springframework.cloud 58 | spring-cloud-contract-wiremock 59 | 4.1.3 60 | test 61 | 62 | 63 | 64 | 65 | io.rest-assured 66 | spring-mock-mvc 67 | 5.4.0 68 | test 69 | 70 | 71 | 72 | commons-io 73 | commons-io 74 | 2.6 75 | 76 | 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-starter-test 82 | test 83 | 84 | 85 | org.junit.vintage 86 | junit-vintage-engine 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | org.springframework.boot 97 | spring-boot-maven-plugin 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-failsafe-plugin 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/Cap05Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap05Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap05Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.domain; 2 | 3 | 4 | import app.car.cap05.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming; 2 | 3 | import app.car.cap05.domain.Driver; 4 | import app.car.cap05.domain.DriverRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.DeleteMapping; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PatchMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.server.ResponseStatusException; 21 | 22 | @Service 23 | @RestController() 24 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class DriverAPI { 26 | 27 | @Autowired 28 | DriverRepository driverRepository; 29 | 30 | @GetMapping("/drivers") 31 | public List listDrivers() { 32 | return driverRepository.findAll(); 33 | } 34 | 35 | 36 | @GetMapping("/drivers/{id}") 37 | public Driver findDriver(@PathVariable("id") Long id){ 38 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 39 | } 40 | 41 | @PostMapping("/drivers") 42 | public Driver createDriver(@RequestBody Driver driver) { 43 | return driverRepository.save(driver); 44 | } 45 | 46 | @PutMapping("/drivers/{id}") 47 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 48 | Driver foundDriver = findDriver(id); 49 | foundDriver.setBirthDate(driver.getBirthDate()); 50 | foundDriver.setName(driver.getName()); 51 | return driverRepository.save(foundDriver); 52 | } 53 | 54 | @PatchMapping("/drivers/{id}") 55 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 56 | Driver foundDriver = findDriver(id); 57 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 58 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 59 | return driverRepository.save(foundDriver); 60 | } 61 | 62 | @DeleteMapping("/drivers/{id}") 63 | public void deleteDriver(@PathVariable("id") Long id) { 64 | driverRepository.delete(findDriver(id)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming; 2 | 3 | import app.car.cap05.domain.Passenger; 4 | import app.car.cap05.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.server.ResponseStatusException; 13 | 14 | @Service 15 | @RestController 16 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 17 | public class PassengerAPI { 18 | 19 | @Autowired 20 | PassengerRepository passengerRepository; 21 | 22 | @GetMapping() 23 | public List listPassengers() { 24 | return passengerRepository.findAll(); 25 | } 26 | 27 | @GetMapping("/{id}") 28 | public Passenger findPassenger(@PathVariable("id") Long id) { 29 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 30 | } 31 | 32 | @PostMapping 33 | public Passenger createPassenger(@RequestBody Passenger passenger) { 34 | return passengerRepository.save(passenger); 35 | } 36 | 37 | @PutMapping("/{id}") 38 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 39 | Passenger p = findPassenger(id); 40 | p.setName(passenger.getName()); 41 | return passengerRepository.save(p); 42 | } 43 | 44 | @PatchMapping("/{id}") 45 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 46 | Passenger foundPassenger = findPassenger(id); 47 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 48 | return passengerRepository.save(foundPassenger); 49 | } 50 | 51 | @DeleteMapping("/{id}") 52 | public void deletePassenger(@PathVariable("id") Long id) { 53 | passengerRepository.delete(findPassenger(id)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming; 2 | 3 | 4 | import app.car.cap05.domain.TravelRequest; 5 | import app.car.cap05.domain.TravelService; 6 | import app.car.cap05.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap05.interfaces.incoming.mapping.TravelRequestMapper; 8 | import app.car.cap05.interfaces.incoming.output.TravelRequestOutput; 9 | import java.util.List; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.hateoas.EntityModel; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestParam; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | @Service 22 | @RestController 23 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 24 | public class TravelRequestAPI { 25 | 26 | @Autowired 27 | TravelService travelService; 28 | 29 | @Autowired 30 | TravelRequestMapper mapper; 31 | 32 | @PostMapping 33 | public EntityModel makeTravelRequest (@RequestBody TravelRequestInput travelRequestInput) { 34 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 35 | TravelRequestOutput output = mapper.map(request); 36 | return mapper.buildOutputModel(request, output); 37 | } 38 | 39 | 40 | @GetMapping("/nearby") 41 | public List> listNearbyRequests(@RequestParam String currentAddress) { 42 | List requests = travelService.listNearbyTravelRequests(currentAddress); 43 | return mapper.buildOutputModel(requests); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TravelRequestInput { 7 | 8 | Long passengerId; 9 | String origin; 10 | String destination; 11 | } 12 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming.mapping; 2 | 3 | import app.car.cap05.domain.Passenger; 4 | import app.car.cap05.domain.PassengerRepository; 5 | import app.car.cap05.domain.TravelRequest; 6 | import app.car.cap05.interfaces.incoming.PassengerAPI; 7 | import app.car.cap05.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap05.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.List; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming.output; 2 | 3 | import app.car.cap05.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap05/src/main/java/app/car/cap05/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | @Value("${interfaces.outcoming.gmaps.host:https://maps.googleapis.com}") 19 | private String gMapsHost; 20 | 21 | private static final String GMAPS_TEMPLATE = "/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 22 | 23 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 24 | 25 | RestTemplate template = new RestTemplate(); 26 | String jsonResult = template.getForObject(gMapsHost + GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 27 | 28 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 29 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cap05/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | -------------------------------------------------------------------------------- /cap05/src/test/java/app/car/cap05/Cap05ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap05ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap05/src/test/java/app/car/cap05/infrastructure/FileUtils.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.infrastructure; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.core.io.ClassPathResource; 5 | 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | public class FileUtils { 10 | 11 | @SneakyThrows 12 | public static String loadFileContents(String fileName) { 13 | 14 | InputStream is = new ClassPathResource(fileName).getInputStream(); 15 | byte[] data = new byte[is.available()]; 16 | is.read(data); 17 | return new String(data); 18 | } 19 | 20 | public static String loadFileContents(String fileName, Map replacements) { 21 | String fileContents = loadFileContents(fileName); 22 | 23 | for (Map.Entry entry : replacements.entrySet()) { 24 | fileContents = fileContents.replace("{{" + entry.getKey() + "}}", entry.getValue()); 25 | } 26 | return fileContents; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cap05/src/test/java/app/car/cap05/interfaces/incoming/PassengerAPITestIT.java: -------------------------------------------------------------------------------- 1 | package app.car.cap05.interfaces.incoming; 2 | 3 | import static io.restassured.RestAssured.given; 4 | import static org.hamcrest.Matchers.equalTo; 5 | import static org.hamcrest.Matchers.notNullValue; 6 | import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; 7 | 8 | import io.restassured.RestAssured; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.boot.test.web.server.LocalServerPort; 13 | 14 | 15 | @SpringBootTest(webEnvironment = RANDOM_PORT) 16 | class PassengerAPITestIT { 17 | 18 | @LocalServerPort 19 | private int port; 20 | 21 | @BeforeEach 22 | void setup() { 23 | RestAssured.port = port; 24 | } 25 | 26 | @Test 27 | void testCreatePassenger() { 28 | 29 | 30 | String createPassengerJSON = "{\"name\":\"Alexandre Saudate\"}"; 31 | 32 | 33 | given() 34 | .contentType(io.restassured.http.ContentType.JSON) 35 | .body(createPassengerJSON) 36 | .post("/passengers") 37 | .then() 38 | .statusCode(200) 39 | .body("id", notNullValue()) 40 | .body("name", equalTo("Alexandre Saudate")) 41 | ; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cap05/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | interfaces.outcoming.gmaps.host=http://localhost:${wiremock.server.port} -------------------------------------------------------------------------------- /cap05/src/test/resources/requests/passengers_api/create_new_passenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alexandre Saudate" 3 | } -------------------------------------------------------------------------------- /cap05/src/test/resources/requests/travel_requests_api/create_new_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "passengerId":"{{passengerId}}", 3 | "origin":"Avenida Paulista, 1000", 4 | "destination":"Avenida Ipiranga, 100" 5 | } -------------------------------------------------------------------------------- /cap06/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap06/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap06/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap06/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap06/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.1 9 | 10 | 11 | app.car 12 | cap06 13 | 0.0.1-SNAPSHOT 14 | cap06 15 | Demo project for Spring Boot 16 | 17 | 18 | 21 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-security 33 | 34 | 35 | org.projectlombok 36 | lombok 37 | true 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-devtools 42 | true 43 | 44 | 45 | 46 | com.h2database 47 | h2 48 | 49 | 50 | 51 | org.springframework.hateoas 52 | spring-hateoas 53 | 54 | 55 | 56 | com.jayway.jsonpath 57 | json-path 58 | 59 | 60 | 61 | org.springframework.cloud 62 | spring-cloud-contract-wiremock 63 | 4.1.3 64 | test 65 | 66 | 67 | 68 | io.rest-assured 69 | spring-mock-mvc 70 | 5.4.0 71 | test 72 | 73 | 74 | 75 | commons-io 76 | commons-io 77 | 2.6 78 | 79 | 80 | 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-starter-test 85 | test 86 | 87 | 88 | org.junit.vintage 89 | junit-vintage-engine 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-maven-plugin 101 | 102 | 103 | org.apache.maven.plugins 104 | maven-failsafe-plugin 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/Cap06Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap06Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap06Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/config/LoadUserConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.config; 2 | 3 | import app.car.cap06.domain.User; 4 | import app.car.cap06.domain.UserRepository; 5 | import jakarta.annotation.PostConstruct; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | 10 | import java.util.List; 11 | 12 | @Configuration 13 | public class LoadUserConfig { 14 | 15 | 16 | @Autowired 17 | PasswordEncoder passwordEncoder; 18 | 19 | @Autowired 20 | UserRepository userRepository; 21 | 22 | @PostConstruct 23 | public void init() { 24 | User admin = new User(); 25 | admin.setPassword(passwordEncoder.encode("password")); 26 | admin.setRoles(List.of("ROLE_ADMIN")); 27 | admin.setUsername("admin"); 28 | admin.setEnabled(true); 29 | 30 | userRepository.save(admin); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | 4 | import app.car.cap06.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/User.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | 4 | import java.util.List; 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.ElementCollection; 7 | import jakarta.persistence.Entity; 8 | import jakarta.persistence.GeneratedValue; 9 | import jakarta.persistence.Id; 10 | import jakarta.persistence.Table; 11 | import lombok.Data; 12 | 13 | @Data 14 | @Entity 15 | @Table(name = "users") 16 | public class User { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @Column(unique = true) 23 | String username; 24 | String password; 25 | 26 | Boolean enabled; 27 | 28 | @ElementCollection 29 | List roles; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/domain/UserRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface UserRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming; 2 | 3 | import app.car.cap06.domain.Driver; 4 | import app.car.cap06.domain.DriverRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.bind.annotation.DeleteMapping; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PatchMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.server.ResponseStatusException; 21 | 22 | @Service 23 | @RestController() 24 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class DriverAPI { 26 | 27 | @Autowired 28 | DriverRepository driverRepository; 29 | 30 | @GetMapping("/drivers") 31 | public List listDrivers() { 32 | return driverRepository.findAll(); 33 | } 34 | 35 | 36 | @GetMapping("/drivers/{id}") 37 | public Driver findDriver(@PathVariable("id") Long id){ 38 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 39 | } 40 | 41 | @PostMapping("/drivers") 42 | public Driver createDriver(@RequestBody Driver driver) { 43 | return driverRepository.save(driver); 44 | } 45 | 46 | @PutMapping("/drivers/{id}") 47 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 48 | Driver foundDriver = findDriver(id); 49 | foundDriver.setBirthDate(driver.getBirthDate()); 50 | foundDriver.setName(driver.getName()); 51 | return driverRepository.save(foundDriver); 52 | } 53 | 54 | @PatchMapping("/drivers/{id}") 55 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 56 | Driver foundDriver = findDriver(id); 57 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 58 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 59 | return driverRepository.save(foundDriver); 60 | } 61 | 62 | @DeleteMapping("/drivers/{id}") 63 | public void deleteDriver(@PathVariable("id") Long id) { 64 | driverRepository.delete(findDriver(id)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming; 2 | 3 | import app.car.cap06.domain.Passenger; 4 | import app.car.cap06.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import jakarta.annotation.security.RolesAllowed; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.server.ResponseStatusException; 14 | 15 | @Service 16 | @RestController 17 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class PassengerAPI { 19 | 20 | @Autowired 21 | PassengerRepository passengerRepository; 22 | 23 | @GetMapping() 24 | public List listPassengers() { 25 | return passengerRepository.findAll(); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Passenger findPassenger(@PathVariable("id") Long id) { 30 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 31 | } 32 | 33 | @PostMapping 34 | @RolesAllowed("ADMIN") 35 | public Passenger createPassenger(@RequestBody Passenger passenger) { 36 | return passengerRepository.save(passenger); 37 | } 38 | 39 | @PutMapping("/{id}") 40 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 41 | Passenger p = findPassenger(id); 42 | p.setName(passenger.getName()); 43 | return passengerRepository.save(p); 44 | } 45 | 46 | @PatchMapping("/{id}") 47 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 48 | Passenger foundPassenger = findPassenger(id); 49 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 50 | return passengerRepository.save(foundPassenger); 51 | } 52 | 53 | @DeleteMapping("/{id}") 54 | public void deletePassenger(@PathVariable("id") Long id) { 55 | passengerRepository.delete(findPassenger(id)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming; 2 | 3 | 4 | import app.car.cap06.domain.TravelRequest; 5 | import app.car.cap06.domain.TravelService; 6 | import app.car.cap06.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap06.interfaces.incoming.mapping.TravelRequestMapper; 8 | import app.car.cap06.interfaces.incoming.output.TravelRequestOutput; 9 | import java.util.List; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.hateoas.EntityModel; 13 | import org.springframework.http.MediaType; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RequestParam; 20 | import org.springframework.web.bind.annotation.RestController; 21 | 22 | @Service 23 | @RestController 24 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 25 | public class TravelRequestAPI { 26 | 27 | @Autowired 28 | TravelService travelService; 29 | 30 | @Autowired 31 | TravelRequestMapper mapper; 32 | 33 | @PostMapping 34 | public EntityModel makeTravelRequest (@RequestBody TravelRequestInput travelRequestInput) { 35 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 36 | TravelRequestOutput output = mapper.map(request); 37 | return mapper.buildOutputModel(request, output); 38 | } 39 | 40 | 41 | @GetMapping("/nearby") 42 | public List> listNearbyRequests(@RequestParam String currentAddress) { 43 | List requests = travelService.listNearbyTravelRequests(currentAddress); 44 | return mapper.buildOutputModel(requests); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TravelRequestInput { 7 | 8 | Long passengerId; 9 | String origin; 10 | String destination; 11 | } 12 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming.mapping; 2 | 3 | import app.car.cap06.domain.Passenger; 4 | import app.car.cap06.domain.PassengerRepository; 5 | import app.car.cap06.domain.TravelRequest; 6 | import app.car.cap06.interfaces.incoming.PassengerAPI; 7 | import app.car.cap06.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap06.interfaces.incoming.output.TravelRequestOutput; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.hateoas.EntityModel; 13 | import org.springframework.hateoas.Link; 14 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.stereotype.Component; 17 | import org.springframework.web.server.ResponseStatusException; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming.output; 2 | 3 | import app.car.cap06.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap06/src/main/java/app/car/cap06/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | @Value("${interfaces.outcoming.gmaps.host:https://maps.googleapis.com}") 19 | private String gMapsHost; 20 | 21 | private static final String GMAPS_TEMPLATE = "/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 22 | 23 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 24 | 25 | RestTemplate template = new RestTemplate(); 26 | String jsonResult = template.getForObject(gMapsHost + GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 27 | 28 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 29 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cap06/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | server.ssl.key-store=classpath:keystore.p12 4 | server.ssl.key-store-password=restbook 5 | server.ssl.key-store-type=PKCS12 6 | server.ssl.key-alias=car 7 | -------------------------------------------------------------------------------- /cap06/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap06/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /cap06/src/test/java/app/car/cap06/Cap06ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap06ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap06/src/test/java/app/car/cap06/infrastructure/FileUtils.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.infrastructure; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.core.io.ClassPathResource; 5 | 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | public class FileUtils { 10 | 11 | 12 | @SneakyThrows 13 | public static String loadFileContents(String fileName) { 14 | 15 | InputStream is = new ClassPathResource(fileName).getInputStream(); 16 | byte[] data = new byte[is.available()]; 17 | is.read(data); 18 | return new String(data); 19 | } 20 | 21 | public static String loadFileContents(String fileName, Map replacements) { 22 | String fileContents = loadFileContents(fileName); 23 | 24 | for (Map.Entry entry : replacements.entrySet()) { 25 | fileContents = fileContents.replace("{{" + entry.getKey() + "}}", entry.getValue()); 26 | } 27 | return fileContents; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cap06/src/test/java/app/car/cap06/interfaces/incoming/PassengerAPITestIT.java: -------------------------------------------------------------------------------- 1 | package app.car.cap06.interfaces.incoming; 2 | 3 | import io.restassured.RestAssured; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.web.server.LocalServerPort; 8 | 9 | import static io.restassured.RestAssured.basic; 10 | import static io.restassured.RestAssured.given; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.notNullValue; 13 | 14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 15 | class PassengerAPITestIT { 16 | 17 | @LocalServerPort 18 | private int port; 19 | 20 | @BeforeEach 21 | void setup() { 22 | RestAssured.baseURI = "https://localhost:" + port; 23 | RestAssured.useRelaxedHTTPSValidation(); 24 | RestAssured.authentication = basic("admin", "password"); 25 | } 26 | 27 | @Test 28 | void testCreatePassenger() { 29 | 30 | 31 | String createPassengerJSON = "{\"name\":\"Alexandre Saudate\"}"; 32 | 33 | 34 | given() 35 | .contentType(io.restassured.http.ContentType.JSON) 36 | .body(createPassengerJSON) 37 | .post("/passengers") 38 | .then() 39 | .statusCode(200) 40 | .body("id", notNullValue()) 41 | .body("name", equalTo("Alexandre Saudate")) 42 | ; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cap06/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | interfaces.outcoming.gmaps.host=http://localhost:${wiremock.server.port} -------------------------------------------------------------------------------- /cap06/src/test/resources/requests/passengers_api/create_new_passenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alexandre Saudate" 3 | } -------------------------------------------------------------------------------- /cap06/src/test/resources/requests/travel_requests_api/create_new_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "passengerId":"{{passengerId}}", 3 | "origin":"Avenida Paulista, 1000", 4 | "destination":"Avenida Ipiranga, 100" 5 | } -------------------------------------------------------------------------------- /cap07/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap07/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap07/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap07/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/Cap07Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap07Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap07Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.config; 2 | 3 | import org.springframework.context.MessageSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 7 | 8 | @Configuration 9 | public class AppConfig { 10 | 11 | 12 | @Bean 13 | public MessageSource messageSource() { 14 | var messageSource = new ReloadableResourceBundleMessageSource(); 15 | messageSource.setBasename("classpath:i18n/messages"); 16 | messageSource.setDefaultEncoding("UTF-8"); 17 | return messageSource; 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/config/LoadUserConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.config; 2 | 3 | import app.car.cap07.domain.User; 4 | import app.car.cap07.domain.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.crypto.password.PasswordEncoder; 8 | 9 | import jakarta.annotation.PostConstruct; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | @Configuration 14 | public class LoadUserConfig { 15 | 16 | 17 | @Autowired 18 | PasswordEncoder passwordEncoder; 19 | 20 | @Autowired 21 | UserRepository userRepository; 22 | 23 | @PostConstruct 24 | public void init() { 25 | User admin = new User(); 26 | admin.setPassword(passwordEncoder.encode("password")); 27 | admin.setRoles(List.of("ROLE_ADMIN")); 28 | admin.setUsername("admin"); 29 | admin.setEnabled(true); 30 | 31 | userRepository.save(admin); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9 | import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; 10 | import org.springframework.security.config.http.SessionCreationPolicy; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetailsService; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | import org.springframework.security.provisioning.InMemoryUserDetailsManager; 16 | import org.springframework.security.provisioning.JdbcUserDetailsManager; 17 | import org.springframework.security.web.DefaultSecurityFilterChain; 18 | 19 | import javax.sql.DataSource; 20 | 21 | import static org.springframework.security.config.Customizer.withDefaults; 22 | 23 | @Configuration 24 | @EnableWebSecurity 25 | @EnableMethodSecurity(jsr250Enabled = true) 26 | public class SecurityConfig { 27 | 28 | 29 | @Autowired 30 | DataSource dataSource; 31 | 32 | @Bean 33 | public DefaultSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 34 | http.csrf(CsrfConfigurer::disable); 35 | http.sessionManagement(configure -> configure.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); 36 | http.authorizeHttpRequests(configure -> configure.anyRequest().authenticated()); 37 | http.httpBasic(withDefaults()); 38 | http.headers(c1 -> c1.frameOptions(c2 -> c2.disable())); 39 | return http.build(); 40 | } 41 | 42 | @Bean 43 | public UserDetailsService userDetailsService() { 44 | var queryUsers = "select username, password, enabled from users where username=?"; 45 | var queryRoles = "select u.username, r.roles from user_roles r, users u where r.user_id = u.id and u.username=?"; 46 | 47 | var jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource); 48 | jdbcUserDetailsManager.setUsersByUsernameQuery(queryUsers); 49 | jdbcUserDetailsManager.setAuthoritiesByUsernameQuery(queryRoles); 50 | return jdbcUserDetailsManager; 51 | } 52 | 53 | 54 | @Bean 55 | public PasswordEncoder passwordEncoder() { 56 | return new BCryptPasswordEncoder(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | import java.time.LocalDate; 9 | 10 | @Data 11 | @Entity 12 | public class Driver { 13 | 14 | 15 | @Id 16 | @GeneratedValue 17 | Long id; 18 | String name; 19 | LocalDate birthDate; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | 4 | import app.car.cap07.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/User.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | 4 | import java.util.List; 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.ElementCollection; 7 | import jakarta.persistence.Entity; 8 | import jakarta.persistence.GeneratedValue; 9 | import jakarta.persistence.Id; 10 | import jakarta.persistence.Table; 11 | import lombok.Data; 12 | 13 | @Data 14 | @Entity 15 | @Table(name = "users") 16 | public class User { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @Column(unique = true) 23 | String username; 24 | String password; 25 | 26 | Boolean enabled; 27 | 28 | @ElementCollection 29 | List roles; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/domain/UserRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface UserRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming; 2 | 3 | import app.car.cap07.domain.Driver; 4 | import app.car.cap07.domain.DriverRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.web.bind.annotation.*; 10 | import org.springframework.web.server.ResponseStatusException; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | 15 | @Service 16 | @RestController() 17 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class DriverAPI { 19 | 20 | @Autowired 21 | DriverRepository driverRepository; 22 | 23 | @GetMapping("/drivers") 24 | public List listDrivers() { 25 | return driverRepository.findAll(); 26 | } 27 | 28 | 29 | @GetMapping("/drivers/{id}") 30 | public Driver findDriver(@PathVariable("id") Long id) { 31 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 32 | } 33 | 34 | @PostMapping("/drivers") 35 | public Driver createDriver(@RequestBody Driver driver) { 36 | return driverRepository.save(driver); 37 | } 38 | 39 | @PutMapping("/drivers/{id}") 40 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 41 | Driver foundDriver = findDriver(id); 42 | foundDriver.setBirthDate(driver.getBirthDate()); 43 | foundDriver.setName(driver.getName()); 44 | return driverRepository.save(foundDriver); 45 | } 46 | 47 | @PatchMapping("/drivers/{id}") 48 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 49 | Driver foundDriver = findDriver(id); 50 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 51 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 52 | return driverRepository.save(foundDriver); 53 | } 54 | 55 | @DeleteMapping("/drivers/{id}") 56 | public void deleteDriver(@PathVariable("id") Long id) { 57 | driverRepository.delete(findDriver(id)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming; 2 | 3 | import app.car.cap07.domain.Passenger; 4 | import app.car.cap07.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import jakarta.annotation.security.RolesAllowed; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.server.ResponseStatusException; 14 | 15 | @Service 16 | @RestController 17 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class PassengerAPI { 19 | 20 | @Autowired 21 | PassengerRepository passengerRepository; 22 | 23 | @GetMapping() 24 | public List listPassengers() { 25 | return passengerRepository.findAll(); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Passenger findPassenger(@PathVariable("id") Long id) { 30 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 31 | } 32 | 33 | @PostMapping 34 | @RolesAllowed("ADMIN") 35 | public Passenger createPassenger(@RequestBody Passenger passenger) { 36 | return passengerRepository.save(passenger); 37 | } 38 | 39 | @PutMapping("/{id}") 40 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 41 | Passenger p = findPassenger(id); 42 | p.setName(passenger.getName()); 43 | return passengerRepository.save(p); 44 | } 45 | 46 | @PatchMapping("/{id}") 47 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 48 | Passenger foundPassenger = findPassenger(id); 49 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 50 | return passengerRepository.save(foundPassenger); 51 | } 52 | 53 | @DeleteMapping("/{id}") 54 | public void deletePassenger(@PathVariable("id") Long id) { 55 | passengerRepository.delete(findPassenger(id)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming; 2 | 3 | 4 | import app.car.cap07.domain.TravelRequest; 5 | import app.car.cap07.domain.TravelService; 6 | import app.car.cap07.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap07.interfaces.incoming.mapping.TravelRequestMapper; 8 | import app.car.cap07.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import jakarta.validation.Valid; 16 | import java.util.List; 17 | 18 | @Service 19 | @RestController 20 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 21 | public class TravelRequestAPI { 22 | 23 | @Autowired 24 | TravelService travelService; 25 | 26 | @Autowired 27 | TravelRequestMapper mapper; 28 | 29 | @PostMapping 30 | public EntityModel makeTravelRequest (@RequestBody @Valid TravelRequestInput travelRequestInput) { 31 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 32 | TravelRequestOutput output = mapper.map(request); 33 | return mapper.buildOutputModel(request, output); 34 | } 35 | 36 | 37 | @GetMapping("/nearby") 38 | public List> listNearbyRequests(@RequestParam String currentAddress) { 39 | List requests = travelService.listNearbyTravelRequests(currentAddress); 40 | return mapper.buildOutputModel(requests); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/errorhandling/DefaultErrorHandler.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.errorhandling; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.MessageSource; 5 | import org.springframework.context.i18n.LocaleContextHolder; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.validation.FieldError; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | import org.springframework.web.bind.annotation.RestControllerAdvice; 12 | 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | 17 | @RestControllerAdvice 18 | public class DefaultErrorHandler { 19 | 20 | @Autowired 21 | private MessageSource messageSource; 22 | 23 | @ExceptionHandler(MethodArgumentNotValidException.class) 24 | @ResponseStatus(HttpStatus.BAD_REQUEST) 25 | public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex) { 26 | 27 | List messages = ex 28 | .getBindingResult() 29 | .getFieldErrors() 30 | .stream() 31 | .map(this::getMessage) 32 | .toList(); 33 | 34 | return new ErrorResponse(messages); 35 | } 36 | 37 | private ErrorData getMessage(FieldError fieldError) { 38 | 39 | return new ErrorData(messageSource.getMessage(fieldError, LocaleContextHolder.getLocale())); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/errorhandling/ErrorData.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.errorhandling; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | @AllArgsConstructor 8 | @Data 9 | public class ErrorData { 10 | 11 | private final String message; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/errorhandling/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.errorhandling; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @AllArgsConstructor 9 | @Data 10 | public class ErrorResponse { 11 | 12 | List errors; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/errorhandling/LocaleResolver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.errorhandling; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; 6 | 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import java.util.List; 9 | import java.util.Locale; 10 | import java.util.Optional; 11 | 12 | @Component 13 | public class LocaleResolver extends AcceptHeaderLocaleResolver { 14 | 15 | private static final Locale DEFAULT_LOCALE = Locale.of("pt", "BR"); 16 | 17 | private static final List ACCEPTED_LOCALES = List.of(DEFAULT_LOCALE, Locale.of("en")); 18 | 19 | @Override 20 | public Locale resolveLocale(HttpServletRequest request) { 21 | final String acceptLanguageHeader = request.getHeader("Accept-Language"); 22 | if (StringUtils.isBlank(acceptLanguageHeader) || acceptLanguageHeader.trim().equals("*")) { 23 | return DEFAULT_LOCALE; 24 | } 25 | List list = Locale.LanguageRange.parse(acceptLanguageHeader); 26 | Locale locale = Locale.lookup(list, ACCEPTED_LOCALES); 27 | return Optional.ofNullable(locale).orElse(DEFAULT_LOCALE); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | import jakarta.validation.constraints.NotEmpty; 6 | import jakarta.validation.constraints.NotNull; 7 | 8 | @Data 9 | public class TravelRequestInput { 10 | 11 | 12 | @NotNull(message = "O campo passengerId não pode ser nulo") 13 | Long passengerId; 14 | 15 | @NotEmpty(message = "O campo origin não pode estar em branco") 16 | String origin; 17 | 18 | @NotEmpty(message = "O campo destination não pode estar em branco") 19 | String destination; 20 | } 21 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.mapping; 2 | 3 | import app.car.cap07.domain.Passenger; 4 | import app.car.cap07.domain.PassengerRepository; 5 | import app.car.cap07.domain.TravelRequest; 6 | import app.car.cap07.interfaces.incoming.PassengerAPI; 7 | import app.car.cap07.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap07.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.List; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming.output; 2 | 3 | import app.car.cap07.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap07/src/main/java/app/car/cap07/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | @Value("${interfaces.outcoming.gmaps.host:https://maps.googleapis.com}") 19 | private String gMapsHost; 20 | 21 | private static final String GMAPS_TEMPLATE = "/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 22 | 23 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 24 | 25 | RestTemplate template = new RestTemplate(); 26 | String jsonResult = template.getForObject(gMapsHost + GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 27 | 28 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 29 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cap07/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | server.ssl.key-store=classpath:keystore.p12 4 | server.ssl.key-store-password=restbook 5 | server.ssl.key-store-type=PKCS12 6 | server.ssl.key-alias=car 7 | -------------------------------------------------------------------------------- /cap07/src/main/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | NotNull=The field {0} must not be null 2 | NotEmpty=The field {0} must not be empty -------------------------------------------------------------------------------- /cap07/src/main/resources/i18n/messages_pt_BR.properties: -------------------------------------------------------------------------------- 1 | NotNull=O campo {0} não pode ser nulo 2 | NotEmpty=O campo {0} não pode estar em branco -------------------------------------------------------------------------------- /cap07/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap07/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /cap07/src/test/java/app/car/cap07/Cap07ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap07ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap07/src/test/java/app/car/cap07/infrastructure/FileUtils.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.infrastructure; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.core.io.ClassPathResource; 5 | 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | public class FileUtils { 10 | 11 | 12 | @SneakyThrows 13 | public static String loadFileContents(String fileName) { 14 | 15 | InputStream is = new ClassPathResource(fileName).getInputStream(); 16 | byte[] data = new byte[is.available()]; 17 | is.read(data); 18 | return new String(data); 19 | } 20 | 21 | public static String loadFileContents(String fileName, Map replacements) { 22 | String fileContents = loadFileContents(fileName); 23 | 24 | for (Map.Entry entry : replacements.entrySet()) { 25 | fileContents = fileContents.replace("{{" + entry.getKey() + "}}", entry.getValue()); 26 | } 27 | return fileContents; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cap07/src/test/java/app/car/cap07/interfaces/incoming/PassengerAPITestIT.java: -------------------------------------------------------------------------------- 1 | package app.car.cap07.interfaces.incoming; 2 | 3 | import io.restassured.RestAssured; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.web.server.LocalServerPort; 8 | 9 | 10 | import static io.restassured.RestAssured.basic; 11 | import static io.restassured.RestAssured.given; 12 | import static org.hamcrest.Matchers.equalTo; 13 | import static org.hamcrest.Matchers.notNullValue; 14 | 15 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 16 | class PassengerAPITestIT { 17 | 18 | @LocalServerPort 19 | private int port; 20 | 21 | @BeforeEach 22 | void setup() { 23 | RestAssured.baseURI = "https://localhost:" + port; 24 | RestAssured.useRelaxedHTTPSValidation(); 25 | RestAssured.authentication = basic("admin", "password"); 26 | } 27 | 28 | @Test 29 | void testCreatePassenger() { 30 | 31 | 32 | String createPassengerJSON = "{\"name\":\"Alexandre Saudate\"}"; 33 | 34 | 35 | given() 36 | .contentType(io.restassured.http.ContentType.JSON) 37 | .body(createPassengerJSON) 38 | .post("/passengers") 39 | .then() 40 | .statusCode(200) 41 | .body("id", notNullValue()) 42 | .body("name", equalTo("Alexandre Saudate")) 43 | ; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cap07/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | interfaces.outcoming.gmaps.host=http://localhost:${wiremock.server.port} -------------------------------------------------------------------------------- /cap07/src/test/resources/requests/passengers_api/create_new_passenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alexandre Saudate" 3 | } -------------------------------------------------------------------------------- /cap07/src/test/resources/requests/travel_requests_api/create_new_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "passengerId":"{{passengerId}}", 3 | "origin":"Avenida Paulista, 1000", 4 | "destination":"Avenida Ipiranga, 100" 5 | } -------------------------------------------------------------------------------- /cap08/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap08/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap08/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap08/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/Cap08Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap08Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap08Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.config; 2 | 3 | import org.springframework.context.MessageSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 7 | import org.springframework.context.support.ResourceBundleMessageSource; 8 | 9 | @Configuration 10 | public class AppConfig { 11 | 12 | 13 | @Bean 14 | public MessageSource messageSource() { 15 | ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 16 | messageSource.setBasename("classpath:i18n/messages"); 17 | messageSource.setDefaultEncoding("UTF-8"); 18 | return messageSource; 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/config/LoadUserConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.config; 2 | 3 | import app.car.cap08.domain.User; 4 | import app.car.cap08.domain.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.crypto.password.PasswordEncoder; 8 | 9 | import jakarta.annotation.PostConstruct; 10 | import java.util.Arrays; 11 | 12 | @Configuration 13 | public class LoadUserConfig { 14 | 15 | 16 | @Autowired 17 | PasswordEncoder passwordEncoder; 18 | 19 | @Autowired 20 | UserRepository userRepository; 21 | 22 | @PostConstruct 23 | public void init() { 24 | app.car.cap08.domain.User admin = new User(); 25 | admin.setPassword(passwordEncoder.encode("password")); 26 | admin.setRoles(Arrays.asList("ROLE_ADMIN")); 27 | admin.setUsername("admin"); 28 | admin.setEnabled(true); 29 | 30 | userRepository.save(admin); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/config/OpenAPIConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Contact; 5 | import io.swagger.v3.oas.models.info.Info; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class OpenAPIConfig { 11 | 12 | 13 | @Bean 14 | public OpenAPI openAPIDocumentation() { 15 | return new OpenAPI() 16 | .info( 17 | new Info() 18 | .title("C.A.R. API") 19 | .description("API do sistema C.A.R., de facilitação de mobilidade urbana") 20 | .version("v1.0") 21 | .contact(new Contact() 22 | .name("Alexandre Saudate") 23 | .email("alesaudate@gmail.com") 24 | ) 25 | ); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.HttpMethod; 7 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; 11 | import org.springframework.security.config.http.SessionCreationPolicy; 12 | import org.springframework.security.core.userdetails.UserDetailsService; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | import org.springframework.security.provisioning.JdbcUserDetailsManager; 16 | import org.springframework.security.web.DefaultSecurityFilterChain; 17 | 18 | import javax.sql.DataSource; 19 | 20 | import static org.springframework.security.config.Customizer.withDefaults; 21 | 22 | 23 | @Configuration 24 | @EnableWebSecurity 25 | @EnableMethodSecurity(jsr250Enabled = true) 26 | public class SecurityConfig { 27 | 28 | 29 | @Autowired 30 | DataSource dataSource; 31 | 32 | @Bean 33 | public DefaultSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 34 | http.csrf(CsrfConfigurer::disable); 35 | http.sessionManagement(configure -> configure.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); 36 | http.authorizeHttpRequests(configure -> 37 | configure 38 | .requestMatchers(HttpMethod.GET, "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**") 39 | .permitAll()); 40 | http.authorizeHttpRequests(configure -> configure.anyRequest().authenticated()); 41 | http.httpBasic(withDefaults()); 42 | http.headers(c1 -> c1.frameOptions(c2 -> c2.disable())); 43 | return http.build(); 44 | } 45 | 46 | 47 | @Bean 48 | public UserDetailsService userDetailsService() { 49 | var jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource); 50 | jdbcUserDetailsManager.setUsersByUsernameQuery("select username, password, enabled from users where username=?"); 51 | jdbcUserDetailsManager.setAuthoritiesByUsernameQuery("select u.username, r.roles from user_roles r, users u where r.user_id = u.id and u.username=?"); 52 | return jdbcUserDetailsManager; 53 | } 54 | 55 | 56 | @Bean 57 | public PasswordEncoder passwordEncoder() { 58 | return new BCryptPasswordEncoder(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.GeneratedValue; 6 | import jakarta.persistence.Id; 7 | import jakarta.validation.constraints.Size; 8 | import lombok.Data; 9 | 10 | import java.time.LocalDate; 11 | 12 | @Data 13 | @Entity 14 | @Schema(description = "Representa um motorista dentro da plataforma") 15 | public class Driver { 16 | 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @Schema(description = "Nome do motorista") 23 | @Size(min=5, max = 255) 24 | String name; 25 | 26 | @Schema(description = "Data de nascimento do motorista") 27 | LocalDate birthDate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | 4 | import app.car.cap08.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/User.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | 4 | import jakarta.persistence.Column; 5 | import jakarta.persistence.ElementCollection; 6 | import jakarta.persistence.Entity; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.Table; 10 | import lombok.Data; 11 | 12 | import java.util.List; 13 | 14 | @Data 15 | @Entity 16 | @Table(name = "users") 17 | public class User { 18 | 19 | @Id 20 | @GeneratedValue 21 | Long id; 22 | 23 | @Column(unique = true) 24 | String username; 25 | String password; 26 | 27 | Boolean enabled; 28 | 29 | @ElementCollection 30 | List roles; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/domain/UserRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface UserRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming; 2 | 3 | import app.car.cap08.domain.Driver; 4 | import app.car.cap08.interfaces.incoming.errorhandling.ErrorResponse; 5 | import io.swagger.v3.oas.annotations.Operation; 6 | import io.swagger.v3.oas.annotations.Parameter; 7 | import io.swagger.v3.oas.annotations.media.Content; 8 | import io.swagger.v3.oas.annotations.media.Schema; 9 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 10 | import io.swagger.v3.oas.annotations.tags.Tag; 11 | 12 | import java.util.List; 13 | 14 | @Tag(name = "Driver API", description = "Manipula dados de motoristas.") 15 | public interface DriverAPI { 16 | 17 | 18 | @Operation(description = "Lista todos os motoristas disponíveis") 19 | List listDrivers() ; 20 | 21 | 22 | @Operation( 23 | description = "Localiza um motorista específico", 24 | responses = { 25 | @ApiResponse(responseCode = "200", description = "Caso o motorista tenha sido encontrado na base"), 26 | @ApiResponse(responseCode = "404", 27 | description = "Caso o motorista não tenha sido encontrado", 28 | content = @Content(schema = @Schema(implementation = ErrorResponse.class)) 29 | ) 30 | }) 31 | Driver findDriver( 32 | @Parameter(description = "ID do motorista a ser localizado") Long id) ; 33 | 34 | Driver createDriver( 35 | @Parameter(description = "Dados do motorista a ser criado") Driver driver) ; 36 | 37 | Driver fullUpdateDriver(Long id, Driver driver); 38 | 39 | Driver incrementalUpdateDriver(Long id, Driver driver) ; 40 | 41 | void deleteDriver(Long id) ; 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/DriverAPIImpl.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming; 2 | 3 | import app.car.cap08.domain.Driver; 4 | import app.car.cap08.domain.DriverRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.web.bind.annotation.*; 10 | import org.springframework.web.server.ResponseStatusException; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | 15 | @Service 16 | @RestController() 17 | @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class DriverAPIImpl implements DriverAPI { 19 | 20 | @Autowired 21 | DriverRepository driverRepository; 22 | 23 | @GetMapping("/drivers") 24 | public List listDrivers() { 25 | return driverRepository.findAll(); 26 | } 27 | 28 | @GetMapping("/drivers/{id}") 29 | public Driver findDriver( 30 | @PathVariable("id") Long id) { 31 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 32 | } 33 | 34 | @PostMapping("/drivers") 35 | public Driver createDriver( 36 | @RequestBody Driver driver) { 37 | return driverRepository.save(driver); 38 | } 39 | 40 | @PutMapping("/drivers/{id}") 41 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 42 | Driver foundDriver = findDriver(id); 43 | foundDriver.setBirthDate(driver.getBirthDate()); 44 | foundDriver.setName(driver.getName()); 45 | return driverRepository.save(foundDriver); 46 | } 47 | 48 | @PatchMapping("/drivers/{id}") 49 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 50 | Driver foundDriver = findDriver(id); 51 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 52 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 53 | return driverRepository.save(foundDriver); 54 | } 55 | 56 | @DeleteMapping("/drivers/{id}") 57 | public void deleteDriver(@PathVariable("id") Long id) { 58 | driverRepository.delete(findDriver(id)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming; 2 | 3 | import app.car.cap08.domain.Passenger; 4 | import app.car.cap08.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import jakarta.annotation.security.RolesAllowed; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.server.ResponseStatusException; 14 | 15 | @Service 16 | @RestController 17 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class PassengerAPI { 19 | 20 | @Autowired 21 | PassengerRepository passengerRepository; 22 | 23 | @GetMapping() 24 | public List listPassengers() { 25 | return passengerRepository.findAll(); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Passenger findPassenger(@PathVariable("id") Long id) { 30 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 31 | } 32 | 33 | @PostMapping 34 | @RolesAllowed("ADMIN") 35 | public Passenger createPassenger(@RequestBody Passenger passenger) { 36 | return passengerRepository.save(passenger); 37 | } 38 | 39 | @PutMapping("/{id}") 40 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 41 | Passenger p = findPassenger(id); 42 | p.setName(passenger.getName()); 43 | return passengerRepository.save(p); 44 | } 45 | 46 | @PatchMapping("/{id}") 47 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 48 | Passenger foundPassenger = findPassenger(id); 49 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 50 | return passengerRepository.save(foundPassenger); 51 | } 52 | 53 | @DeleteMapping("/{id}") 54 | public void deletePassenger(@PathVariable("id") Long id) { 55 | passengerRepository.delete(findPassenger(id)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming; 2 | 3 | 4 | import app.car.cap08.domain.TravelRequest; 5 | import app.car.cap08.domain.TravelService; 6 | import app.car.cap08.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap08.interfaces.incoming.mapping.TravelRequestMapper; 8 | import app.car.cap08.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import jakarta.validation.Valid; 16 | import java.util.List; 17 | 18 | @Service 19 | @RestController 20 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 21 | public class TravelRequestAPI { 22 | 23 | @Autowired 24 | TravelService travelService; 25 | 26 | @Autowired 27 | TravelRequestMapper mapper; 28 | 29 | @PostMapping 30 | public EntityModel makeTravelRequest (@RequestBody @Valid TravelRequestInput travelRequestInput) { 31 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 32 | TravelRequestOutput output = mapper.map(request); 33 | return mapper.buildOutputModel(request, output); 34 | } 35 | 36 | 37 | @GetMapping("/nearby") 38 | public List> listNearbyRequests(@RequestParam String currentAddress) { 39 | List requests = travelService.listNearbyTravelRequests(currentAddress); 40 | return mapper.buildOutputModel(requests); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/errorhandling/DefaultErrorHandler.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.errorhandling; 2 | 3 | import io.swagger.v3.oas.annotations.media.Content; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 6 | import io.swagger.v3.oas.annotations.responses.ApiResponses; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.MessageSource; 9 | import org.springframework.context.i18n.LocaleContextHolder; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.validation.FieldError; 12 | import org.springframework.web.bind.MethodArgumentNotValidException; 13 | import org.springframework.web.bind.annotation.ExceptionHandler; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | import org.springframework.web.bind.annotation.RestControllerAdvice; 16 | 17 | import java.util.List; 18 | import java.util.stream.Collectors; 19 | 20 | 21 | @RestControllerAdvice 22 | public class DefaultErrorHandler { 23 | 24 | @Autowired 25 | private MessageSource messageSource; 26 | 27 | @ExceptionHandler(MethodArgumentNotValidException.class) 28 | @ResponseStatus(HttpStatus.BAD_REQUEST) 29 | @ApiResponses( 30 | @ApiResponse(responseCode = "400", content = @Content( 31 | mediaType = "application/json", 32 | schema = @Schema(implementation = ErrorResponse.class) 33 | )) 34 | ) 35 | public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex) { 36 | 37 | List messages = ex 38 | .getBindingResult() 39 | .getFieldErrors() 40 | .stream() 41 | .map(this::getMessage) 42 | .collect(Collectors.toList()); 43 | 44 | return new ErrorResponse(messages); 45 | } 46 | 47 | private ErrorData getMessage(FieldError fieldError) { 48 | 49 | return new ErrorData(messageSource.getMessage(fieldError, LocaleContextHolder.getLocale())); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/errorhandling/ErrorData.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.errorhandling; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | @AllArgsConstructor 8 | @Data 9 | public class ErrorData { 10 | 11 | private final String message; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/errorhandling/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.errorhandling; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @AllArgsConstructor 9 | @Data 10 | public class ErrorResponse { 11 | 12 | List errors; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/errorhandling/LocaleResolver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.errorhandling; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; 6 | 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.Locale; 11 | import java.util.Optional; 12 | 13 | @Component 14 | public class LocaleResolver extends AcceptHeaderLocaleResolver { 15 | 16 | private static final Locale DEFAULT_LOCALE = Locale.of("pt", "BR"); 17 | 18 | private static final List ACCEPTED_LOCALES = Arrays.asList( 19 | 20 | DEFAULT_LOCALE, 21 | new Locale("en") 22 | ); 23 | 24 | @Override 25 | public Locale resolveLocale(HttpServletRequest request) { 26 | final String acceptLanguageHeader = request.getHeader("Accept-Language"); 27 | if (StringUtils.isBlank(acceptLanguageHeader) || acceptLanguageHeader.trim().equals("*")) { 28 | return DEFAULT_LOCALE; 29 | } 30 | List list = Locale.LanguageRange.parse(acceptLanguageHeader); 31 | Locale locale = Locale.lookup(list, ACCEPTED_LOCALES); 32 | return Optional.ofNullable(locale).orElse(DEFAULT_LOCALE); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | import jakarta.validation.constraints.NotEmpty; 6 | import jakarta.validation.constraints.NotNull; 7 | 8 | @Data 9 | public class TravelRequestInput { 10 | 11 | 12 | @NotNull(message = "O campo passengerId não pode ser nulo") 13 | Long passengerId; 14 | 15 | @NotEmpty(message = "O campo origin não pode estar em branco") 16 | String origin; 17 | 18 | @NotEmpty(message = "O campo destination não pode estar em branco") 19 | String destination; 20 | } 21 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.mapping; 2 | 3 | import app.car.cap08.domain.Passenger; 4 | import app.car.cap08.domain.PassengerRepository; 5 | import app.car.cap08.domain.TravelRequest; 6 | import app.car.cap08.interfaces.incoming.PassengerAPI; 7 | import app.car.cap08.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap08.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.List; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming.output; 2 | 3 | import app.car.cap08.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap08/src/main/java/app/car/cap08/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | @Value("${interfaces.outcoming.gmaps.host:https://maps.googleapis.com}") 19 | private String gMapsHost; 20 | 21 | private static final String GMAPS_TEMPLATE = "/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 22 | 23 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 24 | 25 | RestTemplate template = new RestTemplate(); 26 | String jsonResult = template.getForObject(gMapsHost + GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 27 | 28 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 29 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cap08/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | server.ssl.key-store=classpath:keystore.p12 4 | server.ssl.key-store-password=restbook 5 | server.ssl.key-store-type=PKCS12 6 | server.ssl.key-alias=car 7 | -------------------------------------------------------------------------------- /cap08/src/main/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | NotNull=The field {0} must not be null 2 | NotEmpty=The field {0} must not be empty -------------------------------------------------------------------------------- /cap08/src/main/resources/i18n/messages_pt_BR.properties: -------------------------------------------------------------------------------- 1 | NotNull=O campo {0} não pode ser nulo 2 | NotEmpty=O campo {0} não pode estar em branco -------------------------------------------------------------------------------- /cap08/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap08/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /cap08/src/test/java/app/car/cap08/Cap08ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap08ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap08/src/test/java/app/car/cap08/infrastructure/FileUtils.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.infrastructure; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.core.io.ClassPathResource; 5 | 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | public class FileUtils { 10 | 11 | 12 | @SneakyThrows 13 | public static String loadFileContents(String fileName) { 14 | 15 | InputStream is = new ClassPathResource(fileName).getInputStream(); 16 | byte[] data = new byte[is.available()]; 17 | is.read(data); 18 | return new String(data); 19 | } 20 | 21 | public static String loadFileContents(String fileName, Map replacements) { 22 | String fileContents = loadFileContents(fileName); 23 | 24 | for (Map.Entry entry : replacements.entrySet()) { 25 | fileContents = fileContents.replace("{{" + entry.getKey() + "}}", entry.getValue()); 26 | } 27 | return fileContents; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cap08/src/test/java/app/car/cap08/interfaces/incoming/PassengerAPITestIT.java: -------------------------------------------------------------------------------- 1 | package app.car.cap08.interfaces.incoming; 2 | 3 | import io.restassured.RestAssured; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.web.server.LocalServerPort; 8 | 9 | import static io.restassured.RestAssured.basic; 10 | import static io.restassured.RestAssured.given; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.notNullValue; 13 | 14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 15 | class PassengerAPITestIT { 16 | 17 | @LocalServerPort 18 | private int port; 19 | 20 | @BeforeEach 21 | void setup() { 22 | RestAssured.baseURI = "https://localhost:" + port; 23 | RestAssured.useRelaxedHTTPSValidation(); 24 | RestAssured.authentication = basic("admin", "password"); 25 | } 26 | 27 | @Test 28 | void testCreatePassenger() { 29 | 30 | 31 | String createPassengerJSON = "{\"name\":\"Alexandre Saudate\"}"; 32 | 33 | 34 | given() 35 | .contentType(io.restassured.http.ContentType.JSON) 36 | .body(createPassengerJSON) 37 | .post("/passengers") 38 | .then() 39 | .statusCode(200) 40 | .body("id", notNullValue()) 41 | .body("name", equalTo("Alexandre Saudate")) 42 | ; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cap08/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | interfaces.outcoming.gmaps.host=http://localhost:${wiremock.server.port} -------------------------------------------------------------------------------- /cap08/src/test/resources/requests/passengers_api/create_new_passenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alexandre Saudate" 3 | } -------------------------------------------------------------------------------- /cap08/src/test/resources/requests/travel_requests_api/create_new_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "passengerId":"{{passengerId}}", 3 | "origin":"Avenida Paulista, 1000", 4 | "destination":"Avenida Ipiranga, 100" 5 | } -------------------------------------------------------------------------------- /cap09/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 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 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /cap09/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap09/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cap09/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/Cap09Application.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Cap09Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Cap09Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.config; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.context.MessageSource; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 8 | 9 | @Configuration 10 | @EnableAutoConfiguration 11 | public class AppConfig { 12 | 13 | 14 | @Bean 15 | public MessageSource messageSource() { 16 | ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 17 | messageSource.setBasename("classpath:i18n/messages"); 18 | messageSource.setDefaultEncoding("UTF-8"); 19 | return messageSource; 20 | } 21 | 22 | 23 | 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/config/LoadUserConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.config; 2 | 3 | import app.car.cap09.domain.User; 4 | import app.car.cap09.domain.UserRepository; 5 | import jakarta.annotation.PostConstruct; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | 10 | import java.util.List; 11 | 12 | @Configuration 13 | public class LoadUserConfig { 14 | 15 | 16 | @Autowired 17 | PasswordEncoder passwordEncoder; 18 | 19 | @Autowired 20 | UserRepository userRepository; 21 | 22 | @PostConstruct 23 | public void init() { 24 | User admin = new User(); 25 | admin.setPassword(passwordEncoder.encode("password")); 26 | admin.setRoles(List.of("ROLE_ADMIN")); 27 | admin.setUsername("admin"); 28 | admin.setEnabled(true); 29 | 30 | userRepository.save(admin); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/config/OpenAPIConfig.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Contact; 5 | import io.swagger.v3.oas.models.info.Info; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class OpenAPIConfig { 11 | 12 | 13 | @Bean 14 | public OpenAPI openAPIDocumentation() { 15 | return new OpenAPI() 16 | .info( 17 | new Info() 18 | .title("C.A.R. API") 19 | .description("API do sistema C.A.R., de facilitação de mobilidade urbana") 20 | .version("v1.0") 21 | .contact(new Contact() 22 | .name("Alexandre Saudate") 23 | .email("alesaudate@gmail.com") 24 | ) 25 | ); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/Driver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.GeneratedValue; 6 | import jakarta.persistence.Id; 7 | import jakarta.validation.constraints.Size; 8 | import lombok.Data; 9 | 10 | import java.time.LocalDate; 11 | 12 | @Data 13 | @Entity 14 | @Schema(description = "Representa um motorista dentro da plataforma") 15 | public class Driver { 16 | 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @Schema(description = "Nome do motorista") 23 | @Size(min=5, max = 255) 24 | String name; 25 | 26 | @Schema(description = "Data de nascimento do motorista") 27 | LocalDate birthDate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface DriverRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/Passenger.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import lombok.Data; 7 | 8 | 9 | @Data 10 | @Entity 11 | public class Passenger { 12 | 13 | 14 | @Id 15 | @GeneratedValue 16 | Long id; 17 | String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface PassengerRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/TravelRequest.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.EnumType; 6 | import jakarta.persistence.Enumerated; 7 | import jakarta.persistence.GeneratedValue; 8 | import jakarta.persistence.Id; 9 | import jakarta.persistence.ManyToOne; 10 | import lombok.Data; 11 | 12 | import java.time.LocalDateTime; 13 | 14 | @Data 15 | @Entity 16 | public class TravelRequest { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @ManyToOne 23 | Passenger passenger; 24 | String origin; 25 | String destination; 26 | 27 | @Enumerated(EnumType.STRING) 28 | TravelRequestStatus status; 29 | LocalDateTime creationDate; 30 | } 31 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/TravelRequestRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TravelRequestRepository extends JpaRepository { 7 | 8 | List findByStatus(TravelRequestStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/TravelRequestStatus.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | public enum TravelRequestStatus { 4 | CREATED, ACCEPTED, REFUSED; 5 | } 6 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/TravelService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | 4 | import app.car.cap09.interfaces.outcoming.GMapsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.time.LocalDateTime; 9 | import java.util.List; 10 | 11 | @Service 12 | public class TravelService { 13 | 14 | 15 | @Autowired 16 | TravelRequestRepository travelRequestRepository; 17 | 18 | @Autowired 19 | GMapsService gMapsService; 20 | 21 | private static final int MAX_TRAVEL_TIME = 600; 22 | 23 | public TravelRequest saveTravelRequest(TravelRequest travelRequest) { 24 | travelRequest.setStatus(TravelRequestStatus.CREATED); 25 | travelRequest.setCreationDate(LocalDateTime.now()); 26 | return travelRequestRepository.save(travelRequest); 27 | } 28 | 29 | 30 | public List listNearbyTravelRequests(String currentAddress) { 31 | List requests = travelRequestRepository.findByStatus(TravelRequestStatus.CREATED); 32 | return requests 33 | .stream() 34 | .filter(tr -> gMapsService.getDistanceBetweenAddresses(currentAddress, tr.getOrigin()) < MAX_TRAVEL_TIME) 35 | .toList(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/User.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | 4 | import java.util.List; 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.ElementCollection; 7 | import jakarta.persistence.Entity; 8 | import jakarta.persistence.GeneratedValue; 9 | import jakarta.persistence.Id; 10 | import jakarta.persistence.Table; 11 | import lombok.Data; 12 | 13 | @Data 14 | @Entity 15 | @Table(name = "users") 16 | public class User { 17 | 18 | @Id 19 | @GeneratedValue 20 | Long id; 21 | 22 | @Column(unique = true) 23 | String username; 24 | String password; 25 | 26 | Boolean enabled; 27 | 28 | @ElementCollection 29 | List roles; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/domain/UserRepository.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.domain; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface UserRepository extends JpaRepository { 6 | } 7 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/DriverAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming; 2 | 3 | import app.car.cap09.domain.Driver; 4 | import app.car.cap09.interfaces.incoming.errorhandling.ErrorResponse; 5 | import app.car.cap09.interfaces.incoming.output.Drivers; 6 | import io.swagger.v3.oas.annotations.Operation; 7 | import io.swagger.v3.oas.annotations.Parameter; 8 | import io.swagger.v3.oas.annotations.media.Content; 9 | import io.swagger.v3.oas.annotations.media.Schema; 10 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 11 | import io.swagger.v3.oas.annotations.tags.Tag; 12 | import org.springframework.hateoas.CollectionModel; 13 | import org.springframework.hateoas.EntityModel; 14 | 15 | @Tag(name = "Driver API", description = "Manipula dados de motoristas.") 16 | public interface DriverAPI { 17 | 18 | 19 | @Operation(description = "Lista todos os motoristas disponíveis") 20 | Drivers listDrivers(int page); 21 | 22 | 23 | @Operation( 24 | description = "Localiza um motorista específico", 25 | responses = { 26 | @ApiResponse(responseCode = "200", description = "Caso o motorista tenha sido encontrado na base"), 27 | @ApiResponse(responseCode = "404", 28 | description = "Caso o motorista não tenha sido encontrado", 29 | content = @Content(schema = @Schema(implementation = ErrorResponse.class)) 30 | ) 31 | }) 32 | Driver findDriver( 33 | @Parameter(description = "ID do motorista a ser localizado") Long id) ; 34 | 35 | Driver createDriver( 36 | @Parameter(description = "Dados do motorista a ser criado") Driver driver) ; 37 | 38 | Driver fullUpdateDriver(Long id, Driver driver); 39 | 40 | Driver incrementalUpdateDriver(Long id, Driver driver) ; 41 | 42 | void deleteDriver(Long id) ; 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/DriverAPIImpl.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming; 2 | 3 | import app.car.cap09.domain.Driver; 4 | import app.car.cap09.domain.DriverRepository; 5 | import app.car.cap09.interfaces.incoming.output.Drivers; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.PageRequest; 9 | import org.springframework.hateoas.EntityModel; 10 | import org.springframework.hateoas.Link; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.web.bind.annotation.*; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Optional; 20 | 21 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; 22 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; 23 | 24 | @Service 25 | @RestController() 26 | @RequestMapping(path = "/drivers", produces = MediaType.APPLICATION_JSON_VALUE) 27 | public class DriverAPIImpl implements DriverAPI { 28 | 29 | private static final int PAGE_SIZE = 10; 30 | 31 | @Autowired 32 | DriverRepository driverRepository; 33 | 34 | @GetMapping 35 | public Drivers listDrivers(@RequestParam(name = "page", defaultValue = "0") int page) { 36 | Page driverPage = driverRepository.findAll(PageRequest.of(page, PAGE_SIZE)); 37 | 38 | List> driverList = driverPage.stream().map(EntityModel::of).toList(); 39 | 40 | Link lastPageLink = linkTo(methodOn(DriverAPIImpl.class) 41 | .listDrivers(driverPage.getTotalPages() - 1)) 42 | .withRel("lastPage"); 43 | 44 | return new Drivers(driverList, lastPageLink); 45 | } 46 | 47 | @GetMapping("/{id}") 48 | public Driver findDriver( 49 | @PathVariable("id") Long id) { 50 | return driverRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 51 | } 52 | 53 | @PostMapping 54 | public Driver createDriver( 55 | @RequestBody Driver driver) { 56 | return driverRepository.save(driver); 57 | } 58 | 59 | @PutMapping("/{id}") 60 | public Driver fullUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 61 | Driver foundDriver = findDriver(id); 62 | foundDriver.setBirthDate(driver.getBirthDate()); 63 | foundDriver.setName(driver.getName()); 64 | return driverRepository.save(foundDriver); 65 | } 66 | 67 | @PatchMapping("/{id}") 68 | public Driver incrementalUpdateDriver(@PathVariable("id") Long id, @RequestBody Driver driver) { 69 | Driver foundDriver = findDriver(id); 70 | foundDriver.setBirthDate(Optional.ofNullable(driver.getBirthDate()).orElse(foundDriver.getBirthDate())); 71 | foundDriver.setName(Optional.ofNullable(driver.getName()).orElse(foundDriver.getName())); 72 | return driverRepository.save(foundDriver); 73 | } 74 | 75 | @DeleteMapping("/{id}") 76 | public void deleteDriver(@PathVariable("id") Long id) { 77 | driverRepository.delete(findDriver(id)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/PassengerAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming; 2 | 3 | import app.car.cap09.domain.Passenger; 4 | import app.car.cap09.domain.PassengerRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import jakarta.annotation.security.RolesAllowed; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.server.ResponseStatusException; 14 | 15 | @Service 16 | @RestController 17 | @RequestMapping(path="/passengers", produces = MediaType.APPLICATION_JSON_VALUE) 18 | public class PassengerAPI { 19 | 20 | @Autowired 21 | PassengerRepository passengerRepository; 22 | 23 | @GetMapping() 24 | public List listPassengers() { 25 | return passengerRepository.findAll(); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Passenger findPassenger(@PathVariable("id") Long id) { 30 | return passengerRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 31 | } 32 | 33 | @PostMapping 34 | @RolesAllowed("ADMIN") 35 | public Passenger createPassenger(@RequestBody Passenger passenger) { 36 | return passengerRepository.save(passenger); 37 | } 38 | 39 | @PutMapping("/{id}") 40 | public Passenger fullUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 41 | Passenger p = findPassenger(id); 42 | p.setName(passenger.getName()); 43 | return passengerRepository.save(p); 44 | } 45 | 46 | @PatchMapping("/{id}") 47 | public Passenger incrementalUpdatePassenger(@PathVariable("id") Long id, @RequestBody Passenger passenger) { 48 | Passenger foundPassenger = findPassenger(id); 49 | foundPassenger.setName(Optional.ofNullable(passenger.getName()).orElse(foundPassenger.getName())); 50 | return passengerRepository.save(foundPassenger); 51 | } 52 | 53 | @DeleteMapping("/{id}") 54 | public void deletePassenger(@PathVariable("id") Long id) { 55 | passengerRepository.delete(findPassenger(id)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/TravelRequestAPI.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming; 2 | 3 | 4 | import app.car.cap09.domain.TravelRequest; 5 | import app.car.cap09.domain.TravelService; 6 | import app.car.cap09.interfaces.incoming.input.TravelRequestInput; 7 | import app.car.cap09.interfaces.incoming.mapping.TravelRequestMapper; 8 | import app.car.cap09.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import jakarta.validation.Valid; 16 | import java.util.List; 17 | 18 | @Service 19 | @RestController 20 | @RequestMapping(path = "/travelRequests", produces = MediaType.APPLICATION_JSON_VALUE) 21 | public class TravelRequestAPI { 22 | 23 | @Autowired 24 | TravelService travelService; 25 | 26 | @Autowired 27 | TravelRequestMapper mapper; 28 | 29 | @PostMapping 30 | public EntityModel makeTravelRequest (@RequestBody @Valid TravelRequestInput travelRequestInput) { 31 | TravelRequest request = travelService.saveTravelRequest(mapper.map(travelRequestInput)); 32 | TravelRequestOutput output = mapper.map(request); 33 | return mapper.buildOutputModel(request, output); 34 | } 35 | 36 | 37 | @GetMapping("/nearby") 38 | public List> listNearbyRequests(@RequestParam String currentAddress) { 39 | List requests = travelService.listNearbyTravelRequests(currentAddress); 40 | return mapper.buildOutputModel(requests); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/errorhandling/DefaultErrorHandler.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.errorhandling; 2 | 3 | import io.swagger.v3.oas.annotations.media.Content; 4 | import io.swagger.v3.oas.annotations.media.Schema; 5 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 6 | import io.swagger.v3.oas.annotations.responses.ApiResponses; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.MessageSource; 9 | import org.springframework.context.i18n.LocaleContextHolder; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.validation.FieldError; 12 | import org.springframework.web.bind.MethodArgumentNotValidException; 13 | import org.springframework.web.bind.annotation.ExceptionHandler; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | import org.springframework.web.bind.annotation.RestControllerAdvice; 16 | 17 | import java.util.List; 18 | import java.util.stream.Collectors; 19 | 20 | 21 | @RestControllerAdvice 22 | public class DefaultErrorHandler { 23 | 24 | @Autowired 25 | private MessageSource messageSource; 26 | 27 | @ExceptionHandler(MethodArgumentNotValidException.class) 28 | @ResponseStatus(HttpStatus.BAD_REQUEST) 29 | @ApiResponses( 30 | @ApiResponse(responseCode = "400", content = @Content( 31 | mediaType = "application/json", 32 | schema = @Schema(implementation = ErrorResponse.class) 33 | )) 34 | ) 35 | public ErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex) { 36 | 37 | List messages = ex 38 | .getBindingResult() 39 | .getFieldErrors() 40 | .stream() 41 | .map(this::getMessage) 42 | .toList(); 43 | 44 | return new ErrorResponse(messages); 45 | } 46 | 47 | private ErrorData getMessage(FieldError fieldError) { 48 | 49 | return new ErrorData(messageSource.getMessage(fieldError, LocaleContextHolder.getLocale())); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/errorhandling/ErrorData.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.errorhandling; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | @AllArgsConstructor 8 | @Data 9 | public class ErrorData { 10 | 11 | private final String message; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/errorhandling/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.errorhandling; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @AllArgsConstructor 9 | @Data 10 | public class ErrorResponse { 11 | 12 | List errors; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/errorhandling/LocaleResolver.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.errorhandling; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.springframework.http.HttpHeaders; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; 7 | 8 | import jakarta.servlet.http.HttpServletRequest; 9 | 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.Locale; 13 | import java.util.Optional; 14 | 15 | @Component 16 | public class LocaleResolver extends AcceptHeaderLocaleResolver { 17 | 18 | private static final Locale DEFAULT_LOCALE = Locale.of("pt", "BR"); 19 | 20 | private static final List ACCEPTED_LOCALES = Arrays.asList( 21 | 22 | DEFAULT_LOCALE, 23 | new Locale("en") 24 | ); 25 | 26 | @Override 27 | public Locale resolveLocale(HttpServletRequest request) { 28 | final String acceptLanguageHeader = request.getHeader("Accept-Language"); 29 | if (StringUtils.isBlank(acceptLanguageHeader) || acceptLanguageHeader.trim().equals("*")) { 30 | return DEFAULT_LOCALE; 31 | } 32 | List list = Locale.LanguageRange.parse(acceptLanguageHeader); 33 | Locale locale = Locale.lookup(list, ACCEPTED_LOCALES); 34 | return Optional.ofNullable(locale).orElse(DEFAULT_LOCALE); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/input/TravelRequestInput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.input; 2 | 3 | import lombok.Data; 4 | 5 | import jakarta.validation.constraints.NotEmpty; 6 | import jakarta.validation.constraints.NotNull; 7 | 8 | @Data 9 | public class TravelRequestInput { 10 | 11 | 12 | @NotNull(message = "O campo passengerId não pode ser nulo") 13 | Long passengerId; 14 | 15 | @NotEmpty(message = "O campo origin não pode estar em branco") 16 | String origin; 17 | 18 | @NotEmpty(message = "O campo destination não pode estar em branco") 19 | String destination; 20 | } 21 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/mapping/TravelRequestMapper.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.mapping; 2 | 3 | import app.car.cap09.domain.Passenger; 4 | import app.car.cap09.domain.PassengerRepository; 5 | import app.car.cap09.domain.TravelRequest; 6 | import app.car.cap09.interfaces.incoming.PassengerAPI; 7 | import app.car.cap09.interfaces.incoming.input.TravelRequestInput; 8 | import app.car.cap09.interfaces.incoming.output.TravelRequestOutput; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.hateoas.EntityModel; 11 | import org.springframework.hateoas.Link; 12 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.server.ResponseStatusException; 16 | 17 | import java.util.List; 18 | 19 | @Component 20 | public class TravelRequestMapper { 21 | 22 | @Autowired 23 | private PassengerRepository passengerRepository; 24 | 25 | public TravelRequest map(TravelRequestInput input) { 26 | 27 | Passenger passenger = passengerRepository.findById(input.getPassengerId()) 28 | .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); 29 | 30 | TravelRequest travelRequest = new TravelRequest(); 31 | travelRequest.setOrigin(input.getOrigin()); 32 | travelRequest.setDestination(input.getDestination()); 33 | travelRequest.setPassenger(passenger); 34 | 35 | return travelRequest; 36 | 37 | } 38 | 39 | public TravelRequestOutput map(TravelRequest travelRequest) { 40 | TravelRequestOutput travelRequestOutput = new TravelRequestOutput(); 41 | 42 | travelRequestOutput.setCreationDate(travelRequest.getCreationDate()); 43 | travelRequestOutput.setDestination(travelRequest.getDestination()); 44 | travelRequestOutput.setId(travelRequest.getId()); 45 | travelRequestOutput.setOrigin(travelRequest.getOrigin()); 46 | travelRequestOutput.setStatus(travelRequest.getStatus()); 47 | 48 | return travelRequestOutput; 49 | } 50 | 51 | public EntityModel buildOutputModel(TravelRequest travelRequest, TravelRequestOutput output) { 52 | EntityModel model = EntityModel.of(output); 53 | 54 | Link passengerLink = WebMvcLinkBuilder 55 | .linkTo(PassengerAPI.class) 56 | .slash(travelRequest.getPassenger().getId()) 57 | .withRel("passenger") 58 | .withTitle(travelRequest.getPassenger().getName()); 59 | model.add(passengerLink); 60 | return model; 61 | } 62 | 63 | public List> buildOutputModel(List requests) { 64 | return requests.stream().map(tr -> buildOutputModel(tr, map(tr))).toList(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/output/Drivers.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.output; 2 | 3 | import app.car.cap09.domain.Driver; 4 | import lombok.Getter; 5 | import org.springframework.hateoas.EntityModel; 6 | import org.springframework.hateoas.Link; 7 | import java.util.List; 8 | 9 | 10 | @Getter 11 | public class Drivers{ 12 | 13 | private List> drivers; 14 | 15 | private Link[] links; 16 | 17 | public Drivers(List> content, Link... links) { 18 | this.drivers = content; 19 | this.links = links; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/incoming/output/TravelRequestOutput.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming.output; 2 | 3 | import app.car.cap09.domain.TravelRequestStatus; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | @Data 9 | public class TravelRequestOutput { 10 | 11 | Long id; 12 | String origin; 13 | String destination; 14 | TravelRequestStatus status; 15 | LocalDateTime creationDate; 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cap09/src/main/java/app/car/cap09/interfaces/outcoming/GMapsService.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.outcoming; 2 | 3 | 4 | import com.jayway.jsonpath.JsonPath; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class GMapsService { 13 | 14 | 15 | @Value("${app.car.domain.googlemaps.apikey}") 16 | private String appKey; 17 | 18 | @Value("${interfaces.outcoming.gmaps.host:https://maps.googleapis.com}") 19 | private String gMapsHost; 20 | 21 | private static final String GMAPS_TEMPLATE = "/maps/api/directions/json?origin={origin}&destination={destination}&key={key}"; 22 | 23 | public Integer getDistanceBetweenAddresses(String addressOne, String addressTwo) { 24 | 25 | RestTemplate template = new RestTemplate(); 26 | String jsonResult = template.getForObject(gMapsHost + GMAPS_TEMPLATE, String.class, addressOne, addressTwo, appKey); 27 | 28 | List results = JsonPath.parse(jsonResult).read("$..legs[*].duration.value"); 29 | return results.stream().min(Integer::compareTo).orElse(Integer.MAX_VALUE); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cap09/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | app.car.domain.googlemaps.apikey=chaveGoogle 2 | 3 | server.ssl.key-store=classpath:keystore.p12 4 | server.ssl.key-store-password=restbook 5 | server.ssl.key-store-type=PKCS12 6 | server.ssl.key-alias=car 7 | -------------------------------------------------------------------------------- /cap09/src/main/resources/i18n/messages_en.properties: -------------------------------------------------------------------------------- 1 | NotNull=The field {0} must not be null 2 | NotEmpty=The field {0} must not be empty -------------------------------------------------------------------------------- /cap09/src/main/resources/i18n/messages_pt_BR.properties: -------------------------------------------------------------------------------- 1 | NotNull=O campo {0} não pode ser nulo 2 | NotEmpty=O campo {0} não pode estar em branco -------------------------------------------------------------------------------- /cap09/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesaudate/rest-v2/e63f1ca04a94b9f740dd59218ddca102abe68111/cap09/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /cap09/src/test/java/app/car/cap09/Cap09ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Cap09ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cap09/src/test/java/app/car/cap09/infrastructure/FileUtils.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.infrastructure; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.core.io.ClassPathResource; 5 | 6 | import java.io.InputStream; 7 | import java.util.Map; 8 | 9 | public class FileUtils { 10 | 11 | 12 | @SneakyThrows 13 | public static String loadFileContents(String fileName) { 14 | 15 | InputStream is = new ClassPathResource(fileName).getInputStream(); 16 | byte[] data = new byte[is.available()]; 17 | is.read(data); 18 | return new String(data); 19 | } 20 | 21 | public static String loadFileContents(String fileName, Map replacements) { 22 | String fileContents = loadFileContents(fileName); 23 | 24 | for (Map.Entry entry : replacements.entrySet()) { 25 | fileContents = fileContents.replace("{{" + entry.getKey() + "}}", entry.getValue()); 26 | } 27 | return fileContents; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cap09/src/test/java/app/car/cap09/interfaces/incoming/PassengerAPITestIT.java: -------------------------------------------------------------------------------- 1 | package app.car.cap09.interfaces.incoming; 2 | 3 | import io.restassured.RestAssured; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.web.server.LocalServerPort; 8 | 9 | import static io.restassured.RestAssured.basic; 10 | import static io.restassured.RestAssured.given; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.notNullValue; 13 | 14 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 15 | class PassengerAPITestIT { 16 | 17 | @LocalServerPort 18 | private int port; 19 | 20 | @BeforeEach 21 | void setup() { 22 | RestAssured.baseURI = "https://localhost:" + port; 23 | RestAssured.useRelaxedHTTPSValidation(); 24 | RestAssured.authentication = basic("admin", "password"); 25 | } 26 | 27 | @Test 28 | void testCreatePassenger() { 29 | 30 | 31 | String createPassengerJSON = "{\"name\":\"Alexandre Saudate\"}"; 32 | 33 | 34 | given() 35 | .contentType(io.restassured.http.ContentType.JSON) 36 | .body(createPassengerJSON) 37 | .post("/passengers") 38 | .then() 39 | .statusCode(200) 40 | .body("id", notNullValue()) 41 | .body("name", equalTo("Alexandre Saudate")) 42 | ; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cap09/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | interfaces.outcoming.gmaps.host=http://localhost:${wiremock.server.port} -------------------------------------------------------------------------------- /cap09/src/test/resources/requests/passengers_api/create_new_passenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alexandre Saudate" 3 | } -------------------------------------------------------------------------------- /cap09/src/test/resources/requests/travel_requests_api/create_new_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "passengerId":"{{passengerId}}", 3 | "origin":"Avenida Paulista, 1000", 4 | "destination":"Avenida Ipiranga, 100" 5 | } --------------------------------------------------------------------------------