如何设计模型来存储动态字段ResponseBody

时间:2017-06-02 02:08:01

标签: spring rest spring-mvc model-view-controller spring-boot

在指定特定时间段时,我们准备一个Web API,该API返回该时间段内每个日期的数据。

具体来说,POST

{"targetFrom": "2016-04-01", "targetTo": "2016-04-03"}}

返回以下JSON数据。

{
    "meta": {
        "StartTime": "2017-06-01T06:50:28.001344102Z", 
        "execute_time": 7532.0517, 
        "host": "49a6ced149d2", 
        "rid": ""
    }, 
    "result": {
        "2016-04-01": {
            "0:num": 121, 
            "0:price": 5244614, 
            "1:num": 124, 
            "1:price": 6324547, 
            "2:num": 115, 
            "2:price": 5604491
        }, 
        "2016-04-02": {
            "0:num": 125, 
            "0:price": 6321222, 
            "1:num": 117, 
            "1:price": 5835030, 
            "2:num": 118, 
            "2:price": 5771826
        }, 
        "2016-04-03": {
            "0:num": 118, 
            "0:price": 5486071, 
            "1:num": 131, 
            "1:price": 6563447, 
            "2:num": 111, 
            "2:price": 5740078
        }, 
        "subTotal": {
            "total_2016-04-01_num": 360, 
            "total_2016-04-01_price": 17173652, 
            "total_2016-04-02_num": 360, 
            "total_2016-04-02_price": 17928078, 
            "total_2016-04-03_num": 360, 
            "total_2016-04-03_price": 17789596
            }, 
        "total": {
            "num": 1080, 
            "price": 52891326
        }
    }
}

问题是日期字段的一部分,如“2016-04-01”。 我想在SpringBoot的应用程序端接受这个,考虑处理修改,并希望定义一个合适的模型。 但是,我找不到一个好的方法。

首先,我认为以下是愚蠢的行为。

@JsonProperty("2016-04-01")
private ResAnalyzeResultDayDto result_20160401;

这是愚蠢的,因为它无法对应于在查询时依赖于参数targetFrom或targetTo的返回数据。

那么,我们如何定义一个模型来处理具有根据请求动态变化的Field的响应数据? 如果你有个好主意,请告诉我。

附加说明: 我编写以下代码时,我的相处并不好。

@JsonProperty("[0-9]{4}-[0-9]{2}-[0-9]{2}")
private Map<String,ResAnalyzeResultSubTotalDayDto> maps;

首先,“@ JsonProperty”似乎无法使用正则表达式,我认为它不会自动设置地图的键。

请求部分的代码使用“RestTemplate”。

ReqTotalSalesStatusDto reqGoMonth = new ReqTotalSalesStatusDto();
reqGoMonth.setStrTo("2016-04-03");
reqGoMonth.setStrFrom("2016-04-01");

// Jackson2HttpMessage
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

ResponseEntity<ResAnalyzeDto> resultGoMonth = restTemplate.exchange(
    "http://localhost:18000/analyze"
    , HttpMethod.POST
    , new HttpEntity<>(reqGoMonth)
    , ResAnalyzeDto.class);

3 个答案:

答案 0 :(得分:1)

您可以将所有结果字段添加到地图对象中:

private Map<String,Object> result;
result.forEach((k,v)->{
System.out.println("key: " + k + " value: " + v);
if("total".equals(k)){
    Total total = (Total) v;
} else if("subTotal".equals(k)) {
    SubTotal subTotal = (SubTotal) v;
} else {
    ResAnalyzeResultDayDto resAnalyzeResultDayDto = (ResAnalyzeResultDayDto) v;
}
});

之后你可以检查钥匙。至于你的例子,map值可以是3个不同的对象。 Total,SubTotal或DayInfo(ResAnalyzeResultDayDto)。您可以轻松了解总计和小计,并可以将它们转换为相应的对象类型。对于地图的其余值,他们将被投射到ResAnalyzeResultDayDto。

答案 1 :(得分:0)

谢谢你,barbakini

我按照我教的方式尝试过,但我不能在演员阵容中表现出色,现在迈出了一步。

日志如下

key: 2016-04-01 value: {0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}
v.toString(): {0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}
2017-06-02 17:12:49.962 [maekawa-PC-http-nio-9999-exec-3]   ACS   XXX:[id: tenant_id:] url:/api/v1/totalsalesstatus/common3 status:200 elapsedNanoTime:8455258
2017-06-02 17:12:49.963 [maekawa-PC-http-nio-9999-exec-3]   ERROR  o.a.c.c.C.[.[.[.[dispatcherServlet] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to jp.co.temp.sample.management.report.api.dto.ResAnalyzeResultDayDto] with root cause

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to jp.co.temp.sample.management.report.api.dto.ResAnalyzeResultDayDto
    at jp.co.temp.sample.management.report.api.TotalSalesStatusCommandService.lambda$createFinalResultObj3$3(TotalSalesStatusCommandService.java:609)
    at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
    at jp.co.temp.sample.management.report.api.TotalSalesStatusCommandService.createFinalResultObj3(TotalSalesStatusCommandService.java:600)

答案 2 :(得分:0)

模型

@Data
public class ResAnalyzeResultDayDto  {

@JsonProperty("0:num")
private int num0;

@JsonProperty("0:price")
private int price0;

@JsonProperty("1:num")
private int num1;

@JsonProperty("1:price")
private int price1;

@JsonProperty("2:num")
private int num2;

@JsonProperty("2:price")
private int price2;
}

private ResponseEntity<TotalSalesStatus> createFinalResultObj3(TotalSalesStatus resultObj,
        List<ResponseEntity<ResAnalyzeDto3>> goResponseEntityList ,String disposalDate) {

    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
    this.logger.info("■■UT:[{}] ", methodName);

    int sumTotalNum = 0;
    int sumTotalPrice = 0;

    TotalSalesStatusGrandson totalSalesStatusDay = new TotalSalesStatusGrandson();
    resultObj.setTotalSalesStatusDay(totalSalesStatusDay);

    TotalSalesStatusGrandson totalSalesStatusMonth = new TotalSalesStatusGrandson();
    resultObj.setTotalSalesStatusMonth(totalSalesStatusMonth);

    boolean targetMonthFlag = false;
    for(ResponseEntity<ResAnalyzeDto3> e : goResponseEntityList){
        ResAnalyzeDto3 dto = e.getBody();
        ResAnalyzeMetaDto meta = dto.getMeta();
        Map<String,Map<String,?>> resu = dto.getResult();
        this.logger.info("■■UT:[{}] ResAnalyzeMetaDto  :{}", methodName,meta.toString());
        this.logger.info("■■UT:[{}] ResAnalyzeResultDto:{}", methodName,resu.toString());
            resu.forEach((k,v)->{
                System.out.println("key: " + k + " value: " + v);
                System.out.println("v.toString(): " + v.toString());
                String val = v.toString();
                ObjectMapper mapper = new ObjectMapper();
                if("total".equals(k)){
//                        ResAnalyzeResultTotalDto total = (ResAnalyzeResultTotalDto) v;
                    try {
                        ResAnalyzeResultTotalDto total = mapper.readValue(val,ResAnalyzeResultTotalDto.class);
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                } else if("subTotal".equals(k)) {
//                        ResAnalyzeResultSubTotalDto subTotal = (ResAnalyzeResultSubTotalDto) v;
                    try {
                        ResAnalyzeResultSubTotalDto subTotal = mapper.readValue(val,ResAnalyzeResultSubTotalDto.class);
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                } else {
//                        ResAnalyzeResultDayDto resAnalyzeResultDayDto = (ResAnalyzeResultDayDto) v;
                    try {
                        ResAnalyzeResultDayDto resAnalyzeResultDayDto = mapper.readValue(val,ResAnalyzeResultDayDto.class);
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    }
                }
            });
    }
    TotalSalesStatusGrandson totalSalesStatusYear = new TotalSalesStatusGrandson();
    totalSalesStatusYear.setTotal(new BigDecimal(sumTotalPrice));
    resultObj.setTotalSalesStatusYear(totalSalesStatusYear);
    resultObj.setUnitLabel("sample");
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    ResponseEntity<TotalSalesStatus> result = new ResponseEntity<TotalSalesStatus>(resultObj, headers, HttpStatus.CREATED);
    return result;
}

日志

2017-06-05 13:33:48.382 [maekawa-PC-http-nio-9999-exec-1]   INFO  SAMPLE:[id: tenant_id:] j.c.b.b.m.r.a.TotalSalesStatusCommandService ■■UT:[createFinalResultObj3]
2017-06-05 13:33:48.382 [maekawa-PC-http-nio-9999-exec-1]   INFO  SAMPLE:[id: tenant_id:] j.c.b.b.m.r.a.TotalSalesStatusCommandService ■■UT:[createFinalResultObj3] ResAnalyzeMetaDto  :ResAnalyzeMetaDto(startTime=2017-06-05T04:33:48.499791734Z, executeTime=2.1928, host=bb8bfd9acf04, rid=)
2017-06-05 13:33:48.382 [maekawa-PC-http-nio-9999-exec-1]   INFO  SAMPLE:[id: tenant_id:] j.c.b.b.m.r.a.TotalSalesStatusCommandService ■■UT:[createFinalResultObj3] ResAnalyzeResultDto:{2016-04-01={0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}, 2016-04-02={0:num=125, 0:price=6321222, 1:num=117, 1:price=5835030, 2:num=118, 2:price=5771826}, 2016-04-03={0:num=118, 0:price=5486071, 1:num=131, 1:price=6563447, 2:num=111, 2:price=5740078}, subTotal={total_2016-04-01_num=360, total_2016-04-01_price=17173652, total_2016-04-02_num=360, total_2016-04-02_price=17928078, total_2016-04-03_num=360, total_2016-04-03_price=17789596}, total={num=1080, price=52891326}}
key: 2016-04-01 value: {0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}
v.toString(): {0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('0' (code 48)): was expecting double-quote to start field name
 at [Source: {0:num=121, 0:price=5244614, 1:num=124, 1:price=6324547, 2:num=115, 2:price=5604491}; line: 1, column: 3]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:456)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1771)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:684)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
    at jp.co.temp.sample.management.report.api.TotalSalesStatusCommandService.lambda$createFinalResultObj3$3(TotalSalesStatusCommandService.java:636)
    at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)