【问题标题】:Saving arrays of elements in the json object into different rows将 json 对象中的元素数组保存到不同的行中
【发布时间】:2019-08-31 23:30:57
【问题描述】:

在保存包含多个 json 的 json 对象时,json 对象被保存为单个数组而不是多行。

示例 json:

[
    {
     "id"   : 1, -- this is not a primary key and not unique but cannot be null
     "name" : "John Doe",
     "phone" : [
       { "type" : "home", "ref" : "111-111-1234"},
       { "type" : "work", "ref" : "222-222-2222"}
     ]
   },
   {
    "id"   : 2, -- this is not a primary key and not unique but cannot be null
    "name" : "Jane Doe",
    "phone" : [
      { "type" : "home", "ref" : "111-111-1234"},
      { "type" : "work", "ref" : "222-222-2222"}
    ]
  }
]

这是我保存到数据库后需要的

id   name         phone    
1    John Doe     { "type" : "home", "ref" : "111-111-1234"}
1    John Doe     { "type" : "work", "ref" : "222-222-2222"}
2    Jane Doe     { "type" : "home", "ref" : "111-111-1234"}
2    Jane Doe     { "type" : "work", "ref" : "222-222-2222"}

这就是我得到的

id   name         phone    
1    John Doe     [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]
2    Jane Doe    [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]

这是我如何将 json 对象解析为 pojo 并保存到 db

@Entity
@Table(name="person")
public class person{
    private Integer id;
    private String name;
    private String phone;
    @Transient 
    JsonNode phoneJson;

    private static OhjectMapper mapper = new ObjectMapper();

    getter/setter

    @Transient
    public JsonNode getPhoneJson(){
        return phoneJson;
    }

    public void setPhoneJson(JsonNode phoneJson){
        this.phoneJson = phoneJson;
    }

    @JsonIgnore
    @Column(name="phone")
    public String getPhone() throws Exception{
        return mapper.writeValueAsString(phoneJson);
    }

    public void setPhone(String phone) throws Exception{
        this.phone = mapper.readTree(phone);
    }
}

道-保存

personRepository.save(person)

任何帮助将不胜感激。

更新

多个 jSON 列

[
    {
     "id"   : 1, -- this primary key and not unique but cannot be null
     "name" : { --this element can be empty/null
        "first" : "John",
        "last" : "Doe" 
      },
     "phone" : [
       { "type" : "home", "ref" : 1111111234},
       { "type" : "work", "ref" : 2222222222}
     ]
   },
   {
    "id"   : 2, -- this primary key and not unique but cannot be null
    "name" : {
        "first" : "Jane",
        "last" : "Doe" 
      },
    "phone" : [
      { "type" : "home", "ref" : 1111111234},
      { "type" : "work", "ref" : 2222222222}
    ]
  }
]

我如何得到如下结果

id   name                   phone    
1    [{John},{Doe}]     { "type" : "home", "ref" : "111-111-1234"}
1    [{John},{Doe}]     { "type" : "work", "ref" : "222-222-2222"}
2    [{Jane},{Doe}]     { "type" : "home", "ref" : "111-111-1234"}
2    [{Jane},{Doe}]     { "type" : "work", "ref" : "222-222-2222"}

【问题讨论】:

    标签: json spring-boot spring-data-jpa spring-data spring-data-rest


    【解决方案1】:

    您需要复制Person 对象n 次,其中n 的大小为phone 数组。为了清楚起见,我建议创建两个单独的模型,我们可以分别使用它们来解析 JSON 并保存在 DB 中。您可以在下面找到简单的示例:

    1. JSON 解析为List<JsonPerson>
    2. List<JsonPerson> 转换为List<Person>
    3. 打印List<Person>(可以保存到DB

    例子:

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.type.CollectionType;
    
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            File jsonFile = new File("./resource/test.json").getAbsoluteFile();
    
            ObjectMapper mapper = new ObjectMapper();
            CollectionType personsType = mapper.getTypeFactory().constructCollectionType(List.class, JsonPerson.class);
    
            // parse
            List<JsonPerson> jsonPersons = mapper.readValue(jsonFile, personsType);
    
            // convert
            List<Person> persons = jsonPersons.stream()
                    .map(p -> p.mapTo(mapper))
                    .flatMap(List::stream)
                    .collect(Collectors.toList());
    
            persons.forEach(System.out::println);
    
            // save persons to DB
            // ...
        }
    }
    
    class JsonPerson {
    
        private Integer id;
        private String name;
        private ArrayNode phone;
    
        public List<Person> mapTo(ObjectMapper mapper) {
            List<Person> persons = new ArrayList<>();
            phone.elements().forEachRemaining(phone -> {
                persons.add(map(mapper, phone));
            });
    
            return persons;
        }
    
        private Person map(ObjectMapper mapper, JsonNode p) {
            Person person = new Person();
            person.setId(id);
            person.setName(name);
            try {
                person.setPhone(mapper.writeValueAsString(p));
            } catch (JsonProcessingException e) {
                throw new IllegalStateException(e);
            }
    
            return person;
        }
    
        // getters, setters, toString
    }
    
    class Person {
    
        private Integer id;
        private String name;
        private String phone;
    
        // getters, setters, toString
    }
    

    上面的代码打印:

    Person{id=1, name='John Doe', phone='{"type":"home","ref":"111-111-1234"}'}
    Person{id=1, name='John Doe', phone='{"type":"work","ref":"222-222-2222"}'}
    Person{id=2, name='Jane Doe', phone='{"type":"home","ref":"111-111-1234"}'}
    Person{id=2, name='Jane Doe', phone='{"type":"work","ref":"222-222-2222"}'}
    

    以上代码将解析JSON 与其他部分分开。另外,不要在每个POJO 中创建ObjectMapperPOJO 应该对 ObjectMapperJackson 一无所知。

    更新

    因为nameJSON Object,您可以使用firstlast 属性创建新的POJO - Name,或者将其与phone 类似地处理并反序列化为JsonNode

    class JsonPerson {
    
        private Integer id;
        private JsonNode name;
        private ArrayNode phone;
    
        public List<Person> mapTo(ObjectMapper mapper) {
            List<Person> persons = new ArrayList<>();
            phone.elements().forEachRemaining(phone -> {
                persons.add(map(mapper, phone));
            });
    
            return persons;
        }
    
        private Person map(ObjectMapper mapper, JsonNode p) {
            Person person = new Person();
            person.setId(id);
            person.setName(getNameAsString());
            try {
                person.setPhone(mapper.writeValueAsString(p));
            } catch (JsonProcessingException e) {
                throw new IllegalStateException(e);
            }
    
            return person;
        }
    
        private String getNameAsString() {
            if (name == null) {
                return null;
            }
            StringBuilder builder = new StringBuilder();
            if (name.isObject()) {
                ObjectNode nameObject = (ObjectNode) name;
                builder.append("[");
                builder.append("{").append(nameObject.get("first")).append("}");
                builder.append(",");
                builder.append("{").append(nameObject.get("last")).append("}");
                builder.append("]");
            }
            return builder.toString();
        }
    
        // getters, setters, toString
    }
    

    上面的代码修改后应该打印出来:

    Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
    Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}
    Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
    Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}
    

    getNameAsString 方法被简化,您需要处理所有极端情况并为nullemptysemi-empty 节点创建更好的String 表示。

    【讨论】:

    • 谢谢 Michal,我已经更新了我的问题,因为我有多个 json 列,但只有 phone 列需要保存在不同的行中。此外,在读取值 {List jsonPersons = mapper.readValue(jsonFile, personType);} 我如何捕获传入的 json 请求值?我在模态类中使用了mapper.readtree,在保存到数据库之前对其进行了转换。
    • @404or505,如果其他属性是复杂对象,您始终可以将它们反序列化为POJO 类或*Node 类。更新后看看我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 2018-07-03
    • 1970-01-01
    • 2020-11-01
    相关资源
    最近更新 更多