Spring Boot - Преобразовать объект ответа / json - Свести список объектов в массив в DAO - PullRequest
0 голосов
/ 10 июля 2020

Я создаю систему управления запасами. Входящий инвентарь будет набором продуктов и соответствующих количеств. Таким образом, один ко многим между InwardInventory и InwardOutwardList.

public class InwardOutwardList extends ReusableFields
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long entryid;
    
    @ManyToOne(fetch=FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinColumn(name="productId",nullable=false)
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    Product product;

    Double quantity;
//getter setter
}

Inward Inventory

public class InwardInventory extends ReusableFields implements Cloneable
{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="inwardid")
    Long inwardid;
    @NonNull
    String vehicleNo;
    @ManyToMany(fetch=FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinTable(name = "inwardinventory_entry", joinColumns = {
            @JoinColumn(name = "inwardid", referencedColumnName = "inwardid") }, inverseJoinColumns = {
                    @JoinColumn(name = "entryId", referencedColumnName = "entryId") })
    Set<InwardOutwardList> inwardOutwardList = new HashSet<>();;
    

    @ManyToOne(fetch=FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinColumn(name="warehouse_id",nullable=false)
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    Warehouse warehouse;

Итак, когда я получаю один внутренние запасы, содержащие два продукта: железо и цемент, я получаю данные в виде вложенных файлов jsons, как показано ниже

[{
  "inwardid": 19497,
  "vehicleNo": "TRUCK",
  "inwardOutwardList": [
    {
      "entryid": 19499,
      "product": {
        "productName": "Cement"
      },
      "quantity": 100
    },
    {
      "entryid": 19500,
      "product": {
        "productName": "Iron"
      },
      "quantity": 10
    }
  ],
  "warehouse": {
    "warehouseName": "war2"
  },
  "supplier": {
    "name": "Bright Traders"
  }
}]

Теперь я хочу экспортировать их в CSV. Итак, мне нужно сгладить его, чтобы он имел только один уровень, как показано ниже

[
  {
    "inwardid": 19497,
    "vehicleNo": "TRUCK",
    "productName": "Cement",
    "quantity": 100,
    "warehouseName": "war2"
  },
  {
    "inwardid": 19497,
    "vehicleNo": "TRUCK",
    "productName": "Iron",
    "quantity": 10,
    "warehouseName": "war2"
  }
]

Я написал простые вложенные для каждой итерации, и он выполняет свою работу

private List<InwardInventoryExportFullDAO> transformStructure(List<InwardInventory> iiDataList) 
    {
        List<InwardInventoryExportFullDAO> data = new ArrayList<InwardInventoryExportFullDAO>();
        for(InwardInventory iiData:iiDataList)
        {
            for(InwardOutwardList ioList:iiData.getInwardOutwardList())
            {
                InwardInventoryExportFullDAO tempExportData = new InwardInventoryExportFullDAO();
                tempExportData.setWarehouse(iiData.getWarehouse().getWarehouseName());
                tempExportData.setVehicleNo(iiData.getVehicleNo());
                tempExportData.setQuantity(ioList.getQuantity());
                tempExportData.setProductName(ioList.getProduct().getProductName());
                data.add(tempExportData);
            }
        }
        return data;
    }

Но я не Считаю, что это оптимальное решение, если резко возрастет количество внутренних инвентарных записей. Другой вариант, который я вижу, - это использование параллельных потоков или json картографов. Но я не уверен, какое решение было бы лучшим и оптимальным для этого. Нет ожидаемых записей для экспорта в excel около 10k.

Вложенные циклы, которые я уже написал, занимают ~ 5 секунд для 2k записей. Таким образом, при увеличении нагрузки в будущем может потребоваться 30+ секунд. Итак, ищем лучшее оптимальное решение.

Заранее благодарю

Ответы [ 2 ]

0 голосов
/ 11 июля 2020

Решено, добавив собственный сериализатор

@Component
public class InwardExportSerializer extends StdSerializer<InwardInventory> 
{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    protected InwardExportSerializer(Class<InwardInventory> t) 
    {
        super(t);
    }
    protected InwardExportSerializer() 
    {
        this(null);
    }
    @Override
    public void serialize(InwardInventory value, JsonGenerator gen, SerializerProvider provider) throws IOException 
    {
        for(InwardOutwardList ioList:value.getInwardOutwardList())
        {
            gen.writeStartObject();
            gen.writeNumberField("inwardid", value.getInwardid());
            gen.writeStringField("productname",ioList.getProduct().getProductName() );
            gen.writeEndObject();
        }
        
    }
        
}
0 голосов
/ 10 июля 2020

Вы можете написать собственный JsonDeserializer и извлечь вложенные Json поля в плоское pojo. Выглядит примерно так:

public class Test extends JsonDeserializer<List<InventoryItem>> {

   private final ObjectMapper mapper = new ObjectMapper();
   private final ObjectReader reader = mapper.readerFor(new TypeReference<List<InventoryItem>>() {});

    @Override
    public List<InventoryItem> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

        JsonNode node = p.getCodec().readTree(p);
        String inwardId = node.get("inwardId").textValue();

        List<InventoryItem> foo = reader.readValue(node.get("inwardOutwardList"));

        foo.forEach(o -> o.setInwardId(inwardId));

        return foo;
    }
}

Сначала вы распаковываете идентификатор из объекта root, затем десериализуете элементы и устанавливаете root id для каждого элемента.

...