构造Java中复杂的结构体: StringUtil.replace()

1,422 阅读2分钟

在开发Java工程中,相信大家也遇到过接口的请求体过于复杂,用对象来映射,层层嵌套,不利于构造,不也利于维护,非常麻烦的情况,像这样:

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class AmRequestDTO {
    private Session session = new Session();

    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Session {
        private String session_id;
        private Integer processed_duration;
        private Long timestamp;
        private Integer wanted_sequence_id;
        private String message;
        private List<Sentence> sentence;
        private Integer slice_time;
        private Boolean is_silence;
        private Float valid_speech_ratio;
        private JSONObject extend;
        ...

        @Data
        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class Sentence {
            private Integer sentence_id;
            private String post_processed_text;
            private Float dirty_words_probability;
            private List<Words> words;
            ...

            @Data
            @JsonIgnoreProperties(ignoreUnknown = true)
            public static class Words {
                private Integer end_time;
                private String text;
                private Float confidence;
            }
        }
    }
}

构造这样的请求体,对Java开发者来说,简直就是灾难。(为了方便映射RequestBody里面的字段,没有采用驼峰命名)

一、Java构造复杂结构体的救星:StringUtil.replace(CharSequence, Map<String, V>)

此处的StringUtil不是常见的commons里面的,看POM:

<dependency>
	<groupId>com.github.ifeilong</groupId>
	<artifactId>feilong</artifactId>
	<version>3.0.10</version>
</dependency>

为了大家查阅方便:

二、使用示例

以ES的RequestBody为例,此处只关注主要部分:

{
    "filters": {
        "and": [
            {
                "field": "floor_level_recall",
                "action": "term",
                "value": "${floorLevel}"
            },
            {
                "field": "building_age_lower",
                "action": "lte",
                "value": ${buildingFinishYear}
            },
            {
                "field": "build_area_lower",
                "action": "lte",
                "value": ${houseArea}
            }
        ]
    }
}

上面给定的字符串作为模板,使用 StringUtil.replace(CharSequence, Map<String, V>) 解析匹配的变量:

@Test
public void testStringUtil() {
    // 基准字符串
    String strBenchmark = "{\"filters\":{\"and\":[{\"field\":\"floor_level_recall\",\"action\":\"term\",\"value\":\"${floorLevel}\"}," +
            "{\"field\":\"building_age_lower\",\"action\":\"lte\",\"value\":${buildingFinishYear}}," +
            "{\"field\":\"build_area_lower\",\"action\":\"lte\",\"value\":${houseArea}}]}}";
    // 要匹配的值
    Map<String, String> map = new HashMap<>(3);
    map.put("floorLevel", String.valueOf(19));
    map.put("buildingFinishYear", String.valueOf(2015));
    map.put("houseArea", String.valueOf(119.5));
  
    System.out.println(StringUtil.replace(strBenchmark, map));
}

输出(格式化后):

{
    "filters": {
        "and": [
            {
                "field": "floor_level_recall",
                "action": "term",
                "value": "19"
            },
            {
                "field": "building_age_lower",
                "action": "lte",
                "value": 2015
            },
            {
                "field": "build_area_lower",
                "action": "lte",
                "value": 119.5
            }
        ]
    }
}

至此完成了这个结构体的构造,在实际使用过程中,对于复杂的结构体,都可以采用这种形式,使用fastjson的JSON.toJSONString()方法,先转为String,然后再构造,最后完成的某个字段整个结构体以String或JSON的形式使用。以上是个人的解决办法,欢迎分享更好的办法,一起写出更优雅、简洁的代码!