Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# Maven build
target/

# IDE
.idea/
*.iml
.vscode/
.settings/
.project
.classpath

# Compiled class file
*.class

Expand Down
10 changes: 10 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

132 changes: 76 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,92 @@
# Desafío Técnico: Servlets y AJAX

## Objetivo:
Demostrar el conocimiento sobre Java (mínimo versión 8), manejo de servlets y peticiones AJAX nativas.
## Descripción
Aplicación web de gestión de empleados desarrollada con Java 8, Spring Boot 2.7, Servlets y AJAX (Fetch API).
Utiliza H2 como base de datos en memoria y JDBC para la persistencia.

## Requisitos Técnicos:
### Java:
- Utiliza Java 8 o superior para la implementación.
- Utiliza las características de Java como lambdas y streams, cuando sea apropiado.
- Utilizar Maven como gestor de dependencias.
- Utilizar Spring Boot como Runtime para la ejecución del desafío en conjunto con Apache Tomcat como contenedor web.
## Arquitectura
```
Controller (Servlet) → Service → Repository
↕ ↕
Model ← Mapper → Entity
```
- **Entity**: Representación de la tabla en BD (nunca se expone al cliente).
- **Model**: DTO con `@SerializedName` para serialización JSON.
- **Mapper**: Conversión Entity ↔ Model.
- **Repository**: Acceso a datos con JDBC (`JdbcTemplate`).
- **Service**: Lógica de negocio y validaciones.
- **Servlet**: Controlador HTTP (`HttpServlet`) con endpoint RESTful.

## Requisitos Previos
- Java 8 o superior
- Maven 3.6+

## Cómo Ejecutar

```bash
# Clonar el repositorio
git clone <url-del-repositorio>
cd desafio-legacy

## Parte 1: Implementación de un Servicio Web con Servlets y AJAX
# Compilar y ejecutar
mvn spring-boot:run
```
Crear una aplicación web en Java 8 con Servlets y manejo de AJAX, con las siguientes características:

Endpoint: /api/empleados
GET: Retorna una lista de empleados en formato JSON.
POST: Permite agregar un nuevo empleado enviando datos en formato JSON.
DELETE: Elimina un empleado por su ID.
La aplicación estará disponible en: **http://localhost:8080**

Datos esperados del empleado:
## Endpoints

ID (autogenerado), Nombre, Apellido, RUT/DNI, Cargo, Salario.
| Método | URL | Descripción |
|--------|------------------------|------------------------|
| GET | `/api/empleados` | Listar empleados |
| POST | `/api/empleados` | Crear empleado |
| DELETE | `/api/empleados/{id}` | Eliminar empleado |

Interfaz con AJAX:
Crear una página web simple en HTML + JavaScript (sin frameworks como React o Angular).
Usar AJAX (Fetch API o XMLHttpRequest) para:
- Cargar la lista de empleados sin recargar la página.
- Agregar nuevos empleados mediante un formulario sin recargar la página.
- Eliminar empleados con un botón sin recargar la página.
## Interfaces Disponibles

Requerimientos técnicos:
- No usar frameworks externos, solo Servlets y JDBC para conexión con una BD en memoria como H2.
- Manejo adecuado de excepciones y logging.
- Validación de datos en los endpoints.
```
| URL | Descripción |
|----------------------------|--------------------------------|
| http://localhost:8080 | Interfaz web (HTML + AJAX) |
| http://localhost:8080/h2-console | Consola H2 (JDBC URL: `jdbc:h2:mem:empleadosdb`) |
| http://localhost:8080/swagger-ui.html | Swagger UI |
| http://localhost:8080/openapi.yaml | Especificación OpenAPI |

## Parte 2: Validaciones de Reglas de Negocio con AJAX
## Ejemplo de Uso (cURL)

```
Implementar validaciones en la carga de empleados y nóminas:

1. En el backend (Java 8):
- Rechazar empleados con RUT/DNI duplicado.
- No permitir salarios base menores a $400,000.
- Bonos no pueden superar el 50% del salario base.
- El total de descuentos no puede ser mayor al salario base.
- Si alguna regla se incumple, se debe retornar una respuesta HTTP 400 con un JSON indicando los registros con error.
2. En el frontend (JavaScript + AJAX):
- Implementar validaciones antes de enviar el formulario:
- Verificar que todos los campos estén completos.
- Validar formato del RUT/DNI.
- Validar que el salario base no sea menor a $400,000.
- Mostrar errores de validación de forma dinámica en la página (sin alertas de JavaScript).
```
```bash
# Listar empleados
curl http://localhost:8080/api/empleados

## Entregables:
### Repositorio de GitHub:
- Realiza un Pull request a este repositorio indicando tu nombre, empresa reclutadora, correo y cargo al que postulas.
- Todos los PR serán rechazados, no es un indicador de la prueba.
# Crear empleado
curl -X POST http://localhost:8080/api/empleados \
-H "Content-Type: application/json" \
-d '{"nombre":"Juan","apellido":"Pérez","rut":"12345678-5","cargo":"Desarrollador","salario_base":500000,"bonos":100000,"descuentos":50000}'

# Eliminar empleado
curl -X DELETE http://localhost:8080/api/empleados/1
```

### Documentación:
- Incluye instrucciones claras en un README en formato markdown, sobre cómo ejecutar y probar la aplicación.
## Validaciones de Negocio (Backend)
- RUT/DNI duplicado → HTTP 400
- Salario base menor a $400,000 → HTTP 400
- Bonos mayores al 50% del salario base → HTTP 400
- Descuentos mayores al salario base → HTTP 400
- Campos obligatorios vacíos → HTTP 400
- Formato de RUT inválido → HTTP 400

## Evaluación:
Se evaluará la solución en función de los siguientes criterios:
## Validaciones Frontend
- Campos obligatorios completos
- Formato de RUT/DNI (ej: `12345678-5`)
- Salario base mínimo $400,000
- Errores mostrados dinámicamente (sin `alert()`)

- Correcta implementación de las funcionalidades solicitadas.
- Aplicación de buenas prácticas de desarrollo, patrones de diseño y principios SOLID.
- Uso adecuado de Java y Javascript.
- Claridad y completitud de la documentación.
## Tecnologías
- Java 8
- Spring Boot 2.7.18
- Apache Tomcat (embebido)
- H2 Database (en memoria)
- JDBC (`JdbcTemplate`)
- Servlets (`HttpServlet`)
- Gson (serialización JSON)
- HTML5 + CSS3 + JavaScript (Fetch API)
- SpringDoc OpenAPI (Swagger UI)
66 changes: 66 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>

<groupId>com.previred</groupId>
<artifactId>empleados</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Desafio Legacy - Empleados</name>

<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
14 changes: 14 additions & 0 deletions src/main/java/com/previred/empleados/EmpleadosApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.previred.empleados;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class EmpleadosApplication {

public static void main(String[] args) {
SpringApplication.run(EmpleadosApplication.class, args);
}
}
80 changes: 80 additions & 0 deletions src/main/java/com/previred/empleados/entity/EmpleadoEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.previred.empleados.entity;

public class EmpleadoEntity {

private Long id;
private String nombre;
private String apellido;
private String rut;
private String cargo;
private Double salarioBase;
private Double bonos;
private Double descuentos;

public EmpleadoEntity() {
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String getApellido() {
return apellido;
}

public void setApellido(String apellido) {
this.apellido = apellido;
}

public String getRut() {
return rut;
}

public void setRut(String rut) {
this.rut = rut;
}

public String getCargo() {
return cargo;
}

public void setCargo(String cargo) {
this.cargo = cargo;
}

public Double getSalarioBase() {
return salarioBase;
}

public void setSalarioBase(Double salarioBase) {
this.salarioBase = salarioBase;
}

public Double getBonos() {
return bonos;
}

public void setBonos(Double bonos) {
this.bonos = bonos;
}

public Double getDescuentos() {
return descuentos;
}

public void setDescuentos(Double descuentos) {
this.descuentos = descuentos;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.previred.empleados.exception;

import java.util.List;

public class BusinessValidationException extends RuntimeException {

private final List<String> errores;

public BusinessValidationException(List<String> errores) {
super("Error de validación de negocio");
this.errores = errores;
}

public List<String> getErrores() {
return errores;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.previred.empleados.exception;

public class EmpleadoNotFoundException extends RuntimeException {

public EmpleadoNotFoundException(Long id) {
super("Empleado no encontrado con ID: " + id);
}
}
Loading