excel_upload
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:
|
services:
|
||||||
|
mysql:
|
||||||
postgres:
|
image: mysql:8
|
||||||
image: postgres:15
|
container_name: mysql_admision_dev
|
||||||
container_name: postgres_admision
|
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: data_admision
|
MYSQL_DATABASE: admision_db
|
||||||
POSTGRES_USER: postgres
|
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
|
||||||
POSTGRES_PASSWORD: 1234
|
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
build: .
|
build:
|
||||||
container_name: spring_admision
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev # Dockerfile que corre mvn spring-boot:run
|
||||||
|
container_name: spring_admision_dev
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- mysql
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "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:
|
environment:
|
||||||
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/data_admision
|
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/admision_db?useSSL=false&serverTimezone=UTC
|
||||||
SPRING_DATASOURCE_USERNAME: postgres
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
SPRING_DATASOURCE_PASSWORD: 1234
|
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
|
||||||
@ -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;
|
package com.service.ingresantes.repository;
|
||||||
|
|
||||||
import com.service.ingresantes.entity.Inscripcion;
|
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 org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface InscripcionRepository extends JpaRepository<Inscripcion, Long> {
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue