Map参数解析
> 以下的案例只是提出一种方案,意在拓展大家的思维
```java
/**
* 接口文档配置
*/
@Configuration
public class EasyApiConfig extends DefaultConfigurationCreator {
@Override
public AllConfiguration replenish(AllConfiguration configuration) {
//拿到入参拦截器
ReadRequestConfig requestConfig = configuration.getReadRequestConfig();
//添加自定义参数拦截方法
requestConfig.addReadParams(this::params);
//刷新配置
return super.replenish(configuration);
}
public List<MethodParam> params(Method method, ApiExtra extra) {
List<MethodParam> result = new ArrayList<>();
Parameter[] parameters = method.getParameters();
//如果只有一个Map参数
if(parameters.length>0 && parameters[0].getType().equals(Map.class)){
DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
// 实际方法参数形参名称
String name = discover.getParameterNames(method)[0];
// 获取方法源码的每一行
List<String> lines = extra.getMethodComment().getLines();
for (String line : lines) {
//发现有从Map中取值的代码并赋值的时候,取值字符串即为参数,赋值对象即为参数类型
if(line.contains("=") && line.contains(name+".get(")){
String sub = line.substring(line.indexOf(name + ".get(") + name.length() + 5);
String paramName = sub.substring(0,sub.indexOf(")")).replace("\"","");
String pre = line.substring(0,line.indexOf("=")).trim();
//通过层层截取,拿到参数名称和参数赋值对象字符串
String type = pre.substring(0, pre.indexOf(" "));
//再读取类源码文件,去import中寻找赋值对象的全类名
for (String s : extra.getControllerComment().getLines()) {
if(s.contains("import") && s.endsWith(type+";")){
type = s.substring(s.indexOf("import")+6,s.length()-1).trim();
break;
}
}
//以上数据全部得到以后,可以组装参数了
MethodParam mp = new MethodParam();
//如果是java基础类型,import中找不到的,需要自行处理,下面只是举个String例子
if(type.equals("String")){
type = "java.lang."+type;
}
//通过反射拿到真实类型
try {
mp.setParamType(Class.forName(type));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
mp.setParamName(paramName);
result.add(mp);
}
}
return result;
}
return null;
}
}
```
> 代码思路
1. 添加[接口入参拦截器](doc:I10gUElT),实现拦截方法
2. 通过**反射**的参数来判断是否有**Map类型**参数,如果有则获取Map参数的形参名称
3. 逐行**读取方法源码**,只要发现这个形参名称有**get()操作**并包含**赋值符号**的代码,就认为Map中的key应当为接口参数,于是有了**入参名称**
4. 将上述赋值的代码再进行解析,拿到赋值前的代码,假设为 **A a = map.get("a")**,那么**A**就是这个形参的**实际类型**
5. 拿到A之后接下来就应该去包含这个方法的**文件源码**中查找**import**,也就是去**controller源文件**中查找,逐行遍历源码,发现有import开头并且以A;结尾的,认为是加载的该类**全类名**
6. 之后就通过**反射**来获取全类名的**class**,然后进行下一步处理
7. 需要注意的是,并不是所有的类型都会以import的方式被找到,java基础类型都是没有的,需要自行处理,还有如果是import *进来的也是找不到。