如何从外部将Map接收到Spring Boot应用程序中(UI/Postman)

lvjbypge  于 2022-09-19  发布在  Spring
关注(0)|答案(2)|浏览(152)

下面是我的控制器,它有两种方法。
第一种方法接收产品的列表,第二种方法接收以UniqueID作为密钥的产品的Map
我能够完美地接收和使用列表版本(工作正常)。

但不能成功使用Map版本。请纠正我的错误

我的控制器类如下所示。。。。

@RestController
public class MyBoot1Controller {

    @PostMapping(value = "/storeList")
    public String storeProducts(@RequestBody List<Product> products) {
        System.out.println("Received Products count: " + products.size());
        System.out.println(products);
        return "received " + products.size() + " products into the List.";
    }

    @PostMapping(value = "/storeMap")
    public String storeProducts(@RequestBody Map<UniqueID, Product> products) {
        System.out.println("Received Products count: " + products.size());
        System.out.println(products);
        return "received " + products.size() + " products into the Map.";
    }
}

Product和UniqueID的类定义如下。。。。

public class Product {
    int pid;
    String pname;
    String ptype;
    int plife;
    //getters & setters
}

final public class UniqueID {
    public String uid;

    public UniqueID(String uid) {
        super();
        this.uid = uid;
    }

    @Override
    public String toString() {
        return uid;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    @Override
    public boolean equals(Object u) {
        UniqueID ud = (UniqueID) u;
        return (ud.uid == uid);
    }

    @Override
    public int hashCode() {
        int h = 0, i;
        for (i = 0; i < uid.length(); i++)
            h += (i + 1) * uid.charAt(i);
        h += uid.length();
        return h;
    }
}

在每个(列表和Map)版本中,我使用POST方法从Postman传递的示例数据如下。
下面是列表的JSON输入(工作正常…)

[
    {
        "pid": 1,
        "pname": "laptop",
        "ptype": "computer",
        "plife": 10
    },
    {
        "pid": 2,
        "pname": "keyboard",
        "ptype": "computer",
        "plife": 12
    },
    {
        "pid": 3,
        "pname": "Plastic Flowers",
        "ptype": "Decoration",
        "plife": 3
    }
]

以下是Map的JSON输入(不工作)

{   
    {
        "uid":"first"
    }:
    {
        "pid": 1,
        "pname": "laptop",
        "ptype": "computer",
        "plife": 10
    },

    {
        "uid":"second"
    }:
    {
        "pid": 2,
        "pname": "keyboard",
        "ptype": "computer",
        "plife": 12
    },

    {
        "uid":"third"
    }:
    {
        "pid": 3,
        "pname": "Plastic Flowers",
        "ptype": "Decoration",
        "plife": 3
    }
}

当我使用字符串(而不是UniqueID)作为键时,以下JSON工作正常。。。

{
  "first": {
    "pid": 1,
    "pname": "laptop",
    "ptype": "elec",
    "plife": 10
  },
  "second": {
    "pid": 2,
    "pname": "phone",
    "ptype": "elec",
    "plife": 10
  },
  "third": {
    "pid": 3,
    "pname": "purse",
    "ptype": "leather",
    "plife": 20
  },
  "fourth": {
    "pid": 4,
    "pname": "book",
    "ptype": "stationery",
    "plife": 100
  }
}

**如果密钥中只有一个字段(UniqueID),则可以发送一个字符串。

我知道我上面的JSON格式(对于Map版本)对于Key无效,但是如果我的Key(UniqueID)有多个数据元素,如下面所示呢**

final public class UniqueID {
    public String uid;
    public String personalNumber;
    public String citizenshipNumber;
}
6qftjkof

6qftjkof1#

您显示的第二个JSON是无效JSON,因此没有框架能够反序列化它。
如果您的唯一ID包含多个字段,要回答您应该怎么做的问题,答案是使用不同的JSON结构,例如:

[
  {
    "id": {
      "uid": 1,
      "personalNumber": 1,
      "citizenshipNumber": 1
    },
    "product": {
      "pid": 1,
      "pname": "laptop",
      "ptype": "computer",
      "plife": 10      
    }
  }
]

现在您可以创建一个额外的类,如下所示:

public class ProductWithID {
    private UniqueID id;
    private Product product;
    // TODO: Implement getters + setters
}

在控制器中,您可以使用List<ProductWithID>

@PostMapping(value = "/storeList")
public String storeProducts(@RequestBody List<ProductWithID> products) {
    // TODO: Implement
}

如果您喜欢使用Map,可以在代码中进行翻译。例如:

@PostMapping(value = "/storeList")
public String storeProducts(@RequestBody List<ProductWithID> products) {
    Map<UniqueID, Product> productMap = products
        .stream()
        .toMap(ProductWithID::getId, ProductWithID::getProduct);
    // TODO: Implement
}
jchrr9hc

jchrr9hc2#

首先,您需要使json有效。我建议采用以下结构:

{
  "{\"uid\": \"first\"}": {
    "pid": 1,
    "pname": "laptop",
    "ptype": "computer",
    "plife": 10
  },
  "{\"uid\":\"second\"}": {
    "pid": 2,
    "pname": "keyboard",
    "ptype": "computer",
    "plife": 12
  },
  "{\"uid\":\"third\"}": {
    "pid": 3,
    "pname": "Plastic Flowers",
    "ptype": "Decoration",
    "plife": 3
  }
}

请注意,这些键应该是stings,但它们被序列化为json。
我假设Jackson,因为这个问题被标记为Spring Boot。首先,您需要创建KeyDeserializer

private static final class TestDeserializer extends KeyDeserializer {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public TestDeserializer() {
        super();
    }
    @Override
    public Object deserializeKey(String key, DeserializationContext context) throws IOException {
        return MAPPER.readValue(key, UniqueID.class);
    }
}

并将其注册为UniqueID

@JsonDeserialize(keyUsing = TestDeserializer.class)
public class UniqueID {
    public String uid;
    public String personalNumber;
    public String citizenshipNumber;
}

简单的主要测试方法:

public class Temp {

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<UniqueID, Product> map = objectMapper.readValue(json, TypeFactory.defaultInstance().constructParametricType(Map.class, UniqueID.class, Product.class));
        System.out.println(map);
    }
}

相关问题