incorporamos webflux, video en lotes, incorporamos controller webflux para lotes, separamos el aplicaction properties en prod y dev
This commit is contained in:
4
pom.xml
4
pom.xml
@@ -53,6 +53,10 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-test</artifactId>
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.example.fercoganbackend.controller;
|
||||||
|
|
||||||
|
import com.example.fercoganbackend.entity.Lote;
|
||||||
|
import com.example.fercoganbackend.service.LoteServiceWebFlux;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/webflux/lotes")
|
||||||
|
public class LoteControllerWebFlux {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LoteServiceWebFlux loteService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public java.util.List<Lote> getAll() {
|
||||||
|
return loteService.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<Lote> getById(@PathVariable Long id) {
|
||||||
|
return loteService.findById(id)
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Lote create(@RequestBody Lote remate) {
|
||||||
|
return loteService.save(remate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity<Lote> update(@PathVariable Long id, @RequestBody Lote remate) {
|
||||||
|
return loteService.findById(id)
|
||||||
|
.map(r -> {
|
||||||
|
remate.setId(id);
|
||||||
|
Lote updated = loteService.save(remate);
|
||||||
|
return ResponseEntity.ok(updated);
|
||||||
|
})
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Void> delete(@PathVariable Long id) {
|
||||||
|
loteService.delete(id);
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- NUEVO: SSE por LOTE --------------------
|
||||||
|
// Endpoint que devuelve el flujo de actualizaciones solo para ese lote (id).
|
||||||
|
@GetMapping(value = "/stream/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
|
public Flux<Lote> streamLoteById(@PathVariable Long id) {
|
||||||
|
// flujo de futuras actualizaciones (todos los lotes, luego filtramos por id)
|
||||||
|
Flux<Lote> updates = loteService.getSink().asFlux()
|
||||||
|
.filter(l -> l != null && l.getId() != null && l.getId().equals(id));
|
||||||
|
|
||||||
|
// enviamos primero el estado actual (si existe), luego las actualizaciones
|
||||||
|
Optional<Lote> current = loteService.findById(id);
|
||||||
|
if (current.isPresent()) {
|
||||||
|
return Flux.concat(Flux.just(current.get()), updates);
|
||||||
|
} else {
|
||||||
|
// si no existe ahora, devolvemos solo futuras actualizaciones (por ejemplo creación posterior)
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/stream/cabanaid/{cabanaId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
|
public Flux<Lote> streamLote(@PathVariable Long cabanaId) {
|
||||||
|
// Flujo de futuras actualizaciones (todos los lotes, luego filtramos por cabanaId)
|
||||||
|
Flux<Lote> updates = loteService.getSink().asFlux()
|
||||||
|
.filter(lote -> lote.getCabana().getId().equals(cabanaId));
|
||||||
|
|
||||||
|
// Enviamos primero el estado actual (todos los lotes de la cabaña), luego las actualizaciones
|
||||||
|
List<Lote> currentLotes = loteService.findByCabanaId(cabanaId);
|
||||||
|
|
||||||
|
if (!currentLotes.isEmpty()) {
|
||||||
|
return Flux.concat(Flux.fromIterable(currentLotes), updates);
|
||||||
|
} else {
|
||||||
|
// Si no existen lotes ahora, devolvemos solo futuras actualizaciones
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ public class Lote {
|
|||||||
private Double puja;
|
private Double puja;
|
||||||
private String estado;
|
private String estado;
|
||||||
private Boolean visible = true;
|
private Boolean visible = true;
|
||||||
|
private String video;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "remate_id")
|
@JoinColumn(name = "remate_id")
|
||||||
@@ -26,6 +27,14 @@ public class Lote {
|
|||||||
@JoinColumn(name = "cabana_id")
|
@JoinColumn(name = "cabana_id")
|
||||||
private Cabana cabana;
|
private Cabana cabana;
|
||||||
|
|
||||||
|
public String getVideo() {
|
||||||
|
return video;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideo(String video) {
|
||||||
|
this.video = video;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
package com.example.fercoganbackend.repository;
|
package com.example.fercoganbackend.repository;
|
||||||
|
|
||||||
import com.example.fercoganbackend.entity.Lote;
|
import com.example.fercoganbackend.entity.Lote;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface LoteRepository extends JpaRepository<Lote, Long> {}
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface LoteRepository extends JpaRepository<Lote, Long> {
|
||||||
|
// Con ordenamiento
|
||||||
|
//List<Lote> findByCabanaIdOrderByNumeroLote(Long cabanaId);
|
||||||
|
|
||||||
|
// Para paginación
|
||||||
|
List<Lote> findByCabanaId(Long cabanaId);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class ContadorService {
|
|||||||
} else {
|
} else {
|
||||||
incremento = 500;
|
incremento = 500;
|
||||||
}
|
}
|
||||||
return contador.getAndAdd(incremento);
|
return contador.addAndGet(incremento);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.example.fercoganbackend.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.example.fercoganbackend.entity.Lote;
|
||||||
|
import com.example.fercoganbackend.repository.LoteRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import reactor.core.publisher.Sinks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LoteServiceWebFlux {
|
||||||
|
|
||||||
|
private final LoteRepository repo;
|
||||||
|
private final Sinks.Many<Lote> sink; // canal que emite actualizaciones por lote
|
||||||
|
|
||||||
|
public LoteServiceWebFlux(LoteRepository repo) {
|
||||||
|
this.repo = repo;
|
||||||
|
// replay().latest() guarda el último emitido (por si alguien se suscribe tarde)
|
||||||
|
this.sink = Sinks.many().replay().latest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Lote> findAll() {
|
||||||
|
return repo.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Lote> findByCabanaId(Long id) {
|
||||||
|
return repo.findByCabanaId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Lote> findById(Long id) {
|
||||||
|
return repo.findById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Lote save(Lote lote) {
|
||||||
|
Lote saved = repo.save(lote);
|
||||||
|
emitChange(saved); // notificamos a los suscriptores el lote actualizado
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
// Intentamos obtener el lote antes de borrar para poder notificar su eliminación
|
||||||
|
Optional<Lote> maybe = repo.findById(id);
|
||||||
|
repo.deleteById(id);
|
||||||
|
// Emitimos un "evento de eliminación": un Lote con id y visible = false
|
||||||
|
Lote tombstone = maybe.orElseGet(() -> {
|
||||||
|
Lote t = new Lote();
|
||||||
|
t.setId(id);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
// Si tu entidad Lote tiene campo visible, marcalo; si no, sigue emitiendo el id.
|
||||||
|
try {
|
||||||
|
tombstone.setVisible(false);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
emitChange(tombstone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emitChange(Lote lote) {
|
||||||
|
// emitimos el objeto lote al sink; los controladores filtran por id
|
||||||
|
sink.tryEmitNext(lote);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sinks.Many<Lote> getSink() {
|
||||||
|
return sink;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/main/resources/application-dev.properties
Normal file
3
src/main/resources/application-dev.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
|
||||||
|
spring.datasource.username=andre
|
||||||
|
spring.datasource.password=andre
|
||||||
3
src/main/resources/application-prod.properties
Normal file
3
src/main/resources/application-prod.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
spring.datasource.url=jdbc:mysql://192.168.5.250:3306/TEST_fercoApp
|
||||||
|
spring.datasource.username=ferco
|
||||||
|
spring.datasource.password=9+k+9076[5S26#C1mn"u
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
spring.application.name=fercoganbackend
|
spring.application.name=fercoganbackend
|
||||||
spring.datasource.url=jdbc:mysql://192.168.5.250:3306/TEST_fercoApp
|
spring.profiles.active=dev
|
||||||
spring.datasource.username=ferco
|
|
||||||
spring.datasource.password=9+k+9076[5S26#C1mn"u
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
|||||||
Reference in New Issue
Block a user