20251209 BDR-Servlet_2 - Contenido educativo
Ajuste de pantallaEl ajuste de pantalla se aprecia al ver el vídeo en pantalla completa. Elige la presentación que más te guste:
Porque no estará el serlet correctamente configurado.
00:00:00
Si tú tienes la anotación web serlet bien puesta,
00:00:03
tiene que llegar a ese serlet.
00:00:06
Otra cosa es que ese serlet no haga nada, como es mi caso.
00:00:08
No hace nada.
00:00:10
¿Vale?
00:00:12
Vale.
00:00:20
A ver, como lo tenéis hecho, vamos,
00:00:21
el serlet entero, vamos a completarlo.
00:00:26
Que no os va funcionando a algunos.
00:00:30
ya lo arreglaremos, pero es que no quiero que nos paremos
00:00:32
mucho porque si no lo completamos
00:00:33
todo hoy, entonces vamos a
00:00:35
eternizarnos, que es lo que queremos evitar.
00:00:37
Venga, vale, pues ahora
00:00:40
vamos a completar el servlet.
00:00:42
Ahora ya el servlet
00:00:44
instanciará el servicio y todo eso.
00:00:45
Entonces ahora, tened abierto, porque vamos a ir
00:00:47
copiando y pegando de ahí,
00:00:49
tened abierto el servlet que os he pasado.
00:00:51
¿Qué he metido el qué?
00:00:59
Bueno, hijo, a ver
00:01:00
Espera
00:01:02
A ver, esto lo puedes dejar escrito así
00:01:05
No pasa nada, vamos a irlo completando
00:01:06
Copiando y pegando con lo que hay ahí
00:01:08
Para ir entendiendo lo que hace ese serlet
00:01:10
Entonces, ese serlet es
00:01:12
Debería ser
00:01:14
Este de aquí
00:01:17
Vale, entonces lo primero que os he incluido aquí
00:01:19
Es lo que os he dicho antes
00:01:24
Un serlet por acción, no
00:01:25
Uno por entidad y dentro del distinguir
00:01:27
Uno por entidad
00:01:30
entonces nos vamos a nuestro
00:01:31
serlet
00:01:36
esto lo comentamos ahora
00:01:36
esta es la acción
00:01:39
que la he metido en una acción para comparar
00:01:43
pero da igual, he hecho lo mismo
00:01:45
vale, entonces ahora
00:01:47
si la acción es listar
00:01:49
¿qué hay que hacer? pues llamará al método
00:01:51
getVentas del servicio
00:01:53
y ya está, y ahora construir la salida
00:01:55
y nada más, pero claro
00:01:57
el servicio tiene que estar instanciado
00:01:59
en algún sitio, bueno pues
00:02:01
el servicio, su sitio para ponerle
00:02:03
es que sea una propiedad
00:02:05
del serlet
00:02:08
que es una propiedad del serlet, pues venga
00:02:09
copiad y pegad, esta de aquí
00:02:11
esto de aquí
00:02:13
lo copiáis y pegáis
00:02:14
y lo ponéis en vuestro
00:02:17
serlet
00:02:20
como propiedad del serlet
00:02:21
vale
00:02:24
ala, este es nuestro
00:02:26
objeto-servicio, que es imprescindible
00:02:28
que exista
00:02:30
para que
00:02:31
el método
00:02:33
do-get y do-post puedan hacer
00:02:36
acciones. ¿Vale? Esto es que se está
00:02:38
recargando todo el rato, que es un coñazo.
00:02:40
¿Vale? Entonces, esto
00:02:43
lo que nosotros hacemos a mano, es lo
00:02:44
que ese maravilloso Spring que adoráis
00:02:46
se encarga de hacer, crear los
00:02:48
objetos y meterlos para adentro. Ya está.
00:02:50
Mete los objetos para adentro.
00:02:53
O sea, no hace nada más que
00:02:55
llamar dentro a estas cositas
00:02:56
bueno, pues ahora ya
00:02:58
¿qué queremos hacer si la acción
00:03:01
es lista? pues
00:03:03
si queréis
00:03:05
copiar y pegar
00:03:07
esto que hay dentro de if action
00:03:08
y bueno, primero
00:03:11
copiar esta línea del print writer
00:03:12
que está en el serlet que os he
00:03:17
pasado, porque aquí
00:03:19
esta es
00:03:21
la tubería de salida por la que
00:03:23
el serlet va a mandar el resultado
00:03:25
el serlet una vez que obtenga su resultado
00:03:26
lo va a mandar por su tubería
00:03:30
de salida que es esta
00:03:32
que vamos a sacarla del objeto response
00:03:33
pues vamos a crear primero esa tubería de salida
00:03:35
vamos a sacarla de ahí
00:03:38
pues venga la tubería de salida la copiáis
00:03:39
y la ponéis en vuestro serlet
00:03:42
ala aquí
00:03:44
esa es nuestra tubería de salida
00:03:45
y ahora que tenemos que hacer
00:03:50
pues llamar al servicio para sacar nuestra lista de ventas
00:03:52
pues venga
00:03:55
que es lo que está aquí
00:03:57
Llegamos al servicio
00:03:58
Para sacar nuestra lista de ventas
00:04:00
Y ahora ya construimos la salida
00:04:02
Entonces copiáis esto que está aquí dentro
00:04:04
De este if
00:04:06
Pues lo copiáis aquí
00:04:07
Vale, entonces
00:04:14
El método getVentas del servicio
00:04:26
Que llamará a su vez al del dao
00:04:29
Es
00:04:32
El que yo os pedí que hicierais
00:04:34
¿Verdad?
00:04:36
Pues vamos a hacerlo rápidamente
00:04:38
Este ya sí que lo vamos a hacer nosotros
00:04:40
Entonces vámonos a la clase servicio
00:04:41
vámonos a nuestra clase servicio
00:04:43
que es, a ver si yo no me meto en el proyecto
00:04:46
malo
00:04:49
vámonos a nuestra clase servicio
00:04:50
que teníamos
00:04:53
ya hecho un crear venta y un get venta
00:04:55
pues vamos a hacer
00:04:57
un
00:04:58
get ventas
00:05:00
un get venta me da una lista de ventas, ¿verdad?
00:05:01
que efectivamente no tiene
00:05:07
parámetros de entrada
00:05:12
porque me da todas las ventas de mi base
00:05:13
de datos, y ahora
00:05:17
¿Qué me devolverá este?
00:05:18
Pues me devolverá lo que haga el DAO
00:05:20
En su método
00:05:23
Que se supone que tenéis que completar
00:05:25
FindAll
00:05:26
Entonces habrá que hacer
00:05:27
De la implementación correspondiente
00:05:32
Que estamos usando
00:05:35
Habrá que hacer el método FindAll
00:05:36
Para poder hacer GetVentas
00:05:38
O sea GetVentas y aquí ya lo tenemos
00:05:41
¿Vale?
00:05:42
Aquí
00:05:43
El rojito
00:05:44
Este no sé dónde
00:05:47
pero da igual, vale
00:05:48
bueno, el ventaservice ya está
00:05:49
ahora, vámonos al
00:05:52
dao implementación para hacer ese método
00:05:54
vale
00:05:56
entonces, find all
00:06:02
lo tenéis en blanco
00:06:06
¿verdad? pues
00:06:08
fuera, todo fuera
00:06:11
todo fuera
00:06:14
vale, esto es lo que se supone, vosotros teníais que
00:06:15
haber hecho ahora, igual que este de aquí
00:06:18
pero
00:06:20
este ya sí que es parte de acceso a datos pura y dura
00:06:21
igual que hicisteis
00:06:24
una sentencia select pero por id
00:06:25
hará un select enterito
00:06:27
un select para todos
00:06:29
pues venga, lo que pasa es que ahora ya
00:06:31
sí que en lugar del objeto statement
00:06:33
vamos a usar el prepare
00:06:35
de statement que no permite
00:06:37
la inyección SQL porque este sí que
00:06:39
lo permite, es una chapuza
00:06:41
metéis ahí un drug database, lo mete
00:06:43
alguien en su formulario bien formado
00:06:45
con un or true o lo que
00:06:47
sea y ahí pasa cualquier cosa
00:06:50
pues venga, vamos a hacer nuestro
00:06:51
find all, ala
00:06:53
nuestro objeto resultante va a ser una lista de ventas que es el que vamos a
00:06:55
devolver inicialmente vacío inicialmente vacío y ahora ya vamos a hacer la
00:07:00
sentencia la sentencia ahora ya no va a ser un
00:07:10
statement normal sino un prepare statement de éste
00:07:14
statement y ahora este se crea a partir de la
00:07:21
conexión y la
00:07:25
conexión la sacamos
00:07:27
ya la tenemos
00:07:29
la conexión es la propiedad
00:07:31
de nuestro da implementación
00:07:33
pues con el método
00:07:36
prepareStatement
00:07:37
y aquí le damos el string
00:07:38
de la consulta, le damos
00:07:41
el string
00:07:43
pero donde le metemos los parámetros
00:07:44
interrogaciones, lo que pasa es que
00:07:47
en este caso, precisamente en este
00:07:49
no necesitamos interrogar parámetros
00:07:51
Escofron ventas
00:07:53
Vale, entonces
00:07:57
Este es un recurso que luego habrá que cerrar
00:08:01
Entonces este recurso
00:08:03
Vamos a meterlo en un try
00:08:05
Con recursos de estos
00:08:06
Y ahora
00:08:09
Vamos a
00:08:11
¿Vale?
00:08:12
Hombre, ¿cómo querrías hacerlo?
00:08:14
Si no
00:08:21
Ah, pero ¿y cómo lo has hecho?
00:08:21
Bueno, habrás hecho un statement
00:08:26
Normal
00:08:28
bueno ya, vale
00:08:30
pero bueno, estamos mencionando esto
00:08:33
entonces ahora ya
00:08:34
este, esto cuando
00:08:37
se ejecute, se va a ejecutar
00:08:39
con un
00:08:41
ejecutar query, vale
00:08:41
y este que me va a dar un result set
00:08:44
que el result set es la estructura
00:08:47
para
00:08:52
recoger registros de una consulta
00:08:53
también es un recurso que se va a cerrar
00:08:56
entonces podemos ponerlo
00:08:58
dentro del propio
00:09:00
try, entonces dentro
00:09:02
del propio try
00:09:04
podemos poner esto
00:09:05
entonces aquí abro los recursos
00:09:07
y luego
00:09:14
ya los
00:09:16
los uso
00:09:17
entonces
00:09:19
ahí tenemos el
00:09:22
cat
00:09:27
entonces voy a poner para que se quite el error de
00:09:27
compilación de arriba voy a poner ya
00:09:31
desde aquí el retumbentas
00:09:32
vale
00:09:34
bueno pues ahora
00:09:36
¿Qué vamos a hacer aquí?
00:09:38
Pues vamos a ir recorriendo el result set
00:09:42
Y para cada registro del result set
00:09:44
Instanciamos un objeto 20 y lo mandamos aquí
00:09:46
Y ya está
00:09:49
¿Vale? Pues como recorremos el result set
00:09:49
El result set tiene una sentencia
00:09:52
Un método que es next
00:09:55
Que te va avanzando el registro
00:09:57
Como inicialmente el result set se queda colocado
00:10:00
Antes de la primera lista de registros
00:10:03
pues tenemos que hacer un result set inicial
00:10:08
y el result set
00:10:10
además te devuelve true o false
00:10:12
si hay registro, no hay
00:10:14
entonces la recorrida estándar
00:10:16
de un result set siempre es así
00:10:18
avanzo y si tengo
00:10:20
avanzo y si tengo
00:10:23
avanzo y si tengo, ¿qué hacemos?
00:10:25
vamos a sacar los valores, primero vamos a instanciar
00:10:27
un venta
00:10:29
vacío y ahora le damos los valores
00:10:31
venta.set
00:10:34
id
00:10:37
pues vamos a sacar del registro
00:10:39
rs el campo
00:10:42
get integer
00:10:44
que se llame
00:10:45
id
00:10:48
es decir, con esto saco del registro
00:10:48
en el que estoy colocada
00:10:54
el campo que se llame id
00:10:55
ahora, vset
00:10:57
coche
00:11:00
pues con este saco el campo
00:11:02
que se llame, en la tabla como se llamaba
00:11:05
esto
00:11:09
Coche sería, ¿verdad?
00:11:09
Voy a ir abriéndolo por aquí
00:11:13
Vale
00:11:15
Se llamaría este campo, se llamaría coche
00:11:18
Imagino
00:11:21
V.set
00:11:22
Color
00:11:25
Pues saco del registro
00:11:27
El campo
00:11:30
Que se llame color
00:11:31
Y v.set
00:11:33
Nif comprador
00:11:38
Saco del registro
00:11:39
El campo que se llama
00:11:41
Nif barra baja
00:11:44
comprador curraría
00:11:47
si no lo cambiamos cuando toque
00:11:49
y ahora esta venta que acabo
00:11:51
de instanciar la añado a ventas
00:11:59
ala pues ya me he hecho
00:12:01
este método de find all
00:12:07
vale aquí
00:12:09
en particular haber usado la sentencia
00:12:11
pre compilada es un poco
00:12:14
tonto porque es que no
00:12:16
necesito pasarle parámetros
00:12:17
luego en el delete
00:12:19
que es el otro que nos falta por hacer
00:12:21
ahí si tiene más sentido hacer la sentencia
00:12:23
pre compilada porque ahí
00:12:25
Así que vamos a meter el ID.
00:12:27
¿Vale?
00:12:29
Pero bueno.
00:12:30
¿Vale?
00:12:31
Meteremos la venta.
00:12:32
Entonces, estos campos son los campos de la tabla.
00:12:32
Los nombres de los campos de la tabla.
00:12:36
Que están todos en el registro porque yo le he hecho asterisco.
00:12:38
Si mi select hubiera sido solo select coche color, por ejemplo,
00:12:42
pues yo solamente podría acceder a los campos coche color.
00:12:46
¿Vale?
00:12:49
Es decir, el result set tiene los registros del select.
00:12:51
Los que me ha devuelto el select.
00:12:54
con los campos que me haya devuelto
00:12:55
el select, yo los saco
00:12:57
con los métodos correspondientes
00:12:59
cada rs.next me avanza
00:13:00
un registro siguiente
00:13:03
y me devuelve true si ese registro
00:13:04
existe, entonces cuando ya me avance
00:13:07
a uno que no existe y por tanto me devuelva
00:13:09
falso, el while ya deja de entrar
00:13:11
el recorrido estándar
00:13:13
vale, pues
00:13:15
el find all está
00:13:17
dime
00:13:18
cuando preparo la declaración
00:13:21
ahí le meto la query
00:13:24
Utiliza prepárate statement
00:13:26
Justo
00:13:28
Es el statement normal
00:13:29
¿Vale?
00:13:33
Que en el statement normal también puedes ponerle la query
00:13:34
Cuando la creas, ¿eh?
00:13:37
Con el create statement y luego hacer el execute sin parámetros
00:13:38
Tienes las dos posibilidades
00:13:40
En el otro, ¿vale?
00:13:42
A ver, la diferencia
00:13:44
La diferencia es cómo le metes la query
00:13:45
Es que en el otro me da igual que le metas en el execute
00:13:48
Que arriba
00:13:51
La query la metes concatenando
00:13:51
Rompiendo el string y concatenando
00:13:54
con los parámetros, con lo cual te admite inyección
00:13:56
aquí no, aquí lo vamos a
00:13:58
hacer, lo vamos a ver mejor en el delete
00:14:00
aquí no se va a hacer concatenando
00:14:02
aquí se va a hacer poniendo interrogaciones
00:14:03
y luego vas a tener que hacer
00:14:06
luego unas acciones
00:14:08
adicionales
00:14:10
para inyectarlo por fuera
00:14:12
es decir, no los pones directamente en el
00:14:14
sino a través de métodos, los vas a ir metiendo
00:14:16
con lo cual no puedes hacer la inyección
00:14:18
esa es la diferencia
00:14:20
hombre, si le pones en el asterisco
00:14:21
entonces tienes que poner los nombres de los campos
00:14:25
¿qué quieres?
00:14:27
si quieres todos asterisco
00:14:29
y si quieres unos en concreto
00:14:32
los nombres de los campos separados por comas
00:14:34
vale, pues entonces
00:14:36
el find all está
00:14:38
el ventaservice entonces ya está
00:14:39
find all
00:14:42
get ventas
00:14:44
y ahora ya mi servlet
00:14:45
¿qué hace? llama al get ventas
00:14:47
y ya se construye una tabla
00:14:50
y va recorriendo
00:14:53
Todas estas ventas que ha sacando
00:14:55
Y las va metiendo en la tablita
00:14:57
Las va metiendo en la tablita
00:14:58
¿Vale? Entonces, ahora
00:15:00
Me falta, una vez que
00:15:02
He terminado el for, cerrar la tabla
00:15:06
Que eso lo vamos a copiar y pegar
00:15:09
Pues del
00:15:11
Del servlet, del servlet que os he dado
00:15:11
Que lo tendré
00:15:15
Aquí
00:15:16
¿Vale? Es decir
00:15:17
Falta cerrar la tablita
00:15:20
Falta cerrar la tablita después del for
00:15:22
Pues después del for cerramos la tablita
00:15:26
Y esto cierra mi if
00:15:29
De listar
00:15:32
Uy
00:15:34
Vale, ahora aquí
00:15:36
Lógicamente habría un
00:15:40
El save
00:15:43
Bueno, voy a poner abajo
00:15:50
Pues que
00:15:57
El save
00:15:58
Recuerdes para mi
00:16:00
Interaction
00:16:04
En el series que os he pasado
00:16:05
Lo tengo guardado en un string antes
00:16:08
Para que quede más bonito
00:16:09
Y no arrastrarlo todo el rato
00:16:10
Si la acción sin embargo
00:16:12
Fuera
00:16:16
Eliminar
00:16:17
Que es la otra
00:16:21
Que vamos a hacer
00:16:23
La otra eliminar
00:16:24
Porque es la que nos faltaba el método
00:16:25
Pues entonces lo que sea
00:16:26
lo que sea
00:16:29
la de eliminar me devolverá
00:16:29
un HTML diciendo si ha eliminado correctamente
00:16:35
o no se ha eliminado
00:16:37
no sé si he entendido tu pregunta
00:16:37
el parámetro, no se envía un parámetro
00:16:40
en el index
00:16:44
sí, lo tendremos que recoger aquí
00:16:44
bueno, a ver
00:16:48
es que la opción de eliminar, quien la va a invocar
00:16:49
es el formulario de eliminar
00:16:52
que todavía no tenemos hecho
00:16:54
claro, el formulario de eliminar
00:16:55
claro, nos falta el formulario de eliminar, que es el otro que os he pasado
00:16:56
vale, por ahora este seble
00:17:00
Se queda aquí vacío
00:17:01
Entonces este serlet es
00:17:02
El serlet para la entidad ventas
00:17:04
Y que recoge todo el club de ventas
00:17:07
¿Vale?
00:17:09
Bueno, pues entonces
00:17:12
Vamos a probar esto de listar ventas
00:17:13
A ver si las lista
00:17:16
Tendréis que lanzar la instancia del
00:17:17
Vale, a ver
00:17:20
Antes de probar nada
00:17:32
Porque no va a funcionar
00:17:34
Nos falta el properties, lógicamente
00:17:35
Vamos a revisar la conexión
00:17:37
Esto ya, ¿vale?
00:17:39
es decir, este
00:17:40
getConnection que me
00:17:43
inyecta aquí el service
00:17:45
que usa el serlet
00:17:47
vamos a revisar conexión
00:17:49
cuidado porque conexión
00:17:51
saca
00:17:55
las propiedades de un fichero de propiedades
00:17:56
que este no lo hemos puesto
00:17:59
entonces nos falta este
00:18:00
¿vale? porque si no nos va a decir
00:18:02
uy, nos saca
00:18:05
es decir, nuestra clase
00:18:06
de conexión que hemos copiado y pegado tranquilamente
00:18:09
sale de un archivo de properties
00:18:11
pues hombre, vamos a meter
00:18:13
ese archivo de properties
00:18:15
entonces como está
00:18:16
dentro del cargador de objetos
00:18:18
sácame como un recurso
00:18:21
como flujo, pues tenemos que ponerlo
00:18:23
en una ruta del path
00:18:25
que por defecto en los proyectos de Maven
00:18:27
es la de resources
00:18:28
pero el Eclipse no te crea
00:18:30
el main java resources
00:18:34
directamente, entonces hay que
00:18:37
crearlo a mano, pero no pasa nada
00:18:39
entonces directamente
00:18:41
la carpeta java
00:18:43
en la carpeta
00:18:44
no en la main
00:18:46
en la carpeta main
00:18:48
creáis una folder resources y ya está
00:18:49
entonces
00:18:52
aquí src
00:18:54
aquí en main, veis donde están abajo
00:18:56
todas las carpetas, aquí en main
00:18:58
creáis una
00:19:00
una folder
00:19:02
exactamente
00:19:04
resources
00:19:05
que esta
00:19:07
por llamarse así, por llamarse
00:19:10
resources y no Pepito Pérez
00:19:12
cuando esto se empaquete
00:19:14
en war, en jar, como sea
00:19:16
esto va a ir a la raíz, al pad
00:19:18
con lo cual se va a encontrar todo lo que hay ahí dentro
00:19:20
pues ahora ya en resources
00:19:23
el mismo base de datos property
00:19:24
del otro proyecto lo metéis ahí
00:19:26
pues del otro proyecto
00:19:28
el mismo base de datos
00:19:32
properties
00:19:34
lo metéis ahí
00:19:35
ala, ahí está el base de datos properties
00:19:39
que tendrá la url
00:19:51
donde está el sistema gestor de base de datos
00:19:53
con la base de datos
00:19:55
con la que vais a trabajar
00:19:57
y el usuario, root 1, 2, 3, 4
00:19:58
muy mal usado, pero bueno
00:20:01
vale
00:20:02
pues en principio
00:20:05
estaría todo, en principio
00:20:08
la conexión debería encontrarla
00:20:10
porque con nuestro objeto conexión
00:20:13
saca los datos del properties
00:20:14
y hace la getConnection
00:20:16
y me la devuelve a través del método
00:20:18
getConnection. El service
00:20:20
me llama al DAO,
00:20:24
el DAO llama a findAll,
00:20:26
el findAll
00:20:28
ahora ya
00:20:29
a través de la conexión saca
00:20:32
la lista de ventas y me la devuelve
00:20:34
y el serlet
00:20:36
que ya no sé ni dónde está
00:20:37
aquí, y el serlet
00:20:40
con esas ventas que me ha sacado
00:20:42
pues las construye.
00:20:44
Muy sencillito, ¿vale?
00:20:46
Vale, pues vamos a
00:20:48
volver a lanzar esta aplicación
00:20:50
con que
00:20:52
reiniciéis el
00:20:56
server, ya se redespliega
00:20:58
sola, si aquí os vais al server
00:21:01
y le decís restart
00:21:03
se redespliega la nueva versión de la aplicación
00:21:04
entonces
00:21:07
restart, ahí está
00:21:09
y ahora me voy a abrir el explorador
00:21:15
y voy a
00:21:17
llamar a mi aplicación
00:21:19
que es esta
00:21:21
este es mi formulario
00:21:21
Ahora
00:21:25
Vamos a llamar
00:21:28
Cualquiera de estos que llamemos
00:21:29
Me va a decir que no encuentra el recurso
00:21:31
Porque cualquiera de estos va a un formulario
00:21:33
Que no tenemos hecho
00:21:36
Entonces cualquiera de estos que llame yo
00:21:36
Va a un formulario que todavía no está
00:21:38
Con lo cual no va a salir
00:21:40
Y este ya sí que va al serle directamente
00:21:41
El de abajo sí
00:21:43
Vamos a ver qué pasa
00:21:44
Toma ya
00:21:46
Vale
00:21:48
Connection is null
00:21:51
¿Vale?
00:21:54
Sí
00:21:57
La tengo levantada
00:22:01
Vale, si yo voy hasta arriba
00:22:05
En toda mi traza, no
00:22:06
Este error lo esperaba
00:22:08
Y esto es lo más bonito y maravilloso que os quería explicar hoy
00:22:10
Y me dice
00:22:13
Lo siento
00:22:15
Pero no encuentro el driver
00:22:17
Para esta URL
00:22:18
El properties lo ha leído bien
00:22:20
Porque si no, no habría encontrado esta URL
00:22:23
Que está en el properties
00:22:25
y la cadena de conexión está estupenda
00:22:26
¿cómo que no encuentras
00:22:29
un driver? ¿cómo puede ser
00:22:31
que no lo encuentres?
00:22:33
si tú tienes en tu POM
00:22:35
aquí
00:22:36
tienes aquí en el POM, y no hace falta que entre en el POM
00:22:37
os vais a las dependencias
00:22:41
de Maven y tienes aquí un driver
00:22:43
como un castillo
00:22:45
¿cómo puede ser que no lo encuentre?
00:22:46
pues no lo encuentra
00:22:50
¿y por qué no lo encuentra?
00:22:51
pues claro, aquí viene
00:22:54
la maravilla
00:22:57
y es
00:22:59
porque aquí hay dos programas vivos
00:23:00
sin contar la máquina virtual
00:23:03
aquí está mi aplicación
00:23:05
y está el Tomcat
00:23:07
y cada uno de ellos
00:23:09
tiene su ámbito de instancias
00:23:11
distinto
00:23:13
antes yo tenía
00:23:15
en la aplicación de escritorio teníamos una única instancia
00:23:16
que era mi aplicación
00:23:20
con lo cual todos los objetos existentes
00:23:21
incluyendo los propios driver
00:23:23
estaban en un único ámbito
00:23:25
todos se miraban, se veían con todos
00:23:27
ahora que ha pasado aquí
00:23:30
cuando la aplicación
00:23:32
se ha cargado
00:23:34
cuando el Tomcat se ha cargado
00:23:35
perdón, cuando la aplicación se ha cargado
00:23:38
se ha cargado
00:23:40
la clase
00:23:42
DriverManager
00:23:44
entonces DriverManager que es
00:23:45
a ver
00:23:47
DriverManager es esto
00:23:49
vámonos a la clase Connection
00:23:51
driverManager es este tío, ¿verdad?
00:23:53
donde tenemos el
00:23:59
este
00:24:00
driverManager es este, vale, esta es una clase
00:24:01
que se dedica
00:24:04
a manejar todos los objetos driver
00:24:06
que tenga la aplicación
00:24:08
en mi caso va a tener solo uno, el de MySQL
00:24:09
pero podría tener muchos
00:24:13
esta es una clase que se dedica a manejar
00:24:14
todos los objetos driver que tenga
00:24:16
esta clase cuando se carga
00:24:17
se carga con el
00:24:20
Tomcat, porque cuando mi aplicación arranca
00:24:22
cuando yo la haya arrancado
00:24:24
primero arranca el Tomcat
00:24:26
y luego arranca la aplicación
00:24:28
el Tomcat arranca
00:24:30
y arranca su driver manager
00:24:32
que es su gestor de drivers
00:24:35
que ahí se queda tan pancho
00:24:36
vale, luego arranca la aplicación
00:24:38
y la aplicación
00:24:41
instancia
00:24:43
sus dependencias, entre ellas
00:24:44
la del driver de MySQL, que es esta
00:24:46
vale, esta de aquí
00:24:49
luego
00:24:51
el driver
00:24:53
está en el contexto de objetos
00:24:54
de la aplicación
00:24:56
y el driver manager está en el contexto
00:24:57
de objetos del Tomcat, con lo cual no se ven
00:25:00
entonces, el driver
00:25:02
cuando yo le digo aquí
00:25:04
a driver manager getConnection
00:25:05
cuando hago esto de aquí
00:25:08
driver manager ¿qué hace?
00:25:10
voy a buscar un driver
00:25:12
para manejar esta conexión, voy a buscarlo
00:25:14
dice, pero si no tengo ningún driver
00:25:17
claro, porque driver manager está
00:25:18
mirando en su ámbito
00:25:20
de objetos, y su ámbito de objetos
00:25:22
instanciados es el ámbito del Tomcat
00:25:24
y sin embargo
00:25:25
nuestro driver está instanciado
00:25:27
en el ámbito de la aplicación, porque es una dependencia
00:25:30
de la aplicación, no es una dependencia del Tomcat
00:25:32
es una dependencia de la aplicación
00:25:34
entonces driver mayer te dice, perdóname
00:25:35
no tengo ningún driver, no lo tiene
00:25:37
vale, pues
00:25:40
¿cómo arreglamos esto?
00:25:42
pues hay que hacer una cosa
00:25:43
que es registrarlo
00:25:44
específicamente y decirle
00:25:48
aquí al Tomcat cuando el Tomcat está leyendo
00:25:50
esto, oye tú
00:25:52
instánciate esto, cógete este objeto
00:25:53
que te va a hacer falta, cógete este
00:25:56
porque está instanciado
00:25:58
está registrado, que se llama así
00:25:59
en el ámbito de objetos de la aplicación
00:26:01
pero en el tuyo
00:26:04
bueno, pues ¿cómo se le dice eso?
00:26:04
pues con una sentencia
00:26:08
que se llama
00:26:09
esta de aquí
00:26:10
que esta es la que te obliga
00:26:12
a registrar
00:26:19
objetos, en tu ámbito de objetos
00:26:22
entonces aquí vamos a poner
00:26:24
el
00:26:25
espera, el driver
00:26:26
que el driver, uno podría buscar desde aquí
00:26:29
como se llama, se iría a la dependencia
00:26:31
lo buscaría, como se llama
00:26:33
com.mysql
00:26:35
cjjdbc
00:26:37
driver, este es
00:26:39
mi driver, este es el objeto que yo quiero
00:26:43
este es el objeto que quiero
00:26:45
que se quede visible
00:26:47
en el ámbito de objetos del podcast
00:26:48
pues transformamos y ponemos todo
00:26:50
com.mysql
00:26:52
punto
00:26:56
punto jdbc, no este es el antiguo, es con el cj delante, con el cj, es el moderno,
00:26:59
está aquí, este sería, driver, este sería que está en comma y sql, cj.jdbc.driver,
00:27:12
Y esto puede lanzar una excepción
00:27:26
Porque esa clase no existiera
00:27:33
No pasa nada
00:27:35
Bueno pues con esto
00:27:37
Hacemos que la instancia
00:27:41
Driver que estaba solamente
00:27:43
En el ámbito de dependencias de la aplicación
00:27:44
Pum, pase al Tomcat
00:27:46
Porque Tomcat es el que va haciendo todo eso
00:27:48
Es que se me abre sola la ventanita esa
00:27:50
Entonces
00:27:56
Esto
00:28:00
esta sentencia
00:28:01
es la sentencia que se ha llamado de toda la vida
00:28:09
registrar el driver
00:28:11
para que el driver manager lo encuentre
00:28:13
entonces hasta la versión no sé qué
00:28:15
de los
00:28:18
drivers MySQL hasta la 8
00:28:20
o no sé cuál, había que verlo siempre sí o sí
00:28:21
pero a partir de la
00:28:24
versión 8 de los drivers
00:28:26
el driver se carga solo
00:28:27
con lo cual no hay que
00:28:29
ponerla, pero claro, se carga
00:28:31
solo en tu aplicación
00:28:33
si te está ejecutando otro como es el Tomcat
00:28:35
a él no le vale lo que tú te has cargado
00:28:37
por eso tienes que poner esto
00:28:39
para que él lo vea visible
00:28:41
con lo cual, las aplicaciones web
00:28:43
que se ejecutan a través de
00:28:45
un secundario que es el Tomcat
00:28:47
pues vas a tener que registrar
00:28:49
todos los objetos que necesite
00:28:51
el Cyber Manager
00:28:53
Entonces
00:28:54
A ver, voy a ver porque si lo tengo
00:29:01
Esto, este es el proyecto que voy a subir
00:29:03
Si lo tengo escrito por aquí
00:29:05
Lo copio y pego para que se quede subido
00:29:06
Se suponía
00:29:09
Que lo escribí por aquí para subirlo
00:29:12
Esto
00:29:14
Todo este rollo
00:29:16
En todo este rollo intenté explicar esto
00:29:18
Lo intenté explicar más o menos
00:29:20
Pues todo este rollo lo copio aquí
00:29:21
Para que cuando suba el proyecto
00:29:23
Pues se quede así
00:29:27
Esto lo voy a subir ahora
00:29:28
Porque lo estamos construyendo
00:29:37
¿Vale? Lo voy a subir cuando lo acabemos
00:29:38
Vale
00:29:41
¡Hala!
00:29:42
Pues ahora ya sí no debería
00:29:45
Darme ese error de que no encuentro el driver
00:29:47
Ahora tienes que encontrarlo muchacho
00:29:49
Vale
00:29:50
Pues vamos a
00:29:52
Reiniciar el server
00:29:54
Restart
00:29:57
Vamos a darle marcha a Catalina
00:30:01
Y...
00:30:06
Ah, que tenía cerrado yo mi explorador
00:30:11
Tengo aquí mi este
00:30:14
Listar ventas
00:30:17
Mirad que bonito
00:30:19
¿Vale? Ventas listadas
00:30:20
Todo estupendo
00:30:23
Vamos a hacer eliminar ventas
00:30:24
Que ahora ya sé que va a necesitar un formulario
00:30:26
Con otro, el método que nos faltaba
00:30:28
Eliminar ventas
00:30:30
claro, pero eso como una sentencia ya está
00:30:31
no haría falta devolver nada
00:30:38
en el método de
00:30:40
bueno, no hace falta devolver
00:30:43
hombre, un mensaje de ok
00:30:44
que menos
00:30:45
pero lo que sí que necesita a cambio es un parámetro
00:30:46
es que id quieres eliminar
00:30:50
que este no necesitaba nada
00:30:52
pues venga
00:30:53
dígame
00:30:55
¿te acuerdas de un cambio
00:30:56
de que estaba barra coche
00:30:57
que no fuera el barra venta
00:30:59
si, en el
00:31:01
index, en el index
00:31:04
aquí, en el
00:31:07
index, aquí
00:31:09
yo tenía puesto coches porque era la url
00:31:10
del otro proyecto, pues ventas
00:31:13
vale, pues vamos
00:31:14
ahora a hacer eliminar
00:31:17
que es el que nos faltaba, podríais
00:31:18
hacer estos
00:31:21
y ya está
00:31:22
desde webapp
00:31:23
todo lo que
00:31:30
webapp es la raíz
00:31:32
de la url, de alguna manera
00:31:34
vale, pues venga, eliminar
00:31:37
venta, pues vamos a hacer este
00:31:39
formulario al que me lleva este enlace
00:31:40
pues más que hacerlo, lo vais a copiar
00:31:42
de lo que os he pasado
00:31:45
yo y los domingos por la tarde, subiendo
00:31:46
cosas para que no
00:31:52
nos herniemos copiando
00:31:54
Venga, vamos a copiar el form
00:31:56
Eliminar
00:32:03
Y lo hacemos colgar
00:32:04
De webapp
00:32:10
Webapp, vale, ¿dónde está webapp?
00:32:11
Jolines, que no veo ni webapp
00:32:32
Ahí, paste
00:32:34
Vale, pues vamos a ver el formulario
00:32:35
De eliminar, aparte del estilo
00:32:40
ese tan bonito que nos ha dado ChaGPT.
00:32:42
Eliminar
00:32:45
venta. Cuidado
00:32:46
el action del formulario.
00:32:48
Vamos a cambiarlo
00:32:51
porque mi serlet yo lo he
00:32:51
hecho colgar de ventas.
00:32:53
Cuidado. Cuidado
00:32:56
primero. Action del formulario.
00:32:57
Juanjo y Ana.
00:33:00
Que luego decís, ¿dónde habéis cambiado? Pues en el
00:33:02
action del formulario.
00:33:03
Ventas. ¿Vale?
00:33:06
Y ahora, le pasamos
00:33:08
como parámetro escondido
00:33:10
qué queremos hacer con ese formulario, ¿vale?
00:33:11
Como parámetro escondido le pasamos E, que es eliminar,
00:33:14
lo que queremos hacer, ¿vale?
00:33:17
Que es eliminar.
00:33:19
Y ahora le pasamos el ID de la venta
00:33:20
con esta caja tan bonita de números
00:33:23
que me va a salir luego y un volver al menú y ya está.
00:33:25
Luego los parámetros que envía este formulario
00:33:28
son como escondido la acción a hacer
00:33:30
para que el ser le sepa que tiene que eliminar
00:33:32
y el ID y ya está.
00:33:35
Pero, importante,
00:33:37
este método no va en GET
00:33:40
no debería ir en GET
00:33:42
sino que va en POST
00:33:43
¿es obligatorio?
00:33:45
no es obligatorio
00:33:47
pero es conveniente para evitar mal funcionamiento
00:33:48
¿por qué este en POST y el otro en GET?
00:33:52
claro
00:33:55
el otro iba en GET
00:33:56
porque el otro consultaba
00:33:57
no cambiaba datos de la base de datos
00:33:58
este
00:34:01
al igual que el de actualizar o insertar
00:34:02
va a modificar los datos
00:34:05
con lo cual debería ir en POST
00:34:07
¿por qué exactamente?
00:34:09
pues bueno, por muchas implicaciones
00:34:11
o sea, una por ejemplo, una importante
00:34:13
cuando tú le das a F5
00:34:15
a un formulario
00:34:17
¿vale? si el formulario
00:34:18
es, tú lo tienes
00:34:21
como GET, no te pide
00:34:23
confirmación de reenvío
00:34:25
entonces, si estás modificando los datos
00:34:26
si es un formulario que modifica, igual lo estás
00:34:29
haciendo un insert una y otra vez, una y otra vez
00:34:30
y no quieres hacerlo, sin embargo, si el formulario
00:34:33
es POST y tú le das a F5
00:34:35
él te dice
00:34:37
desear reenviar los datos del formulario
00:34:38
esa ya es la primera cosa
00:34:41
interesante
00:34:43
segunda, los GET
00:34:43
van a la, los formularios GET
00:34:47
los resultados de los formularios GET
00:34:49
van a la caché
00:34:50
se cachean, los POST no
00:34:52
¿vale?
00:34:54
entonces, es que es justo lo que
00:34:57
queremos
00:34:59
los POST no queremos que se
00:34:59
cacheen, porque si se cachean, yo a lo mejor
00:35:03
creo que estoy insertando ventas
00:35:05
y no lo estoy haciendo
00:35:06
porque estoy todo el rato en local
00:35:07
con el get no es tan importante
00:35:09
que estar tirando de la cache
00:35:12
vale, si tiro de la cache
00:35:14
no estaré refrescando la consulta
00:35:16
pero lo grave es cuando estoy actualizando
00:35:18
cosas sin saber
00:35:20
entonces hay diferencias entre
00:35:21
cómo trata el navegador
00:35:24
un formulario get y un formulario post
00:35:25
cómo lo trata, vale
00:35:28
entonces precisamente por esa diferencia en cómo se trata
00:35:29
un formulario get y post desde el navegador
00:35:32
asumimos
00:35:34
Que las acciones CRU de modificar van en POST y las de consultar en GET.
00:35:36
Aparte que ya sabéis que en el POST los parámetros se mandan en el cuerpo de la petición,
00:35:45
con lo cual no son visibles a simple vista y en el GET se mandan.
00:35:51
Entonces, un segundo, en un formulario que vas a insertar datos y estás mandando los datos,
00:35:54
si lo mandas como get
00:36:00
es que van todos puestos
00:36:02
en la URL y los ves, se ven
00:36:04
se ven directamente
00:36:06
lo que vas a insertar Pepito con su DNI
00:36:07
con su no sé qué, mejor en post
00:36:09
y así va en el cuerpo y no ves los datos
00:36:12
que vas a insertar, estoy convencido
00:36:13
que me podría haber callado mucho antes
00:36:16
porque ya estarías convencido de antes
00:36:18
claro, vale
00:36:19
pues entonces, este va a hacer post
00:36:21
con lo cual
00:36:24
a qué punto de mi serlet va a llegar
00:36:26
va a llegar aquí
00:36:28
pero no pasa nada porque yo no me voy a duplicar
00:36:30
el mismo código en los dos sitios
00:36:33
de aquí hago este código y ya está
00:36:34
¿vale? no significa esto
00:36:36
que el formulario haya cambiado de post a get
00:36:39
el formulario sigue siendo post y se trata
00:36:41
como post en el navegador, pero el código
00:36:43
de respuesta pues se va
00:36:45
aquí arriba, entonces se va aquí arriba
00:36:47
y ahora ya sí, oye si el parámetro
00:36:49
action es igual a eliminar
00:36:50
que va a ser precisamente el parámetro
00:36:52
action que va a ser el que lleva
00:36:55
el formulario
00:36:57
¿no? lleva el parámetro
00:36:57
eliminar, pues entonces
00:37:00
ahora ya tendremos que sacar el id
00:37:02
y eliminar por id
00:37:04
pues venga, ahora ya tendremos que hacer
00:37:05
nuestro service y llamar
00:37:08
al método
00:37:10
service.delete
00:37:10
uy, no lo tenemos
00:37:17
eliminar venta, pues vamos a crearlo
00:37:18
en el servicio
00:37:20
a ver, el código
00:37:20
no es que lo esté dejando, o sea, es que
00:37:26
este método doPost
00:37:28
está ejecutando
00:37:30
este código, pero el formulario sigue siendo
00:37:32
post, lo que pasa es que no duplico el código
00:37:34
en los dos sitios, porque como va a ser el mismo
00:37:36
pero una cosa es el código de respuesta
00:37:37
y otra cosa es como trata
00:37:40
el navegador el formulario por cuestiones
00:37:41
independientes
00:37:44
vale, pues entonces aquí
00:37:46
vamos a hacernos
00:37:48
en el servicio
00:37:50
en el ventaservice este
00:37:51
vamos a hacernos el método que nos falta
00:37:55
que es el de
00:37:59
public
00:38:00
vamos a
00:38:02
en lugar de un void
00:38:05
pues para ya usar el parámetro
00:38:08
de retorno para ver si realmente se eliminó
00:38:10
o no, pues vamos a
00:38:13
un boolean, para yo poder devolver
00:38:14
en un html, si se eliminó correctamente
00:38:16
no, no se pudo eliminar, yo que sé
00:38:18
pues venga
00:38:20
delete venta
00:38:22
delete venta que
00:38:24
necesita un integer id
00:38:26
y ahora este es el que me va a llamar
00:38:28
directamente al dao.deleteventa by id
00:38:31
vale
00:38:36
que es el que tenemos que hacer
00:38:37
entonces me da un error porque el deleteventa by id
00:38:39
que yo había dejado planteado
00:38:42
no me devolvía boolean pero lo cambiamos a boolean y ya está
00:38:44
facilísimo
00:38:47
venga vámonos al dao implementación
00:38:50
y este deleteventa by id que estaba
00:38:54
sin hacer, vamos a ponerle
00:38:56
primero un boolean
00:38:59
y ahora ya si que vamos a las
00:39:00
maravillas del
00:39:04
prepare statement
00:39:06
pues venga
00:39:07
mi sentencia
00:39:09
va a ser prepare
00:39:11
statement
00:39:15
conexión
00:39:17
el objeto conexión que es
00:39:21
connection
00:39:23
connection punto
00:39:24
prepare statement
00:39:27
ahora delete
00:39:28
from
00:39:31
coches
00:39:32
creo que se llamaba la tabla
00:39:34
no, se llamaba ventas
00:39:37
coches era la base de datos
00:39:40
delete from ventas
00:39:41
where
00:39:43
id igual
00:39:44
y ahora ya si que si
00:39:47
pumba
00:39:49
interrogación, nada de concatenar y partir
00:39:50
ahí el este
00:39:53
ahora este como es un recurso que se va
00:39:54
a cerrar, pues lo meto yo en mi try
00:39:57
con recursos
00:39:59
lo meto en el try
00:40:00
con recursos este de aquí
00:40:04
y ahora ya
00:40:06
antes de ejecutar
00:40:10
el delete, tengo que fijar en los parámetros
00:40:11
pues venga
00:40:14
este solo tiene uno
00:40:16
que es entero, pues ps.set
00:40:18
int
00:40:21
la interrogación de posición
00:40:22
1, dale el valor id
00:40:24
uy, id
00:40:26
no, id
00:40:28
así
00:40:29
vale
00:40:31
que yo tengo una sentencia
00:40:33
con más interrogaciones
00:40:35
o el ID igual a no sé
00:40:38
cuántos que tienen más interrogaciones
00:40:40
por eso es un SQL gordote
00:40:42
pues voy fijando cada una
00:40:43
uno es la primera interrogación en orden de aparición
00:40:46
dos la segunda interrogación en orden de aparición
00:40:49
porque este no es una colección
00:40:50
de datos
00:40:57
lo que empieza por cero son las colecciones
00:40:57
los arrays, todo lo que es
00:41:00
Esto no son datos, en realidad.
00:41:02
Hombre, es la mejor forma de transmitir
00:41:09
aquí falta algo, ¿no? ¿Qué otro símbolo pondrías?
00:41:12
Interrogación no es porque yo lo diga, sino porque es así.
00:41:15
No, no, porque me apetece, no.
00:41:21
Porque el método prepareStateMath
00:41:23
interpreta donde hay interrogaciones
00:41:28
que tú lo vas a fijar luego.
00:41:31
Tienen que ser interrogaciones sí o sí por obligación
00:41:32
¿A qué te refieres?
00:41:35
¿Va a la interrogación por una X, por ejemplo?
00:41:41
Hombre, pero entonces
00:41:46
¿No estamos haciendo una sentencia
00:41:47
Con el preparo de statement?
00:41:49
¿Estás haciendo un statement normal a que puedes meter inyección?
00:41:51
Que no queremos eso
00:41:54
A ver, lo puedes hacer de esa manera
00:41:55
Pero tienes un código peligroso
00:41:59
Una aplicación con unos agujeros de seguridad
00:42:01
muy gordos
00:42:03
de inyecciones SQL
00:42:04
no, porque
00:42:09
esto ya se ha precompilado
00:42:10
con lo cual esto no es una concatenación tal cual
00:42:12
entonces si el usuario me mete
00:42:15
aquí un Drop Database
00:42:17
el Drop Database no encaja en ese
00:42:18
hueco, porque eso ya está precompilado
00:42:21
y él ya sabe por esa precompilación
00:42:23
que aquí tiene que ir un entero
00:42:25
entonces tú le metes algo que sea un entero
00:42:27
como un Drop Database y dice
00:42:29
uy, esto no me encaja aquí, aquí se lo ponen enteros
00:42:30
Entonces, no casa.
00:42:33
Sin embargo, con lo que tú has hecho...
00:42:34
¿Dónde?
00:42:35
Hombre, pero es que tal vez
00:42:41
te estás tú matando a ti mismo porque tú eres
00:42:42
el que nos está escribiendo esto.
00:42:43
Si puedes cambiar de lado abajo, puedes cambiar de lado arriba.
00:42:45
No tiene sentido.
00:42:47
¿Cómo que no tiene sentido?
00:42:49
No acabo de entender lo que me estás diciendo tú.
00:42:51
Aquí la idea, la aplicación
00:42:53
se craquea desde fuera.
00:42:55
Desde sus puntos de entrada.
00:42:57
Aquí el único punto de entrada es la interrogación.
00:42:59
No hay otro.
00:43:01
porque todo lo demás es código
00:43:02
que has escrito tú
00:43:05
en el otro, el más
00:43:07
y lo que pones aquí es un punto
00:43:13
de entrada, porque es directamente
00:43:16
el parámetro que tú metes
00:43:17
y ahí como es una concatenación
00:43:20
cuela cualquier cosa
00:43:22
porque es concatenación
00:43:24
pero aquí no estamos concatenando
00:43:25
aquí estamos
00:43:26
¿dónde?
00:43:27
en el primer caso
00:43:30
en el primer caso
00:43:40
no te explotas
00:43:42
no te explotas
00:43:43
pero tú tienes que concatenar bien
00:43:44
si tú lo concatenas
00:43:48
podemos hacer luego un ejemplito
00:43:49
que claro que te explota
00:43:51
pero tienes que ser listo
00:43:52
y no concatenar con lo que él espera
00:43:53
y luego concatenar
00:43:58
con el procedimiento almacenado que sea
00:43:59
de los database, o sea, poner una cosa
00:44:01
SQL que concatenada
00:44:03
con lo que tú has escrito tenga sentido
00:44:05
y claro que hay posibilidades
00:44:07
¿Cómo?
00:44:09
¿Qué has dicho?
00:44:15
A ver, esta situación
00:44:18
de aquí arriba
00:44:23
esta
00:44:24
y poner la interrogación
00:44:32
aquí dentro, no tienen nada que ver
00:44:36
¿por qué?
00:44:38
en esta, tú primero haces
00:44:42
un stream
00:44:44
que aquí no hay todavía ni jdbc
00:44:45
ni seguro, haces un stream
00:44:48
y ahora este stream lo haces
00:44:49
cogiendo este stream
00:44:51
y concatenándole algo que te ha metido
00:44:53
alguien en un formulario.
00:44:56
Imagínate que sea algo que te ha metido
00:44:58
alguien es uno
00:45:00
and no sé qué, and no sé
00:45:01
cuánto, punto y coma,
00:45:04
llamado de orden de almacenado. Algo
00:45:05
cuyo resultado final
00:45:07
es un script válido en SQL.
00:45:09
Bueno, pues ese
00:45:13
script válido en SQL ahora lo ejecuta
00:45:14
sin pensar.
00:45:16
Pues se hace todo lo que hay en ese
00:45:18
script. Claro, el que sea
00:45:20
tendría que hacer todas las pruebas necesarias
00:45:22
para que lo que pone aquí
00:45:24
encaje y te genera un SQL válido.
00:45:25
Pero no deja de ser
00:45:28
una prueba y error que se puede hacer y es un
00:45:29
agujero de seguridad y no es tan
00:45:31
difícil de hacer. La opción
00:45:33
la tienes abierta. Abajo es
00:45:35
imposible. Abajo es imposible
00:45:37
porque ahora cambio. Yo pongo
00:45:40
aquí una interrogación y luego
00:45:42
lo fijo con el set view.
00:45:43
Aquí, ahora ya
00:45:46
JDBC te analiza
00:45:47
esto, te hace un preanálisis
00:45:49
y te dice, vale, esto es una
00:45:51
sele y aquí tengo una cajita
00:45:53
donde solo voy a permitir que
00:45:55
entre un número entero, solo voy a permitir un número entero
00:45:57
y ese número entero lo meto
00:45:59
con setting, si tú le metes
00:46:01
aquí
00:46:04
le metes
00:46:05
algo que no sea
00:46:08
un entero, es que no te va a dejar
00:46:10
te va a decir, te va a petar
00:46:12
la aplicación, porque esto es una
00:46:13
cajita para un entero
00:46:15
sin embargo ahí es una concatenación para lo que te dé la gana
00:46:16
lo otro es lo que te dé la gana
00:46:20
el otro es una cadena
00:46:25
la cadena que tú quieras
00:46:26
pero que no te tiene
00:46:27
pero da igual
00:46:30
porque tú no verificas en ningún momento
00:46:32
que sea un íntegro, tú haces el ejecute
00:46:34
tú no verificas que sea un íntegro
00:46:36
aquí, ¿dónde estamos?
00:46:39
aquí
00:46:43
¿en qué momento?
00:46:44
¿en qué momento he comprometido yo
00:46:45
a que eso sea un íntegro?
00:46:48
¿en qué momento?
00:46:50
a ver, no, pero es que esto lo ha convertido
00:46:51
a stream, yo aquí puedo meter cualquier
00:46:58
cosa
00:47:00
a ver
00:47:00
aquí en el
00:47:09
te refieres, cuando tú llamas al find by id
00:47:11
este método sí te está haciendo
00:47:13
un filtrado
00:47:16
el método sí te está haciendo un filtrado
00:47:16
pero en un caso genérico
00:47:19
esto podría ser estructurado de otra manera
00:47:20
estamos hablando de que esta sentencia
00:47:22
tiene un agujero de seguridad
00:47:24
en mi arquitectura de aplicación en concreto
00:47:25
que yo he filtrado
00:47:29
poniendo un método antes que tenga un ID
00:47:30
pues hombre, no te va
00:47:32
a compilar, pero hablo
00:47:34
en general, en general esto es un agujero de seguridad
00:47:36
porque aquí puedes concatenar con cualquier
00:47:39
cosa
00:47:40
No he entendido nada de lo que has dicho
00:47:52
Más que no lo he entendido, que no lo he oído
00:47:57
Yo es que no lo he oído
00:48:00
Pero con que lo hayáis oído y entendido vosotros es suficiente
00:48:03
Pero bueno, la idea
00:48:06
La idea está, ¿no?
00:48:09
Claro
00:48:13
O sea, que esto, jolín, es que metes lo que vas a hacer
00:48:13
Claro, bueno
00:48:16
Vale, pues ya está
00:48:19
Vale, pues
00:48:25
Bueno, pues ahora
00:48:29
Fijamos
00:48:31
¿Quién se ha ido?
00:48:32
Vale, entonces fijamos este entero
00:48:39
Y ahora
00:48:41
Lo ejecutamos
00:48:42
como este es un delete
00:48:44
es un execute
00:48:49
update
00:48:51
¿vale?
00:48:52
porque actualiza la base de datos
00:48:55
entonces el execute update este
00:48:57
aparte te da información
00:48:59
sobre la cantidad de registros que se han visto
00:49:01
afectados, como estamos borrando
00:49:03
por id debería ser 1
00:49:05
entonces va a ser 1 o ninguno
00:49:06
vamos a utilizar ese dato para
00:49:09
devolver el true o false
00:49:11
Entonces pues vamos a hacerle aquí
00:49:12
Yo que sé
00:49:14
Return psqtudate
00:49:15
Igual a 1
00:49:18
¿Vale?
00:49:19
Y me va a devolver true
00:49:21
Y aquí
00:49:23
Y aquí
00:49:24
Return
00:49:29
¿Vale?
00:49:31
Y aquí
00:49:35
Falses
00:49:36
Si no ha salido por aquí
00:49:38
Es porque
00:49:42
Bueno, a ver, es que es por ID
00:49:44
Entonces
00:49:52
Retún falso, vale
00:49:53
Y aquí esto es por el catch
00:49:57
¿Verdad?
00:50:00
Ah, en el venta dao, efectivamente
00:50:05
Vale, en el venta dao
00:50:07
Que lo tengo abierto en algún sitio
00:50:09
En el venta dao
00:50:11
Sí, el venta dado
00:50:13
Lo tengo
00:50:17
El venta dado lo tenía con voy
00:50:19
Divertidamente
00:50:20
Vale
00:50:21
Venga, venta dado, me devuelve un boolean
00:50:24
Venta dado, implementación
00:50:27
Ahora ya sí
00:50:30
Me dice que añada el catch
00:50:32
Añadimos el catch
00:50:33
Vale
00:50:36
Y ahora me borra
00:50:37
Si lo
00:50:40
El resultado es igual a uno
00:50:41
Sale por aquí
00:50:43
Y ya está
00:50:44
Y si sale por el catch
00:50:52
Pues falso
00:50:53
Venga, delete venta está
00:50:55
Y ahora ya
00:50:57
Nuestro serlet
00:50:59
Que estaba
00:51:01
Vale, a ver
00:51:02
¿Os parece si le digo que lo retrasamos un poco?
00:51:05
No, no, no
00:51:07
Lo que pasa es que le tengo que decir
00:51:08
Que baje a
00:51:13
Firmar mi guardia
00:51:14
- Materias:
- Programación
- Niveles educativos:
- ▼ Mostrar / ocultar niveles
- Formación Profesional
- Ciclo formativo de grado superior
- Segundo Curso
- Subido por:
- Raquel G.
- Licencia:
- Todos los derechos reservados
- Visualizaciones:
- 1
- Fecha:
- 9 de diciembre de 2025 - 14:16
- Visibilidad:
- Clave
- Centro:
- IES ROSA CHACEL
- Duración:
- 51′ 17″
- Relación de aspecto:
- 1.78:1
- Resolución:
- 1920x1080 píxeles
- Tamaño:
- 239.18 MBytes