Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store images in a separate table and fetch them on demand #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
29 changes: 29 additions & 0 deletions src/main/java/my/app/data/entity/ImageData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package my.app.data.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;

@Entity
public class ImageData extends AbstractEntity {

@Lob
@Column(length = 1000000)
private byte[] data;

public ImageData() {
}

public ImageData(byte[] data) {
this.data = data;
}

public void setData(byte[] data) {
this.data = data;
}

public byte[] getData() {
return data;
}

}
25 changes: 16 additions & 9 deletions src/main/java/my/app/data/entity/SampleBook.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
package my.app.data.entity;

import java.time.LocalDate;
import javax.persistence.Column;
import java.util.UUID;

import javax.annotation.Nonnull;
import javax.persistence.Entity;
import javax.persistence.Lob;

import org.hibernate.annotations.Type;

@Entity
public class SampleBook extends AbstractEntity {

@Lob
@Column(length = 1000000)
private byte[] image;
@Nonnull
private String name;
@Nonnull
private String author;
private LocalDate publicationDate;
@Nonnull
private Integer pages;
@Nonnull
private String isbn;
@Type(type = "uuid-char")
private UUID imageId;

public byte[] getImage() {
return image;
public UUID getImageId() {
return imageId;
}
public void setImage(byte[] image) {
this.image = image;

public void setImage(UUID imageId) {
this.imageId = imageId;
}
public String getName() {
return name;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/my/app/data/entity/SamplePerson.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package my.app.data.entity;

import java.time.LocalDate;
import javax.annotation.Nonnull;
import javax.persistence.Entity;
import javax.validation.constraints.Email;

@Entity
public class SamplePerson extends AbstractEntity {

@Nonnull
private String firstName;
@Nonnull
private String lastName;
@Email
@Nonnull
private String email;
@Nonnull
private String phone;
private LocalDate dateOfBirth;
@Nonnull
private String occupation;
private boolean important;

Expand Down
31 changes: 20 additions & 11 deletions src/main/java/my/app/data/entity/User.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
package my.app.data.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Set;
import javax.persistence.Column;
import java.util.UUID;

import javax.annotation.Nonnull;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Lob;
import javax.persistence.Table;

import org.hibernate.annotations.Type;

import com.fasterxml.jackson.annotation.JsonIgnore;

import my.app.data.Role;

@Entity
@Table(name = "application_user")
public class User extends AbstractEntity {

@Nonnull
private String username;
@Nonnull
private String name;
@JsonIgnore
private String hashedPassword;
@Enumerated(EnumType.STRING)
@ElementCollection(fetch = FetchType.EAGER)
@Nonnull
private Set<Role> roles;
@Lob
@Column(length = 1000000)
private byte[] profilePicture;
@Nonnull
@Type(type = "uuid-char")
private UUID profilePictureId;

public String getUsername() {
return username;
Expand All @@ -51,11 +59,12 @@ public Set<Role> getRoles() {
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public byte[] getProfilePicture() {
return profilePicture;
}
public void setProfilePicture(byte[] profilePicture) {
this.profilePicture = profilePicture;

public UUID getProfilePictureId() {
return profilePictureId;
}

public void setProfilePictureId(UUID profilePictureId) {
this.profilePictureId = profilePictureId;
}
}
11 changes: 11 additions & 0 deletions src/main/java/my/app/data/service/ImageDataRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package my.app.data.service;

import java.util.UUID;

import org.springframework.data.jpa.repository.JpaRepository;

import my.app.data.entity.ImageData;

public interface ImageDataRepository extends JpaRepository<ImageData, UUID> {

}
26 changes: 24 additions & 2 deletions src/main/java/my/app/data/service/SampleBookService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package my.app.data.service;

import java.util.Base64;
import java.util.Optional;
import java.util.UUID;

import javax.transaction.Transactional;

import my.app.data.entity.ImageData;
import my.app.data.entity.SampleBook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
Expand All @@ -12,17 +17,24 @@
public class SampleBookService {

private final SampleBookRepository repository;
private final ImageDataRepository imageDataRepository;

@Autowired
public SampleBookService(SampleBookRepository repository) {
public SampleBookService(SampleBookRepository repository, ImageDataRepository imageDataRepository) {
this.repository = repository;
this.imageDataRepository = imageDataRepository;
}

public Optional<SampleBook> get(UUID id) {
return repository.findById(id);
}

public SampleBook update(SampleBook entity) {
@Transactional
public SampleBook update(SampleBook entity, ImageData sampleBookImage) {
if (sampleBookImage != null) {
sampleBookImage = imageDataRepository.save(sampleBookImage);
entity.setImage(sampleBookImage.getId());
}
return repository.save(entity);
}

Expand All @@ -38,4 +50,14 @@ public int count() {
return (int) repository.count();
}

@Transactional
public String getImageUrl(SampleBook entity) {
Optional<ImageData> image = imageDataRepository.findById(entity.getImageId());
if (image.isEmpty()) {
return "";
}
return "data:image;base64," + Base64.getEncoder().encodeToString(image.get().getData());
}


}
30 changes: 25 additions & 5 deletions src/main/java/my/app/data/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
package my.app.data.service;

import java.util.Base64;
import java.util.Optional;
import java.util.UUID;
import my.app.data.entity.User;
import org.springframework.beans.factory.annotation.Autowired;

import javax.transaction.Transactional;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import my.app.data.entity.ImageData;
import my.app.data.entity.User;

@Service
public class UserService {

private final UserRepository repository;
private final ImageDataRepository imageDataRepository;

@Autowired
public UserService(UserRepository repository) {
public UserService(UserRepository repository, ImageDataRepository imageDataRepository) {
this.repository = repository;
this.imageDataRepository = imageDataRepository;
}

public Optional<User> get(UUID id) {
return repository.findById(id);
}

public User update(User entity) {
@Transactional
public User update(User entity, ImageData profilePicture) {
if (profilePicture != null) {
profilePicture = imageDataRepository.save(profilePicture);
entity.setProfilePictureId(profilePicture.getId());
}
return repository.save(entity);
}

Expand All @@ -38,4 +49,13 @@ public int count() {
return (int) repository.count();
}

@Transactional
public String getProfilePictureUrl(User user) {
Optional<ImageData> image = imageDataRepository.findById(user.getProfilePictureId());
if (image.isEmpty()) {
return "";
}
return "data:image;base64," + Base64.getEncoder().encodeToString(image.get().getData());
}

}
19 changes: 11 additions & 8 deletions src/main/java/my/app/views/MainLayout.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package my.app.views;

import java.io.ByteArrayInputStream;
import java.util.Optional;

import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.avatar.Avatar;
Expand All @@ -17,11 +20,11 @@
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.server.auth.AccessAnnotationChecker;
import com.vaadin.flow.theme.lumo.LumoUtility;
import java.io.ByteArrayInputStream;
import java.util.Optional;

import my.app.components.appnav.AppNav;
import my.app.components.appnav.AppNavItem;
import my.app.data.entity.User;
import my.app.data.service.UserService;
import my.app.security.AuthenticatedUser;
import my.app.views.adminroleonly.AdminroleonlyView;
import my.app.views.loggedin.LoggedInView;
Expand All @@ -37,12 +40,14 @@ public class MainLayout extends AppLayout {

private H2 viewTitle;

private AuthenticatedUser authenticatedUser;
private AccessAnnotationChecker accessChecker;
private final AuthenticatedUser authenticatedUser;
private final AccessAnnotationChecker accessChecker;
private final UserService userService;

public MainLayout(AuthenticatedUser authenticatedUser, AccessAnnotationChecker accessChecker) {
public MainLayout(AuthenticatedUser authenticatedUser, AccessAnnotationChecker accessChecker, UserService userService) {
this.authenticatedUser = authenticatedUser;
this.accessChecker = accessChecker;
this.userService = userService;

setPrimarySection(Section.DRAWER);
addDrawerContent();
Expand Down Expand Up @@ -110,9 +115,7 @@ private Footer createFooter() {
User user = maybeUser.get();

Avatar avatar = new Avatar(user.getName());
StreamResource resource = new StreamResource("profile-pic",
() -> new ByteArrayInputStream(user.getProfilePicture()));
avatar.setImageResource(resource);
avatar.setImage(userService.getProfilePictureUrl(user));
avatar.setThemeName("xsmall");
avatar.getElement().setAttribute("tabindex", "-1");

Expand Down
Loading