<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
近期由於專案中需要,所以需要通過Feign封裝一個對Harbor操作的sdk資訊。
在呼叫的過程中發現,當請求引數中帶有"/"時,Feign預設會將"/"當成路徑去解析,而不是當成完整的一個引數解析,範例如下
請求路徑為:api/v2.0/projects/{projectName}/repositories
註解引數為:@PathVariable("projectName")
正常請求為:api/v2.0/projects/test/repositories
異常路徑為:api/v2.0/projects/test/pro/repositories
相信細心的同學已經發現上面的差異了,正常的{projectName}中對應的值為test,而異常的卻對應為test/pro,所以當異常的請求打到harbor的機器時,被解析為api/v2.0/projects/test/pro/repositories,所以會直接返回404
以上就是背景了,所以接下來我們討論一下解決方案
首先我們知道springboot中預設是帶有幾種註釋引數處理器的
@MatrixVariableParameterProcessor @PathVariableParameterProcessor @QueryMapParameterProcessor @RequestHeaderParameterProcessor @RequestParamParameterProcessor @RequestPartParameterProcessor
因為我們的請求引數是在路徑中的,所以預設我們會使用@PathVariableParameterProcessor來標識路徑引數,而我們需要跳脫的引數其實也是在路徑中,所以我們先來看一下@PathVariableParameterProcessor是如何實現的
public boolean processArgument(AnnotatedParameterProcessor.AnnotatedParameterContext context, Annotation annotation, Method method) { String name = ((PathVariable)ANNOTATION.cast(annotation)).value(); Util.checkState(Util.emptyToNull(name) != null, "PathVariable annotation was empty on param %s.", new Object[]{context.getParameterIndex()}); context.setParameterName(name); MethodMetadata data = context.getMethodMetadata(); String varName = '{' + name + '}'; if (!data.template().url().contains(varName) && !this.searchMapValues(data.template().queries(), varName) && !this.searchMapValues(data.template().headers(), varName)) { data.formParams().add(name); } return true; }
其實在原始碼中,springboot並沒有做什麼神器的事情,就是獲取使用了PathVariable註解的引數,然後再將其新增到fromParams中就可以。
看到這裡我們是不是可以想到,既然在這裡我們可以拿到對應的引數了,那想做什麼事情不都是由我們自己來決定了,接下來說幹就幹,
首先我們宣告一個屬於自己的註解,
import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; /** * @CreateAt: 2022/6/11 0:46 * @ModifyAt: 2022/6/11 0:46 * @Version 1.0 */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SlashPathVariable { /** * Alias for {@link #name}. */ @AliasFor("name") String value() default ""; /** * The name of the path variable to bind to. * @since 4.3.3 */ @AliasFor("value") String name() default ""; /** * Whether the path variable is required. * <p>Defaults to {@code true}, leading to an exception being thrown if the path * variable is missing in the incoming request. Switch this to {@code false} if * you prefer a {@code null} or Java 8 {@code java.util.Optional} in this case. * e.g. on a {@code ModelAttribute} method which serves for different requests. * @since 4.3.3 */ boolean required() default true; }
宣告完註解後,我們就需要來自定義自己的引數解析器了,首先繼承AnnotatedParameterProcessor
import feign.MethodMetadata; import feign.Util; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; import org.springframework.web.bind.annotation.PathVariable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Method; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @CreateAt: 2022/6/11 0:36 * @ModifyAt: 2022/6/11 0:36 * @Version 1.0 */ public class SlashPathVariableParameterProcessor implements AnnotatedParameterProcessor { private static final Class<SlashPathVariable> ANNOTATION=SlashPathVariable.class; @Override public Class<? extends Annotation> getAnnotationType() { return (Class<? extends Annotation>) ANNOTATION; } @Override public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) { MethodMetadata data = context.getMethodMetadata(); String name = ANNOTATION.cast(annotation).value(); Util.checkState(Util.emptyToNull(name) != null, "SlashPathVariable annotation was empty on param %s.", new Object[]{context.getParameterIndex()}); context.setParameterName(name); data.indexToExpander().put(context.getParameterIndex(),this::expandMap); return true; } private String expandMap(Object object) { String encode = URLEncoder.encode(URLEncoder.encode(object.toString(), Charset.defaultCharset()), Charset.defaultCharset()); return encode; } }
可以看到上面的程式碼,我們獲取到自定義註解的引數後,將當前引數新增打Param後,並且為當前引數指定自定義的編碼格式。
最後,我們再通過Bean的形式將對應的註解新增到容器中
import feign.Contract; import org.springframework.cloud.openfeign.AnnotatedParameterProcessor; import org.springframework.cloud.openfeign.support.SpringMvcContract; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * @CreateAt: 2022/6/11 0:48 * @ModifyAt: 2022/6/11 0:48 * @Version 1.0 */ @Component public class SlashBean { @Bean public Contract feignContract(){ List<AnnotatedParameterProcessor> processors=new ArrayList<>(); processors.add(new SlashPathVariableParameterProcessor()); return new SpringMvcContract(processors); } }
最後我們將上面的引數註解PathVariable換成我們自定義的@SlashPathVariable,就大功告成了
通過以上的形式進行注入的話,會注入到Spring全域性,所以在使用的過程中需要考慮是否符合場景
以上就是Feign利用自定義註解實現路徑的跳脫詳解的詳細內容,更多關於Feign路徑的跳脫的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45