输出 Spring Postman 中的引导是反向的

Output Spring Boot is reversed in Postman

我的问题:当我在 Postman 中执行 @Post 时,我从价格中获取数据,但不是小猫数据。

我输入以下内容:

{
    "name": "Frizzle",
    "dateOfBirth": "2019-07-27",
    "weight": 7.1,
    "breed": "Birman",
    "firstVaccination": "yes",
    "secondVaccination": "yes",
    "breedPrice": 8000,
    "firstVaccinationPrice": 80.50,
    "secondVaccinationPrice": 80.10
}

这就是我在 Postman:

中得到的结果
{
        "id": 3,
        "name": null,
        "dateOfBirth": null,
        "weight": 0.0,
        "breed": null,
        "firstVaccination": null,
        "secondVaccination": null,
        "fileUpload": null,
        "price": {
            "id": 3,
            "broadPrice": 8000.0,
            "firstVaccinationPrice": 80.5,
            "secondVaccinationPrice": 80.1,
            "totalPrice": 8160.6
        }
}

我试过在几个地方更改代码,但我不明白为什么它输出价格部分而不是小猫数据部分。我想让它输出小猫数据。所以基本上我想要的是让他反转它,return 小猫的数据并给出空的价格数据。

我的文件是这样的。

Kitten.java

import com.sun.istack.NotNull;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@Table(name = "kittens")
public class Kitten {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotNull
    private String name;

    @NotNull
    @Column(name = "date_of_birth")
    private LocalDate dateOfBirth;

    @NotNull
    @Column
    private double weight;

    @NotNull
    @Column(name = "breed")
    private String breed;

    @Column(name = "first_vaccination")
    private String firstVaccination;

    @Column(name = "second_vaccination")
    private String secondVaccination;

    @OneToOne(mappedBy = "kitten")
    private FileUpload fileUpload;

    @OneToOne(fetch = FetchType.LAZY,
            mappedBy = "kitten")
    private Price price;

    public Kitten(String name, LocalDate dateOfBirth, double weight, String breed, String firstVaccination, String secondVaccination) {
    }

    public Kitten() {

    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }

    public String getFirstVaccination() {
        return firstVaccination;
    }

    public void setFirstVaccination(String firstVaccination) {
        this.firstVaccination = firstVaccination;
    }

    public String getSecondVaccination() {
        return secondVaccination;
    }

    public void setSecondVaccination(String secondVaccination) {
        this.secondVaccination = secondVaccination;
    }

    public FileUpload getFileUpload() {
        return fileUpload;
    }

    public void setFileUpload(FileUpload fileUpload) {
        this.fileUpload = fileUpload;
    }

    public Price getPrice() {
        return price;
    }

    public void setPrice(Price price) {
        this.price = price;
    }
}

Price.java

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.NotNull;

import javax.persistence.*;

@Entity
@Table(name = "prices")
public class Price {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotNull
    @Column(name = "breed_price")
    private double breedPrice;

    @Column(name = "first_vaccination_price")
    private double firstVaccinationPrice;

    @Column(name = "second_vaccination_price")
    private double secondVaccinationPrice;

    @JsonIgnore
    @OneToOne(fetch = FetchType.LAZY,
            cascade = CascadeType.ALL,
            orphanRemoval = true)
    @JoinColumn(name = "kitten_id")
    private Kitten kitten;

    public Price() {

    }

    public Price(double breedPrice, double firstVaccinationPrice, double secondVaccinationPrice) {
        this.breedPrice = breedPrice;
        this.firstVaccinationPrice = firstVaccinationPrice;
        this.secondVaccinationPrice = secondVaccinationPrice;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public double getBreedPrice() {
        return breedPrice;
    }

    public void setBreedPrice(double breedPrice) {
        this.breedPrice = breedPrice;
    }

    public double getFirstVaccinationPrice() {
        return firstVaccinationPrice;
    }

    public void setFirstVaccinationPrice(double firstVaccinationPrice) {
        this.firstVaccinationPrice = firstVaccinationPrice;
    }

    public double getSecondVaccinationPrice() {
        return secondVaccinationPrice;
    }

    public void setSecondVaccinationPrice(double secondVaccinationPrice) {
        this.secondVaccinationPrice = secondVaccinationPrice;
    }

    public Kitten getKitten() {
        return kitten;
    }

    public void setKitten(Kitten kitten) {
        this.kitten = kitten;
    }

    public Double getTotalPrice() {
        return this.getBreedPrice() + this.getFirstVaccinationPrice() + this.getSecondVaccinationPrice();
    }
}

KittenBuilder.java

import nl.danielle.cattery.payload.KittenRequest;

import java.time.LocalDate;

public class KittenBuilder {

    //Kitten    
    private String name;
    private LocalDate dateOfBirth;
    private double weight;
    private String breed;
    private String firstVaccination;
    private String secondVaccination;

    //Price
    private double breedPrice;
    private double firstVaccinationPrice;
    private double secondVaccinationPrice;

    public KittenBuilder(KittenRequest kittenRequest) {
        this.name = kittenRequest.getName();
        this.dateOfBirth = kittenRequest.getDateOfBirth();
        this.weight = kittenRequest.getWeight();
        this.breed = kittenRequest.getBreed();
        this.firstVaccination = kittenRequest.getFirstVaccination();
        this.secondVaccination = kittenRequest.getSecondVaccination();
        this.breedPrice = kittenRequest.getBreedPrice();
        this.firstVaccinationPrice = kittenRequest.getFirstVaccinationPrice();
        this.secondVaccinationPrice = kittenRequest.getSecondVaccinationPrice();
    }

    public Kitten buildKitten() {
        return new Kitten(name, dateOfBirth, weight, breed, firstVaccination, secondVaccination);
    }

    public Price buildPrice() {
        return new Price(breedPrice, firstVaccinationPrice, secondVaccinationPrice);
    }
}

KittenRequest.java

import com.sun.istack.NotNull;

import java.time.LocalDate;

public class KittenRequest {
    //Kitten
    @NotNull
    private String name;
    @NotNull
    private LocalDate dateOfBirth;
    @NotNull
    private double weight;
    @NotNull
    private String breed;
    private String firstVaccination;
    private String secondVaccination;

    //Price
    @NotNull
    private double breedPrice;
    private double firstVaccinationPrice;
    private double secondVaccinationPrice;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }

    public String getFirstVaccination() {
        return firstVaccination;
    }

    public void setFirstVaccination(String firstVaccination) {
        this.firstVaccination = firstVaccination;
    }

    public String getSecondVaccination() {
        return secondVaccination;
    }

    public void setSecondVaccination(String secondVaccination) {
        this.secondVaccination = secondVaccination;
    }

    public double getBreedPrice() {
        return breedPrice;
    }

    public void setBreedPrice(double breedPrice) {
        this.breedPrice = breedPrice;
    }

    public double getFirstVaccinationPrice() {
        return firstVaccinationPrice;
    }

    public void setFirstVaccinationPrice(double firstVaccinationPrice) {
        this.firstVaccinationPrice = firstVaccinationPrice;
    }

    public double getSecondVaccinationPrice() {
        return secondVaccinationPrice;
    }

    public void setSecondVaccinationPrice(double secondVaccinationPrice) {
        this.secondVaccinationPrice = secondVaccinationPrice;
    }
}

KittenController.java

import nl.danielle.cattery.model.FileUpload;
import nl.danielle.cattery.payload.KittenRequest;
import nl.danielle.cattery.payload.ResponseMessage;
import nl.danielle.cattery.service.FileStorageServiceImpl;
import nl.danielle.cattery.service.KittenService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;

@RestController
@RequestMapping(value = "/kittens")
public class KittenController {

    final KittenService kittenService;

    final FileStorageServiceImpl storageService;

    public KittenController(KittenService kittenService, FileStorageServiceImpl storageService) {
        this.kittenService = kittenService;
        this.storageService = storageService;
    }

    @GetMapping(value = "")
    public ResponseEntity<Object> getKittens() {
        return ResponseEntity.ok().body(kittenService.getKittens());
    }

    @GetMapping(value = "/{id}")
    public ResponseEntity<Object> getKitten(@PathVariable("id") long id) {
        return ResponseEntity.ok().body(kittenService.getKittenById(id));
    }

    @PostMapping(value = "/add")
    public ResponseEntity<Object> saveKitten(@RequestBody KittenRequest kitten) {
        long newId = kittenService.saveKitten(kitten);

        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(newId).toUri();

        return ResponseEntity.created(location).build();
    }

    @PutMapping(value = "/{id}")
    public ResponseEntity<Object> updateKitten(@PathVariable("id") long id, @RequestBody KittenRequest kitten) {
        kittenService.updateKitten(id, kitten);
        return ResponseEntity.noContent().build();
    }

    @PutMapping(value = "/{id}/price")
    public ResponseEntity<Object> updatePrice(@PathVariable("id") long id, @RequestBody KittenRequest price) {
        kittenService.updatePrice(id, price);
        return ResponseEntity.noContent().build();
    }

    @DeleteMapping(value = "/{id}")
    public ResponseEntity<Object> deleteKitten(@PathVariable("id") long id) {
        kittenService.deleteKitten(id);
        return ResponseEntity.noContent().build();
    }

    @PostMapping("/upload/kittenid/{id}")
    public ResponseEntity<ResponseMessage> uploadFile(@PathVariable long id, @RequestParam("file") MultipartFile file) {

        try {
            storageService.store(file, id);

            String message = "Uploaded the file successfully: " + file.getOriginalFilename();
            return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));

        } catch (Exception e) {
            String message = "Could not upload the file: " + file.getOriginalFilename() + "!";
            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message));
        }
    }

    @GetMapping("/download/{id}")
    public ResponseEntity<byte[]> getFileById(@PathVariable("id") String id) {
        FileUpload fileUpload = storageService.getFileById(id);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileUpload.getName() + "\"")
                .body(fileUpload.getData());
    }
}

KittenService.java

package nl.danielle.cattery.service;

import nl.danielle.cattery.exceptions.DatabaseErrorException;
import nl.danielle.cattery.exceptions.RecordNotFoundException;
import nl.danielle.cattery.model.Kitten;
import nl.danielle.cattery.model.KittenBuilder;
import nl.danielle.cattery.model.Price;
import nl.danielle.cattery.payload.KittenRequest;
import nl.danielle.cattery.repository.KittenRepository;
import nl.danielle.cattery.repository.PriceRepository;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class KittenServiceImpl implements KittenService {

    final KittenRepository kittenRepository;

    final PriceRepository priceRepository;

    public KittenServiceImpl(KittenRepository kittenRepository, PriceRepository priceRepository) {
        this.kittenRepository = kittenRepository;
        this.priceRepository = priceRepository;
    }

    @Override
    public Collection<Kitten> getKittens() {
        return kittenRepository.findAll();
    }

    @Override
    public Kitten getKittenById(long id) {
        if (!kittenRepository.existsById(id)) {
            throw new RecordNotFoundException();
        }
        return kittenRepository.findById(id).orElse(null);
    }

    @Override
    public long saveKitten(KittenRequest kittenRequest) {

        Kitten newKitten = new KittenBuilder(kittenRequest).buildKitten();
        Price newPrice = new KittenBuilder(kittenRequest).buildPrice();

        Price savedPrice = priceRepository.save(newPrice);
        newKitten.setPrice(savedPrice);
        newPrice.setKitten(newKitten);

        return kittenRepository.save(newKitten).getId();
    }

    @Override
    public void updateKitten(long id, KittenRequest kitten) {
        if (kittenRepository.existsById(id)) {
            try {
                Kitten existingKitten = kittenRepository.findById(id).orElse(null);
                existingKitten.setName(kitten.getName());
                existingKitten.setDateOfBirth(kitten.getDateOfBirth());
                existingKitten.setWeight(kitten.getWeight());
                existingKitten.setBreed(kitten.getBreed());
                existingKitten.setFirstVaccination(kitten.getFirstVaccination());
                existingKitten.setSecondVaccination(kitten.getSecondVaccination());
                kittenRepository.save(existingKitten);
            } catch (Exception ex) {
                throw new DatabaseErrorException();
            }
        } else {
            throw new RecordNotFoundException();
        }
    }

    @Override
    public void updatePrice(long id, KittenRequest price) {
        if (priceRepository.existsById(id)) {
            try {
                Price existingPrice = priceRepository.findById(id).orElse(null);
                existingPrice.setBreedPrice(price.getBreedPrice());
                existingPrice.setFirstVaccinationPrice(price.getFirstVaccinationPrice());
                existingPrice.setSecondVaccinationPrice(price.getSecondVaccinationPrice());
                priceRepository.save(existingPrice);
            } catch (Exception ex) {
                throw new DatabaseErrorException();
            }
        } else {
            throw new RecordNotFoundException();
        }
    }

    @Override
    public void deleteKitten(long id) {
        kittenRepository.deleteById(id);
    }
}

关于您的代码,我有很多话要说,但让我们看看这里的主要问题是什么。如果您查看 KittenBuilder 您使用此构建器创建了一个 Kitten,但您的 Kitten 构造函数是空的,那么问题很简单。

public Kitten(String name, LocalDate dateOfBirth, double weight, String breed, String firstVaccination, String secondVaccination) {
    this.name = name;
    this.dateOfBirth = dateOfBirth;
    this.weight = weight;
    this.breed = breed;
    this.firstVaccination = firstVaccination;
    this.secondVaccination = secondVaccination;
}

这将填充 Kitten 对象,您就可以开始了。


关于您的代码的一些建议

如果您想知道为什么在指定 null 约束时保存 null 值是因为 spring boot 的最新版本不在 Web 启动器中包含验证启动器,你必须自己包含它。

在你pom.xml添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

并且您必须在您的服务中包含注释 @Transactional 以使您的操作原子化,例如在您的创建小猫方法中您希望以原子方式保留价格和小猫。

@Service
@Transactional
class KittenServiceImpl implementes ...

最好的做法之一是不要直接在控制器中使用实体,而是使用 DTO(数据传输对象),这样您就可以将实体中所需的属性映射到 DTO(这这样你就可以只包含你的小猫属性并保留价格实体)。

最后的奖金:

public Kitten getKittenById(long id) {
    if (!kittenRepository.existsById(id)) {
       throw new RecordNotFoundException("");
    }
    return kittenRepository.findById(id).orElse(null);
}

这可以简化为:

public Kitten getKittenById(long id) {
    return kittenRepository.findById(id).orElseThrow(() -> new RecordNotFoundException());
}