李锋镝的园子资料

本文主要介绍李锋镝的园子资料 方法和在新技术下所面对的“挑战”,方便大家深入理解李锋镝的园子资料 过程。本文也将分享李锋镝的园子资料 所遇到的问题和应对策略,怎么解决怎么做的问题。
通过深入本文可以理解代码原理,进行代码文档的下载,也可以查看相应 Demo 部署效果。

背景

作为网关,有些时候可能报文的结构并不符合前端或者某些服务的需求,或者因为某些原因,其他服务修改报文结构特别麻烦、或者需要修改的地方特别多,这个时候就需要走网关单独转换一次。

实现

话不多说,直接上代码。

首先,我们定义好配置:

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()方法,使用objectMapperJsonNodeObjectNode来实现对JSON的解析、转换等工作。

接下来我们定义一个枚举类,方便我们去匹配对应的报文转换实现类。

package com.lifengdi.gateway.enums;  import lombok.Getter; import org.apache.commons.lang.StringUtils; import org.springframework.lang.Nullable;  /**  * 报文结构转换转换类型枚举类  *  * @author: Li Fengdi  * @date: 2020-7-11 16:57:07  */ @Getter public enum TransformContentTypeEnum {      DEFAULT(null, "jsonMessageTransformImpl")     , APPLICATION_JSON("application/json", "jsonMessageTransformImpl")     ;     /**      * 内容类型      */     private String contentType;      /**      * 报文转换结构实现类      */     private String transImpl;      TransformContentTypeEnum(String contentType, String transImpl) {         this.contentType = contentType;         this.transImpl = transImpl;     }      /**      * 根据contentType获取对应枚举      * <p>      * 如果contentType为空则返回默认枚举      * </p>      *      * @param contentType contentType      * @return TransformContentTypeEnum      */     public static TransformContentTypeEnum getWithDefault(@Nullable String contentType) {         if (StringUtils.isNotBlank(contentType)) {             for (TransformContentTypeEnum transformContentTypeEnum : values()) {                 if (contentType.equals(transformContentTypeEnum.contentType)) {                     return transformContentTypeEnum;                 }             }         }         return DEFAULT;     } } 

这个类也很简单,定义枚举,然后一个静态方法,静态方法的作用是根据响应头中的contentType来获取对应的报文结构转换实现类,如果获取不到,则会返回一个默认的实现类,我这里定义的默认的实现类就是我们上边写的JsonMessageTransformImpl类。

最后呢,我们定义一个工厂类,供我们的Filter调用。

package com.lifengdi.gateway.transform;  import com.lifengdi.gateway.enums.TransformContentTypeEnum; import com.lifengdi.gateway.properties.MessageTransformProperties; import com.lifengdi.gateway.properties.entity.MessageTransformUrl; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils;  import javax.annotation.Resource; import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference;  /**  * 报文结构转换工厂类  *  * @author: Li Fengdi  * @date: 2020-7-11 16:57:07  */ @Component public class MessageTransformFactory {      @Resource     private Map<String, AbstractMessageTransform> messageTransformMap;      @Resource     private MessageTransformProperties messageTransformProperties;      /**      * 根据contentType获取对应的内容转换实现类      *      * @param contentType 内容类型      * @return 内容转换实现类      */     private AbstractMessageTransform getMessageTransform(String contentType) {         return messageTransformMap.get(TransformContentTypeEnum.getWithDefault(contentType).getTransImpl());     }      /**      * 报文转换      *      * @param originalContent 原始内容      * @param transformUrl    url      * @return 转换后的消息      */     private String messageTransform(String originalContent, MessageTransformUrl transformUrl) {         String contentType = transformUrl.getContentType();         AbstractMessageTransform messageTransform = getMessageTransform(contentType);          return messageTransform.transform(originalContent, transformUrl);     }      /**      * 判断是否是需要转换报文结构的接口,如果是则转换,否则返回原值      *      * @param path            接口路径      * @param originalContent 原始内容      * @return 转换后的内容      */     public String compareAndTransform(String path, String originalContent) {         if (StringUtils.isBlank(originalContent)) {             return null;         }         List<MessageTransformUrl> urlList = messageTransformProperties.getUrlList();         if (CollectionUtils.isEmpty(urlList)) {             return originalContent;         }         return urlList .stream()                 .filter(transformUrl -> transformUrl.getPathList().contains(path))                 .findFirst()                 .map(url -> messageTransform(originalContent, url))                 .orElse(originalContent);     }      /**      * 判断是否是需要转换报文结构的接口,如果是则转换,否则返回原值      *      * @param path              接口路径      * @param originalContent   原始内容      * @param originalByteArray 二进制原始内容      * @param charset           charset      * @param newResponseBody   新报文内容      * @return 响应体数组数组      */     public byte[] compareAndTransform(String path, String originalContent, byte[] originalByteArray, Charset charset,                                       AtomicReference<String> newResponseBody) {         if (StringUtils.isBlank(originalContent)) {             return null;         }         List<MessageTransformUrl> urlList = messageTransformProperties.getUrlList();         if (CollectionUtils.isEmpty(urlList)) {             return originalByteArray;         }         return urlList.stream()                 .filter(transformUrl -> transformUrl.getPathList().contains(path))                 .findFirst()                 .map(url -> {                     String messageTransform = messageTransform(originalContent, url);                     if (originalContent.equals(messageTransform)) {                         return originalByteArray;                     }                     newResponseBody.set(messageTransform);                     return messageTransform.getBytes(charset);                 })                 .orElse(originalByteArray);     } } 

这个工厂对外提供的方法只有compareAndTransform()两个方法,主要功能就是判断是否是需要转换报文结构的接口,如果是则转换,否则返回原值。

接下来就是在我们的Filter调用即可。调用代码如下:

content = messageTransformFactory.compareAndTransform(path, responseBody, content, charset, newResponseBody); 

Git地址:https://github.com/lifengdi/spring-cloud-gateway-demo

最后

上面的只是简单的示例,很多情况都没有考虑进去,大家借鉴即可。

原文地址:https://www.lifengdi.com/archives/article/2006

李锋镝的园子资料部分资料来自网络,侵权毕设源码联系删除

区块链毕设网(www.qklbishe.com)全网最靠谱的原创区块链毕设代做网站
部分资料来自网络,侵权联系删除!
资源收费仅为搬运整理打赏费用,用户自愿支付 !
qklbishe.com区块链毕设代做网专注|以太坊fabric-计算机|java|毕业设计|代做平台 » 李锋镝的园子资料

提供最优质的资源集合

立即查看 了解详情