Este conjunto de ejercicios en Python está organizado por bloques temáticos, y cubre los fundamentos del lenguaje de forma progresiva. Se incluyen:
Impresión y variables: primeros pasos con print(), declaración de variables, tipos básicos (enteros, float, booleanos, cadenas).
Funciones: creación de funciones con parámetros y valores de retorno, uso de funciones para modularizar código.
Condicionales: uso de if, elif y else para tomar decisiones en base a condiciones.
Bucles: implementación de bucles for y while para repetición de instrucciones.
Colecciones: manejo de listas, tuplas, conjuntos y diccionarios. Acceso, modificación y recorrido.
Archivos: lectura y escritura de archivos de texto utilizando open(), y comprensión básica de flujos de datos.
Entrada de datos: uso de input() para interactuar con el usuario.
Estos ejercicios están diseñados para estudiantes que se están iniciando en la programación, y cada script representa un problema o concepto básico resuelto de manera clara y concisa.
Variables
Ejercicio 1: Crea tres variables: una que guarde tu nombre, otra tu edad, y otra tu ciudad. Imprime los valores con un mensaje como: «Hola, mi nombre es [nombre], tengo [edad] años y vivo en [ciudad].»
Ejercicio 2: Declara una variable con tu edad. Luego usa esta variable para calcular cuántos días, horas y minutos has vivido (aproximadamente).
Ejercicio 3: Escribe un programa que pida al usuario su nombre y su comida favorita. Luego imprime un mensaje como: «Hola [nombre], me alegra saber que te gusta [comida favorita].»
Ejercicio 4: Declara una variable de cada tipo:
Un número entero (int), por ejemplo, 42.
Un número decimal (float), por ejemplo, 3.14.
Una cadena de texto (str), por ejemplo, «Hola».
Un valor booleano (bool), por ejemplo, True.
Imprime el valor y el tipo de cada variable con type().
Condicionales
Bloque 1: Introducción al uso de if
Ejercicio 1: Pide al usuario un número. Si el número es mayor que 10, imprime: "El número es mayor que 10." Si no, no hagas nada.
Ejercicio 2: Pide al usuario su edad. Si tiene 18 años o más, imprime: "Eres mayor de edad." Si tiene menos de 18, imprime: "Eres menor de edad."
Ejercicio 3: Declara una variable con un número cualquiera. Si el número es positivo, imprime: "El número es positivo." Si el número es negativo, imprime: "El número es negativo." Si el número es 0, imprime: "El número es cero."
Bloque 2: Operadores Comparativos
Ejercicio 4: Pide al usuario dos números. Usa condicionales para imprimir:
"El primer número es mayor que el segundo."
"El segundo número es mayor que el primero."
"Ambos números son iguales."
Ejercicio 5: Pide al usuario un número. Si el número está entre 1 y 100 (inclusive), imprime: "El número está dentro del rango." Si no, imprime: "El número está fuera del rango."
Bloque 3: Uso de Condiciones Anidadas
Ejercicio 6: Pide al usuario una letra. Si la letra es una vocal (a, e, i, o, u), imprime: "Es una vocal." Si no, imprime: "No es una vocal."
Ejercicio 7: Pide al usuario un número del 1 al 7 y muestra el día de la semana correspondiente:
1: Lunes
2: Martes
…
7: Domingo Si el número no está entre 1 y 7, imprime: "Número fuera de rango."
Bloque 4: Problemas de Aplicación
Ejercicio 8: Pide al usuario una contraseña y verifica si es igual a "secreto123". Si es correcta, imprime: "Acceso concedido." Si no, imprime: "Contraseña incorrecta."
Ejercicio 9: Pide al usuario una temperatura en grados Celsius. Si la temperatura es:
Mayor o igual a 30: imprime "Hace calor."
Entre 10 y 29: imprime "El clima es templado."
Menor a 10: imprime "Hace frío."
Ejercicio 10: Pide al usuario el precio de un producto. Si el precio es mayor a 1000, aplica un descuento del 10% y muestra el precio final. Si no, muestra el precio sin descuento.
Bucles
Bloque 1: Iterar sobre listas
Dada una lista de números, calcula la suma de todos los elementos.numeros = [1, 2, 3, 4, 5]
Dada una lista de nombres, imprime cada nombre en mayúsculas.nombres = ["ana", "luis", "carlos"]
Crea una nueva lista que contenga solo los números pares de una lista dada.numeros = [10, 15, 20, 25, 30]
Bloque 2: Iterar sobre diccionarios
Dado un diccionario de productos y precios, imprime cada producto junto con su precio.productos = {"manzana": 1.5, "banana": 0.8, "leche": 2.3}
Encuentra la suma total de los precios de los productos.
Crea una lista de productos cuyo precio sea mayor que un valor dado (por ejemplo, 1.0).
Bloque 3: Iterar sobre cadenas
Dada una cadena, cuenta cuántas vocales contiene.cadena = "Python es genial"
Invierte una cadena usando un bucle.cadena = "Hola Mundo"
Elimina los espacios de una cadena y genera una nueva sin ellos.cadena = "Hola a todos"
Bloque 4: Iterar con índices (range y enumerate)
Usa range para imprimir los números del 1 al 10.# Salida esperada: 1, 2, ..., 10
Usa range para generar una tabla de multiplicar (por ejemplo, la tabla del 5).numero = 5
Usa enumerate para imprimir el índice y el valor de cada elemento en una lista.frutas = ["manzana", "banana", "pera"]
Bloque 5: Bucle controlado por condición while
Imprime los números del 1 al 10 usando un bucle while.
Solicita al usuario números hasta que introduzca un 0, luego calcula la suma de los números ingresados.
Dado un número, encuentra su factorial usando un bucle while.numero = 5
Bloque 6: Bucle infinito controlado con break
Simula una contraseña: solicita al usuario que introduzca una contraseña correcta hasta que lo haga bien.contrasena_correcta = "python123"
Genera números aleatorios entre 1 y 10 hasta que se genere un número mayor que 8.import random
Crea un programa que permita al usuario adivinar un número secreto entre 1 y 20. Termina cuando el usuario lo adivine o escriba «salir».
Funciones
Ejercicio 1: Función de resta
Define una función llamada restar que acepte dos parámetros y devuelva su diferencia.
Prueba la función con diferentes valores.
Ejercicio 2: Función de saludo personalizado
Define una función llamada saludo_personalizado que acepte dos parámetros: nombre y edad.
La función debe imprimir un mensaje como «Hola, [nombre]. Tienes [edad] años.»
Prueba la función con diferentes valores.
Ejercicio 3: Función de multiplicación
Define una función llamada multiplicar que acepte dos parámetros y devuelva su producto.
Prueba la función con diferentes valores.
Ejercicio 4: Función de número par o impar
Define una función llamada es_par que acepte un número y devuelva True si el número es par y False si es impar.
Prueba la función con diferentes valores.
Ejercicio 5: Función con parámetros por defecto
Define una función llamada saludar_con_titulo que acepte dos parámetros: nombre y titulo, con un valor por defecto para titulo.
La función debe imprimir un mensaje como «Hola, [titulo] [nombre].»
Prueba la función con y sin el parámetro titulo.
Ejercicio 6: Función con *args
Define una función llamada promedio que acepte una cantidad arbitraria de números y devuelva su promedio.
Prueba la función con diferentes cantidades de argumentos.
Ejercicio 7: Función con **kwargs
Define una función llamada imprimir_detalles que acepte una cantidad arbitraria de parámetros con nombre y los imprima en formato clave-valor.
Prueba la función con diferentes conjuntos de parámetros.
Trabajando con Archivos
Lectura de contenido: Crea un programa que lea el contenido de un archivo llamado notas.txt y lo imprima en la consola.
Contar líneas: Escribe un programa que cuente cuántas líneas tiene un archivo de texto llamado poema.txt.
Buscar palabra: Diseña un programa que busque una palabra dada por el usuario dentro de un archivo llamado articulo.txt e indique cuántas veces aparece.
Escritura de lista: Escribe un programa que tome una lista de nombres y los guarde en un archivo llamado nombres.txt, un nombre por línea.
Copiar contenido: Implementa un programa que copie el contenido de un archivo llamado origen.txt a un archivo llamado destino.txt.
Descarga solución de los ejercicios.
En programamación un solución puede tener multiples soluciones, mas tratandose de un lenguaje tan dinámico como Python. En el siguieten archivo encotraras una de esas posibilidades, pero recuerda que no por eso tu planteamiento para resolverlo sería incorrecto.
Desarrollar una aplicación web con frontend (HTML/JS) separado de un backend (PHP en POO + MySQL) expuesto como Web Service (API REST). La app debe incluir sistema de sesión con login y al menos un CRUD completo. El proyecto se versionará en GitHub con un README detallado y aplicará medidas mínimas de seguridad.
1) Alcance funcional mínimo
Elige una entidad (ej.: biblioteca, inventario, reservas, incidencias, tareas, alumnos/cursos). Debe incluir, como mínimo:
1 entidad principal con CRUD completo: Crear, Leer (lista + detalle), Actualizar, Eliminar.
Autenticación de usuarios con login/logout y sesión (no solo “mock”).
Autorización básica: acciones protegidas solo para usuarios autenticados.
Listado con búsqueda y/o filtrado en el frontend.
Validaciones en front y back.
Sugerencia de entidades: users (para login) + una entidad de negocio como items, courses, tickets, bookings, etc.
2) Requisitos técnicos
Backend
Lenguaje: PHP (>=7.4; recomendable 8.x).
Estilo: POO (clases para modelos, controladores, servicios/repositorios).
Acceso a datos: MySQL con prepared statements (PDO o MySQLi).
Rutas tipo REST: /api/... que devuelvan JSON.
Gestión de sesión (PHP session)
Frontend
HTML + CSS + JS (vanilla).
Consume la API vía fetch.
Separación front/back
epositorio con carpetas: /frontend y /backend.
Base de datos
Script db/schema.sql + db/seed.sql (opcional) para poblar datos de prueba.
GitHub
Uso de commits frecuentes, ramas (opcional) y README completo.
Documentación
README.md en raíz con: descripción, arquitectura, requisitos, instalación, variables de entorno, comandos, endpoints, roles, capturas/GIF, autores.
3) Seguridad (mínimos obligatorios)
Passwords: almacenar con password_hash() / password_verify().
Reglas de BD: usuario MySQL con mínimos privilegios (solo la base usada).
Errores: no exponer trazas en producción; logs internos.
Validación: back valida todo; front valida para UX, pero back es la autoridad
Backups: script/nota de backup de la BD (aunque sea manual).
4) Entregables
URL del repositorio GitHub (público o acceso concedido si privado).
README.md completo.
Script SQL (db/schema.sql + seed.sql opcional).
Capturas o GIF corto del flujo principal (login + CRUD).
Colección de Postman/Thunder Client (opcional, suma).
Checklist de seguridad marcada (ver abajo).
5) Plantilla de README.md (copiar/pegar)
# Nombre del Proyecto
Descripción corta del dominio elegido y objetivo de la app.
## Arquitectura – Frontend (HTML/JS) en `/frontend` consumiendo API REST JSON. – Backend (PHP OOP + MySQL) en `/backend` exponiendo `/api/…`.
## Requisitos – PHP 8.x, MySQL 5.7/8.x, servidor web (Apache/Nginx), Node (opcional). – Copiar `.env.example` a `.env` y completar valores.
## Instalación 1. Clonar repo. 2. Importar `db/schema.sql` (y `db/seed.sql` opcional). 3. Configurar VirtualHost/servir `/backend/public` como raíz del back. 4. Configurar `FRONT_ORIGIN` en `.env` y CORS. 5. Abrir `/frontend/index.html` (o servir con dev server).
SonarQube es una plataforma de análisis estático de código diseñada para inspeccionar la calidad y seguridad del software de forma automática. Dicho sin humo ni marketing: SonarQube lee tu código como un detective obsesivo y te señala errores, malas prácticas, vulnerabilidades y “deuda técnica” (ese conjunto de decisiones rápidas que luego pasan factura).
A través de reglas basadas en estándares de la industria, SonarQube evalúa aspectos como bugs potenciales, código duplicado, complejidad, cobertura de pruebas, vulnerabilidades de seguridad y mantenibilidad. El resultado no es solo una lista de fallos, sino una radiografía del estado real del proyecto, permitiendo mejorar el código de forma continua.
En entornos profesionales se integra dentro del ciclo de desarrollo (CI/CD), analizando automáticamente cada cambio en el código para evitar que los problemas crezcan en silencio. La filosofía es simple pero poderosa: la calidad no se inspecciona al final, se construye desde el principio.
En esta práctica utilizarás SonarQube para analizar un proyecto real, interpretar sus métricas y aplicar mejoras, entendiendo cómo la calidad del código impacta directamente en la seguridad, el rendimiento y la mantenibilidad del software. Porque el código funciona… hasta que deja de hacerlo, y ahí es donde empieza la ingeniería de verdad.
Arquitectura del proyecto
En la máquina Ubuntu tendrás:
SonarQube (contenedor): servidor web + motor de análisis.
PostgreSQL (contenedor): base de datos de SonarQube.
Contenedores de desarrollo: php-apache, tomcat, etc.
Código fuente en el HOST (carpeta del alumno/grupo) y montado en los contenedores de desarrollo.
Sonar Scanner (mejor en un contenedor aparte, o instalado en el host) que:
lee el código (desde el host o volumen compartido)
manda el análisis a SonarQube por HTTP.
Patrón recomendado:
El código vive en /home/alumno/proyectos/proyectoX
Ese directorio se monta en:
el contenedor de desarrollo (para ejecutar)
el contenedor “scanner” (para analizar)
FASE 1 — Montar SonarQube en Docker (Ubuntu)
Dejar SonarQube funcionando en la misma máquina Ubuntu, dentro de contenedores Docker, con base de datos PostgreSQL y persistencia, accesible desde el navegador.
Al terminar, podrás entrar a:
http://localhost:9000 (si estás en la misma máquina)
o http://IP_DE_LA_MAQUINA:9000 (si accedes desde otra)
1) Comprobar requisitos previos
1.1 Verifica que Docker funciona
En la terminal:
docker --version
docker ps
Si docker ps no da error, Docker está operativo.
1.2 Verifica que tienes Docker Compose
En Ubuntu moderno suele ser el plugin docker compose (con espacio):
docker compose version
Si te funciona, perfecto. Si no, lo instalaremos más adelante (pero normalmente ya viene si Docker está bien instalado).
2) Preparar carpeta del proyecto
Vamos a trabajar de forma ordenada en una carpeta específica para SonarQube.
mkdir -p ~/proyectos/sonarqube-docker
cd ~/proyectos/sonarqube-docker
Dentro crearemos el docker-compose.yml.
3) Ajuste del sistema: vm.max_map_count (IMPORTANTE)
SonarQube usa Elasticsearch internamente y en Linux necesita este parámetro del kernel.
3.1 Ver el valor actual
sysctl vm.max_map_count
Si te devuelve algo como 65530 o mas bajo, hay que subirlo.
3.2 Subirlo temporalmente (hasta reinicio)
sudo sysctl -w vm.max_map_count=262144
3.3 Hacerlo permanente
echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/99-sonarqube.conf
sudo sysctl --system
✅ Comprobación final:
sysctl vm.max_map_count
Debe quedar en 262144.
4) Crear el archivo docker-compose.yml
En la carpeta ~/proyectos/sonarqube-docker crea el archivo:
4) (Opcional pero recomendado) Proyecto Java simple
Entramos:
cd ~/proyectos/grupo01/proyecto-java
nano src/Main.java
public class Main {
public static int suma(int a, int b){
return a + b;
}
public static int suma2(int a, int b){ // duplicación
return a + b;
}
public static void main(String[] args){
int x = 5;
int y = 5;
if(x == y){
System.out.println("Iguales");
}
int z = 100; // código muerto
System.out.println(suma(x, y));
}
}
Ir a SonarQube → Projects → ver Proyecto Java Grupo01.
6) Problemas típicos y cómo sobrevivir
“Not authorized”
Token mal puesto o copiado con espacios.
Regenera token y prueba otra vez.
“Project not found”
Falta sonar-project.properties o está mal.
Verifica que esté en la raíz del proyecto.
“SonarQube is not ready”
El servidor aún no terminó de arrancar.
Espera 30–60s y repite.
Importante
Sonar no ejecuta código → lo analiza estáticamente
Detecta:
Duplicación
Código muerto
Riesgos de seguridad
Mala mantenibilidad
El análisis queda guardado aunque el scanner desaparezca
Esto es exactamente lo que hacen empresas reales en CI/CD
Magnífica jugada pedagógica. Aquí el alumno deja de jugar con ejemplos de juguete y entra en territorio real: código con historia, decisiones, cicatrices y pecado técnico acumulado. Eso es donde SonarQube brilla de verdad. Vamos a plantearlo como RETO FINAL — Análisis real de un proyecto propio listo para entregar a alumnos.
🧪 RETO FINAL — Auditoría real con SonarQube
Misión
Vas a analizar con SonarQube un proyecto real desarrollado por ti, no un ejemplo:
Puedes elegir UNO o Todos:
Tu CRUD Java/PHP del proyecto anterior
Un WordPress (tema propio, plugin o código modificado)
Riesgos de seguridad (inyección, validación, etc.)
3. Code Smells
Problemas de diseño/mantenibilidad.
4. Duplicación
Código repetido.
5. Complejidad
Métodos demasiado complejos.
Fase 4 — Informe técnico (parte importante del reto)
Debes escribir un informe con:
Estado inicial
Quality Gate: PASS / FAIL
Nº Bugs
Nº Vulnerabilities
Nº Code Smells
Maintainability Rating
Análisis crítico
Selecciona mínimo 5 problemas reales y explica:
Qué problema detectó SonarQube
Por qué es un problema técnico real
Qué riesgo tiene (mantenibilidad, seguridad, errores)
Cómo lo solucionaste
Refactorización aplicada
Ejemplos:
Eliminación de duplicación
Validación de entrada
Mejora de legibilidad
División de funciones largas
Tipado fuerte
Eliminación de código muerto
Estado final
Nuevo Quality Gate
Cambios en métricas
Mejora del rating
Bonus
Integrar análisis en GitHub Actions / GitLab CI
Hacer que el merge falle si el gate está en rojo
Añadir tests → mejorar coverage
Analizar plugin o tema WordPress completo
Comparar análisis antes/después
Cambiar SonarQube a español
Método 1 — Cambiar idioma del usuario (lo primero que debes probar)
Entra en SonarQube → http://localhost:9000
Arriba a la derecha → My Account
Preferences
Language → Spanish (Español)
Guardar
Si tu versión tiene traducción cargada, la interfaz cambia inmediatamente (menús, labels, etc.).
Si NO aparece Español en la lista
Entonces tu SonarQube no tiene el paquete de idioma instalado (pasa en algunas builds).
Método 2 — Instalar plugin de idioma (si disponible)
Administration → Marketplace
Buscar: Spanish o Localization
Si aparece plugin de idioma → Install
Reiniciar SonarQube
⚠️ En versiones recientes de SonarQube Community, el marketplace ya no siempre incluye todos los idiomas, y parte de la interfaz puede quedarse en inglés aunque cambies idioma. No es fallo, es así por diseño.
Realidad técnica
El análisis, reglas, métricas → no dependen del idioma
Muchos equipos trabajan SonarQube en inglés (terminología estándar industria)
Aunque pongas español, algunas secciones seguirán en inglés
Descripción: Permite conectarte a un servidor remoto mediante SSH y abrir carpetas, editar archivos, ejecutar terminal y trabajar exactamente igual que si el proyecto estuviera en tu equipo local. VS Code instala automáticamente un “mini-servidor” en la máquina remota para que todo funcione de forma transparente.
Qué la hace especial (dato importante):
No trabajas sobre copias → trabajas directamente en el servidor
Enviar un archivo desde un formulario HTML hacia un Servlet.
Procesar peticiones multipart/form-data.
Guardar una imagen en el servidor.
Obtener el nombre del archivo subido.
Persistir la referencia en base de datos.
Entender el flujo completo cliente → servidor → disco → BD → vista.
Arquitectura del proceso
El flujo que vamos a implementar es el siguiente:
[Formulario HTML]
↓
POST multipart/form-data
↓
[Servlet controlador]
↓
Procesa campos + fichero
↓
Guarda imagen en disco
↓
Inserta datos en BD (nombre del archivo)
↓
Redirección a galería
↓
[Vista HTML muestra la imagen]
Video
El Servlet
Anotaciones necesarias
@WebServlet("/BestiasFoto")
@MultipartConfig
public class BestiasFoto extends HttpServlet {
Lee un campo normal del formulario (texto, hidden, number…)
HttpServletRequest
getPart("foto")
Recupera un archivo (o parte) del multipart con ese name
HttpServletResponse
sendRedirect("url")
Redirige al navegador a otra página tras el POST
HttpServletResponse
getWriter()
Permite escribir una respuesta de texto al cliente
Multipart / Part
Elemento
Método
¿Para qué sirve?
Part
getSubmittedFileName()
Devuelve el nombre original del fichero enviado
Part
getInputStream()
Devuelve un stream con los bytes del archivo
Part
getSize()
Tamaño del archivo en bytes (útil para validar)
Part
getContentType()
Tipo MIME (ej. image/png)
Files / Path
Elemento
Método
¿Para qué sirve?
Paths
get(String)
Crea un Path a partir de una ruta o nombre
Path
getFileName()
Devuelve el último segmento (nombre)
Files
copy(InputStream, Path, ...)
Copia datos de un stream a un fichero
File
getAbsolutePath()
Ruta absoluta en disco
File
getName()
Nombre del archivo sin ruta
Validaciones en la subida de imágenes (métodos independientes)
Validar el nombre del archivo
Evitar archivos duplicados
Validar tipo MIME
Validar extensión
Validar tamaño
Validar que el archivo sea realmente una imagen
Generar nombre seguro (UUID)
Cada método tiene una responsabilidad única.
1. Validar nombre de archivo
Evitar nombres peligrosos, rutas maliciosas o caracteres inválidos.
Método
private String validarNombreArchivo(String originalName) throws ServletException {
if (originalName == null || originalName.isBlank()) {
throw new ServletException("El archivo no tiene nombre válido");
}
// eliminar rutas potenciales
String nombre = Paths.get(originalName).getFileName().toString();
// permitir solo letras, números, punto, guion y guion bajo
if (!nombre.matches("[a-zA-Z0-9._-]+")) {
throw new ServletException("Nombre de archivo inválido");
}
return nombre;
}
Qué hace
Evita nombres vacíos
Elimina rutas (C:\algo\malicioso\file.jpg)
Bloquea caracteres peligrosos
Reduce riesgo de path traversal
2. Validar tipo MIME
Evitar que suban archivos ejecutables disfrazados de imagen.
Método
private void validarTipoMime(Part part) throws ServletException {
String mime = part.getContentType();
if (mime == null || !mime.startsWith("image/")) {
throw new ServletException("Solo se permiten archivos de imagen");
}
}
Qué hace
Comprueba que el archivo es image/*
Bloquea .exe, .jsp, .php, etc.
3. Validar extensión
Permitir solo formatos conocidos.
Método
private void validarExtension(String fileName) throws ServletException {
String ext = "";
int punto = fileName.lastIndexOf('.');
if (punto >= 0) {
ext = fileName.substring(punto + 1).toLowerCase();
}
switch (ext) {
case "jpg":
case "jpeg":
case "png":
case "gif":
case "webp":
return;
default:
throw new ServletException("Extensión no permitida");
}
}
Qué hace
Extrae la extensión
Permite solo imágenes conocidas
Evita subir scripts renombrados
4. Validar tamaño del archivo
Evitar archivos demasiado grandes.
Método
private void validarTamano(Part part, long maxBytes) throws ServletException {
if (part.getSize() == 0) {
throw new ServletException("El archivo está vacío");
}
if (part.getSize() > maxBytes) {
throw new ServletException("El archivo supera el tamaño permitido");
}
}
Uso típico
validarTamano(part, 2*1024*1024); // 2 MB
5. Validar que realmente sea imagen
Evitar archivos falsos con extensión .jpg pero que no son imagen.
Método
private void validarContenidoImagen(InputStream input) throws ServletException, IOException {
BufferedImage img = ImageIO.read(input);
if (img == null) {
throw new ServletException("El archivo no es una imagen válida");
}
}
Qué hace
Intenta decodificar la imagen
Si falla → no es imagen real
6. Evitar archivos duplicados
No sobrescribir archivos existentes.
Método
private File evitarDuplicado(File carpeta, String fileName) {
File file = new File(carpeta, fileName);
if (!file.exists()) {
return file;
}
String nombre = fileName;
String base = nombre;
String ext = "";
int punto = nombre.lastIndexOf('.');
if (punto >= 0) {
base = nombre.substring(0, punto);
ext = nombre.substring(punto);
}
int contador = 1;
File nuevo;
do {
nuevo = new File(carpeta, base + "_" + contador + ext);
contador++;
} while (nuevo.exists());
return nuevo;
}
Qué hace
Si ya existe:
dragon.jpg
Genera:
dragon_1.jpg
dragon_2.jpg
dragon_3.jpg
7. Generar nombre seguro (UUID)
Esto penalizaria el SEO si se trata de archivos que los buscadores pudiesen indexar
Evitar colisiones y nombres maliciosos.
Método
private String generarNombreSeguro(String original) {
String ext = "";
int punto = original.lastIndexOf('.');
if (punto >= 0) {
ext = original.substring(punto);
}
return java.util.UUID.randomUUID().toString() + ext;
}
Qué hace
Convierte:
dragon.png
en algo como:
f47ac10b-58cc-4372-a567-0e02b2c3d479.png
8. Crear carpeta si no existe
private void asegurarCarpeta(File carpeta) throws ServletException {
if (!carpeta.exists()) {
if (!carpeta.mkdirs()) {
throw new ServletException("No se pudo crear la carpeta de subida");
}
}
}
Subir un archivo parece trivial, pero en realidad es una intersección entre E/S, seguridad, validación, arquitectura y persistencia. Cuando el alumno domina esto, deja de “subir fotos” y empieza a construir backend serio.
Antes de modificar algo, hay que localizar el nodo.
3.1 getElementById (el clásico)
HTML:
document.querySelector("#titulo"); // por id
document.querySelector(".clase"); // por clase
document.querySelector("h1"); // por etiqueta
document.querySelector("div p"); // descendiente
JS:
const titulo = document.getElementById("titulo");
console.log(titulo);
Devuelve un solo elemento.
3.2 querySelector (el más versátil)
Permite usar selectores CSS.
document.querySelector("#titulo"); // por id
document.querySelector(".clase"); // por clase
document.querySelector("h1"); // por etiqueta
document.querySelector("div p"); // descendiente
10. Ejercicio guiado — Pintar lista desde un array
HTML:
<ulid="lista"></ul>
JS:
const datos = ["Manzana", "Pera", "Plátano", "Kiwi"];
const lista = document.getElementById("lista");
datos.forEach(fruta => {
const li = document.createElement("li");
li.textContent = fruta;
lista.append(li);
});
Resultado: el DOM se construye dinámicamente.
11. Cómo piensa un programador al usar el DOM
El flujo mental correcto es:
Selecciono el nodo contenedor
Creo elementos nuevos
Les pongo contenido
Los inserto en el DOM
Es exactamente el mismo pensamiento que usarías manipulando objetos en Java.
12. Errores comunes
❌ Usar innerHTML para todo
Malo para seguridad y mantenimiento.
❌ Crear elementos sin insertarlos
Si no haces append/prepend → no aparecen.
❌ Duplicar IDs
Un ID debe ser único.
❌ Mezclar lógica y HTML sin orden
Primero datos, luego render.
13. Mini-reto
Crea una tabla HTML y, desde JavaScript, genera 5 filas con:
Nombre
Edad
Ciudad
Todo debe construirse con createElement.
Nada de escribir filas en el HTML.
14. Lo que debes haber aprendido
Al terminar este bloque debes poder:
Entender qué es el DOM
Seleccionar elementos
Modificar texto
Manipular atributos y clases
Crear elementos dinámicamente
Insertar y eliminar nodos
Construir HTML desde datos
Si esto está claro, en el siguiente bloque el cerebro da el salto natural:
JSON → JavaScript → DOM
Y ahí empieza el verdadero front conectado a tu backend JEE.
El DOM no es difícil. Solo es un árbol. Y los árboles, curiosamente, se doman rama por rama. 🌿
puedes hacerme una tabla con los metodos o atributos que puedo sacar de cada elemento.
El DOM es como una criatura mitológica hecha de objetos. Cada elemento HTML hereda poderes de varias “clases ancestrales”: Node → Element → HTMLElement. Eso significa que casi todos los elementos comparten un mismo arsenal de propiedades y métodos. No memorizas etiquetas… entiendes la especie.
Aquí tienes la tabla de referencia esencial que usarás constantemente.
Métodos y atributos principales de un elemento DOM