Не отображается картинка из БД
Суть такая. Создаётся пост с параметрами title, description, images. Эти данные записывается в базу. После чего данные отображаются в виде постов. Проблема в том, что пост создается, но без картинки, хотя в базе она существует.
Ещё заметил, что в таблице images столбец post_id всегда создается пустым, хотя долен брать брать ID поста в котором был создан
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${title}"></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<header th:insert="blocks/header :: header"></header>
<div class="album py-5 bg-body-tertiary">
<div class="container mt-5">
<div class="container mt-5">
<div th:each="post : ${posts}" class="alert alert-info mt-2">
<img th:src="@{/images/post.images}" alt="img" class="img-thumbnail" height="80pxa"/>
<h3 th:text="${post.title}"/>
<p th:text="${post.description}"/>
<a th:href="'/post/' + ${post.id}" class="btn btn-warning">Детальнее</a>
</div>
</div>
<div class="d-grid gap-2 d-md-block">
<a href="/post/creat">
<br>
<button type="button" class="btn btn-primary">Добавить модель</button>
</a>
</div>
</div>
</div>
<footer th:insert="blocks/footer :: footer"></footer>
</body>
</html>
Класс: Image
package ru.monkeyTeam.demo.models;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@Table(name = "images")
@AllArgsConstructor
@NoArgsConstructor
public class Image {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "size")
private String size;
@Column(name = "originalFileName")
private String originalFileName;
@Column(name = "contentType")
private String contentType;
@Lob
private byte[] bytes;
@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
@JoinColumn(name = "post_id")
private Post post;
}
Класс: Post
package ru.monkeyTeam.demo.models;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "posts")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Post {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "title")
private String title;
@Column(name = "description", columnDefinition = "text")
private String description;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "post", targetEntity = Image.class)
private List<Image> images = new ArrayList<>();
private LocalDateTime dateTime;
@PrePersist
private void init() {
dateTime = LocalDateTime.now();
}
public void addImageToPost(Image image) {
images.add(image);
}
}
Класс: PostService
package ru.monkeyTeam.demo.services;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.objenesis.SpringObjenesis;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import ru.monkeyTeam.demo.models.Image;
import ru.monkeyTeam.demo.models.Post;
import ru.monkeyTeam.demo.repositories.PostRepository;
import java.io.IOException;
@Service
@Slf4j
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
public Iterable<Post> listPost(String title) {
if (title != null) {
return postRepository.findByTitle(title);
}
return postRepository.findAll();
}
public void savePost(Post post, MultipartFile file) throws IOException {
Image image = new Image();
if (!file.isEmpty()) {
image.setName(file.getName());
image.setOriginalFileName(file.getOriginalFilename());
image.setContentType(file.getContentType());
image.setSize(String.valueOf(file.getSize()));
image.setBytes(file.getBytes());
post.addImageToPost(image);
}
log.info("Saving new Post. Title: {}" , post.getTitle());
postRepository.save(post);
}
public void deletePost(Long id) {
log.info("Delete post {}" , postRepository.findById(id));
postRepository.deleteById(id);
}
public Post getPostById(Long id) {
return postRepository.findById(id).orElse(null);
}
}
Класс: PostController
package ru.monkeyTeam.demo.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import ru.monkeyTeam.demo.models.Post;
import ru.monkeyTeam.demo.services.PostService;
import java.io.IOException;
@Controller
@RequiredArgsConstructor
public class PostController {
private final PostService postService;
@GetMapping("/")
public String posts(@RequestParam(name = "title", required = false) String title,Model model) {
model.addAttribute("posts", postService.listPost(title));
return "posts";
}
@GetMapping("/post/creat")
public String pageCreatPost(Model model) {
return "post_creat";
}
@PostMapping("/post/creat")
// @RequestMapping(value = "/post/creat", method = RequestMethod.POST)
public String createPost(@RequestParam("file") MultipartFile file, Post post) throws IOException {
postService.savePost(post, file);
return "redirect:/";
}
@PostMapping("/post/delete/{id}")
public String deletePost(@PathVariable Long id) {
postService.deletePost(id);
return "redirect:/";
}
@GetMapping("post/{id}")
public String postInfo(@PathVariable Long id, Model model) {
Post post = postService.getPostById(id);
model.addAttribute("post", post);
model.addAttribute("images", post.getImages());
return "post_info";
}
}
Класс: ImageController
package ru.monkeyTeam.demo.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import ru.monkeyTeam.demo.models.Image;
import ru.monkeyTeam.demo.repositories.ImageRepository;
import java.io.ByteArrayInputStream;
@RestController
@RequiredArgsConstructor
public class ImageController {
private final ImageRepository imageRepository;
@GetMapping("/images/{id}")
private ResponseEntity<?> getImageById(@PathVariable Long id) {
Image image = imageRepository.findById(id).orElse(null);
return ResponseEntity.ok()
.header("fileName", image.getOriginalFileName())
.contentType(MediaType.valueOf(image.getContentType()))
.contentLength(Long.parseLong(image.getSize()))
.body(new InputStreamResource(new ByteArrayInputStream(image.getBytes())));
}
}
Источник: Stack Overflow на русском