实现思路
1. 根据bean工厂查找beanName对应的Bean
2. 查找对应的字节码文件
3. 根据方法名(methodName)和参数(params)查找方法
3.1 遍历bean的所有方法
3.2 根据方法名和参数数量过滤
3.3 当所有参数类型一致时找到唯一方法
3.4 当类型不同时,判断类型是否都为数字(Number)类型
3.5 如果都是数字类型也当做参数类型一致(postman无法区分Integer类型和Long类型)
3.6 如果都是数字类型,调用数字类型的valueOf方法强转参数
4. 调用方法
具体实现请看代码
前言
使用postman测试接口方法时,经常需要更换url。针对当前问题尝试实现通用方法调用。
一、数据准备
Spring容器:获取Spring容器中注册的Bean
参数对象:封装请求的参数
返回结果:封装返回为自定义的Json结果
二、使用步骤
1.参数对象
代码如下(示例):
@Data
class MethodParam {
private String beanName;
private String methodName;
private Object[] params;
}
2.返回结果
package org.yanse.vo;
import lombok.Data;
import org.yanse.model.ErrorCode;
/**
* 返回前端的结果
*/
@Data
public class JsonResult {
private boolean success = true;
private String msg;
private Object data;
private int code;
private JsonResult() {
}
private JsonResult(boolean success, String msg) {
this.success = success;
this.msg = msg;
}
private JsonResult(boolean success, String msg, Object data) {
this.success = success;
this.msg = msg;
this.data = data;
}
private JsonResult(boolean success, String msg, int code) {
this.success = success;
this.msg = msg;
this.code = code;
}
private JsonResult(boolean success, String msg, int code, Object data) {
this.success = success;
this.msg = msg;
this.code = code;
this.data = data;
}
/**
* 成功无返回结果
*
* @return JsonResult
*/
public static JsonResult success() {
return new JsonResult(true, null);
}
/**
* 成功有返回信息
*
* @param msg 接口状态信息
* @return JsonResult
*/
public static JsonResult success(String msg) {
return new JsonResult(true, msg);
}
/**
* 成功有返回数据和信息
*
* @param msg 接口状态信息
* @param data 返回给前端的数据
* @return JsonResult
*/
public static JsonResult success(String msg, Object data) {
return new JsonResult(true, msg, data);
}
/**
* 成功只返回数据
*
* @param data 返回给前端的数据
* @return JsonResult
*/
public static JsonResult success(Object data) {
return new JsonResult(true, null, data);
}
/**
* 失败只返回数据
*
* @param data 返回给前端的数据
* @return JsonResult
*/
public static JsonResult error(Object data) {
return new JsonResult(false, null, data);
}
/**
* 失败有返回信息
*
* @param msg 接口状态信息
* @return JsonResult
*/
public static JsonResult error(String msg) {
return new JsonResult(false, msg);
}
/**
* 失败有返回信息和数据
*
* @param msg 接口状态信息
* @param data 返回给前端的数据
* @return JsonResult
*/
public static JsonResult error(String msg, Object data) {
return new JsonResult(false, msg, data);
}
public static JsonResult info(ErrorCode errorCode) {
int code = errorCode.getCode();
boolean success = code == 200;
return new JsonResult(success, errorCode.getMsg(), code);
}
public static JsonResult info(ErrorCode errorCode, Object data) {
int code = errorCode.getCode();
boolean success = code == 200;
return new JsonResult(success, errorCode.getMsg(), code, data);
}
}
3.错误码
package org.yanse.model;
/**
* 使用枚举类型来封装异常码和异常信息
*/
public enum ErrorCode {
//RPC层调用错误码
DB_SERVICE_OK(20100, "服务正常"),
DB_SERVICE_DB_DAO_ERROR(20104, "返回数据库的具体异常信息"),
DB_SERVICE_UNKNOWN_ERROR(20101, "未知异常"),
DB_SERVICE_AGENT_ERROR(20102, "DBServiceAgent异常"),
DB_SERVICE_NETWORK_ERROR(20103, "网络异常"),
DB_SERVICE_INVALID_FUNCTION(20105, "方法名不存在"),
DB_SERVICE_INVALID_PARAMETER(20106, "方法参数错误"),
DB_SERVICE_FUNCTION_NO_ACCESS(20107, "对此方法无访问权限");
private String msg;
private int code;
private ErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public String getMsg() {
return this.msg;
}
public int getCode() {
return this.code;
}
}
2.实现方法
代码如下(示例):
@RestController
public class MethodTest {
@Autowired
private ApplicationContext context;
@PostMapping("/method/test")
public JsonResult methodTest(@RequestBody MethodParam methodParam) throws InvocationTargetException, IllegalAccessException {
// 获取bean工厂
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
// 获取bean实例
Object bean = beanFactory.getBean(methodParam.getBeanName());
// 获取bean字节码文件
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(methodParam.getBeanName());
String beanClassName = beanDefinition.getBeanClassName();
Class<?> beanClass;
try {
beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return JsonResult.error("ClassNotFoundException", e.getMessage());
}
Method method = null;
Method[] methods = beanClass.getDeclaredMethods();
for (Method beanMethod : methods) {
int parameterCount = beanMethod.getParameterCount();
String name = beanMethod.getName();
// 先根据方法名和参数数量过滤
if (parameterCount == methodParam.getParams().length && name.equals(methodParam.getMethodName())) {
// 在根据参数顺序过滤
Class<?>[] parameterTypes = beanMethod.getParameterTypes();
boolean match = true;
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> parameterType = parameterTypes[i];
Object param = methodParam.getParams()[i];
Class<?> paramClass = param.getClass();
// 同时是基本数据类型或相同类型
boolean equalsType = paramClass.equals(parameterType);
boolean isNumber = Number.class.isAssignableFrom(paramClass) && Number.class.isAssignableFrom(parameterType);
if (!equalsType) {
if (isNumber) {
Method valueOf = null;
try {
valueOf = parameterType.getDeclaredMethod("valueOf", String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return JsonResult.error("NoSuchMethodException", e.getMessage());
}
methodParam.getParams()[i] = valueOf.invoke(null, param.toString());
continue;
}
match = false;
break;
}
}
if (match) {
method = beanMethod;
break;
}
}
}
if (method == null) {
return JsonResult.error("The method name does not exist or the number of parameters is incorrect");
}
Object result;
try {
result = method.invoke(bean, methodParam.getParams());
} catch (IllegalAccessException e) {
e.printStackTrace();
return JsonResult.error("IllegalAccessException", e.getMessage());
} catch (InvocationTargetException e) {
e.printStackTrace();
return JsonResult.error("InvocationTargetException", e.getMessage());
}
return result instanceof JsonResult ? (JsonResult) result : JsonResult.success(result);
}
}
测试
postman调用测试
emp表根据eno查询数据
请求和参数
返回结果
目录
实现思路
具体实现请看代码
一、数据准备
二、使用步骤
1.参数对象
2.返回结果
3.错误码
2.实现方法
测试