您好,登錄后才能下訂單哦!
本篇內容主要講解“Feign怎么利用自定義注解實現路徑轉義”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Feign怎么利用自定義注解實現路徑轉義”吧!
近期由于項目中需要,所以需要通過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,就大功告成了
到此,相信大家對“Feign怎么利用自定義注解實現路徑轉義”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。