有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

DTO中的java动态字段类型

我正在使用Spring-MVC,我有一个如下结构的DTO,从客户机(一个foo实体)接收JSON数据,并将其保存到带有JPA的数据库中:

public class FooDTO {

    public Integer id;
    public String label;
    public Double amount;
    public List<Integer> states;
    ...

但是,当客户机想要编辑foo实体时,我必须按照下面的方式构造它

public class FooDTO {

    public Integer id;
    public String label;
    public Double amount;
    public List<SimpleDto> states;
    ...

SimpleDto

public class SimpleDto {
    public Integer value;
    public String label;
}

区别在于states类型有时是List<SimpleDto>有时是List<Integer>,我不想创建另一个dto

那么,如何在dto(json)中实现动态字段类型呢

p.S JSON数据由com.fasterxml.jackson.core处理


共 (6) 个答案

  1. # 2 楼答案

    我建议您使用不同的类:FooInfoDTO、foodailsdto。它通常在您拥有主详细信息表单时使用。在master(表)中,显示有关对象的简短信息(一个DTO),然后导航到详细信息,获取完整的对象数据(另一个DTO)

  2. # 3 楼答案

    使用自定义反序列化程序是解决问题的一种方法

        public class DynamicDeserializer extends JsonDeserializer {
        @Override
        public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            String requestString = jp.readValueAsTree().toString();
            JSONArray jo = new JSONArray(requestString);
            List<SimpleDto> simpleDtoList = new ArrayList<>();
            List<Integer> integers = new ArrayList<>();
            if(jo!=null && jo.length()>0) {
                for (int i = 0; i < jo.length(); i++) {
                    Object string = jo.get(0);
                    if(string!=null && string instanceof JSONObject){
                        JSONObject value = jo.getJSONObject(i);
                        SimpleDto simpleDto = new SimpleDto();
                        simpleDto.setValue(value.getInt("value"));
                        simpleDtoList.add(simpleDto);
                    }else{
                        integers.add(jo.getInt(0));
                    }
                }
            }
    
    
            return integers.isEmpty() ? simpleDtoList:integers;
        }
    }
    

    发送和打印请求的控制器

    @PostMapping("/test")
        public Optional<TestObject> testDynamicMapper(
                @RequestBody final TestObject testObject) {
            List<Object> states = testObject.getStates();
    
            for (Object object:states) {
                if(object instanceof SimpleDto){
                    SimpleDto dto = (SimpleDto)object;
                    System.out.println(dto.getValue());
                }
                if(object instanceof Integer){
                    Integer dto = (Integer)object;
                    System.out.println(dto);
                }
            }
    
    
            return Optional.of(testObject);
        }
    

    存在泛型映射的pojo类

    public class TestObject implements Serializable {
    
        @JsonDeserialize(using = DynamicDeserializer.class)
        private List<Object> states;
    
    
        public List<Object> getStates() {
            return states;
        }
    
        public void setStates(List<Object> states) {
            this.states = states;
        }
    
    
    }
    

    对象列表的输入有效负载

    {
      "states": [
        {
          "label": "1",
          "value": 0
        }
      ]
    }
    

    整数列表的输入有效负载

    {
      "states": [
          1,2
      ]
    }
    
  3. # 4 楼答案

    您可以使用JsonCreator注释和两个构造函数来表示项POJO。如果数组中有一个基元1-arg将使用构造函数。在完全设置对象的情况下2-arg将使用构造函数。请参见以下示例:

    import com.fasterxml.jackson.annotation.JsonCreator;
    import com.fasterxml.jackson.annotation.JsonCreator.Mode;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.List;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            String json = "{\"id\":1,\"label\":\"LABEL\",\"amount\":1.23,\"states\":[1,{\"value\":2},{\"value\":3,\"label\":\"LAB\"}]}";
            ObjectMapper mapper = new ObjectMapper();
    
            Foo foo = mapper.readValue(json, Foo.class);
            System.out.println(foo);
        }
    }
    
    class Foo {
    
        private Integer id;
        private String label;
        private Double amount;
        private List<State> states;
    
        // getters, setters, toString
    }
    
    class State {
    
        private Integer value;
        private String label;
    
        @JsonCreator(mode = Mode.DELEGATING)
        public State(@JsonProperty("value") Integer value) {
            this(value, null);
        }
    
        @JsonCreator
        public State(@JsonProperty("value") Integer value, @JsonProperty("label") String label) {
            this.value = value;
            this.label = label;
        }
    
        // getters, setters, toString
    }
    

    以上代码打印:

    Foo{id=1, label='LABEL', amount=1.23, states=[State{value=1, label='null'}, State{value=2, label='null'}, State{value=3, label='LAB'}]}
    

    使用的版本:2.9.8

  4. # 5 楼答案

    我建议不要添加另一个促进重复的DTO。 但是,您仍然需要添加另一个DTO,该DTO将专用于您各自的服务。您只需使用层次结构定义DTO

    public class FooDTO {
    
        public Integer id;
        public String label;
        public Double amount;
    }
    

    定义您的响应DTO以提供详细信息,方法是将通用详细信息DTO扩展为FooDTO,如下所示:

    public class FooDetailsOutDTO extends FooDTO {
    
        public List<Integer> states;
    
    }
    

    对于“编辑”,定义DTO如下:

    public class FooUpdateDetailsInDTO extends FooDTO {
    
         public List<SimpleDto> states;
    
    }
    
  5. # 6 楼答案

    写dto

    public class FooDTO {
    
        public Integer id;
        public String label;
        public Double amount;
        public List<Object> states;
    }
    

    在服务类中键入DTO并处理异常