public static String compareMd5ResultString(List<String> changedGroupKeys) throws IOException {
        if (null == changedGroupKeys) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (String groupKey : changedGroupKeys) {
            String[] dataIdGroupId = GroupKey.parseKey(groupKey);
            sb.append(dataIdGroupId[0]);
            sb.append(Constants.WORD_SEPARATOR);
            sb.append(dataIdGroupId[1]);
            // if have tenant, then set it
            boolean b = (dataIdGroupId.length == DATA_ID_GROUP_ID_THREE_LEN
                    || dataIdGroupId.length == DATA_ID_GROUP_ID_FOUR_LEN)
                    && StringUtil.isNotBlank(dataIdGroupId[2]);
            if (b) {
                sb.append(Constants.WORD_SEPARATOR);
                sb.append(dataIdGroupId[2]);
            }
            sb.append(Constants.LINE_SEPARATOR);
        }
        // To encode WORD_SEPARATOR and LINE_SEPARATOR invisible characters, encoded value is %02 and %01
        return URLEncoder.encode(sb.toString(), "UTF-8");
    }
@Test
    public void assetCompareMd5ResultString() throws IOException {
        Assert.isTrue("".equals(Md5Util.compareMd5ResultString(null)));
        String result = "prescription%02dynamic-threadpool-example%02message-consume%01" +
                "prescription%02dynamic-threadpool-example%02message-produce%01";
        List<String> changedGroupKeys = new ArrayList<>(2);
        changedGroupKeys.add("prescription+dynamic-threadpool-example+message-consume+12");
        changedGroupKeys.add("prescription+dynamic-threadpool-example+message-produce+11");
        Assert.isTrue(result.equals(Md5Util.compareMd5ResultString(changedGroupKeys)));
    }