diff --git a/.gitignore b/.gitignore index f6af9b8..7cb8db5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ bin/ *.uml *.uxf *.umlcd +target/ diff --git a/008_java_oo/java_util.md b/008_java_oo/java_util.md index e6305a6..32e6a2d 100644 --- a/008_java_oo/java_util.md +++ b/008_java_oo/java_util.md @@ -434,9 +434,9 @@ anteceden y preceden ```mermaid %%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%% graph LR - c1(cc1)-->c2(cc2)-->c1 - c2-->c3(cc3)-->c2 - c3-->c4(cc4)-->c3 + c1((cc1))-->c2((cc2))-->c1 + c2-->c3((cc3))-->c2 + c3-->c4((cc4))-->c3 ``` ```java @@ -605,18 +605,20 @@ public class TestRepasoArray { ```mermaid %%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}, 'flowchart': {'curve': 'monotoneX'}}}%% -flowchart RL - jln(java.lang.number)-->jld(java.lang.Double)--bytes-->8 - jln-->jlf(java.lang.Float)--bytes-->4 - jln-->jll(java.lang.Long)--bytes-->8 - jln-->jli(java.lang.Integer)--bytes-->4 - jln-->jls(java.lang.Short)--bytes-->2 - jln-->jlb(java.lang.Byte)--bytes-->1 - jln-->jlc(java.lang.Character)--bytes-->2 - jln-->jlbol(java.lang.Boolean)--bytes-->docs(JVM docs) +flowchart LR + jln(java.lang.number)-->jld(java.lang.Double)-->b8 + jln-->jlf(java.lang.Float)-->b4((4 bytes)) + jln-->jll(java.lang.Long)-->b8((8 bytes)) + jln-->jli(java.lang.Integer)-->b4 + jln-->jls(java.lang.Short)-->b2((2 bytes)) + jln-->jlb(java.lang.Byte)-->b1((1 byte)) + jln-->jlc(java.lang.Character)-->b2 + jln-->jlbol(java.lang.Boolean)-->docs{{JVM docs}} click docs "https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-2.html#jvms-2.3.4" "Documentación Java" _blank ``` +
+ ```java public static void main(String[] args) { Double numero_double = 33.0; diff --git a/009_emprendimiento/README.md b/009_emprendimiento/README.md index 2dda5ff..027539e 100644 --- a/009_emprendimiento/README.md +++ b/009_emprendimiento/README.md @@ -5,7 +5,7 @@ - [Curso](https://app.aluracursos.com/course/lean-startup-metodo-eficaz-idea-negocio-empresa), Resumen [Lean Startup](./lean_startup.md) - [Curso](https://app.aluracursos.com/course/emprendimiento-idea-plan-negocios), -Resumen [Emprendimiento]() +Resumen [Emprendimiento](./emprendimiento.md) - [Curso](https://app.aluracursos.com/course/pitch-entrevistas-presentaciones-impactantes), Resumen [Pitch para entrevistas]() - Artículo diff --git a/009_emprendimiento/apple_lcm.webp b/009_emprendimiento/apple_lcm.webp new file mode 100644 index 0000000..7388d18 Binary files /dev/null and b/009_emprendimiento/apple_lcm.webp differ diff --git a/009_emprendimiento/bmc_template.jpg b/009_emprendimiento/bmc_template.jpg new file mode 100644 index 0000000..92b54bc Binary files /dev/null and b/009_emprendimiento/bmc_template.jpg differ diff --git a/009_emprendimiento/emprendimiento.md b/009_emprendimiento/emprendimiento.md new file mode 100644 index 0000000..fd2e864 --- /dev/null +++ b/009_emprendimiento/emprendimiento.md @@ -0,0 +1,433 @@ +# Emprendimiento + +Curso +[Emprendimiento](https://app.aluracursos.com/course/emprendimiento-idea-plan-negocios) + +## De la idea al plan de negocios + +### Agenda + +- Pilares del emprendimiento + - Qué es emprender + - Características de la mentalidad del emprendedor + - 3 fuerzas del negocio + - Emprendedor + - Oportunidades + - Recursos +- Ideas y oportunidades + - Ideas vs oportunidades + - Atractividad del mercado + - Margen (precios y costes) + - Diferenciación estratégica +- Modelo de negocio + - Propuesta de valor + - Business Model Canvas +- Plan de negocios + - 9 elementos del plan + +## Emprendimiento + +> ***El proceso de crear algo nuevo asumiendo los riesgos y recompensas*** Robert +Hisrich + +### Mindset emprendedor + +- Compromiso +- Determinación +- Perseverancia +- Ambición (crecimiento) +- Orientado a objetivos +- Iniciativa y proactividad +- Tolerancia a estés +- Asumir riesgos calculados +- Comparte riesgos +- Buen manejo de errores y fracasos +- Capacidad de aprendizaje +- Construir equipos + +### Mindset anti-emprendedor + +- Sentimiento de invulnerabilidad +- Infexibilidad +- Antiautoridad +- Impulsividad +- Falta de control +- Perfeccionismo +- Creer saberlo todo +- Querer trabajar poco + +### Startup + +- Nuevos mercados y productos +- Tecnología +- Escalable +- Disruptiva +- Incertidumbre +- Debe probar su modelo de negocio +- Puede transformase en ¿unicornio? + +**StartUp vs Negocio LifeStyle** + +### Intraemprendimiento + +Emprender dentro de una corporación tiene oportunidades más restrictivas + +- Representar intereses de un conjunto mayor +- Core Business +- Legado de la organización +- Enfoque a corto plazo +- Sin riesgos + +Innovación radical como oportunidad de intraemprendimiento + +En una startup todos son emprendedores + +## Ejemplo Bytebank + +- Una empresa - un producto +- Tarjeta de crédito virtual 100% +- Dos emprendedores +- \+ 6 exfuncionarios del sector bancario +- Compras online +- Público objetivo: jóvenes de clase media +- Autoservicio: Sin sucursales +- Seguro contra extravío +- Transparencia + +---- + +## Pilares del emprendimiento + +1. **Fundadores** + - Emprendedor + - Equipo de fundación + - Experiencia y conocimiento + - Autoridad + - Gestión, habilidades y competencias + - Actitud, tenacidad, osadía +2. **Oportunidades** + - Encontrar la oportunidad + - Necesidad/problema real + - Tamaño del mercado + - Crecimiento + - Momento correcto + - Fuerzas (externas e internas) + - Lucratividad y rentabilidad + - Clientes 'ángeles' (pioneros) +3. **Recursos** + - Financieros + - Tecnología + - Producción + - Personas + - Sistemas + - Consejeros/consultores + - Controles de gestión + +
+ +| Guia del emprendedor || +| - | - | +| **¿Mis metas están definidas?** | Aspiraciones personales
Tamaño y sostenibilidad del negocio
Tolerancia a riesgos | +| **¿Mi estrategia es correcta?** | Definida y clara
Lucrativa y con alto potencial de crecimiento
Durabilidad | +| **¿Puedo ejecutar la estrategia?** | Recursos
Infraestructura
Papel del fundador | + +
+ +| Modelo Flavio Augusto || +| - | - | +| **¿Lo ves antes que todos?** | Como una información privilegiada
ej. equipo fútbol en USA | +| **Coraje** | ¡Nadie te va a empujar, tienes que saltar! | +| **Competencia** | Tú tienes que hacerlo realidad | + +
+ +|Fórmula Daniel Wainmann ||| +| - | - | - | +| Suerte | Talento | Estrategia | +| **10%** | **10%** | **80%** | + +
+ +> Referencias: +> - The Questions Every Entrepreneurs Must Answer +> *(Harvard Business Review) - Amar Bhide* +> - Being a Sucessful Entrepreneur isn't Only About Having the Best Ideas +> *(Harvard Business Review) - Andy Molinsky* +> - Six Fundamentals Every Entrepreneur Needs +> *(Harvard Business Review) - Bob Diener* +> - TEDx Emprender e innovar en América Latina *Daniel Wainmann* + +## Ideas y oportunidades + +> **El problema debe ser más importante que la solución** Daniel Wainmann + + +### Valor potencial + +**`Problema` + `Solucion con diferencial` + `Emprendedor`** + +..*"Las ideas son abuntantes, y las **soluciones escasas**"*.. + +### Atractivad del mercado + +- Tamaño del mercado + - ¿Cuántos clientes potenciales posee tu empresa? + - ¿Cuánto genera esa industria actualmente en $? + - ¿Tu producto es algo realmente necesario? +- Compradores preparados + - ¿Cuál es el nivel de preparación de tus compradores? +- Homogeneidad de los compradores + - ¿Las necesidades de su público son las mismas? + - ¿Necesitas personalizar? +- Verificar las reglas del segmento/area/rubro del país + +### Margen precio costo + +¿El margen líquido vale la pena? + +| Rubro | Margen | +| - | - | +| Minería | 7% | +| Aviación | 11% | +| Farmacia | 15% | +| Entretenimiento | 13% | +| Seguros | 8% | +| Energía | 4% | +| Supermercado | 2% | +| Cigarrillos | 28% | +| Software | 12% | + +| Tecnología | Margen | +| - | - | +| Baidu | 47.35% | +| Adobe | 23% | +| Microsoft | 21% | +| AWS | 23% | +| Apple | 24% | +| Yahoo | 7% | + + +### Escalabilidad e implementación + +[](./viab_graph.png) +[](./esca_graph.png) + +### Recurrencia + +Ejs. de servicios por subscripción: Gimnasios, Netflix, Spotify, etc. + +### Competencia + +- ¿Como se mueve el mercado en este momento? +- ¿Cuales son los competidores y sustitutos? +- Mirar fuera de la "mesa de juego" + +### Diferencial + +**¿Que te diferencia?** Ejemplo marcas de vehículos + +- Precio + - Volkswagen + - Ford +- Lujo + - Mercedes-Benz +- "Lujo y performance" + - BMW +- Calidad y precio + - Nissan +- Seguridad + - Volvo +- Performance y diseño + - Ferrari +- Tecnología + - Tesla + +### Facilidad de divulgación + +¿De que forma se va a anunciar/comunicar con el cliente? + +### Equipo de trabajo + +Personas necesarias para que la empresa sea atractiva para inversionistas y +consumidores + +> [Four VCs on Evaluating Opportunities ](https://hbswk.hbs.edu/item/four-vcs-on-evaluating-opportunities) +*(Harvard Business School) - Lauren Barley* +[Creating a Culture of Entrepreneurship](https://hbswk.hbs.edu/item/skills-and-behaviors-that-make-entrepreneurs-successful) +*Richard Patton* + +## Propuesta de valor + +- Necesidad: ¿Que necesidades resuelve tu producto o servicio? +- Segmentos de clientes: Edad, clase social, género, intereses, etc. +- Posicionamento +- ¿Mercado nuevo o existente? +- ¿Tendrá complementos? +- ¿Cual es el MVP? +- Precios/Categorías de precios +- Precio o Costo para el cliente para cambiar a tu producto/servicio + +### Tecnologías, operaciones y márgenes + +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}, 'flowchart': {'curve': 'monotoneY'}}}%% +flowchart LR +subgraph "Que actividades son necesarias para desarrollar el producto" +MB["Marketing & +Branding"] +VN[Ventas] +ET[Entregas] +JR[Jurídico] +CT[Contabilidad] +DS[Desarrollo] +RH["Recuros +Humanos"] +end +``` + +Propiedad intelectual - ¿Hay algo que sea patentable? + +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}, 'flowchart': {'curve': 'monotoneY'}}}%% +flowchart LR +subgraph "Donde y como tu producto puede ser adquirido" +VN[Teléfono] +ET[Aplicación] +JR[Página web] +DS[Supermercados] +RH[WhatsApp] +CT["Redes +Sociales"] +end +``` + +### Generar demanda + +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}, 'flowchart': {'curve': 'monotoneY'}}}%% +flowchart LR +subgraph "¿Como atraer clientes?" +JR["Google adsense +Social media ads"] +VN[Outdoor] +RH[Eventos] +CT[Freemium] +VR[Viralización] +DS["Revistas +Periodicos"] +ET["Radio, TV +podcast"] +end +``` + +### Customer Lifetime Value + +¿Cual es el CVL esperado? Valor del tiempo de vida del cliente + +- **CLV** `=` Valor medio de compras de un cliente `x` compras por año `x` años de permanencia + +¿Cual es el costo de adquisición del cliente (CAC)? + +- **CAC** `=` Gastos `/` Nro. de clientes nuevos + +¿Existe una oportunidad de *Upsell*? + +Recurrencia, subscripción + +### Margen + +[](./punto_muerto.png) + +- Margen de ganancia +- Costos fijos +- Punto de equilibrio (*breakeven*) + +### Ritmo de crecimiento + +¿El mercado está parando o en crecimiento, a que ritmo? + +### Capital de giro + +¿Cual es la necesidad de capital de giro del negocio? + +## Business Model Canvas + +[](./bmc_template.jpg) + +### Ejms. BMC + +[](./tesla_lcm.webp) +[](./google_lcm.webp) +[](./apple_lcm.webp) +[](./skype_lcm.webp) +[](./facebook_lcm.webp) + +## Plan de negocio + +*.."La idea parecía fantástica, pero los números dicen otra cosa"..* + +### Resumen ejecutivo + +La oportunidad de llamar la atencion del inversor + +- Conceptp del negocio +- UVP (Unique Value Proposition) +- Inversion necesaria +- Clientes y mercado + +### Producto o servicio + +- Funcionalidades +- Público objetivo +- Fuentes de ingresos +- Estado actual de desarrollo +- ¿Existe algo similar en otro país o mercado? +- ¿Como fidelizar al cliente? + +### Equipo + +- ¿Quienes son los fundadores? +- Capacidad de cada fundador par el éxito +- División de responsbilidades + +### Mercado + +- Tamaño del mercado +- Potencial de crecimiento +- Competencia +- Puntos fuertes y débiles + +### Marketing y ventas + +- ¿Como promover? +- ¿Como distribuir? +- ¿Como fijar el precio? + +### Organización + +- Construcción de equipos +- Plan de contratación +- Tercerización +- Aliados +- Canales de ventas + +### Cronograma + +- Responsables +- Plazos +- Hitos (*milestones*) + +### Riesgos + +- El mejor y el peor escenario +- Principales riesgos +- Como mitigar los riesgos + +### Finazas + +- Estado de resultados +- Flujo de caja +- Tasación +- Balance +- Fuentes de financiación + diff --git a/009_emprendimiento/esca-graph.svg b/009_emprendimiento/esca-graph.svg new file mode 100644 index 0000000..73460d5 --- /dev/null +++ b/009_emprendimiento/esca-graph.svg @@ -0,0 +1 @@ +EscalabilidadIngresosGastos050100150200250 \ No newline at end of file diff --git a/009_emprendimiento/esca_graph.png b/009_emprendimiento/esca_graph.png new file mode 100644 index 0000000..205abd9 Binary files /dev/null and b/009_emprendimiento/esca_graph.png differ diff --git a/009_emprendimiento/facebook_lcm.webp b/009_emprendimiento/facebook_lcm.webp new file mode 100644 index 0000000..2e2b586 Binary files /dev/null and b/009_emprendimiento/facebook_lcm.webp differ diff --git a/009_emprendimiento/google_lcm.webp b/009_emprendimiento/google_lcm.webp new file mode 100644 index 0000000..cbb5566 Binary files /dev/null and b/009_emprendimiento/google_lcm.webp differ diff --git a/009_emprendimiento/lean_canvas_model_dark.webp b/009_emprendimiento/lean_canvas_model_dark.webp new file mode 100644 index 0000000..0b14f19 Binary files /dev/null and b/009_emprendimiento/lean_canvas_model_dark.webp differ diff --git a/009_emprendimiento/lean_canvas_model_template.webp b/009_emprendimiento/lean_canvas_model_template.webp new file mode 100644 index 0000000..a3c46dd Binary files /dev/null and b/009_emprendimiento/lean_canvas_model_template.webp differ diff --git a/009_emprendimiento/punto_muerto.png b/009_emprendimiento/punto_muerto.png new file mode 100644 index 0000000..ea86a55 Binary files /dev/null and b/009_emprendimiento/punto_muerto.png differ diff --git a/009_emprendimiento/skype_lcm.webp b/009_emprendimiento/skype_lcm.webp new file mode 100644 index 0000000..928748b Binary files /dev/null and b/009_emprendimiento/skype_lcm.webp differ diff --git a/009_emprendimiento/tesla_lcm.webp b/009_emprendimiento/tesla_lcm.webp new file mode 100644 index 0000000..a5deca0 Binary files /dev/null and b/009_emprendimiento/tesla_lcm.webp differ diff --git a/009_emprendimiento/viab-graph.svg b/009_emprendimiento/viab-graph.svg new file mode 100644 index 0000000..54ae39b --- /dev/null +++ b/009_emprendimiento/viab-graph.svg @@ -0,0 +1 @@ +ViabilidadIngresosGastos0204060 \ No newline at end of file diff --git a/009_emprendimiento/viab_graph.png b/009_emprendimiento/viab_graph.png new file mode 100644 index 0000000..efa30f4 Binary files /dev/null and b/009_emprendimiento/viab_graph.png differ diff --git a/010_spring_boot/README.md b/010_spring_boot/README.md index b63123a..8d1f57c 100644 --- a/010_spring_boot/README.md +++ b/010_spring_boot/README.md @@ -4,4 +4,6 @@ Tablero en [trello](https://trello.com/b/gWJsG18e/g5-formaci%C3%B3n-spring-boot) - [Curso](https://app.aluracursos.com/course/introduccion-sql-mysql-manipule-consulte-datos) Java y [bases de datos](./base_de_datos.md) - +- Lectura [JDBC](https://www.aluracursos.com/blog/conociendo-el-jdbc) +- [Curso](https://app.aluracursos.com/course/java-jdbc-trabajando-base-datos) +Java y [JDBC](./jdbc.md) diff --git a/010_spring_boot/base_de_datos.md b/010_spring_boot/base_de_datos.md index 33a9073..f4dfda0 100644 --- a/010_spring_boot/base_de_datos.md +++ b/010_spring_boot/base_de_datos.md @@ -292,7 +292,7 @@ realizado su primera compra. ```sql -- show databases; -use jugos; +USE jugos; CREATE TABLE cliente( dni VARCHAR(20), nombre VARCHAR(150), @@ -317,7 +317,7 @@ CREATE TABLE cliente( #### Creación de tabla **`vendedor`** ```sql -use jugos; +USE jugos; CREATE TABLE vendedor( matricula VARCHAR(4), nombre VARCHAR(100), @@ -328,7 +328,7 @@ CREATE TABLE vendedor( #### Elimnar tabla ```sql -use jugos; +USE jugos; -- CREATE TABLE vendedor2( -- matricula VARCHAR(4), -- nombre VARCHAR(100), diff --git a/010_spring_boot/java_jdbc/control-de-stock/pom.xml b/010_spring_boot/java_jdbc/control-de-stock/pom.xml new file mode 100644 index 0000000..cb1dbd9 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/pom.xml @@ -0,0 +1,42 @@ + + 4.0.0 + com.alura + control-de-stock + 0.0.1-SNAPSHOT + Control de Stock + Proyecto para trabajar con bases de datos con JDBC + + 17 + + + + mysql + mysql-connector-java + 8.0.33 + + + com.mchange + c3p0 + 0.9.5.5 + + + com.mchange + mchange-commons-java + 0.2.20 + + + + + + org.apache.plugins + maven-compiler-plugin + 3.11.0 + + ${java.version} + ${java.version} + true + + + + + diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/ControlDeStockMain.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/ControlDeStockMain.java new file mode 100644 index 0000000..1cb926e --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/ControlDeStockMain.java @@ -0,0 +1,14 @@ +package com.alura.jdbc; + +import javax.swing.JFrame; + +import com.alura.jdbc.view.ControlDeStockFrame; + +public class ControlDeStockMain { + + public static void main(String[] args) { + ControlDeStockFrame produtoCategoriaFrame = new ControlDeStockFrame(); + produtoCategoriaFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + +} \ No newline at end of file diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/CategoriaController.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/CategoriaController.java new file mode 100644 index 0000000..4a6bb94 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/CategoriaController.java @@ -0,0 +1,26 @@ +package com.alura.jdbc.controller; + +import java.util.List; + +import com.alura.jdbc.dao.CategoriaDAO; +import com.alura.jdbc.factory.ConnectionFactory; +import com.alura.jdbc.modelo.Categoria; + +public class CategoriaController { + + private CategoriaDAO categoriaDAO; + + public CategoriaController() { + var factory = new ConnectionFactory(); + this.categoriaDAO = new CategoriaDAO(factory.recuperaConexion()); + } + + public List listar() { + return categoriaDAO.listar(); + } + + public List cargaReporte() { + return this.categoriaDAO.listarConProductos(); + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java new file mode 100644 index 0000000..44ac0d7 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java @@ -0,0 +1,40 @@ +package com.alura.jdbc.controller; + +import java.util.List; + +import com.alura.jdbc.dao.ProductoDAO; +import com.alura.jdbc.factory.ConnectionFactory; +import com.alura.jdbc.modelo.Categoria; +import com.alura.jdbc.modelo.Producto; + +public class ProductoController { + + private ProductoDAO productoDAO; + + public ProductoController() { + this.productoDAO = new ProductoDAO(new ConnectionFactory().recuperaConexion()); + } + + public int modificar(Producto producto) { + return productoDAO.modificar(producto); + } + + public int eliminar(Integer id) { + return productoDAO.eliminar(id); + } + + public List listar() { + return productoDAO.listar(); + } + + public List listar(Categoria categoria) { + return productoDAO.listar(categoria.getId()); + } + + public void guardar(Producto producto, Integer categoriaId) { + producto.setCategoriaId(categoriaId); + productoDAO.guardar(producto); + } + + +} \ No newline at end of file diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/CategoriaDAO.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/CategoriaDAO.java new file mode 100644 index 0000000..5c96438 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/CategoriaDAO.java @@ -0,0 +1,135 @@ +package com.alura.jdbc.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import com.alura.jdbc.modelo.Categoria; +import com.alura.jdbc.modelo.Producto; + +public class CategoriaDAO { + private final Connection con; + + public CategoriaDAO(Connection conexion) { + this.con = conexion; + } + + public void guardar(Categoria categoria) { + try { + final PreparedStatement statement = con.prepareStatement( + "INSERT INTO categoria(nombre) VALUES(?)", + Statement.RETURN_GENERATED_KEYS); + try (statement) { + ejecutaRegistro(categoria, statement); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private void ejecutaRegistro(Categoria categoria, PreparedStatement statement) + throws SQLException { + statement.setString(1, categoria.getNombre()); + statement.execute(); + final ResultSet resultSet = statement.getGeneratedKeys(); + try (resultSet) { + while (resultSet.next()) { + categoria.setId(resultSet.getInt(1)); + System.out.println(String.format("Categoria agregada %s: ", categoria)); + } + } + } + + public List listar() { + List resultado = new ArrayList<>(); + final String query = "SELECT ID, NOMBRE FROM categoria;"; + System.out.println(query); + try { + + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.execute(); + ResultSet resultSet = statement.getResultSet(); + while (resultSet.next()) { + Categoria fila = new Categoria( + resultSet.getInt("ID"), + resultSet.getString("NOMBRE") + ); + resultado.add(fila); + } + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int modificar(Categoria categoria) { + try { + final String query = "UPDATE categoria SET NOMBRE=? WHERE ID=?;"; + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.setString(1, categoria.getNombre()); + statement.setInt(2, categoria.getId()); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int eliminar(Integer id) { + try { + final PreparedStatement statement = con.prepareStatement("DELETE FROM categoria WHERE ID=?;"); + try (statement) { + statement.setInt(1, id); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public List listarConProductos() { + List resultado = new ArrayList<>(); + final String query = "SELECT C.ID, C.NOMBRE, P.ID, P.NOMBRE, P.CANTIDAD FROM categoria C " + + "INNER JOIN producto P ON C.ID = P.CATEGORIA_ID "; + System.out.println(query); + try { + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.execute(); + final ResultSet resultSet = statement.getResultSet(); + try (resultSet){ + while (resultSet.next()) { + Integer categoriaId = resultSet.getInt("C.ID"); + String categoriaNombre = resultSet.getString("C.NOMBRE"); + var categoria = resultado + .stream() + .filter(cat -> cat.getId().equals(categoriaId)) + .findAny().orElseGet(() -> { + Categoria cat = new Categoria(categoriaId, categoriaNombre); + resultado.add(cat); + return cat; + }); + Producto producto = new Producto(resultSet.getInt("P.ID"), + resultSet.getString("P.NOMBRE"), + resultSet.getInt("P.CANTIDAD")); + categoria.agregar(producto); + } + }; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + return resultado; + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/ProductoDAO.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/ProductoDAO.java new file mode 100644 index 0000000..6582262 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/ProductoDAO.java @@ -0,0 +1,144 @@ +package com.alura.jdbc.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import com.alura.jdbc.modelo.Producto; + +public class ProductoDAO { + private final Connection con; + + public ProductoDAO(Connection conexion) { + this.con = conexion; + } + + public void guardar(Producto producto) { + try { + final PreparedStatement statement = con.prepareStatement( + "INSERT INTO producto(nombre, descripcion, cantidad, categoria_id) VALUES(?,?,?,?)", + Statement.RETURN_GENERATED_KEYS); + try (statement) { + ejecutaRegistro(producto, statement); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private void ejecutaRegistro(Producto producto, PreparedStatement statement) + throws SQLException { + statement.setString(1, producto.getNombre()); + statement.setString(2, producto.getDescripcion()); + statement.setInt(3, producto.getCantidad()); + statement.setInt(4, producto.getCategoriaId()); + statement.execute(); + final ResultSet resultSet = statement.getGeneratedKeys(); + try (resultSet) { + while (resultSet.next()) { + producto.setId(resultSet.getInt(1)); + System.out.println(String.format("Producto insertado %s: ", producto)); + } + } + } + + public List listar() { + List resultado = new ArrayList<>(); + try { + final PreparedStatement statement = con.prepareStatement( + "SELECT ID, NOMBRE, DESCRIPCION, CANTIDAD, CATEGORIA_ID FROM producto;"); + try (statement) { + statement.execute(); + ResultSet resultSet = statement.getResultSet(); + while (resultSet.next()) { + Producto fila = new Producto( + resultSet.getInt("ID"), + resultSet.getString("NOMBRE"), + resultSet.getString("DESCRIPCION"), + resultSet.getInt("CANTIDAD"), + resultSet.getInt("CATEGORIA_ID") + ); + resultado.add(fila); + } + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int modificar(Producto producto) { + String query = "UPDATE producto SET NOMBRE=?, DESCRIPCION=?, CANTIDAD=? "; + if (producto.getCategoriaId() != null) { + query += ", CATEGORIA_ID=? WHERE ID=?;"; + } else { + query += " WHERE ID=?;"; + } + + try { + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.setString(1, producto.getNombre()); + statement.setString(2, producto.getDescripcion()); + statement.setInt(3, producto.getCantidad()); + if (producto.getCategoriaId() != null) { + statement.setInt(4, producto.getCategoriaId()); + statement.setInt(5, producto.getId()); + } else { + statement.setInt(4, producto.getId()); + } + //System.out.println(statement.toString()); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int eliminar(Integer id) { + try { + final PreparedStatement statement = con.prepareStatement("DELETE FROM producto WHERE ID=?;"); + try (statement) { + statement.setInt(1, id); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public List listar(Integer id) { + List resultado = new ArrayList<>(); + final String query = "SELECT ID, NOMBRE, DESCRIPCION, CANTIDAD, CATEGORIA_ID FROM producto WHERE categoria_id=?;"; + //System.out.println(query); + try { + final PreparedStatement statement = con.prepareStatement(query); + statement.setInt(1, id); + try (statement) { + statement.execute(); + ResultSet resultSet = statement.getResultSet(); + while (resultSet.next()) { + Producto fila = new Producto( + resultSet.getInt("ID"), + resultSet.getString("NOMBRE"), + resultSet.getString("DESCRIPCION"), + resultSet.getInt("CANTIDAD"), + resultSet.getInt("CATEGORIA_ID") + ); + resultado.add(fila); + } + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java new file mode 100644 index 0000000..87e4420 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java @@ -0,0 +1,37 @@ +package com.alura.jdbc.factory; + +import java.sql.Connection; +import javax.sql.DataSource; + +import com.mchange.v2.c3p0.ComboPooledDataSource; + +public class ConnectionFactory { + + private final static String driver = "jdbc:mysql://"; + private final static String dbaddr = "192.168.0.8:3306/"; + private final static String params = "?useTimeZone=true&serverTimeZone=UTC"; + private final static String dbname = "control_de_stock"; + private final static String dburl = driver+dbaddr+dbname+params; + private final static String dbuser = "alura"; + private final static String dbpass = "alura"; + + private DataSource datasource; + + public ConnectionFactory() { + var pooledDataSource = new ComboPooledDataSource(); + pooledDataSource.setJdbcUrl(dburl); + pooledDataSource.setUser(dbuser); + pooledDataSource.setPassword(dbpass); + pooledDataSource.setMaxPoolSize(10); + this.datasource = pooledDataSource; + } + + public Connection recuperaConexion() { + //return DriverManager.getConnection(dburl, dbuser, dbpass); + try { + return this.datasource.getConnection(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Categoria.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Categoria.java new file mode 100644 index 0000000..5ca7ef9 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Categoria.java @@ -0,0 +1,44 @@ +package com.alura.jdbc.modelo; + +import java.util.ArrayList; +import java.util.List; + +public class Categoria { + + private Integer id; + private String nombre; + private List productos; + + public Categoria(int id, String nombre) { + this.id = id; + this.nombre = nombre; + } + + public String getNombre() { + return this.nombre; + } + + public void setId(int id) { + this.id = id; + } + + public Integer getId() { + return this.id; + } + + @Override + public String toString() { + return this.getNombre(); + } + + public void agregar(Producto producto) { + if (this.productos == null) { + this.productos = new ArrayList<>(); + } + this.productos.add(producto); + } + + public List getProductos() { + return this.productos; + } +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Producto.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Producto.java new file mode 100644 index 0000000..82faf06 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Producto.java @@ -0,0 +1,71 @@ +package com.alura.jdbc.modelo; + +public class Producto { + private Integer id; + private String nombre; + private String descripcion; + private Integer cantidad; + private Integer categoriaId; + + public Producto(String nombre, String descripcion, Integer cantidad) { + this.nombre = nombre; + this.descripcion = descripcion; + this.cantidad = cantidad; + } + + public Producto(Integer id, String nombre, String descripcion, Integer cantidad) { + this.id = id; + this.nombre = nombre; + this.descripcion = descripcion; + this.cantidad = cantidad; + } + + public Producto(Integer id, String nombre, String descripcion, Integer cantidad, Integer categoriaId) { + this.id = id; + this.nombre = nombre; + this.descripcion = descripcion; + this.cantidad = cantidad; + this.categoriaId = categoriaId; + } + + public Producto(Integer id, String nombre, Integer cantidad) { + this.id = id; + this.nombre = nombre; + this.cantidad = cantidad; + } + + public String getNombre() { + return this.nombre; + } + + public String getDescripcion() { + return this.descripcion; + } + + public int getCantidad() { + return this.cantidad; + } + + public void setId(int id) { + this.id = id; + } + + public Integer getId() { + return this.id; + } + + @Override + public String toString() { + return String.format("{id: %d, nombre: %s, descripción: %s, cantidad: %d, categoria: %d}", + this.id, this.nombre, this.descripcion, this.cantidad, this.categoriaId); + } + + public void setCategoriaId(Integer categoriaId) { + this.categoriaId = categoriaId; + } + + public Integer getCategoriaId() { + return this.categoriaId; + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaConexion.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaConexion.java new file mode 100644 index 0000000..1e54b07 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaConexion.java @@ -0,0 +1,16 @@ +package com.alura.jdbc.pruebas; + +import java.sql.Connection; +import java.sql.SQLException; + +import com.alura.jdbc.factory.ConnectionFactory; + +public class PruebaConexion { + + public static void main(String[] args) throws SQLException { + Connection con = new ConnectionFactory().recuperaConexion(); + System.out.println("Cerrando conexión"); + con.close(); + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaDelete.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaDelete.java new file mode 100644 index 0000000..c4e14a1 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaDelete.java @@ -0,0 +1,16 @@ +package com.alura.jdbc.pruebas; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import com.alura.jdbc.factory.ConnectionFactory; + +public class PruebaDelete { + public static void main(String[] args) throws SQLException { + Connection con = new ConnectionFactory().recuperaConexion(); + Statement stmnt = con.createStatement(); + stmnt.execute("DELETE FROM producto WHERE ID=99"); + System.out.println(stmnt.getUpdateCount()); + } +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaPoolDeConexiones.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaPoolDeConexiones.java new file mode 100644 index 0000000..b995991 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/pruebas/PruebaPoolDeConexiones.java @@ -0,0 +1,19 @@ +package com.alura.jdbc.pruebas; + +import java.sql.Connection; +import java.sql.SQLException; + +import com.alura.jdbc.factory.ConnectionFactory; + +public class PruebaPoolDeConexiones { + + public static void main(String[] args) throws SQLException { + ConnectionFactory connectionFactory = new ConnectionFactory(); + for (int i = 0; i < 20; i++) { + @SuppressWarnings("unused") + Connection con = connectionFactory.recuperaConexion(); + System.out.println("Abriendo conexión nro: "+(i+1)); + } + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ControlDeStockFrame.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ControlDeStockFrame.java new file mode 100644 index 0000000..751ea03 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ControlDeStockFrame.java @@ -0,0 +1,285 @@ +package com.alura.jdbc.view; + +import java.awt.Color; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Optional; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.DefaultTableModel; + +import com.alura.jdbc.controller.CategoriaController; +import com.alura.jdbc.controller.ProductoController; +import com.alura.jdbc.modelo.Categoria; +import com.alura.jdbc.modelo.Producto; + +public class ControlDeStockFrame extends JFrame { + + private static final long serialVersionUID = 1L; + + private JLabel labelNombre, labelDescripcion, labelCantidad, labelCategoria; + private JTextField textoNombre, textoDescripcion, textoCantidad; + private JComboBox comboCategoria; + private JButton botonGuardar, botonModificar, botonLimpiar, botonEliminar, botonReporte; + private JTable tabla; + private DefaultTableModel modelo; + private ProductoController productoController; + private CategoriaController categoriaController; + + public ControlDeStockFrame() { + super("Productos"); + + this.categoriaController = new CategoriaController(); + this.productoController = new ProductoController(); + + Container container = getContentPane(); + setLayout(null); + + configurarCamposDelFormulario(container); + + configurarTablaDeContenido(container); + + configurarAccionesDelFormulario(); + } + + private void configurarTablaDeContenido(Container container) { + tabla = new JTable(); + + modelo = (DefaultTableModel) tabla.getModel(); + modelo.addColumn("Identificador del Producto"); + modelo.addColumn("Nombre del Producto"); + modelo.addColumn("Descripción del Producto"); + modelo.addColumn("Cantidad"); + + cargarTabla(); + + tabla.setBounds(10, 205, 760, 280); + + botonEliminar = new JButton("Eliminar"); + botonModificar = new JButton("Modificar"); + botonReporte = new JButton("Ver Reporte"); + botonEliminar.setBounds(10, 500, 80, 20); + botonModificar.setBounds(100, 500, 80, 20); + botonReporte.setBounds(190, 500, 80, 20); + + container.add(tabla); + container.add(botonEliminar); + container.add(botonModificar); + container.add(botonReporte); + + setSize(800, 600); + setVisible(true); + setLocationRelativeTo(null); + } + + private void configurarCamposDelFormulario(Container container) { + labelNombre = new JLabel("Nombre del Producto"); + labelDescripcion = new JLabel("Descripción del Producto"); + labelCantidad = new JLabel("Cantidad"); + labelCategoria = new JLabel("Categoría del Producto"); + + labelNombre.setBounds(10, 10, 240, 15); + labelDescripcion.setBounds(10, 50, 240, 15); + labelCantidad.setBounds(10, 90, 240, 15); + labelCategoria.setBounds(10, 130, 240, 15); + + labelNombre.setForeground(Color.BLACK); + labelDescripcion.setForeground(Color.BLACK); + labelCategoria.setForeground(Color.BLACK); + + textoNombre = new JTextField(); + textoDescripcion = new JTextField(); + textoCantidad = new JTextField(); + comboCategoria = new JComboBox<>(); + comboCategoria.addItem(new Categoria(0, "Elige una categoría")); + + var categorias = this.categoriaController.listar(); + categorias.forEach(categoria -> comboCategoria.addItem(categoria)); + + textoNombre.setBounds(10, 25, 265, 20); + textoDescripcion.setBounds(10, 65, 265, 20); + textoCantidad.setBounds(10, 105, 265, 20); + comboCategoria.setBounds(10, 145, 265, 20); + + botonGuardar = new JButton("Guardar"); + botonLimpiar = new JButton("Limpiar"); + botonGuardar.setBounds(10, 175, 80, 20); + botonLimpiar.setBounds(100, 175, 80, 20); + + container.add(labelNombre); + container.add(labelDescripcion); + container.add(labelCantidad); + container.add(labelCategoria); + container.add(textoNombre); + container.add(textoDescripcion); + container.add(textoCantidad); + container.add(comboCategoria); + container.add(botonGuardar); + container.add(botonLimpiar); + } + + private void configurarAccionesDelFormulario() { + botonGuardar.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + guardar(); + limpiarTabla(); + cargarTabla(); + } + }); + + botonLimpiar.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + limpiarFormulario(); + } + }); + + botonEliminar.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + eliminar(); + limpiarTabla(); + cargarTabla(); + } + }); + + botonModificar.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + modificar(); + limpiarTabla(); + cargarTabla(); + } + }); + + botonReporte.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + abrirReporte(); + } + }); + } + + private void abrirReporte() { + new ReporteFrame(this); + } + + private void limpiarTabla() { + modelo.getDataVector().clear(); + } + + private boolean tieneFilaElegida() { + return tabla.getSelectedRowCount() == 0 || tabla.getSelectedColumnCount() == 0; + } + + private boolean tieneCatElegida() { + return !(comboCategoria.getSelectedItem().toString().equals(comboCategoria.getItemAt(0).toString())); + } + + private void modificar() { + if (tieneFilaElegida()) { + JOptionPane.showMessageDialog(this, "Por favor, elije un item"); + return; + } + if (tieneCatElegida()) { + Optional.ofNullable(modelo.getValueAt(tabla.getSelectedRow(), tabla.getSelectedColumn())) + .ifPresentOrElse(fila -> { + Producto producto = new Producto( + Integer.valueOf(modelo.getValueAt(tabla.getSelectedRow(), 0).toString()), + (String) modelo.getValueAt(tabla.getSelectedRow(), 1), + (String) modelo.getValueAt(tabla.getSelectedRow(), 2), + Integer.valueOf(modelo.getValueAt(tabla.getSelectedRow(), 3).toString()), + (Integer) ((Categoria) comboCategoria.getSelectedItem()).getId()); + int cantidadActualizada; + cantidadActualizada = this.productoController.modificar(producto); + JOptionPane.showMessageDialog(this, cantidadActualizada+" Item actualizado con éxito!"); + }, () -> JOptionPane.showMessageDialog(this, "Por favor, elije un item")); + } else { + Optional.ofNullable(modelo.getValueAt(tabla.getSelectedRow(), tabla.getSelectedColumn())) + .ifPresentOrElse(fila -> { + var producto = new Producto( + Integer.valueOf(modelo.getValueAt(tabla.getSelectedRow(), 0).toString()), + (String) modelo.getValueAt(tabla.getSelectedRow(), 1), + (String) modelo.getValueAt(tabla.getSelectedRow(), 2), + Integer.valueOf(modelo.getValueAt(tabla.getSelectedRow(), 3).toString())); + int cantidadActualizada; + cantidadActualizada = this.productoController.modificar(producto); + JOptionPane.showMessageDialog(this, cantidadActualizada+" Item actualizado con éxito!"); + }, () -> JOptionPane.showMessageDialog(this, "Por favor, elije un item")); + } + } + + private void eliminar() { + if (tieneFilaElegida()) { + JOptionPane.showMessageDialog(this, "Por favor, elije un item"); + return; + } + + Optional.ofNullable(modelo.getValueAt(tabla.getSelectedRow(), tabla.getSelectedColumn())) + .ifPresentOrElse(fila -> { + Integer id = Integer.valueOf(modelo.getValueAt(tabla.getSelectedRow(), 0).toString()); + + int cantidadEliminada; + cantidadEliminada = this.productoController.eliminar(id); + modelo.removeRow(tabla.getSelectedRow()); + + JOptionPane.showMessageDialog(this, cantidadEliminada+" Item eliminado con éxito!"); + }, () -> JOptionPane.showMessageDialog(this, "Por favor, elije un item")); + } + + private void cargarTabla() { + var productos = this.productoController.listar(); + productos.forEach(producto -> modelo.addRow( + new Object[] { + producto.getId(), + producto.getNombre(), + producto.getDescripcion(), + producto.getCantidad(), + producto.getCategoriaId() + } + ) + ); + } + + private void guardar() { + if (textoNombre.getText().isBlank() || textoDescripcion.getText().isBlank()) { + JOptionPane.showMessageDialog(this, "Los campos Nombre y Descripción son requeridos."); + return; + } + + Integer cantidadInt; + + try { + cantidadInt = Integer.parseInt(textoCantidad.getText()); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, String + .format("El campo cantidad debe ser numérico dentro del rango %d y %d.", 0, Integer.MAX_VALUE)); + return; + } + + //var producto = new HashMap(); + //producto.put("NOMBRE",textoNombre.getText()); + //producto.put("DESCRIPCION", textoDescripcion.getText()); + //producto.put("CANTIDAD", String.valueOf(cantidadInt)); + var producto = new Producto(textoNombre.getText(), + textoDescripcion.getText(), + cantidadInt); + + var categoria = (Categoria) comboCategoria.getSelectedItem(); + + this.productoController.guardar(producto, categoria.getId()); + JOptionPane.showMessageDialog(this, "Registrado con éxito!"); + this.limpiarFormulario(); + } + + private void limpiarFormulario() { + this.textoNombre.setText(""); + this.textoDescripcion.setText(""); + this.textoCantidad.setText(""); + this.comboCategoria.setSelectedIndex(0); + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ReporteFrame.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ReporteFrame.java new file mode 100644 index 0000000..88fabf5 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ReporteFrame.java @@ -0,0 +1,64 @@ +package com.alura.jdbc.view; + +import java.awt.Container; + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; + +import com.alura.jdbc.controller.CategoriaController; +//import com.alura.jdbc.controller.ProductoController; + +public class ReporteFrame extends JFrame { + + private static final long serialVersionUID = 1L; + + private JTable tablaReporte; + private DefaultTableModel modelo; + + private CategoriaController categoriaController; + //private ProductoController productoController; + + public ReporteFrame(ControlDeStockFrame controlDeStockFrame) { + super("Reporte de produtos del stock"); + + this.categoriaController = new CategoriaController(); + //this.productoController = new ProductoController(); + + Container container = getContentPane(); + setLayout(null); + + tablaReporte = new JTable(); + tablaReporte.setBounds(0, 0, 600, 400); + container.add(tablaReporte); + + modelo = (DefaultTableModel) tablaReporte.getModel(); + modelo.addColumn(""); + modelo.addColumn(""); + modelo.addColumn(""); + modelo.addColumn(""); + + cargaReporte(); + + setSize(600, 400); + setVisible(true); + setLocationRelativeTo(controlDeStockFrame); + } + + private void cargaReporte() { + var contenido = categoriaController.cargaReporte(); + contenido.forEach(categoria -> { + modelo.addRow(new Object[] { categoria.getId(), + categoria.getNombre(), + "Artículo", "Stock" }); + var productos = categoria.getProductos(); + productos.forEach(producto -> + modelo.addRow(new Object[] { "", + producto.getId(), + producto.getNombre(), + producto.getCantidad() } + )); + }); + } + +} diff --git a/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/tests/PruebaConexion.java b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/tests/PruebaConexion.java new file mode 100644 index 0000000..ccd0380 --- /dev/null +++ b/010_spring_boot/java_jdbc/control-de-stock/src/main/java/com/alura/tests/PruebaConexion.java @@ -0,0 +1,24 @@ +package com.alura.tests; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class PruebaConexion { + + private final static String driver = "jdbc:mysql://"; + private final static String dbaddr = "192.168.0.8:3306/"; + private final static String params = "?useTimeZone=true&serverTimeZone=UTC"; + private final static String dbname = "control_de_stock"; + private final static String dburl = driver+dbaddr+dbname+params; + private final static String dbuser = "alura"; + private final static String dbpass = "alura"; + + public static void main(String[] args) throws SQLException { + System.out.println("hola"); + Connection con = DriverManager.getConnection(dburl, dbuser, dbpass); + con.close(); + System.out.println("chao"); + } + +} diff --git a/010_spring_boot/jdbc.md b/010_spring_boot/jdbc.md new file mode 100644 index 0000000..3ec8068 --- /dev/null +++ b/010_spring_boot/jdbc.md @@ -0,0 +1,677 @@ +# JDBC + +```sh +mysql -u -h -p +``` + +```sql +CREATE DATABASE control_de_stock; +USE control_de_stock; + +CREATE TABLE producto( + id INT AUTO_INCREMENT, + nombre VARCHAR(50) NOT NULL, + descripcion VARCHAR(255), + cantidad INT NOT NULL DEFAULT 0, + PRIMARY KEY(id) +)Engine=InnoDB; + +INSERT INTO producto( + nombre, descripcion, cantidad) + values('Mesa', 'Mesa de 4 lugares', 10); + +INSERT INTO producto( + nombre, descripcion, cantidad) + values( 'Celular', 'Celular Samsung', 50); + +SELECT * FROM producto; + ++----+----------+-------------------+----------+ +| id | nombre | descripcion | cantidad | ++----+----------+-------------------+----------+ +| 1 | Mesa | Mesa de 4 lugares | 10 | +| 2 | Celuclar | Celular Samsung | 50 | ++----+----------+-------------------+----------+ +``` + +
+ +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%% +flowchart +subgraph "Conexión a base de datos" +DB1[(MySQL)] +DB2[(SQL Server)] +DB3[(MariaDB)] +app1["Aplicación +Java"] +DV1[/"Driver MySQL +MySqlConnector.getConnection()"\] +DV2[/"Driver SQL Server +SqlServerConnection.Provider.connect()"\] +DV3[/MariaDB Driver\] +DBC{{"JDBC +DriverManager.getConnection()"}} +app1-->DBC +DBC-->DV1-->DB1 +DV1-->DB3 +DBC-->DV3-->DB3 +DBC-->DV2-->DB2 +end +``` + +### Url de conexión + +**`jdbc::///?`** + +ejm. `jdbc:mysql//localhost:3306/control_de_stock` + +## Proyecto + +### Configuración de maven - [pom.xml](./java_jdbc/control-de-stock/pom.xml) + +```xml + + 4.0.0 + com.alura + control-de-stock + 0.0.1-SNAPSHOT + Control de Stock + Proyecto para trabajar con bases de datos con JDBC + + 17 + + + + mysql + mysql-connector-java + 8.0.33 + + + + + + org.apache.plugins + maven.compiler.plugin + 4.0.0 + + ${java.version} + ${java.version} + true + + + + + +``` + +### Prueba del conector + +```java +package com.alura.tests; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class PruebaConexion { + + private static String dbname = "control_de_stock"; + private static String dbuser = "alura"; + private static String dbpass = "alura"; + private static String dburl = "192.168.0.8:3306"; + private static String params = "useTimeZone=true&serverTimeZone=UTC"; + + public static void main(String[] args) throws SQLException { + System.out.println("hola"); + Connection con = DriverManager.getConnection( + "jdbc:mysql://"+dburl+"/"+dbname+"?"+params, dbuser, dbpass); + con.close(); + System.out.println("chao"); + } + +} +``` + +### Uso de Clase +[ConnectionFactory](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java) + +```java +package com.alura.jdbc.factory; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class ConnectionFactory { + + private static String dbdriver = "jdbc:mysql://"; + private static String dburl = dbdriver+"192.168.0.8:3306/"; + private static String params = "?useTimeZone=true&serverTimeZone=UTC"; + private static String dbname = "control_de_stock"; + private static String dbuser = "alura"; + private static String dbpass = "alura"; + + public Connection recuperaConexion() throws SQLException { + return DriverManager.getConnection(dburl + dbname + params, dbuser, dbpass); + } +} +``` + +### Uso de try with resources para las conexiones + +En clase +[ProductoController](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java) +para cierre automático de recursos `Statement`, `ResultSet`, `Connection`. + +Y tratamiento de *querys* con `PreparedStatement` + +```java +... + + public void guardar(Map producto) throws SQLException { + String nombre = producto.get("NOMBRE"); + String descripcion = producto.get("DESCRIPCION"); + int cantidad = Integer.valueOf(producto.get("CANTIDAD")); + int max_cantidad = 50; + + final Connection con = new ConnectionFactory().recuperaConexion(); + try (con) { + con.setAutoCommit(false); + final PreparedStatement statement = con.prepareStatement( + "INSERT INTO producto(nombre, descripcion, cantidad) VALUES(?,?,?)", + Statement.RETURN_GENERATED_KEYS); + + try (statement) { + do { + int cantidad_a_guardar = Math.min(cantidad, max_cantidad); + ejecutaRegistro(nombre, descripcion, cantidad_a_guardar, statement); + cantidad -= max_cantidad; + } while (cantidad > 0); + con.commit(); + } catch (Exception e) { + con.rollback(); + } + } + } + +... +``` + +## Pool de conexiones + +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%% +flowchart +subgraph "Conexión a base de datos" +DB1[(MySQL)] +DB2[(SQL Server)] +DB3[(MariaDB)] +app1("Aplicación +Java") +app2>"Connection +Factory"] +app1-->app2 +subgraph DS[Datasource] +subgraph C3P0 +pl("Pool de +Conexiones") +end +end +app2-->DS-->DBC +DV1[/"Driver MySQL +MySqlConnector.getConnection()"\] +DV2[/"Driver SQL Server +SqlServerConnection.Provider.connect()"\] +DV3[/MariaDB Driver\] +DBC{{"JDBC +DriverManager.getConnection()"}} +DBC-->DV1-->DB1 +DV1-->DB3 +DBC-->DV3-->DB3 +DBC-->DV2-->DB2 +end +``` + +### Implentando Pool Datasource en [ConnectionFactory](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java) + + +- [c3p0](https://www.mchange.com/projects/c3p0/) - DJBC3 Connection and Statement +Pooling + +- [mchange-commons-java](https://www.mchange.com/projects/mchange-commons-java/index.html) + +Dependencias [pom.xml](./java_jdbc/control-de-stock/pom.xml) + +```xml + ... + + com.mchange + c3p0 + 0.9.5.5 + + + com.mchange + mchange-commons-java + 0.2.20 + 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> z8kfsxax1wlsb2gfqn07n|10dba097, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> z8kfsxax1wlsb2gfqn07n|10dba097, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://192.168.0.8:3306/control_de_stock?useTimeZone=true&serverTimeZone=UTC, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] +Abriendo conexión nro: 1 +Abriendo conexión nro: 2 +Abriendo conexión nro: 3 +Abriendo conexión nro: 4 +Abriendo conexión nro: 5 +Abriendo conexión nro: 6 +Abriendo conexión nro: 7 +Abriendo conexión nro: 8 +Abriendo conexión nro: 9 +Abriendo conexión nro: 10 +``` + +```sql +SHOW PROCESSLIST; + ++-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+ +| Id | User | Host | db | Command | Time | State | Info | Progress | ++-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+ +| 193 | alura | 192.168.0.10:36856 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 194 | alura | 192.168.0.10:36854 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 195 | alura | 192.168.0.10:36852 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 196 | alura | 192.168.0.10:36882 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 197 | alura | 192.168.0.10:36896 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 198 | alura | 192.168.0.10:36880 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 199 | alura | 192.168.0.10:36902 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 200 | alura | 192.168.0.10:36918 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 201 | alura | 192.168.0.10:36920 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 202 | alura | 192.168.0.10:36934 | control_de_stock | Sleep | 15 | | NULL | 0.000 | +| 203 | alura | 192.168.0.8:42234 | NULL | Query | 0 | starting | show processlist | 0.000 | ++-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+ +11 rows in set (0.001 sec) +``` + +## Dao + +Data Access Object [wiki](https://en.wikipedia.org/wiki/Data_access_object) en +clase +[ProductoDAO](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/ProductoDAO.java) + + +```mermaid +%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%% +flowchart +subgraph "Conexión a base de datos" +DB1[(MySQL)] +DB2[(SQL Server)] +DB3[(MariaDB)] +app1("Aplicación +Java") +CF("Connection +Factory") +subgraph DAO +direction RL +MD[Modelo] +CT[Controlador] +CT-->CF +CT-->MD +end +app1-->CT +app1-->MD +subgraph DS[Datasource] +subgraph C3P0 +PC("Pool de +Conexiones") +end +end +CF-->DS-->DBC +DV1[/"Driver MySQL +MySqlConnector.getConnection()"\] +DV2[/"Driver SQL Server +SqlServerConnection.Provider.connect()"\] +DV3[/MariaDB Driver\] +DBC{{"JDBC +DriverManager.getConnection()"}} +DBC-->DV1-->DB1 +DV1-->DB3 +DBC-->DV3-->DB3 +DBC-->DV2-->DB2 +end +``` + +```java +package com.alura.jdbc.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import com.alura.jdbc.modelo.Producto; + +public class ProductoDAO { + private final Connection con; + + public ProductoDAO(Connection conexion) { + this.con = conexion; + } + + public void guardar(Producto producto) { + try { + final PreparedStatement statement = con.prepareStatement( + "INSERT INTO producto(nombre, descripcion, cantidad) VALUES(?,?,?)", + Statement.RETURN_GENERATED_KEYS); + try (statement) { + ejecutaRegistro(producto, statement); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private void ejecutaRegistro(Producto producto, PreparedStatement statement) + throws SQLException { + statement.setString(1, producto.getNombre()); + statement.setString(2, producto.getDescripcion()); + statement.setInt(3, producto.getCantidad()); + statement.execute(); + final ResultSet resultSet = statement.getGeneratedKeys(); + try (resultSet) { + while (resultSet.next()) { + producto.setId(resultSet.getInt(1)); + System.out.println(String.format("Producto insertado %s: ", producto)); + } + } + } + + public List listar() { + List resultado = new ArrayList<>(); + try { + final PreparedStatement statement = con.prepareStatement( + "SELECT ID, NOMBRE, DESCRIPCION, CANTIDAD FROM producto;"); + try (statement) { + statement.execute(); + ResultSet resultSet = statement.getResultSet(); + while (resultSet.next()) { + Producto fila = new Producto( + resultSet.getInt("ID"), + resultSet.getString("NOMBRE"), + resultSet.getString("DESCRIPCION"), + resultSet.getInt("CANTIDAD") + ); + resultado.add(fila); + } + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int modificar(Producto producto) { + try { + final String query = "UPDATE producto SET NOMBRE=?, DESCRIPCION=?, CANTIDAD=? WHERE ID=?;"; + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.setString(1, producto.getNombre()); + statement.setString(2, producto.getDescripcion()); + statement.setInt(3, producto.getCantidad()); + statement.setInt(4, producto.getId()); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int eliminar(Integer id) { + try { + final PreparedStatement statement = con.prepareStatement("DELETE FROM producto WHERE ID=?;"); + try (statement) { + statement.setInt(1, id); + statement.execute(); + int resultado = statement.getUpdateCount(); + return resultado; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} +``` + +### MVC + +El proyecto sigue el patrón **M**odelo **V**ista **Controlador** + +Ejm. Producto + +- [Modelo](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Producto.java) +- [Vista](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ControlDeStockFrame.java) +- [Controlador](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java) + + ```java + package com.alura.jdbc.controller; + + import java.util.List; + + import com.alura.jdbc.dao.ProductoDAO; + import com.alura.jdbc.factory.ConnectionFactory; + import com.alura.jdbc.modelo.Producto; + + public class ProductoController { + + private ProductoDAO productoDAO; + + public ProductoController() { + this.productoDAO = new ProductoDAO(new ConnectionFactory().recuperaConexion()); + } + + public int modificar(Producto producto) { + return productoDAO.modificar(producto); + } + + public int eliminar(Integer id) { + return productoDAO.eliminar(id); + } + + public List listar() { + return productoDAO.listar(); + } + + public void guardar(Producto producto) { + productoDAO.guardar(producto); + } + + + } + ``` + +- Para cada tabla del modelo hay una clase de dominio + - Para la tabla de `producto` hay una clase `Producto` asociada + - Los objetos del tipo `Producto` representan un registro de la tabla +- Para acceder a la tabla se utiliza el estándar **Data Access Object (DAO)** + - Para cada clase de dominio hay un **DAO** asociado. Ejm, la clase + `Producto` posee la clase `ProductoDAO` + - Todos los métodos JDBC relacionados al producto están encapsulados en `ProductoDAO` +- Aplicación escrita en capas + - Las capas más conocidas son las de **view**, **controller**, **modelo** y + **persistencia**, que componen el estándar **MVC** +- El flujo de una consulta entre las capas es el siguiente + - `view` <--> `controller` <--> `persistencia` + +> **Note** No es buena práctica dejar los detalles de implementación de una capa en otras +que no tienen esta responsabilidad (ejm. la capa de controller lanzar una +SQLException) +> +> Esta es una aplicación desktop embebida, pero hay otros tipos de aplicaciones +con otros tipos de view, como html para aplicaciones web. + +## Relación entre tablas + +Creación tabla `categoria` + 4 categorías + +```sql +CREATE TABLE categoria(id INT AUTO_INCREMENT, + nombre VARCHAR(50) NOT NULL, + PRIMARY KEY(id) +)Engine=InnoDB; + +INSERT INTO categoria(nombre) + VALUES('Muebles'),('Tecnología'),('Menaje'),('Calzado'); +``` + +Modifcando tabla para agregar la columna `categoria_id` + +```sql +ALTER TABLE producto ADD COLUMN categoria_id INT; +``` + +Creando **llave foranea** + +```sql +ALTER TABLE producto ADD FOREIGN KEY(categoria_id) REFERENCES categoria(id); +``` + +Asignación de categoría a productos + +```sql +UPDATE producto SET categoria_id=1 WHERE id=1; +... +UPDATE producto SET categoria_id=1 WHERE id>11 AND id<17; +... +``` + +```sql +SELECT * FROM categoria; + ++----+-------------+ +| id | nombre | ++----+-------------+ +| 1 | Muebles | +| 2 | Tecnología | +| 3 | Menaje | +| 4 | Calzado | ++----+-------------+ +``` + +```sql +SELECT * FROM producto; + ++----+------------+--------------------------------+----------+--------------+ +| id | nombre | descripcion | cantidad | categoria_id | ++----+------------+--------------------------------+----------+--------------+ +| 1 | Mesa | Mesa de 4 lugares | 10 | 1 | +| 2 | Celular | Celular Samsung | 50 | 2 | +| 3 | Vaso | Vaso de cristal | 10 | 3 | +| 5 | Cuchara | Cuchara de plastico | 100 | 3 | +| 7 | Mouse | Mouse inálambrico | 100 | 2 | +| 9 | Linterna | Linterna con pilas recargables | 50 | 2 | +| 11 | Zapatillas | Zapatillas de futbol | 40 | 4 | +| 12 | Botellas | Botellas de vidrio | 50 | 1 | +| 13 | Botellas | Botellas de plástico | 24 | 1 | +| 14 | Platos | Platos de plastico | 50 | 1 | +| 15 | Platos | Platos de plastico | 10 | 1 | +| 16 | Platos | Platos de loza | 50 | 1 | +| 30 | Teclado | Teclado inalámbrico | 6 | 2 | ++----+------------+--------------------------------+----------+--------------+ +``` + +## Inner JOIN + +Cuando se tiene una relación entre tablas se debe cuidar de no crear el problema +de quieries `N+1`. Es decir, no buscar los datos de una relación en otras queries. + +Esto puede producir problemas de performance tanto en la aplicación como en la DB. + +Para ello utilizar ***join*** en la query SQL + +```java +... + public List listarConProductos() { + List resultado = new ArrayList<>(); + final String query = "SELECT C.ID, C.NOMBRE, P.ID, P.NOMBRE, P.CANTIDAD" + + "FROM categoria C INNER JOIN producto P ON C.ID = P.CATEGORIA_ID "; + System.out.println(query); + try { + final PreparedStatement statement = con.prepareStatement(query); + try (statement) { + statement.execute(); + final ResultSet resultSet = statement.getResultSet(); + try (resultSet){ + while (resultSet.next()) { + Integer categoriaId = resultSet.getInt("C.ID"); + String categoriaNombre = resultSet.getString("C.NOMBRE"); + var categoria = resultado + .stream() + .filter(cat -> cat.getId().equals(categoriaId)) + .findAny().orElseGet(() -> { + Categoria cat = new Categoria(categoriaId, + categoriaNombre); + resultado.add(cat); + return cat; + }); + Producto producto = new Producto(resultSet.getInt("P.ID"), + resultSet.getString("P.NOMBRE"), + resultSet.getInt("P.CANTIDAD")); + categoria.agregar(producto); + } + }; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + return resultado; + } +... +``` + +Aplicación [Control de Stock](./java_jdbc/control-de-stock/) +