#java #spring #spring-boot #hibernate #jpa
#java #весна #весенняя загрузка #спящий режим #jpa
Вопрос:
У меня есть объект с именем «Bga», в котором есть список изображений. Я пытаюсь создать Bga, отправляющий свои данные через JSON, и в том же запросе я хочу загрузить изображение, поэтому я могу каскадировать его, и таблица «Image» в базе данных будет иметь внешний ключ, исходящий из Bga, а у Bga будет свой список изображений.
Что я делаю:
Отправка составной формы: введите описание изображения здесь
Который содержит данные JSON из объекта Bga: введите описание изображения здесь
И вторая запись — это изображение, которое я загрузил
Я могу создать Bga и загрузить изображение отдельно, но я не знаю, как это сделать так, чтобы я мог каскадировать его.
POST-запрос:
@PostMapping
@ResponseBody
public ResponseEntity<Bga> createBga(@RequestPart("bga") Bga bga, @RequestPart("file") MultipartFile file) throws IOException {
fileStorage.save(file);
bgaRepository.save(bga);
return ResponseEntity.status(HttpStatus.OK).body(bga);
}
А затем служба, которая загружает изображение:
@Service
public class FileStorageService {
@Autowired
private ImagemRepository imagemRepository;
public Imagem save(MultipartFile file) throws IOException {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
Imagem Imagem = new Imagem(fileName, file.getContentType(), file.getBytes());
return imagemRepository.save(Imagem);
}
}
Я использую репозиторий JPA для обоих
Сущность Bga:
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="BGA")
public class Bga implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id_bga;
private String nome;
private int num_bga;
@OneToMany(mappedBy = "bga", cascade = CascadeType.ALL)
private List<Imagem> imagens;
public Bga() {
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getNum_bga() {
return num_bga;
}
public void setNum_bga(int num_bga) {
this.num_bga = num_bga;
}
public long getId_bga() {
return id_bga;
}
public void setId_bga(long id_bga) {
this.id_bga = id_bga;
}
public List<Imagem> getImagens() {
return imagens;
}
public void setImagens(List<Imagem> imagens) {
this.imagens = imagens;
}
И изображение объекта:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
@Entity
public class Imagem {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id_imagem;
private String name;
private String type;
@Lob
private byte[] imagem;
@ManyToOne
@JoinColumn(name = "id_bga", referencedColumnName = "id_bga")
private Bga bga;
public Imagem() {
}
public Long getId_imagem() {
return id_imagem;
}
public void setId_imagem(Long id_imagem) {
this.id_imagem = id_imagem;
}
public byte[] getImagem() {
return imagem;
}
public void setImagem(byte[] imagem) {
this.imagem = imagem;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Imagem(String name, String type, byte[] imagem) {
this.name = name;
this.type = type;
this.imagem = imagem;
}
public Bga getBga() {
return bga;
}
public void setBga(Bga bga) {
this.bga = bga;
}
Но то, как я делаю Bga, не получает загруженное изображение:
введите описание изображения здесь
Как сделать это таким образом, чтобы я мог каскадировать его, чтобы образ таблицы имел внешний ключ, поступающий из bga?
Ответ №1:
Будьте осторожны с границами транзакций. Вы хотите, чтобы 1 транзакция хранила файл BGA, поэтому:
- Создайте @Service с помощью транзакционного метода, который принимает файл и bga
- Автоматическое подключение FileStorageService и BgaRepository к сервису
- Запустите
fileStorage.save(file)
иbgaRepository.save(bga)
в этом методе, затем установите bga на изображении
Расширьте свой FileStorageService, чтобы также использовать объект Bga:
@Service
public class FileStorageService {
@Autowired
private ImagemRepository imagemRepository;
@Autowired // NEW
private BgaRepository bgaRepository; // NEW
@Transactional // NEW
public Imagem save(Bga bga, MultipartFile file) throws IOException {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
Imagem Imagem = new Imagem(fileName, file.getContentType(), file.getBytes());
bgaRepository.save(bga); // NEW
Imagem.setBga(bga); // NEW
return imagemRepository.save(Imagem);
}
}
и в вашем контроллере вызывайте только 1 службу с обоими DTO:
@PostMapping
@ResponseBody
public ResponseEntity<Bga> createBga(@RequestPart("bga") Bga bga, @RequestPart("file") MultipartFile file) throws IOException {
fileStorage.save(bga, file); // NEW: passing in 'bga' here
// bgaRepository.save(bga); .. DELETED
return ResponseEntity.status(HttpStatus.OK).body(bga);
}
Комментарии:
1. Не могли бы вы показать мне, как это делается, пожалуйста? Я никогда не слышал о «транзакционном методе», я вроде как новичок в Spring Boot.
2. @werliney, я отредактировал свой ответ с помощью примера кода