通过web上下文获取到所有 RequestMapping 的方法集合,根据 HandlerMethod 提供的方法调用对应 Method 的反射方法。
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
@RequiredArgsConstructor
public class UrlToController implements CommandLineRunner {
/**
* 上下文
*/
@Autowired
WebApplicationContext applicationContext;
private final HashMap<String, HandlerMethod> requestMapping = new HashMap<>();
@Override
public void run(String... args) throws Exception {
loadControllerMethods();
}
/**
* 加载控制器方法
*/
public void loadControllerMethods() {
// 获取RequestMappingHandlerMapping实例
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
// 获取映射的方法集合
Map<RequestMappingInfo, HandlerMethod> methodMap = mapping.getHandlerMethods();
// 遍历方法集合,提取路径模式和方法的映射关系
methodMap.forEach((key, value) -> {
// 初始化路径模式集合
Set<PathPattern> patterns = null;
// 检查路径模式条件是否存在
if (key != null && key.getPathPatternsCondition() != null) {
patterns = key.getPathPatternsCondition().getPatterns();
}
// 检查路径模式集合是否非空
if (patterns != null && !patterns.isEmpty()) {
// 获取第一个路径模式
PathPattern pathPattern = patterns.iterator().next();
// 提取并保存路径模式字符串及其对应的处理方法
if (pathPattern != null) {
String urlPath = pathPattern.getPatternString();
requestMapping.put(urlPath, value);
}
}
});
// Object invoke = invokeControllerMethod("/CustomMenu/selectListByType/{type}");
// System.out.println(invoke);
// System.out.println(requestMapping);
}
/**
* 根据URL路径调用控制器方法
*
* 该方法首先检查是否已为给定的URL路径注册了处理方法如果已注册,
* 它会从应用程序上下文中获取控制器实例,然后调用该控制器的相应方法
* 如果未注册或调用过程中发生异常,将返回错误信息或null
*
* @param urlPath URL路径,用于查找相应的处理方法
* @param args 传递给控制器方法的参数,可变参数列表
* @return 控制器方法的返回值,或在异常情况下的错误信息,如果未找到处理方法则返回null
*/
public Object invokeControllerMethod(String urlPath, Object... args) {
if (requestMapping.containsKey(urlPath)) { // 检查是否有对应的处理方法
try {
HandlerMethod handlerMethod = requestMapping.get(urlPath); // 获取处理方法
Object controller = applicationContext.getBean(handlerMethod.getBeanType()); // 获取控制器实例
return handlerMethod.getMethod().invoke(controller, args); // 调用控制器方法,并返回结果
} catch (Exception e) {
e.printStackTrace(); // 打印异常堆栈跟踪
return e.getMessage(); // 返回异常信息
}
} else {
return null; // 如果没有对应的处理方法,返回null
}
}
}