作为网关,有些时候可能报文的结构并不符合前端或者某些服务的需求,或者因为某些原因,其他服务修改报文结构特别麻烦、或者需要修改的地方特别多,这个时候就需要走网关单独转换一次。
实现话不多说,直接上代码。
首先,我们定义好配置:
package com.lifengdi.gateway.properties.entity; import lombok.Data; import org.springframework.util.CollectionUtils; import java.util.*; /** * 需要转换报文结构的URL地址配置类 * * @author: Li Fengdi * @date: 2020-7-11 16:57:07 */ @Data public class MessageTransformUrl { // 接口地址,多个地址使用英文逗号分隔 private String[] paths; /** * <p>格式</p> * <p>新字段:老字段</p> * <p>若新老字段一致,可以只配置新字段</p> */ private List<String> fields; /** * <p>返回体类型,默认为json </p> * <p>可配置的类型参见{@link com.lifengdi.gateway.enums.TransformContentTypeEnum}</p> * <p>如需自定义配置,可以继承{@link com.lifengdi.gateway.transform.AbstractMessageTransform}类, * 或者实现{@link com.lifengdi.gateway.transform.IMessageTransform}接口类,重写transform方法</p> */ private String contentType; private Set<String> pathList; public Set<String> getPathList() { if (CollectionUtils.isEmpty(pathList) && Objects.nonNull(paths)) { setPathList(new HashSet<>(Arrays.asList(paths))); } return pathList; } } package com.lifengdi.gateway.properties; import com.lifengdi.gateway.properties.entity.MessageTransformUrl; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.List; /** * 报文结构转换参数配置 * @author: Li Fengdi * @date: 2020-7-11 16:55:53 */ @Component @ConfigurationProperties(prefix = "trans") @Data public class MessageTransformProperties { private List<MessageTransformUrl> urlList; }在yaml文件中的配置如下:
# 报文转换配置 trans: url-list: - paths: /jar/api/cockpit content-type: application/json fields: # 新字段:老字段,若新老字段一致,可以只配置新字段 - code:rs - msg:rsdesp - data:resultMessage - paths: /war/api/delivertool fields: - code:rs - msg:rsdesp - data:resultMessage这里呢,大家也可以根据需要,放入数据库或者其他可以动态修改的地方,这里只是图方便,所以直接放在yaml文件中。
其次我们定义一个报文转换接口类,方便后续的扩展。这个接口很简单,只有一个transform()方法,主要功能就是转换报文结构。
package com.lifengdi.gateway.transform; import com.lifengdi.gateway.properties.entity.MessageTransformUrl; /** * 报文结构转换接口 * * @author: Li Fengdi * @date: 2020-7-11 16:57:07 */ public interface IMessageTransform { /** * 转换报文结构 * * @param originalContent 需要转换的原始内容 * @param transformUrl MessageTransformUrl * @return 转换后的结构 */ String transform(String originalContent, MessageTransformUrl transformUrl); }然后我们再增加一个抽象类,这个类主要提供一个解耦的作用,也是为了方便后续进行扩展。
package com.lifengdi.gateway.transform; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import javax.annotation.Resource; /** * 报文转换抽象类 * * @author: Li Fengdi * @date: 2020-7-11 16:57:07 */ public abstract class AbstractMessageTransform implements IMessageTransform { @Resource protected ObjectMapper objectMapper; /** * ResponseResult转JSON * * @param object 需要转换为json的对象 * @return JSON字符串 */ public String toJsonString(Object object) throws JsonProcessingException { return objectMapper.writeValueAsString(object); } }这个类非常简单,只有一个toJsonString()方法,主要作用就是将对象转换成json字符串。
接着我们继续来写一个实现类,主要功能就是实现JSON类型的报文的结构转换,如果需要其他类型的报文的同学,可以自定义开发。
package com.lifengdi.gateway.transform.impl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.lifengdi.gateway.properties.entity.MessageTransformUrl; import com.lifengdi.gateway.transform.AbstractMessageTransform; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Service; import java.util.List; /** * application/json类型转换实现类 * @author: Li Fengdi * @date: 2020-7-11 16:57:07 */ @Service @Slf4j public class JsonMessageTransformImpl extends AbstractMessageTransform { @Override public String transform(String originalContent, MessageTransformUrl transformUrl) { if (StringUtils.isBlank(originalContent)) { return originalContent; } try { // 原始报文转换为JsonNode JsonNode jsonNode = objectMapper.readTree(originalContent); List<String> fields = transformUrl.getFields(); // 创建新的JSON对象 ObjectNode rootNode = objectMapper.createObjectNode(); fields.forEach(field -> { String[] fieldArray = field.split(":"); String newFiled = fieldArray[0]; String oldField = fieldArray.length > 1 ? fieldArray[1] : newFiled; if (jsonNode.has(oldField)) { rootNode.set(newFiled, jsonNode.get(oldField)); } }); return toJsonString(rootNode); } catch (JsonProcessingException e) { log.error("application/json类型转换异常,originalContent:{},transformUrl:{}", originalContent, transformUrl); return originalContent; } } }这个类继承了AbstractMessageTransform这个类,重写了transform()方法,使用objectMapper、JsonNode、ObjectNode来实现对JSON的解析、转换等工作。