excel_upload

main
elmer-20 1 month ago
parent 90c7688af1
commit 1bfa6a6ade

@ -0,0 +1,2 @@
MYSQL_DATABASE=data_admision
MYSQL_ALLOW_EMPTY_PASSWORD=yes

@ -0,0 +1,18 @@
# Usa Maven y JDK para compilar y correr código
FROM maven:3.9.2-eclipse-temurin-17
WORKDIR /app
# Copia solo pom.xml primero para cache
COPY pom.xml .
# Pre-descarga dependencias
RUN mvn dependency:go-offline
# Copia el código fuente
COPY src ./src
EXPOSE 8080
# Ejecuta Spring Boot directamente (hot reload)
CMD ["mvn", "spring-boot:run"]

@ -1,23 +1,34 @@
services:
postgres:
image: postgres:15
container_name: postgres_admision
mysql:
image: mysql:8
container_name: mysql_admision_dev
environment:
POSTGRES_DB: data_admision
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 1234
MYSQL_DATABASE: admision_db
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
ports:
- "5432:5432"
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
backend:
build: .
container_name: spring_admision
build:
context: .
dockerfile: Dockerfile.dev # Dockerfile que corre mvn spring-boot:run
container_name: spring_admision_dev
depends_on:
- postgres
- mysql
ports:
- "8080:8080"
volumes:
- .:/app # Monta tu código para ver cambios sin rebuild
- ~/.m2:/root/.m2 # Cache de Maven para no bajar deps siempre
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/data_admision
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: 1234
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/admision_db?useSSL=false&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: ""
command: mvn spring-boot:run # Ejecuta Spring directamente
restart: unless-stopped
volumes:
mysql_data:

@ -0,0 +1,27 @@
version: "3.9"
services:
mysql:
image: mysql:8
container_name: mysql_admision
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_ALLOW_EMPTY_PASSWORD: ${MYSQL_ALLOW_EMPTY_PASSWORD}
ports:
- "3306:3306"
restart: unless-stopped
backend:
build:
context: .
dockerfile: Dockerfile
container_name: spring_admision
depends_on:
- mysql
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: ""
restart: unless-stopped

@ -34,10 +34,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
@ -50,9 +50,19 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version> <!-- usa la última versión estable -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
@ -64,17 +74,18 @@
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

@ -0,0 +1,32 @@
package com.service.ingresantes.controller;
import com.service.ingresantes.service.ExcelService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/excel")
public class ExcelController {
private final ExcelService excelService;
public ExcelController(ExcelService excelService) {
this.excelService = excelService;
}
@PostMapping("/upload")
public ResponseEntity<String> uploadExcel(@RequestParam("file") MultipartFile file) {
try {
excelService.importarExcel(file);
return ResponseEntity.ok("Archivo subido y procesado correctamente!");
} catch (Exception e) {
return ResponseEntity.badRequest().body("Error al procesar el archivo: " + e.getMessage());
}
}
@GetMapping("/ping")
public String ping() {
return "API funcionando123456!";
}
}

@ -0,0 +1,32 @@
package com.service.ingresantes.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Table(name = "asignaturas")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Asignatura {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer codigo;
private String nombre;
private Integer cantidadPreguntas;
private Double ponderacion;
// Nuevo campo: puntaje por pregunta
private Double puntajePorPregunta;
@ManyToOne
@JoinColumn(name = "area_id")
private Area area;
}

@ -0,0 +1,29 @@
package com.service.ingresantes.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Table(name = "carpeta_examen")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CarpetaExamen {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String tipo; // claves, ids, respuestas
private String ruta;
@ManyToOne
@JoinColumn(name = "proceso_id")
private Proceso proceso;
@ManyToOne
@JoinColumn(name = "area_id")
private Area area;
}

@ -0,0 +1,11 @@
package com.service.ingresantes.repository;
import com.service.ingresantes.entity.Asignatura;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AsignaturaRepository extends JpaRepository<Asignatura, Long> {
// Aquí puedes agregar consultas personalizadas si lo necesitas
// Ejemplo: List<Asignatura> findByNombre(String nombre);
}

@ -0,0 +1,11 @@
package com.service.ingresantes.repository;
import com.service.ingresantes.entity.CarpetaExamen;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface CarpetaExamenRepository extends JpaRepository<CarpetaExamen, Long> {
List<CarpetaExamen> findByProcesoIdAndAreaId(Long procesoId, Long areaId);
}

@ -1,11 +1,13 @@
package com.service.ingresantes.repository;
import com.service.ingresantes.entity.Inscripcion;
import com.service.ingresantes.entity.Postulante;
import com.service.ingresantes.entity.Proceso;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface InscripcionRepository extends JpaRepository<Inscripcion, Long> {
List<Inscripcion> findByProcesoId(Long procesoId);
// Método para verificar si existe una inscripción de un postulante a un proceso
boolean existsByPostulanteAndProceso(Postulante postulante, Proceso proceso);
}

@ -0,0 +1,190 @@
package com.service.ingresantes.service;
import com.service.ingresantes.entity.*;
import com.service.ingresantes.repository.*;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import jakarta.transaction.Transactional;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
@Service
public class ExcelService {
private final PostulanteRepository postulanteRepo;
private final ProcesoRepository procesoRepo;
private final ProgramaRepository programaRepo;
private final ModalidadRepository modalidadRepo;
private final InscripcionRepository inscripcionRepo;
public ExcelService(PostulanteRepository postulanteRepo,
ProcesoRepository procesoRepo,
ProgramaRepository programaRepo,
ModalidadRepository modalidadRepo,
InscripcionRepository inscripcionRepo) {
this.postulanteRepo = postulanteRepo;
this.procesoRepo = procesoRepo;
this.programaRepo = programaRepo;
this.modalidadRepo = modalidadRepo;
this.inscripcionRepo = inscripcionRepo;
}
// --- Método auxiliar para leer cualquier celda como String ---
private String getCellStringValue(Cell cell) {
if (cell == null) return "";
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue().trim();
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
return cell.getLocalDateTimeCellValue().toLocalDate().toString();
} else {
return String.valueOf((long) cell.getNumericCellValue());
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
@Transactional
public void importarExcel(MultipartFile file) throws Exception {
InputStream is = file.getInputStream();
Workbook workbook = WorkbookFactory.create(is);
Sheet sheet = workbook.getSheetAt(0);
DateTimeFormatter fechaHoraFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (Row row : sheet) {
if (row.getRowNum() == 0) continue; // Saltar encabezado
String dni = getCellStringValue(row.getCell(0));
if (dni.isEmpty()) {
System.out.println("Fila " + row.getRowNum() + ": DNI vacío, se omite");
continue;
}
Postulante postulante = postulanteRepo.findById(dni).orElseGet(() -> {
try {
Postulante p = new Postulante();
p.setDni(dni);
p.setPaterno(getCellStringValue(row.getCell(1)));
p.setMaterno(getCellStringValue(row.getCell(2)));
p.setNombres(getCellStringValue(row.getCell(3)));
p.setSexo(getCellStringValue(row.getCell(4)));
String fechaNacStr = getCellStringValue(row.getCell(5));
if (!fechaNacStr.isEmpty()) {
try { p.setFechaNacimiento(LocalDate.parse(fechaNacStr)); } catch (Exception e) {}
}
String edadStr = getCellStringValue(row.getCell(6));
if (!edadStr.isEmpty()) {
try { p.setEdad(Integer.parseInt(edadStr)); } catch (NumberFormatException ignored) {}
}
p.setUbigeoResidencia(getCellStringValue(row.getCell(7)));
p.setDepartamentoResidencia(getCellStringValue(row.getCell(8)));
p.setProvinciaResidencia(getCellStringValue(row.getCell(9)));
p.setDistritoResidencia(getCellStringValue(row.getCell(10)));
String egresoStr = getCellStringValue(row.getCell(11));
if (!egresoStr.isEmpty()) {
try { p.setEgreso(Integer.parseInt(egresoStr)); } catch (NumberFormatException ignored) {}
}
p.setCodModular(getCellStringValue(row.getCell(12)));
p.setUbigeoColegio(getCellStringValue(row.getCell(13)));
p.setDepartamentoColegio(getCellStringValue(row.getCell(14)));
p.setProvinciaColegio(getCellStringValue(row.getCell(15)));
p.setDistritoColegio(getCellStringValue(row.getCell(16)));
System.out.println("Fila " + row.getRowNum() + ": Postulante creado -> " + dni);
return postulanteRepo.save(p);
} catch (Exception e) {
System.out.println("Fila " + row.getRowNum() + ": Error guardando postulante " + dni + " -> " + e.getMessage());
return null;
}
});
if (postulante == null) continue;
String fechaInsStr = getCellStringValue(row.getCell(17));
LocalDateTime fechaInscripcion;
if (!fechaInsStr.isEmpty()) {
try {
fechaInscripcion = LocalDateTime.parse(fechaInsStr, fechaHoraFormatter);
} catch (Exception e) {
try { fechaInscripcion = LocalDate.parse(fechaInsStr).atStartOfDay(); }
catch (Exception ex) { fechaInscripcion = LocalDateTime.now(); }
}
} else {
fechaInscripcion = LocalDateTime.now();
}
String procesoStr = getCellStringValue(row.getCell(18));
if (procesoStr.isEmpty()) {
System.out.println("Fila " + row.getRowNum() + ": Proceso vacío, se omite");
continue;
}
Long procesoId;
try { procesoId = Long.parseLong(procesoStr); }
catch (NumberFormatException e) {
System.out.println("Fila " + row.getRowNum() + ": Proceso inválido -> " + procesoStr);
continue;
}
Optional<Proceso> procesoOpt = procesoRepo.findById(procesoId);
if (procesoOpt.isEmpty()) {
System.out.println("Fila " + row.getRowNum() + ": Proceso no encontrado -> " + procesoId);
continue;
}
Proceso proceso = procesoOpt.get();
String programaStr = getCellStringValue(row.getCell(19));
Optional<ProgramaEstudio> programaOpt = programaRepo.findById(Long.parseLong(programaStr));
if (programaOpt.isEmpty()) {
System.out.println("Fila " + row.getRowNum() + ": Programa no encontrado -> " + programaStr);
continue;
}
ProgramaEstudio programa = programaOpt.get();
String modalidadStr = getCellStringValue(row.getCell(20));
Optional<Modalidad> modalidadOpt = modalidadRepo.findById(Long.parseLong(modalidadStr));
if (modalidadOpt.isEmpty()) {
System.out.println("Fila " + row.getRowNum() + ": Modalidad no encontrada -> " + modalidadStr);
continue;
}
Modalidad modalidad = modalidadOpt.get();
boolean existe = inscripcionRepo.existsByPostulanteAndProceso(postulante, proceso);
if (existe) {
System.out.println("Fila " + row.getRowNum() + ": La inscripción ya existe para el postulante " + dni);
continue;
}
try {
Inscripcion inscripcion = new Inscripcion();
inscripcion.setFechaInscripcion(fechaInscripcion);
inscripcion.setPostulante(postulante);
inscripcion.setProceso(proceso);
inscripcion.setPrograma(programa);
inscripcion.setModalidad(modalidad);
inscripcionRepo.save(inscripcion);
System.out.println("Fila " + row.getRowNum() + ": Inscripción guardada -> " + dni);
} catch (Exception e) {
System.out.println("Fila " + row.getRowNum() + ": Error guardando inscripción -> " + e.getMessage());
}
}
workbook.close();
is.close();
}
}

@ -14,19 +14,21 @@
# con docker
spring.application.name=ingresantes
# CONEXION POSTGRESQL (VARIABLES DE ENTORNO)
spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/data_admision?useSSL=false&serverTimezone=UTC}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME:root}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD:}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA / HIBERNATE
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
# MOSTRAR SQL
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.format_sql=true
# Habilitar subida de archivos
spring.servlet.multipart.enabled=true
# Tamaño máximo de archivo y request
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
Loading…
Cancel
Save