FEAT : Gestion des miniatures via thumbnails
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -87,6 +87,11 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.coobird</groupId>
|
||||||
|
<artifactId>thumbnailator</artifactId>
|
||||||
|
<version>0.4.20</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -218,4 +218,18 @@ public class PhotoController {
|
|||||||
return "redirect:/photo/" + id;
|
return "redirect:/photo/" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== THUMBNAIL IMAGE ========================== */
|
||||||
|
@GetMapping("/photo/{id}/thumb")
|
||||||
|
public ResponseEntity<Resource> thumb(@PathVariable Long id) {
|
||||||
|
PhotoDTO photo = photoService.getPhotoById(id);
|
||||||
|
if (photo == null || photo.getUuidThumbnail() == null)
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
Resource r = photoService.loadAsResource(photo.getUuidThumbnail());
|
||||||
|
if (!r.exists())
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,5 +15,6 @@ public class PhotoDTO {
|
|||||||
private LocalDateTime dateUpload;
|
private LocalDateTime dateUpload;
|
||||||
private String visibilite;
|
private String visibilite;
|
||||||
private UtilisateurDTO proprietaire;
|
private UtilisateurDTO proprietaire;
|
||||||
|
private String uuidThumbnail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class PhotoMapper {
|
|||||||
dto.setDateUpload(p.getDateUpload());
|
dto.setDateUpload(p.getDateUpload());
|
||||||
dto.setVisibilite(p.getVisibilite().name());
|
dto.setVisibilite(p.getVisibilite().name());
|
||||||
Utilisateur u = p.getProprietaire();
|
Utilisateur u = p.getProprietaire();
|
||||||
|
dto.setUuidThumbnail(p.getUuidThumbnail());
|
||||||
if (u != null) {
|
if (u != null) {
|
||||||
UtilisateurDTO uDTO = new UtilisateurDTO();
|
UtilisateurDTO uDTO = new UtilisateurDTO();
|
||||||
uDTO.setId(u.getId());
|
uDTO.setId(u.getId());
|
||||||
|
|||||||
@@ -34,4 +34,7 @@ public class Photo {
|
|||||||
|
|
||||||
@OneToMany(mappedBy = "photo", cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToMany(mappedBy = "photo", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
private Set<Partage> partages = new HashSet<>();
|
private Set<Partage> partages = new HashSet<>();
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String uuidThumbnail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -53,14 +55,27 @@ public class PhotoServiceImpl implements PhotoService {
|
|||||||
Path uploadPath = Paths.get(uploadDir);
|
Path uploadPath = Paths.get(uploadDir);
|
||||||
if (!Files.exists(uploadPath))
|
if (!Files.exists(uploadPath))
|
||||||
Files.createDirectories(uploadPath);
|
Files.createDirectories(uploadPath);
|
||||||
Files.copy(file.getInputStream(),
|
// ========= LIRE LE FICHIER UNE SEULE FOIS =========
|
||||||
uploadPath.resolve(uuid),
|
byte[] bytes = file.getBytes();
|
||||||
StandardCopyOption.REPLACE_EXISTING);
|
// ========= SAUVEGARDE ORIGINAL =========
|
||||||
|
Path originalPath = uploadPath.resolve(uuid);
|
||||||
|
Files.write(originalPath, bytes);
|
||||||
|
// ========= MINIATURE =========
|
||||||
|
String thumbUuid = "thumb-" + uuid + ".jpg";
|
||||||
|
Path thumbPath = uploadPath.resolve(thumbUuid);
|
||||||
|
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) {
|
||||||
|
net.coobird.thumbnailator.Thumbnails.of(bis)
|
||||||
|
.size(300, 300)
|
||||||
|
.outputFormat("jpg")
|
||||||
|
.toFile(thumbPath.toFile());
|
||||||
|
}
|
||||||
|
// ========= BDD =========
|
||||||
Utilisateur owner = utilisateurRepository.findByEmail(ownerEmail)
|
Utilisateur owner = utilisateurRepository.findByEmail(ownerEmail)
|
||||||
.orElseThrow(() -> new RuntimeException("Utilisateur introuvable"));
|
.orElseThrow(() -> new RuntimeException("Utilisateur introuvable"));
|
||||||
Photo p = new Photo();
|
Photo p = new Photo();
|
||||||
p.setNomFichierOriginal(original);
|
p.setNomFichierOriginal(original);
|
||||||
p.setUuidFichier(uuid);
|
p.setUuidFichier(uuid);
|
||||||
|
p.setUuidThumbnail(thumbUuid);
|
||||||
p.setVisibilite(Photo.Visibilite.valueOf(visibilite));
|
p.setVisibilite(Photo.Visibilite.valueOf(visibilite));
|
||||||
p.setDateUpload(LocalDateTime.now());
|
p.setDateUpload(LocalDateTime.now());
|
||||||
p.setProprietaire(owner);
|
p.setProprietaire(owner);
|
||||||
@@ -72,6 +87,8 @@ public class PhotoServiceImpl implements PhotoService {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============= GET PHOTO BY ID ==========================
|
//============= GET PHOTO BY ID ==========================
|
||||||
@Override
|
@Override
|
||||||
public PhotoDTO getPhotoById(Long id) {
|
public PhotoDTO getPhotoById(Long id) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<h2>Photos dans l’album</h2>
|
<h2>Photos dans l’album</h2>
|
||||||
<div th:each="p : ${album.photos}" style="display:inline-block; margin:10px;">
|
<div th:each="p : ${album.photos}" style="display:inline-block; margin:10px;">
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">
|
<a th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<a th:if="${canAdmin}" th:href="@{'/album/' + ${album.id} + '/remove/' + ${p.id}}"
|
<a th:if="${canAdmin}" th:href="@{'/album/' + ${album.id} + '/remove/' + ${p.id}}"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<a th:each="p : ${photosPage.content}"
|
<a th:each="p : ${photosPage.content}"
|
||||||
th:href="@{'/photo/' + ${p.id}}"
|
th:href="@{'/photo/' + ${p.id}}"
|
||||||
style="display:inline-block; margin:10px;">
|
style="display:inline-block; margin:10px;">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}"
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}"
|
||||||
width="150"
|
width="150"
|
||||||
style="border:1px solid #ccc;"/>
|
style="border:1px solid #ccc;"/>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<a th:each="p : ${photosPrivees.content}" th:if="${p != null}"
|
<a th:each="p : ${photosPrivees.content}" th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<a th:each="p : ${photosPubliques.content}" th:if="${p != null}"
|
<a th:each="p : ${photosPubliques.content}" th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<div style="display:flex; gap:20px; flex-wrap:wrap;">
|
<div style="display:flex; gap:20px; flex-wrap:wrap;">
|
||||||
<div th:each="p : ${mesPhotosPartagees.content}" th:if="${p != null}">
|
<div th:each="p : ${mesPhotosPartagees.content}" th:if="${p != null}">
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">
|
<a th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"
|
||||||
style="display:block; border:1px solid #ccc;"/>
|
style="display:block; border:1px solid #ccc;"/>
|
||||||
</a>
|
</a>
|
||||||
<!--compteur de partages -->
|
<!--compteur de partages -->
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<a th:each="p : ${photosPartagees.content}"
|
<a th:each="p : ${photosPartagees.content}"
|
||||||
th:if="${p != null}"
|
th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -16,7 +16,7 @@
|
|||||||
<h2>Photos dans l’album</h2>
|
<h2>Photos dans l’album</h2>
|
||||||
<div th:each="p : ${album.photos}" style="display:inline-block; margin:10px;">
|
<div th:each="p : ${album.photos}" style="display:inline-block; margin:10px;">
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">
|
<a th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<a th:if="${canAdmin}" th:href="@{'/album/' + ${album.id} + '/remove/' + ${p.id}}"
|
<a th:if="${canAdmin}" th:href="@{'/album/' + ${album.id} + '/remove/' + ${p.id}}"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<a th:each="p : ${photosPage.content}"
|
<a th:each="p : ${photosPage.content}"
|
||||||
th:href="@{'/photo/' + ${p.id}}"
|
th:href="@{'/photo/' + ${p.id}}"
|
||||||
style="display:inline-block; margin:10px;">
|
style="display:inline-block; margin:10px;">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}"
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}"
|
||||||
width="150"
|
width="150"
|
||||||
style="border:1px solid #ccc;"/>
|
style="border:1px solid #ccc;"/>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<a th:each="p : ${photosPrivees.content}" th:if="${p != null}"
|
<a th:each="p : ${photosPrivees.content}" th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<a th:each="p : ${photosPubliques.content}" th:if="${p != null}"
|
<a th:each="p : ${photosPubliques.content}" th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<div style="display:flex; gap:20px; flex-wrap:wrap;">
|
<div style="display:flex; gap:20px; flex-wrap:wrap;">
|
||||||
<div th:each="p : ${mesPhotosPartagees.content}" th:if="${p != null}">
|
<div th:each="p : ${mesPhotosPartagees.content}" th:if="${p != null}">
|
||||||
<a th:href="@{'/photo/' + ${p.id}}">
|
<a th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"
|
||||||
style="display:block; border:1px solid #ccc;"/>
|
style="display:block; border:1px solid #ccc;"/>
|
||||||
</a>
|
</a>
|
||||||
<!--compteur de partages -->
|
<!--compteur de partages -->
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<a th:each="p : ${photosPartagees.content}"
|
<a th:each="p : ${photosPartagees.content}"
|
||||||
th:if="${p != null}"
|
th:if="${p != null}"
|
||||||
th:href="@{'/photo/' + ${p.id}}">
|
th:href="@{'/photo/' + ${p.id}}">
|
||||||
<img th:src="@{'/photo/' + ${p.id} + '/raw'}" width="120"/>
|
<img th:src="@{'/photo/' + ${p.id} + '/thumb'}" width="120"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user