diff --git a/MottuFlow/jsonsAPIREST/API - MottuFlow.postman_collection.json b/MottuFlow/jsonsAPIREST/API - MottuFlow.postman_collection.json index aceec54..d8f7c33 100644 --- a/MottuFlow/jsonsAPIREST/API - MottuFlow.postman_collection.json +++ b/MottuFlow/jsonsAPIREST/API - MottuFlow.postman_collection.json @@ -1,10 +1,10 @@ { "info": { - "_postman_id": "8ba14ee2-7d92-43a3-90b1-6de1d3e44871", + "_postman_id": "2d6678fb-b100-479d-a5ee-a2e5a535dea4", "name": "API - MottuFlow", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "39334205", - "_collection_link": "https://galactic-resonance-365575.postman.co/workspace/MottuFlow-Endpoints~479ea491-7731-4683-b0a4-56afc7df5c83/collection/39334205-8ba14ee2-7d92-43a3-90b1-6de1d3e44871?action=share&source=collection_link&creator=39334205" + "_collection_link": "https://galactic-resonance-365575.postman.co/workspace/MottuFlow-Endpoints~479ea491-7731-4683-b0a4-56afc7df5c83/collection/39334205-2d6678fb-b100-479d-a5ee-a2e5a535dea4?action=share&source=collection_link&creator=39334205" }, "item": [ { @@ -22,17 +22,7 @@ "type": "noauth" }, "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "User-Agent", - "value": "insomnia/11.5.0", - "disabled": true - } - ], + "header": [], "body": { "mode": "raw", "raw": "{\n \"email\": \"admin@email.com\",\n \"senha\": \"adminmottu\"\n}", @@ -319,14 +309,14 @@ } }, "url": { - "raw": "{{baseUrl}}/funcionario/editar/2", + "raw": "{{baseUrl}}/funcionario/editar/4", "host": [ "{{baseUrl}}" ], "path": [ "funcionario", "editar", - "2" + "4" ] } }, @@ -850,6 +840,40 @@ }, "response": [] }, + { + "name": "Buscar Moto por Modelo (GET)", + "protocolProfileBehavior": { + "followRedirects": true, + "disableUrlEncoding": false, + "disableCookies": false + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/motos/buscar-por-modelo/Mottu Pop", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "motos", + "buscar-por-modelo", + "Mottu Pop" + ] + } + }, + "response": [] + }, { "name": "Criar Moto (POST)", "protocolProfileBehavior": { @@ -1651,6 +1675,40 @@ }, "response": [] }, + { + "name": "Buscar Status por Moto (GET)", + "protocolProfileBehavior": { + "followRedirects": true, + "disableUrlEncoding": false, + "disableCookies": false + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/status/buscar-por-moto/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "status", + "buscar-por-moto", + "1" + ] + } + }, + "response": [] + }, { "name": "Buscar Status por TIpo Status (GET)", "protocolProfileBehavior": { @@ -2263,6 +2321,49 @@ } } ] + }, + { + "name": "MasteringDatabase", + "item": [ + { + "name": "DATABASE - relatorioFuncionario", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/database/funcionario/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "database", + "funcionario", + "1" + ] + } + }, + "response": [] + }, + { + "name": "DATABASE - relatorioMoto", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/database/moto/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "database", + "moto", + "1" + ] + } + }, + "response": [] + } + ] } ], "auth": { @@ -2306,7 +2407,7 @@ }, { "key": "jwt", - "value": "" + "value": "" } ] -} \ No newline at end of file +} diff --git a/MottuFlow/pom.xml b/MottuFlow/pom.xml index 348e659..2636ba7 100644 --- a/MottuFlow/pom.xml +++ b/MottuFlow/pom.xml @@ -1,4 +1,3 @@ - efetuarLogin( @Valid @RequestBody DadosLogin dados ) { var authToken = new UsernamePasswordAuthenticationToken( dados.email(), dados.senha() ); @@ -46,6 +48,7 @@ public ResponseEntity efetuarLogin( @Valid @RequestBody DadosLogin d return ResponseEntity.ok( new DadosToken( tokenAcesso, refreshToken, expiracaoRefresh ) ); } + @SecurityRequirements() @PostMapping( "/atualizar-token" ) public ResponseEntity atualizarToken( @Valid @RequestBody DadosRefreshToken dados ) { Funcionario funcionario = fS.validarRefreshTokenFuncionario( dados.refreshToken() ); @@ -58,6 +61,7 @@ public ResponseEntity atualizarToken( @Valid @RequestBody DadosRefre return ResponseEntity.ok(new DadosToken(tokenAcesso, refreshTokenExistente, expiracaoRefresh)); } + @SecurityRequirements() @PostMapping("/verificar-jwt") public ResponseEntity verificarJwt(@RequestBody Map body) { String tokenAcesso = body.get("tokenAcesso"); diff --git a/MottuFlow/src/main/java/com/sprint/MottuFlow/controller/rest/MasteringDatabaseController.java b/MottuFlow/src/main/java/com/sprint/MottuFlow/controller/rest/MasteringDatabaseController.java new file mode 100644 index 0000000..64352a0 --- /dev/null +++ b/MottuFlow/src/main/java/com/sprint/MottuFlow/controller/rest/MasteringDatabaseController.java @@ -0,0 +1,26 @@ +package com.sprint.MottuFlow.controller.rest; + +import org.springframework.web.bind.annotation.*; +import com.sprint.MottuFlow.domain.masteringdatabase.MasteringDatabaseService; +import java.util.Map; + +@RestController +@RequestMapping("/api/database") +public class MasteringDatabaseController { + + private final MasteringDatabaseService mdS; + + public MasteringDatabaseController(MasteringDatabaseService mdS) { + this.mdS = mdS; + } + + @GetMapping("/funcionario/{id}") + public String relatorioFuncionario(@PathVariable Long id) { + return mdS.executarRelatorioFuncionario(id); + } + + @GetMapping("/moto/{id}") + public String motoJson(@PathVariable Long id) { + return mdS.executarFuncaoMoto(id); + } +} diff --git a/MottuFlow/src/main/java/com/sprint/MottuFlow/domain/masteringdatabase/MasteringDatabaseService.java b/MottuFlow/src/main/java/com/sprint/MottuFlow/domain/masteringdatabase/MasteringDatabaseService.java new file mode 100644 index 0000000..2399348 --- /dev/null +++ b/MottuFlow/src/main/java/com/sprint/MottuFlow/domain/masteringdatabase/MasteringDatabaseService.java @@ -0,0 +1,67 @@ +package com.sprint.MottuFlow.domain.masteringdatabase; + +import org.springframework.stereotype.Service; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; + +import javax.sql.DataSource; +import java.sql.Clob; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Map; + +@Service +public class MasteringDatabaseService { + + private final SimpleJdbcCall relatorioFuncionarioCall; + private final SimpleJdbcCall funcaoMotoCall; + private final DataSource dataSource; + + public MasteringDatabaseService(DataSource dataSource) { + this.dataSource = dataSource; + + this.relatorioFuncionarioCall = new SimpleJdbcCall(dataSource) + .withCatalogName("PCT_MOTTUFLOW") + .withProcedureName("RELATORIO_FUNCIONARIO_MOTO_STATUS") + .withoutProcedureColumnMetaDataAccess() + .declareParameters( + new org.springframework.jdbc.core.SqlParameter("P_ID_FUNCIONARIO", Types.NUMERIC), + new SqlOutParameter("P_JSON", Types.CLOB) + ); + + this.funcaoMotoCall = new SimpleJdbcCall(dataSource) + .withCatalogName("PCT_MOTTUFLOW") + .withFunctionName("MOTO_TO_JSON"); + + } + + public String executarRelatorioFuncionario(Long idFuncionario) { + Map out = relatorioFuncionarioCall.execute(Map.of("P_ID_FUNCIONARIO", idFuncionario)); + Object clobObj = out.get("P_JSON"); + + if (clobObj instanceof Clob) { + Clob clob = (Clob) clobObj; + try { + return clob.getSubString(1, (int) clob.length()); + } catch (SQLException e) { + throw new RuntimeException("Erro ao ler CLOB", e); + } + } + return clobObj != null ? clobObj.toString() : null; + } + + public String executarFuncaoMoto(Long idMoto) { + Object clobObj = funcaoMotoCall.executeFunction(Object.class, Map.of("P_ID_MOTO", idMoto)); + + if (clobObj instanceof Clob) { + Clob clob = (Clob) clobObj; + try { + return clob.getSubString(1, (int) clob.length()); + } catch (SQLException e) { + throw new RuntimeException("Erro ao ler CLOB", e); + } + } + return clobObj != null ? clobObj.toString() : null; + } +} diff --git a/MottuFlow/src/main/resources/application.properties b/MottuFlow/src/main/resources/application.properties index 542c771..e739027 100644 --- a/MottuFlow/src/main/resources/application.properties +++ b/MottuFlow/src/main/resources/application.properties @@ -1,40 +1,23 @@ spring.application.name=MottuFlow -spring.datasource.url=jdbc:mysql://localhost:3306/mottuflow?createDatabaseIfNotExist=true -spring.datasource.username=root -spring.datasource.password=root - -spring.jpa.hibernate.ddl-auto=update +spring.datasource.url=jdbc:oracle:thin:@oracle.fiap.com.br:1521/orcl +spring.datasource.username=rm554874 +spring.datasource.password=231105 +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver + +spring.datasource.hikari.maximum-pool-size=5 +spring.datasource.hikari.minimum-idle=1 +spring.datasource.hikari.idle-timeout=10000 +spring.datasource.hikari.max-lifetime=60000 +spring.datasource.hikari.connection-timeout=30000 + +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect spring.jpa.show-sql=true -spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect +spring.jpa.hibernate.ddl-auto=none spring.flyway.enabled=true spring.flyway.locations=classpath:db/migration -spring.flyway.repair=true +spring.flyway.baseline-on-migrate=true spring.flyway.repair-on-migrate=true -logging.level.root=WARN - -logging.level.org.springframework=WARN -logging.level.org.hibernate=WARN -logging.level.com.mysql.cj=WARN -logging.level.oracle.jdbc=WARN -logging.level.org.apache.tomcat=WARN -logging.level.org.apache.catalina=WARN -logging.level.org.springframework.security=WARN -logging.level.org.springframework.web=WARN -logging.level.org.springframework.boot=WARN -logging.level.org.springframework.data=WARN -logging.level.org.springframework.context=WARN -logging.level.org.springframework.validation=WARN -logging.level.org.hibernate.orm.deprecation=ERROR -spring.jpa.open-in-view=false -logging.level.org.springframework.orm.jpa.JpaBaseConfiguration=ERROR - -logging.level.com.sprint.MottuFlow=WARN - -spring.main.allow-bean-definition-overriding=true - -server.address=0.0.0.0 server.port=8080 - diff --git a/MottuFlow/src/main/resources/db/migration/V1__create-table-baseline.sql b/MottuFlow/src/main/resources/db/migration/V1__create-table-baseline.sql new file mode 100644 index 0000000..70e8757 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V1__create-table-baseline.sql @@ -0,0 +1,5 @@ +CREATE TABLE baseline_placeholder ( + id NUMBER(1) +); + +DROP TABLE baseline_placeholder; diff --git a/MottuFlow/src/main/resources/db/migration/V1__create-table-funcionario.sql b/MottuFlow/src/main/resources/db/migration/V1__create-table-funcionario.sql deleted file mode 100644 index 3b014be..0000000 --- a/MottuFlow/src/main/resources/db/migration/V1__create-table-funcionario.sql +++ /dev/null @@ -1,25 +0,0 @@ -CREATE TABLE funcionario ( - id_funcionario BIGINT PRIMARY KEY AUTO_INCREMENT, - nome VARCHAR(100) NOT NULL, - cpf VARCHAR(14) NOT NULL UNIQUE, - cargo VARCHAR(50) NOT NULL, - telefone VARCHAR(20) NOT NULL, - email VARCHAR(50) NOT NULL UNIQUE, - senha VARCHAR(255) NOT NULL, - refresh_token VARCHAR(255) DEFAULT NULL, - expiracao_refresh_token DATETIME DEFAULT NULL -); - -INSERT INTO funcionario ( - nome, - cpf, - cargo, - telefone, - email, - senha, - refresh_token, - expiracao_refresh_token -) VALUES -('CONTA ADMIN', '000.000.000-00', 'ADMIN', '(00) 00000-0000', 'admin@email.com', '$2a$12$HkHTbCOCrUW55EXH8MjZfO.8MpjpyKWsVd.4oM1xCbceqtCpaqOFK', NULL, NULL), -('João Mecânico', '111.111.111-11', 'MECANICO', '(11) 11111-1111', 'joao@email.com', '$2a$12$WvSaeLKOeMhnaT65b1cHaeHQKyOz5M0cNDDNZ0eDbdmeLqoYbnFhi', NULL, NULL), -('Maria Gerente', '222.222.222-22', 'GERENTE', '(22) 22222-2222', 'maria@email.com', '$2a$12$AymGyslp9tPClu/sIsfaNOVcAgUEdWXfrqG8liodWVIczQA9XYJ/e', NULL, NULL); \ No newline at end of file diff --git a/MottuFlow/src/main/resources/db/migration/V2__create-table-funcionario.sql b/MottuFlow/src/main/resources/db/migration/V2__create-table-funcionario.sql new file mode 100644 index 0000000..a36ced7 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V2__create-table-funcionario.sql @@ -0,0 +1,48 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE funcionario ( + id_funcionario NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + nome VARCHAR2(100) NOT NULL, + cpf VARCHAR2(14) NOT NULL UNIQUE, + cargo VARCHAR2(50) NOT NULL, + telefone VARCHAR2(20) NOT NULL, + email VARCHAR2(50) NOT NULL UNIQUE, + senha VARCHAR2(255) NOT NULL, + refresh_token VARCHAR2(255) DEFAULT NULL, + expiracao_refresh_token TIMESTAMP DEFAULT NULL + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO funcionario (nome, cpf, cargo, telefone, email, senha) +SELECT 'CONTA ADMIN', '00000000000', 'ADMIN', '00000000000', 'admin@email.com', '$2a$12$e6QJwFNdnau90pQN/3OkFeelAPVi8nCsJped.YQYxEy/573E1nR1G' +FROM dual +WHERE NOT EXISTS (SELECT 1 FROM funcionario WHERE email = 'admin@email.com'); + +INSERT INTO funcionario (nome, cpf, cargo, telefone, email, senha) +SELECT 'Joao Silva', '12345678900', 'Gerente', '11999990001', 'joao.silva@email.com', '$2a$12$P7BetbmT3nap8KkA/sD4aOHD8SI2JHSgkUrCuuzljXtd.wtpbEFHC' +FROM dual +WHERE NOT EXISTS (SELECT 1 FROM funcionario WHERE email = 'joao.silva@email.com'); + +INSERT INTO funcionario (nome, cpf, cargo, telefone, email, senha) +SELECT 'Maria Souza', '22345678900', 'Tecnico', '11999990002', 'maria.souza@email.com', '$2a$12$P7BetbmT3nap8KkA/sD4aOHD8SI2JHSgkUrCuuzljXtd.wtpbEFHC' +FROM dual +WHERE NOT EXISTS (SELECT 1 FROM funcionario WHERE email = 'maria.souza@email.com'); + +INSERT INTO funcionario (nome, cpf, cargo, telefone, email, senha) +SELECT 'Carlos Lima', '32345678900', 'Mecanico', '11999990003', 'carlos.lima@email.com', '$2a$12$P7BetbmT3nap8KkA/sD4aOHD8SI2JHSgkUrCuuzljXtd.wtpbEFHC' +FROM dual +WHERE NOT EXISTS (SELECT 1 FROM funcionario WHERE email = 'carlos.lima@email.com'); + +INSERT INTO funcionario (nome, cpf, cargo, telefone, email, senha) +SELECT 'Ana Costa', '42345678900', 'Supervisor', '11999990004', 'ana.costa@email.com', 'senha123' +FROM dual +WHERE NOT EXISTS (SELECT 1 FROM funcionario WHERE email = 'ana.costa@email.com'); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V2__create-table-patio.sql b/MottuFlow/src/main/resources/db/migration/V2__create-table-patio.sql deleted file mode 100644 index b1752fc..0000000 --- a/MottuFlow/src/main/resources/db/migration/V2__create-table-patio.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE patio ( - id_patio BIGINT PRIMARY KEY AUTO_INCREMENT, - nome VARCHAR(100) NOT NULL, - endereco VARCHAR(200) NOT NULL, - capacidade_maxima INT NOT NULL -); - -INSERT INTO patio (nome, endereco, capacidade_maxima) VALUES -('Patio Central', 'Rua Principal, 1000', 50), -('Patio Norte', 'Av. Norte, 250', 30), -('Patio Sul', 'Av. Sul, 500', 40); diff --git a/MottuFlow/src/main/resources/db/migration/V3__create-table-moto.sql b/MottuFlow/src/main/resources/db/migration/V3__create-table-moto.sql deleted file mode 100644 index c54d772..0000000 --- a/MottuFlow/src/main/resources/db/migration/V3__create-table-moto.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE moto ( - id_moto BIGINT PRIMARY KEY AUTO_INCREMENT, - placa VARCHAR(10) NOT NULL, - modelo VARCHAR(50) NOT NULL, - fabricante VARCHAR(50) NOT NULL, - ano INT NOT NULL, - id_patio BIGINT NOT NULL, - localizacao_atual VARCHAR(100) NOT NULL, - FOREIGN KEY (id_patio) REFERENCES patio(id_patio) - ON DELETE RESTRICT - ON UPDATE CASCADE -); - -INSERT INTO moto (placa, modelo, fabricante, ano, id_patio, localizacao_atual) VALUES -('ABC-1234', 'Mottu Pop', 'Honda', 2022, 1, 'Vaga 01'), -('DEF-5678', 'Mottu Sport', 'TVS', 2021, 1, 'Vaga 02'), -('GHI-9012', 'Mottu E', 'Yadea', 2023, 2, 'Vaga 01'), -('JKL-3456', 'Mottu Pop', 'Honda', 2022, 3, 'Vaga 03'); \ No newline at end of file diff --git a/MottuFlow/src/main/resources/db/migration/V3__create-table-patio.sql b/MottuFlow/src/main/resources/db/migration/V3__create-table-patio.sql new file mode 100644 index 0000000..19c9650 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V3__create-table-patio.sql @@ -0,0 +1,38 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE patio ( + id_patio NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + nome VARCHAR2(100) NOT NULL, + endereco VARCHAR2(200) NOT NULL, + capacidade_maxima NUMBER NOT NULL + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO patio (id_patio, nome, endereco, capacidade_maxima) +SELECT 1, 'Patio Central', 'Rua A 123', 50 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM patio WHERE id_patio = 1); + +INSERT INTO patio (id_patio, nome, endereco, capacidade_maxima) +SELECT 2, 'Patio Norte', 'Rua B 456', 30 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM patio WHERE id_patio = 2); + +INSERT INTO patio (id_patio, nome, endereco, capacidade_maxima) +SELECT 3, 'Patio Sul', 'Rua C 789', 40 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM patio WHERE id_patio = 3); + +INSERT INTO patio (id_patio, nome, endereco, capacidade_maxima) +SELECT 4, 'Patio Leste', 'Rua D 321', 20 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM patio WHERE id_patio = 4); + +INSERT INTO patio (id_patio, nome, endereco, capacidade_maxima) +SELECT 5, 'Patio Oeste', 'Rua E 654', 25 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM patio WHERE id_patio = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V4__create-table-camera.sql b/MottuFlow/src/main/resources/db/migration/V4__create-table-camera.sql deleted file mode 100644 index 1abcab2..0000000 --- a/MottuFlow/src/main/resources/db/migration/V4__create-table-camera.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE camera ( - id_camera BIGINT PRIMARY KEY AUTO_INCREMENT, - status_operacional VARCHAR(20) NOT NULL, - localizacao_fisica VARCHAR(255) NOT NULL, - id_patio BIGINT NOT NULL, - FOREIGN KEY (id_patio) REFERENCES patio(id_patio) - ON DELETE RESTRICT - ON UPDATE CASCADE -); - -INSERT INTO camera (status_operacional, localizacao_fisica, id_patio) VALUES -('OPERACIONAL', 'Entrada principal', 1), -('OPERACIONAL', 'Saída norte', 1), -('MANUTENCAO', 'Corredor lateral', 2), -('OPERACIONAL', 'Entrada sul', 3); \ No newline at end of file diff --git a/MottuFlow/src/main/resources/db/migration/V4__create-table-moto.sql b/MottuFlow/src/main/resources/db/migration/V4__create-table-moto.sql new file mode 100644 index 0000000..e50bcd5 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V4__create-table-moto.sql @@ -0,0 +1,43 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE moto ( + id_moto NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + placa VARCHAR2(10) NOT NULL, + modelo VARCHAR2(50) NOT NULL, + fabricante VARCHAR2(50) NOT NULL, + ano NUMBER NOT NULL, + id_patio NUMBER NOT NULL, + localizacao_atual VARCHAR2(100) NOT NULL, + CONSTRAINT fk_moto_patio FOREIGN KEY (id_patio) + REFERENCES patio(id_patio) + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO moto (id_moto, placa, modelo, fabricante, ano, id_patio, localizacao_atual) +SELECT 1, 'ABC1234', 'Mottu Pop', 'Honda', 2020, 1, 'Rua A' FROM dual +WHERE NOT EXISTS (SELECT 1 FROM moto WHERE id_moto = 1); + +INSERT INTO moto (id_moto, placa, modelo, fabricante, ano, id_patio, localizacao_atual) +SELECT 2, 'DEF5678', 'Mottu Sport', 'TVS', 2021, 2, 'Rua B' FROM dual +WHERE NOT EXISTS (SELECT 1 FROM moto WHERE id_moto = 2); + +INSERT INTO moto (id_moto, placa, modelo, fabricante, ano, id_patio, localizacao_atual) +SELECT 3, 'GHI9012', 'Mottu E', 'Yadea', 2019, 3, 'Rua C' FROM dual +WHERE NOT EXISTS (SELECT 1 FROM moto WHERE id_moto = 3); + +INSERT INTO moto (id_moto, placa, modelo, fabricante, ano, id_patio, localizacao_atual) +SELECT 4, 'JKL3456', 'Mottu Pop', 'Honda', 2022, 4, 'Rua D' FROM dual +WHERE NOT EXISTS (SELECT 1 FROM moto WHERE id_moto = 4); + +INSERT INTO moto (id_moto, placa, modelo, fabricante, ano, id_patio, localizacao_atual) +SELECT 5, 'MNO7890', 'Mottu Pop', 'Honda', 2023, 5, 'Rua E' FROM dual +WHERE NOT EXISTS (SELECT 1 FROM moto WHERE id_moto = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V5__create-table-aruco_tag.sql b/MottuFlow/src/main/resources/db/migration/V5__create-table-aruco_tag.sql deleted file mode 100644 index 78bc583..0000000 --- a/MottuFlow/src/main/resources/db/migration/V5__create-table-aruco_tag.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE aruco_tag ( - id_tag BIGINT PRIMARY KEY AUTO_INCREMENT, - codigo VARCHAR(50) NOT NULL, - status VARCHAR(20) NOT NULL, - id_moto BIGINT NOT NULL, - FOREIGN KEY (id_moto) REFERENCES moto(id_moto) - ON DELETE CASCADE - ON UPDATE CASCADE -); - -INSERT INTO aruco_tag (codigo, status, id_moto) VALUES -('TAG001', 'ATIVO', 1), -('TAG002', 'ATIVO', 2), -('TAG003', 'INATIVO', 3), -('TAG004', 'ATIVO', 4); \ No newline at end of file diff --git a/MottuFlow/src/main/resources/db/migration/V5__create-table-camera.sql b/MottuFlow/src/main/resources/db/migration/V5__create-table-camera.sql new file mode 100644 index 0000000..e12abd8 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V5__create-table-camera.sql @@ -0,0 +1,40 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE camera ( + id_camera NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + status_operacional VARCHAR2(20) NOT NULL, + localizacao_fisica VARCHAR2(255) NOT NULL, + id_patio NUMBER NOT NULL, + CONSTRAINT fk_camera_patio FOREIGN KEY (id_patio) + REFERENCES patio(id_patio) + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO camera (id_camera, status_operacional, localizacao_fisica, id_patio) +SELECT 1, 'Operacional', 'Entrada Patio Central', 1 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM camera WHERE id_camera = 1); + +INSERT INTO camera (id_camera, status_operacional, localizacao_fisica, id_patio) +SELECT 2, 'Manutencao', 'Saida Patio Norte', 2 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM camera WHERE id_camera = 2); + +INSERT INTO camera (id_camera, status_operacional, localizacao_fisica, id_patio) +SELECT 3, 'Operacional', 'Corredor Patio Sul', 3 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM camera WHERE id_camera = 3); + +INSERT INTO camera (id_camera, status_operacional, localizacao_fisica, id_patio) +SELECT 4, 'Inoperante', 'Portao Patio Leste', 4 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM camera WHERE id_camera = 4); + +INSERT INTO camera (id_camera, status_operacional, localizacao_fisica, id_patio) +SELECT 5, 'Operacional', 'Garagem Patio Oeste', 5 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM camera WHERE id_camera = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V6__create-table-aruco_tag.sql b/MottuFlow/src/main/resources/db/migration/V6__create-table-aruco_tag.sql new file mode 100644 index 0000000..72ee50a --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V6__create-table-aruco_tag.sql @@ -0,0 +1,40 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE aruco_tag ( + id_tag NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + codigo VARCHAR2(50) NOT NULL, + status VARCHAR2(20) NOT NULL, + id_moto NUMBER NOT NULL, + CONSTRAINT fk_aruco_moto FOREIGN KEY (id_moto) + REFERENCES moto(id_moto) + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO aruco_tag (id_tag, codigo, status, id_moto) +SELECT 1, 'TAG001', 'Ativo', 1 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM aruco_tag WHERE id_tag = 1); + +INSERT INTO aruco_tag (id_tag, codigo, status, id_moto) +SELECT 2, 'TAG002', 'Ativo', 2 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM aruco_tag WHERE id_tag = 2); + +INSERT INTO aruco_tag (id_tag, codigo, status, id_moto) +SELECT 3, 'TAG003', 'Inativo', 3 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM aruco_tag WHERE id_tag = 3); + +INSERT INTO aruco_tag (id_tag, codigo, status, id_moto) +SELECT 4, 'TAG004', 'Ativo', 4 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM aruco_tag WHERE id_tag = 4); + +INSERT INTO aruco_tag (id_tag, codigo, status, id_moto) +SELECT 5, 'TAG005', 'Manutencao', 5 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM aruco_tag WHERE id_tag = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V6__create-table-localidade.sql b/MottuFlow/src/main/resources/db/migration/V6__create-table-localidade.sql deleted file mode 100644 index 54504f7..0000000 --- a/MottuFlow/src/main/resources/db/migration/V6__create-table-localidade.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE localidade ( - id_localidade BIGINT PRIMARY KEY AUTO_INCREMENT, - data_hora DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - ponto_referencia VARCHAR(100) NOT NULL, - id_moto BIGINT NOT NULL, - id_patio BIGINT NOT NULL, - id_camera BIGINT NOT NULL, - FOREIGN KEY (id_moto) REFERENCES moto(id_moto) - ON DELETE CASCADE - ON UPDATE CASCADE, - FOREIGN KEY (id_patio) REFERENCES patio(id_patio) - ON DELETE CASCADE - ON UPDATE CASCADE, - FOREIGN KEY (id_camera) REFERENCES camera(id_camera) - ON DELETE CASCADE - ON UPDATE CASCADE -); - -INSERT INTO localidade (ponto_referencia, id_moto, id_patio, id_camera) VALUES -('Entrada principal', 1, 1, 1), -('Saída norte', 2, 1, 2), -('Corredor lateral', 3, 2, 3), -('Vaga sul', 4, 3, 4); \ No newline at end of file diff --git a/MottuFlow/src/main/resources/db/migration/V7__create-table-localidade.sql b/MottuFlow/src/main/resources/db/migration/V7__create-table-localidade.sql new file mode 100644 index 0000000..aea69ef --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V7__create-table-localidade.sql @@ -0,0 +1,43 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE localidade ( + id_localidade NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + data_hora TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + ponto_referencia VARCHAR2(100) NOT NULL, + id_moto NUMBER NOT NULL, + id_patio NUMBER NOT NULL, + id_camera NUMBER NOT NULL, + CONSTRAINT fk_local_moto FOREIGN KEY (id_moto) REFERENCES moto(id_moto), + CONSTRAINT fk_local_patio FOREIGN KEY (id_patio) REFERENCES patio(id_patio), + CONSTRAINT fk_local_camera FOREIGN KEY (id_camera) REFERENCES camera(id_camera) + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO localidade (id_localidade, data_hora, ponto_referencia, id_moto, id_patio, id_camera) +SELECT 1, TIMESTAMP '2025-11-01 08:00:00', 'Portao A', 1, 1, 1 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM localidade WHERE id_localidade = 1); + +INSERT INTO localidade (id_localidade, data_hora, ponto_referencia, id_moto, id_patio, id_camera) +SELECT 2, TIMESTAMP '2025-11-01 08:10:00', 'Portao B', 2, 2, 2 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM localidade WHERE id_localidade = 2); + +INSERT INTO localidade (id_localidade, data_hora, ponto_referencia, id_moto, id_patio, id_camera) +SELECT 3, TIMESTAMP '2025-11-01 08:20:00', 'Portao C', 3, 3, 3 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM localidade WHERE id_localidade = 3); + +INSERT INTO localidade (id_localidade, data_hora, ponto_referencia, id_moto, id_patio, id_camera) +SELECT 4, TIMESTAMP '2025-11-01 08:30:00', 'Portao D', 4, 4, 4 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM localidade WHERE id_localidade = 4); + +INSERT INTO localidade (id_localidade, data_hora, ponto_referencia, id_moto, id_patio, id_camera) +SELECT 5, TIMESTAMP '2025-11-01 08:40:00', 'Portao E', 5, 5, 5 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM localidade WHERE id_localidade = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V7__create-table-registro_status.sql b/MottuFlow/src/main/resources/db/migration/V7__create-table-registro_status.sql deleted file mode 100644 index c760282..0000000 --- a/MottuFlow/src/main/resources/db/migration/V7__create-table-registro_status.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE registro_status ( - id_status BIGINT PRIMARY KEY AUTO_INCREMENT, - tipo_status VARCHAR(50) NOT NULL, - descricao VARCHAR(255), - data_status DATETIME DEFAULT CURRENT_TIMESTAMP, - id_moto BIGINT NOT NULL, - id_funcionario BIGINT NOT NULL, - FOREIGN KEY (id_moto) REFERENCES moto(id_moto) - ON DELETE CASCADE - ON UPDATE CASCADE, - FOREIGN KEY (id_funcionario) REFERENCES funcionario(id_funcionario) - ON DELETE RESTRICT - ON UPDATE CASCADE -); - -INSERT INTO registro_status (tipo_status, descricao, id_moto, id_funcionario) VALUES -('DISPONIVEL', 'Moto pronta para uso', 1, 1), -('MANUTENCAO', 'Troca de óleo', 2, 2), -('RESERVADO', 'Reservada para cliente', 3, 2), -('BAIXA_BOLETIM_OCORRENCIA', 'Perda por BO', 4, 1); diff --git a/MottuFlow/src/main/resources/db/migration/V8__create-table-registro_status.sql b/MottuFlow/src/main/resources/db/migration/V8__create-table-registro_status.sql new file mode 100644 index 0000000..14d69a6 --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V8__create-table-registro_status.sql @@ -0,0 +1,42 @@ +BEGIN + EXECUTE IMMEDIATE ' + CREATE TABLE registro_status ( + id_status NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + tipo_status VARCHAR2(50) NOT NULL, + descricao VARCHAR2(255), + data_status TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + id_moto NUMBER NOT NULL, + id_funcionario NUMBER NOT NULL, + CONSTRAINT fk_moto_status FOREIGN KEY (id_moto) REFERENCES moto(id_moto), + CONSTRAINT fk_funcionario_status FOREIGN KEY (id_funcionario) REFERENCES funcionario(id_funcionario) + ) + '; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ + +INSERT INTO registro_status (id_status, tipo_status, descricao, id_moto, id_funcionario) +SELECT 1, 'DISPONIVEL', 'Moto pronta para uso', 1, 1 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM registro_status WHERE id_status = 1); + +INSERT INTO registro_status (id_status, tipo_status, descricao, id_moto, id_funcionario) +SELECT 2, 'MANUTENCAO', 'Aguardando documentacao.', 2, 3 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM registro_status WHERE id_status = 2); + +INSERT INTO registro_status (id_status, tipo_status, descricao, id_moto, id_funcionario) +SELECT 3, 'MANUTENCAO', 'Revisao geral.', 3, 2 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM registro_status WHERE id_status = 3); + +INSERT INTO registro_status (id_status, tipo_status, descricao, id_moto, id_funcionario) +SELECT 4, 'RESERVADO', 'Reservada via app.', 4, 4 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM registro_status WHERE id_status = 4); + +INSERT INTO registro_status (id_status, tipo_status, descricao, id_moto, id_funcionario) +SELECT 5, 'BAIXA_BOLETIM_OCORRENCIA', 'Moto furtada.', 5, 1 FROM dual +WHERE NOT EXISTS (SELECT 1 FROM registro_status WHERE id_status = 5); + +COMMIT; diff --git a/MottuFlow/src/main/resources/db/migration/V9__create-packages.sql b/MottuFlow/src/main/resources/db/migration/V9__create-packages.sql new file mode 100644 index 0000000..3f1816b --- /dev/null +++ b/MottuFlow/src/main/resources/db/migration/V9__create-packages.sql @@ -0,0 +1,109 @@ +DECLARE + v_count NUMBER; +BEGIN + SELECT COUNT(*) + INTO v_count + FROM all_objects + WHERE object_type = 'PACKAGE' + AND object_name = 'PCT_MOTTUFLOW' + AND owner = USER; + + IF v_count = 0 THEN + EXECUTE IMMEDIATE ' + CREATE OR REPLACE PACKAGE pct_mottuflow AS + PROCEDURE relatorio_funcionario_moto_status(p_id_funcionario IN NUMBER, p_json OUT CLOB); + PROCEDURE soma_fato_motos; + FUNCTION moto_to_json(p_id_moto IN NUMBER) RETURN CLOB; + FUNCTION validar_senha(p_id_funcionario IN NUMBER, p_senha IN VARCHAR2) RETURN VARCHAR2; + END pct_mottuflow; + '; + + EXECUTE IMMEDIATE ' + CREATE OR REPLACE PACKAGE BODY pct_mottuflow AS + PROCEDURE relatorio_funcionario_moto_status( + p_id_funcionario IN NUMBER, + p_json OUT CLOB + ) IS + BEGIN + SELECT JSON_OBJECT( + ''id_funcionario'' VALUE f.id_funcionario, + ''nome'' VALUE f.nome, + ''cargo'' VALUE f.cargo, + ''motos'' VALUE COALESCE( + JSON_ARRAYAGG( + JSON_OBJECT( + ''id_moto'' VALUE m.id_moto, + ''placa'' VALUE m.placa, + ''status'' VALUE rs.tipo_status + ) + ), + JSON_ARRAY() + ) + ) + INTO p_json + FROM funcionario f + LEFT JOIN registro_status rs ON f.id_funcionario = rs.id_funcionario + LEFT JOIN moto m ON rs.id_moto = m.id_moto + WHERE f.id_funcionario = p_id_funcionario + GROUP BY f.id_funcionario, f.nome, f.cargo; + EXCEPTION + WHEN NO_DATA_FOUND THEN p_json := ''{\"erro\":\"Funcionario nao encontrado\"}''; + WHEN OTHERS THEN p_json := ''{\"erro\":\"'' || SQLERRM || ''\"}''; + END; + + FUNCTION validar_senha(p_id_funcionario IN NUMBER, p_senha IN VARCHAR2) + RETURN VARCHAR2 IS + v_senha_bd VARCHAR2(255); + BEGIN + SELECT senha INTO v_senha_bd + FROM funcionario + WHERE id_funcionario = p_id_funcionario; + + IF v_senha_bd = p_senha THEN + RETURN ''Valido''; + ELSE + RETURN ''Invalido''; + END IF; + + EXCEPTION + WHEN NO_DATA_FOUND THEN + RETURN ''Funcionario nao encontrado''; + WHEN TOO_MANY_ROWS THEN + RETURN ''Mais de um funcionario retornado''; + WHEN OTHERS THEN + RETURN ''Erro inesperado: '' || SQLERRM; + END; + + PROCEDURE soma_fato_motos IS + v_total NUMBER; + BEGIN + SELECT COUNT(*) INTO v_total FROM moto; + DBMS_OUTPUT.PUT_LINE(''Total de motos: '' || v_total); + END; + + FUNCTION moto_to_json(p_id_moto IN NUMBER) RETURN CLOB IS + v_json CLOB; + BEGIN + SELECT JSON_OBJECT( + ''id_moto'' VALUE m.id_moto, + ''placa'' VALUE m.placa, + ''modelo'' VALUE m.modelo, + ''fabricante'' VALUE m.fabricante, + ''ano'' VALUE m.ano, + ''localizacao_atual'' VALUE m.localizacao_atual + ) + INTO v_json + FROM moto m + WHERE m.id_moto = p_id_moto; + + RETURN v_json; + EXCEPTION + WHEN NO_DATA_FOUND THEN RETURN ''{\"erro\":\"Moto nao encontrada\"}''; + WHEN OTHERS THEN RETURN ''{\"erro\":\"'' || SQLERRM || ''\"}''; + END; + + END pct_mottuflow; + '; + END IF; +END; +/ diff --git a/README.md b/README.md index e7aad57..42977c5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Este repositório é para uso exclusivo para a matéria de MASTERING RELATIONAL AND NON-RELATIONAL DATABASE +## Professor Marcel Thomé Filho / pf1547 + +--- +
MottuFlow

𝙈𝙤𝙩𝙩𝙪𝙁𝙡𝙤𝙬

@@ -5,37 +10,31 @@ ![Java](https://img.shields.io/badge/Java-21-orange.svg) ![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.x-brightgreen.svg) -![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15-blue.svg) +![Oracle](https://img.shields.io/badge/Oracle-Database-red.svg) ![Thymeleaf](https://img.shields.io/badge/Thymeleaf-3.x-lightgreen.svg) -![Deploy](https://img.shields.io/badge/Deploy-Render-46E3B7.svg) ## Visão Geral - **📱 Arquitetura Híbrida**: API REST para integração mobile + Interface web Thymeleaf - **🔒 Segurança Robusta**: Autenticação JWT e Spring Security - **📊 Gestão Completa**: Controle de funcionários, frotas, pátios e status em tempo real -- **☁️ Deploy em Produção**: Aplicação rodando no Render com PostgreSQL ### 🌐 Acesso à Aplicação | Ambiente | URL | Status | |----------|-----|--------| -| **🚀 Produção** | [mottuflowjava.onrender.com](https://mottuflowjava.onrender.com) | [![Status](https://img.shields.io/badge/Status-Online-success)](https://mottuflowjava.onrender.com) | | **💻 Local** | http://localhost:8080 | Desenvolvimento | -> ⚠️ **Nota**: O serviço gratuito do Render entra em modo sleep após inatividade. O primeiro acesso pode levar ~50 segundos para iniciar. -### 🎥 Demonstração +### 🎥 Demonstração com o Banco de dados Oracle + Uso das Procedures -[![Ver demonstração da aplicação](https://img.shields.io/badge/YouTube-Demonstração%20da%20Aplicação-red?style=for-the-badge&logo=youtube)](https://www.youtube.com/watch?v=vQ2NEXrVQ-Q) - -[![Ver integração com mobile](https://img.shields.io/badge/YouTube-Integração%20com%20Mobile-red?style=for-the-badge&logo=youtube)](https://youtu.be/j_LRC3WB7pA) +[![Ver demonstração da aplicação](https://img.shields.io/badge/YouTube-Demonstração%20da%20Aplicação-red?style=for-the-badge&logo=youtube)](https://youtu.be/bOPGT5gL_h0) ### 🔗 Recursos Externos - **[📂 Repositório GitHub](https://github.com/thejaobiell/MottuFlowJava)** -- **[🔌 Collection Postman](https://github.com/thejaobiell/MottuFlowJava/blob/main/MottuFlow/jsonsAPIREST/API%20-%20MottuFlow.postman_collection.json)** +- **[🔌 Collection Postman](https://github.com/thejaobiell/MottuFlowJava/blob/database/MottuFlow/jsonsAPIREST/API%20-%20MottuFlow.postman_collection.json)** --- @@ -47,6 +46,7 @@ O projeto utiliza branches separadas para gerenciar ambientes de desenvolvimento |--------|----------|----------------|-----| | **`main`** | Desenvolvimento Local | MySQL 8.0+ | http://localhost:8080 | | **`sprint4`** | Produção | PostgreSQL 15 (Render) | https://mottuflowjava.onrender.com | +| **`database`** | Mastering Database (**Apenas para matéria de Mastering Database**) | Oracle Database | http://localhost:8080/api | --- @@ -60,6 +60,7 @@ O projeto utiliza branches separadas para gerenciar ambientes de desenvolvimento | **📹 Câmeras** | Sistema de monitoramento | Configuração e status | | **🏷️ ArUco Tags** | Identificação visual | Cadastro e rastreamento | | **📍 Status & Localização** | Tracking em tempo real | Posição, disponibilidade, alertas | +| **Procedures** | Integração com a matéria de `MASTERING RELATIONAL AND NON-RELATIONAL DATABASE` | Relatorios de Funcionario e Moto | ### Recursos Avançados @@ -68,7 +69,6 @@ O projeto utiliza branches separadas para gerenciar ambientes de desenvolvimento - ✅ **Autenticação Segura** - JWT + Spring Security - ✅ **Migração de Dados** - Flyway para versionamento de BD - ✅ **Validação de Dados** - Bean Validation integrado -- ✅ **Deploy em Produção** - Render + Render PostgreSQL ## 🛠️Tecnologias @@ -80,23 +80,17 @@ O projeto utiliza branches separadas para gerenciar ambientes de desenvolvimento - **Spring Web** - API REST ### Database & Migration -- **PostgreSQL 15** - Banco de dados em produção(Disponibilizado pelo Render) -- **MySQL 8.0** - Suporte para desenvolvimento local -- **PostgreSQL (Render)** - Banco de dados gerenciado +- **Oracle Database** - Suporte para desenvolvimento local - **Flyway** - Controle de versão do schema - **HikariCP** - Pool de conexões otimizado ### Frontend & Templates - **Thymeleaf** - Engine de templates -### InfraEstrutura -- **Render** - Plataforma de deploy em nuvem - ## Arquitetura ``` MottuFlow/ -├── 📄 DockerFile # Arquivo DockerFile para Deploy(apenas disponível na branch `sprint4`) ├── 📁 src/main/java/com/sprint/MottuFlow/ │ ├── 📁 controller/ # Controladores REST e Web │ │ ├── 📁 rest/ # Endpoints API REST @@ -107,6 +101,7 @@ MottuFlow/ │ │ ├── 📁 camera/ # Câmeras │ │ ├── 📁 funcionario/ # Funcionários │ │ ├── 📁 localidade/ # Localidades +│ │ ├── 📁 masteringdatabase/ # Service para integração para matéria de MASTERING RELATIONAL AND NON-RELATIONAL DATABASE │ │ ├── 📁 moto/ # Motocicletas │ │ ├── 📁 patio/ # Pátios │ │ └── 📁 status/ # Status das motos @@ -135,20 +130,18 @@ MottuFlow/ ## Instalação ### Pré-requisitos - **Java 21+** ([OpenJDK](https://openjdk.org/install/) ou [Oracle JDK](https://www.oracle.com/java/technologies/downloads/)) -- **PostgreSQL 15+** (produção) ou **MySQL 8.0+** (desenvolvimento local) -- **Maven 3.8+** ([Download](https://maven.apache.org/download.cgi)) +- **Oracle Database** (via [Docker](https://hub.docker.com/r/gvenzl/oracle-free) ou usando o Oracle da Própria Fiap) +- **Maven 3.8+ (OPICIONAL)** ([Download](https://maven.apache.org/download.cgi)) - **Git** ([Download](https://git-scm.com/downloads)) -- **Database Client** (Extensão para consultar o banco de dados) - - [Database Client](https://marketplace.visualstudio.com/items?itemName=cweijan.vscode-database-client2) - - [Database Client JDBC](https://marketplace.visualstudio.com/items?itemName=cweijan.dbclient-jdbc) +- **Oracle SQL Developer Extension for VSCode** [(Extensão para consultar o banco de dados) ](https://marketplace.visualstudio.com/items?itemName=Oracle.sql-developer) #### Via Terminal (Linux/macOS/WSL) ```bash # Clone o repositório -git clone -b main https://github.com/thejaobiell/MottuFlowJava.git +git clone https://github.com/thejaobiell/MottuFlowJava.git cd MottuFlowJava -# (Opcional) Troque para a branch de deploy -git checkout sprint4 +# Troque para a branch de deploy +git checkout database cd MottuFlow ./mvnw spring-boot:run ``` @@ -156,10 +149,10 @@ cd MottuFlow #### Via CMD (Windows) ```cmd # Clone o repositório -git clone -b main https://github.com/thejaobiell/MottuFlowJava.git +git clone main https://github.com/thejaobiell/MottuFlowJava.git cd MottuFlowJava # (Opcional) Troque para a branch de deploy -git checkout sprint4 +git checkout database cd MottuFlow # Execute a aplicação .\mvnw.cmd spring-boot:run @@ -171,181 +164,77 @@ cd MottuFlow ### Banco de Dados -A aplicação utiliza configurações diferentes dependendo da branch: +#### 🌿 Branch `Database` - Oracle Database -#### 🌿 Branch `main` - MySQL (Desenvolvimento Local) +##### `application.properties` (Branch database) +```properties +spring.application.name=MottuFlow -##### **Linux (Ubuntu/Debian)** -```bash -sudo apt update -sudo apt install mysql-server mysql-client -sudo mysql_secure_installation -``` - -##### **Windows** -1. Baixe o **MySQL Installer**: - [Download MySQL Installer](https://dev.mysql.com/downloads/installer/) -2. Durante a instalação, escolha: - * **Server Only** (somente servidor) ou **Full** (se quiser Workbench e utilitários). - * Configure a senha do usuário `root`. -3. Após a instalação, inicie o MySQL. -4. Para acessar via terminal do Windows: - * Pressione `Win + R`, digite `cmd` e execute: - ```bash - mysql -u root -p - ``` - * Digite a senha configurada. +spring.datasource.url=jdbc:oracle:thin:@oracle.fiap.com.br:1521/orcl +spring.datasource.username= +spring.datasource.password= +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver -##### Criação do Usuário e Banco (MySQL) -```sql --- Execute no MySQL como root -CREATE USER 'mottu_user'@'%' IDENTIFIED BY 'user123'; -GRANT ALL PRIVILEGES ON mottuflow.* TO 'mottu_user'@'%'; -FLUSH PRIVILEGES; -``` +spring.datasource.hikari.maximum-pool-size=5 +spring.datasource.hikari.minimum-idle=1 +spring.datasource.hikari.idle-timeout=10000 +spring.datasource.hikari.max-lifetime=60000 +spring.datasource.hikari.connection-timeout=30000 -##### `application.properties` (Branch main) -```properties -spring.application.name=MottuFlow -spring.datasource.url=jdbc:mysql://localhost:3306/mottuflow?createDatabaseIfNotExist=true -spring.datasource.username=mottu_user -spring.datasource.password=user123 -spring.jpa.hibernate.ddl-auto=update +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect spring.jpa.show-sql=true -spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect -spring.datasource.hikari.maximum-pool-size=10 -spring.datasource.hikari.minimum-idle=5 -spring.datasource.hikari.connection-timeout=20000 -spring.datasource.hikari.keepalive-time=300000 -spring.datasource.hikari.max-lifetime=1800000 -spring.datasource.hikari.idle-timeout=300000 -spring.datasource.hikari.connection-test-query=SELECT 1 +spring.jpa.hibernate.ddl-auto=none + spring.flyway.enabled=true spring.flyway.locations=classpath:db/migration -spring.flyway.repair=true +spring.flyway.baseline-on-migrate=true spring.flyway.repair-on-migrate=true -logging.level.root=WARN -logging.level.org.springframework=WARN -logging.level.org.hibernate=WARN -logging.level.com.sprint.MottuFlow=WARN -spring.main.allow-bean-definition-overriding=true -server.address=0.0.0.0 + server.port=8080 ``` --- -#### 🚀 Branch `sprint4` - PostgreSQL (Produção - Render) +### 🧩 Como Usar o **Oracle SQL Developer Extension for VSCode** -O PostgreSQL é usado automaticamente na branch `sprint4` para produção no Render. +#### 1. Abrir o painel da extensão -##### Credenciais do Render -```bash -HOST: dpg-d3sh9eili9vc73fr27ug-a.oregon-postgres.render.com -USERNAME: rm554874 -PASSWORD: F11qMduTmfLy8Xw15NBCTbsr7ypmBPbi -DATABASE: mottuflowdb -PORT: 5432 -``` +* Pressione `Ctrl+Shift+P` e digite **Database Client: Open View** +* Ou clique no ícone **Database** na barra lateral esquerda. -##### `application.properties` (Branch sprint4) -```properties -spring.application.name=MottuFlow -spring.datasource.url=${DATABASE_URL} -spring.datasource.username=${DATABASE_USERNAME} -spring.datasource.password=${DATABASE_PASSWORD} -spring.datasource.driver-class-name=org.postgresql.Driver -spring.datasource.hikari.maximum-pool-size=10 -spring.datasource.hikari.minimum-idle=5 -spring.datasource.hikari.connection-timeout=20000 -spring.datasource.hikari.keepalive-time=300000 -spring.datasource.hikari.max-lifetime=1800000 -spring.datasource.hikari.idle-timeout=300000 -spring.datasource.hikari.connection-test-query=SELECT 1 -spring.jpa.hibernate.ddl-auto=update -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -spring.jpa.show-sql=false -spring.jpa.open-in-view=false -spring.flyway.enabled=true -spring.flyway.locations=classpath:db/migration -spring.flyway.repair=true -spring.flyway.repair-on-migrate=true -logging.level.root=WARN -spring.main.allow-bean-definition-overriding=true -server.address=0.0.0.0 -server.port=${PORT:8080} -``` - ---- +#### 2. Criar uma nova conexão -## 🗄️ Database Client (VSCode) +1. Clique no botão **+** (Add Connection). +2. Escolha o tipo de banco: **Oracle**. +3. Preencha os campos: -### Instalação das Extensões + * **Host:** `oracle.fiap.com.br` + * **Port:** `1521` + * **Service Name / SID:** `orcl` + * **User:** `` + * **Password:** `` +4. Clique em **Test Connection** para verificar. +5. Se funcionar, clique em **Save**. -1. Abra o VSCode -2. Acesse a aba de Extensões (Ctrl+Shift+X) -3. Instale as seguintes extensões: - - **Database Client** (cweijan.vscode-database-client2) - - **Database Client JDBC** (cweijan.dbclient-jdbc) +#### 3. Conectar-se ao banco -### Configurando Conexões +* Após salvar, dê **duplo clique** na conexão criada. +* O banco aparecerá expandido com as pastas: *Tables*, *Views*, *Procedures*, etc. -#### Conexão MySQL (Branch main - Desenvolvimento Local) +#### 4. Executar comandos SQL -1. Clique no ícone do **Database Client** na barra lateral do VSCode -2. Clique em **"Create Connection"** (ícone de +) -3. Selecione **MySQL** -4. Preencha os dados: - ``` - Host: localhost - Port: 3306 - Username: mottu_user - Password: user123 - Database: mottuflow - ``` -5. Clique em **Connect** +1. Clique com o botão direito no banco → **New Query**. +2. Digite seus comandos SQL, por exemplo: -#### Conexão PostgreSQL (Branch sprint4 - Produção Render) - -1. Clique no ícone do **Database Client** na barra lateral do VSCode -2. Clique em **"Create Connection"** (ícone de +) -3. Selecione **PostgreSQL** -4. Preencha os dados: - ``` - Host: dpg-d3sh9eili9vc73fr27ug-a.oregon-postgres.render.com - Port: 5432 - Username: rm554874 - Password: F11qMduTmfLy8Xw15NBCTbsr7ypmBPbi - Database: mottuflowdb + ```sql + SELECT * FROM funcionario; ``` -5. Marque a opção **SSL** (obrigatório para Render) -6. Clique em **Connect** - -### Utilizando o Database Client - -#### Explorando Tabelas -- Expanda a conexão criada -- Navegue por **Schemas → Public → Tables** -- Clique com botão direito em uma tabela para: - - **Show Table Data**: Visualizar dados - - **Show Create Statement**: Ver o SQL de criação +3. Execute com `Ctrl+Enter` ou clicando em **Run** (▶). --- ## Uso -### 🌐 Acessando a Aplicação em Produção - -A aplicação está disponível em: **[mottuflowjava.onrender.com](https://mottuflowjava.onrender.com)** - -> ⚠️ **Importante**: No plano gratuito do Render, a aplicação entra em modo sleep após 15 minutos de inatividade. O primeiro acesso pode levar até 50 segundos para "acordar" o serviço. - -#### Health Check -O Render verifica automaticamente a saúde da aplicação em: -[/actuator/health](https://mottuflowjava.onrender.com/actuator/health) - ---- - ### 💻 Executando Localmente #### 1. Iniciando a Aplicação @@ -369,21 +258,17 @@ Clique aqui para acessar o Swagger UI: http://localhost:8080/swagger-ui/index. ## Acessos Principais -| Serviço | URL Local | URL Produção | Descrição | -|---------|-----------|--------------|-----------| -| **🖥️ Interface Web** | http://localhost:8080 | https://mottuflowjava.onrender.com | Dashboard principal | -| **📡 API REST** | http://localhost:8080/api | https://mottuflowjava.onrender.com/api | Endpoints REST | -| **📚 Documentação** | http://localhost:8080/swagger-ui.html | https://mottuflowjava.onrender.com/swagger-ui.html | Swagger UI | +| Serviço | URL Local | Descrição | +|---------|-----------|-----------| +| **🖥️ Interface Web** | http://localhost:8080 | Dashboard principal | +| **📡 API REST** | http://localhost:8080/api | Endpoints REST | +| **📚 Documentação** | http://localhost:8080/swagger-ui.html | Swagger UI | #### Usuários Padrão | Usuário | Senha | Cargo | Acesso | |---------|-------|--------|--------| | `admin@email.com` | `adminmottu` | Administrador | Completo | -| `joao@email.com` | `joao123` | Mecânico | Limitado | -| `maria@email.com` | `maria123` | Gerente | Completo | - -> Recomendado usar a conta de Administrador para teste --- @@ -394,8 +279,8 @@ O Flyway gerencia as migrações automaticamente: ``` src/main/resources/db/ └── migration/ - ├── V1__create-table-funcionario.sql - └── V2__create-table-patio.sql + ├── V1__baseline.sql + └── V2__create-table-funcionario.sql ``` --- @@ -406,11 +291,10 @@ Todas as requisições para a **API MottuFlow** exigem autenticação via **JWT ### Usando o Postman -1. **Importe** a coleção [API - MottuFlow.postman_collection.json](https://github.com/thejaobiell/MottuFlowJava/blob/main/MottuFlow/jsonsAPIREST/API%20-%20MottuFlow.postman_collection.json) no Postman. +1. **Importe** a coleção [API - MottuFlow.postman_collection.json](https://github.com/thejaobiell/MottuFlowJava/blob/database/MottuFlow/jsonsAPIREST/API%20-%20MottuFlow.postman_collection.json) no Postman. 2. **Configure a variável de ambiente `baseURL`**: - **Local**: `http://localhost:8080/api` - - **Produção**: `https://mottuflowjava.onrender.com/api` 3. No menu **`0 - JWT`**, execute o **POST Pegar Token JWT**, informando no **body** o `email` e `senha` do funcionário: @@ -425,7 +309,7 @@ Todas as requisições para a **API MottuFlow** exigem autenticação via **JWT 5. Vá até **API - MottuFlow → Variables**. -6. Substitua o valor da variável `jwt` pelo seu **token de acesso**. +6. Substitua o valor da variável `jwt` pelo seu **token de acesso** sem estar entre aspas. 7. Agora todos os endpoints da coleção já estarão autenticados! @@ -440,7 +324,6 @@ Todas as requisições para a **API MottuFlow** exigem autenticação via **JWT ### Variáveis de Ambiente - `{{baseUrl}}`: - Local: `http://localhost:8080/api` - - Produção: `https://mottuflowjava.onrender.com/api` - `{{jwt}}`: Token JWT obtido no login --- @@ -480,6 +363,28 @@ Content-Type: application/json --- +## 📊 Relatórios Avançados (Branch `database` - Oracle) - MASTERING RELATIONAL AND NON-RELATIONAL DATABASE + +### Relatório de Funcionário +```http +GET /database/funcionario/{id} +Authorization: Bearer {jwt_token} +``` + +**Exemplo:** `/database/funcionario/1` + +--- + +### Relatório de Moto +```http +GET /database/moto/{id} +Authorization: Bearer {jwt_token} +``` + +**Exemplo:** `/database/moto/1` + +--- + ## 👥 Funcionários ### Listar Funcionários @@ -957,26 +862,6 @@ Authorization: Bearer {jwt_token} ### ❌ Problemas Comuns -
-Primeiro acesso muito lento - -**Causa:** No plano gratuito do Render, serviços ficam em sleep após 15 minutos de inatividade. - -**Solução:** Aguarde até 50 segundos no primeiro acesso. Requisições subsequentes serão rápidas. - -
- -
-Erro de conexão com banco de dados local - -**Solução:** -1. Verifique se está na branch `main` -2. Confirme se o MySQL está rodando: `sudo systemctl status mysql` -3. Confirme as credenciais em `application.properties` -4. Crie o banco manualmente se necessário: `CREATE DATABASE mottuflow;` - -
-
Token JWT inválido ou expirado