Как отправить JSON и изображение в одном и том же POST-запросе и каскадировать его? Весенняя загрузка

#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, поэтому:

  1. Создайте @Service с помощью транзакционного метода, который принимает файл и bga
  2. Автоматическое подключение FileStorageService и BgaRepository к сервису
  3. Запустите 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, я отредактировал свой ответ с помощью примера кода