当前位置:网站首页>Feign通过自定义注解实现路径的转义
Feign通过自定义注解实现路径的转义
2022-06-28 04:21:00 【qq_43479892】
优质资源分享
| 学习路线指引(点击解锁) | 知识定位 | 人群定位 |
|---|---|---|
| 🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
| Python量化交易实战 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |

本文主要讲解如果通过注解实现对路由中的路径进行自定义编码
背景
近期由于项目中需要,所以需要通过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全局,所以在使用的过程中需要考虑是否符合场景
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
边栏推荐
- native关键字的作用
- The development of the Internet has promoted the emergence of a series of new models such as unbounded retail, digital retail and instant retail
- 恭喜我自己,公众号粉丝破万
- Necessary skills for test and development: actual combat of security test vulnerability shooting range
- 知识点滴 - 关于汉语学习的网络资源
- Web3来临时的风口浪尖
- How to traverse collections Ordereddict, taking it and forgetting items
- A queue of two stacks
- Why is the frame rate calculated by opencv wrong?
- Oracledata installation problems
猜你喜欢

Detailed reading of the thesis: implementing volume models for handowriting text recognition

A doctor's 22 years in Huawei (full of dry goods)

Matlab exercises -- basic data processing

The coming wave of Web3

Pager when importing text files from MySQL

玩转双指针

How do I get the STW (pause) time of a GC (garbage collector)?

Severe tire damage: the first rock band in the world to broadcast live on the Internet

Annual comprehensive analysis of China's audio market in 2022

10: 00 interview, came out at 10:02, the question is really too
随机推荐
[CSP-J2020] 优秀的拆分
Principle and implementation of SSD for target detection
Severe tire damage: the first rock band in the world to broadcast live on the Internet
在线直播源码,JS动态效果之,侧边栏滚动固定效果
【Matlab BP回归预测】GA优化BP回归预测(含优化前的对比)【含源码 1901期】
A bit of knowledge - online resources on Chinese Learning
The growth summer challenge is coming | learn and create two major tracks, and start the tutor registration!
27 years, Microsoft IE is over!
浅析搭建视频监控汇聚平台的必要性及场景应用
S32ds jump to defaultisr
Games104 operation 2-colorgrading
Matlab exercises -- basic data processing
Resolve cross domain
Project practice! Teach you JMeter performance test hand in hand
OracleData安装问题
CUPTI error: CUPTI could not be loaded or symbol could not be found.
Taco: a data enhancement technique for character recognition
Go language learning tutorial (14)
?位置怎么写才能输出true
Establishment of SSH Framework (Part 2)