package org.ssssssss.magicapi.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.ssssssss.magicapi.provider.ApiServiceProvider; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 请求映射 */ public class MappingHandlerMapping { /** * 已缓存的映射信息 */ private static Map mappings = new ConcurrentHashMap<>(); private static Logger logger = LoggerFactory.getLogger(MappingHandlerMapping.class); /** * spring中的请求映射处理器 */ private RequestMappingHandlerMapping requestMappingHandlerMapping; /** * 请求处理器 */ private RequestHandler handler; /** * 请求到达时处理的方法 */ private Method method = RequestHandler.class.getDeclaredMethod("invoke", HttpServletRequest.class, HttpServletResponse.class, Map.class, Map.class); /** * 接口信息读取 */ private ApiServiceProvider magicApiService; /** * 统一接口前缀 */ private String prefix; /** * 缓存已映射的接口信息 */ private List apiInfos = Collections.synchronizedList(new ArrayList<>()); public MappingHandlerMapping() throws NoSuchMethodException { } public void setPrefix(String prefix) { this.prefix = prefix; } /** * 根据request获取对应的接口信息 */ public static ApiInfo getMappingApiInfo(HttpServletRequest request) { NativeWebRequest webRequest = new ServletWebRequest(request); // 找到注册的路径 String requestMapping = (String) webRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); // 根据请求方法和路径获取接口信息 return getMappingApiInfo(buildMappingKey(request.getMethod(), requestMapping)); } /** * 根据绑定的key获取接口信息 */ public static ApiInfo getMappingApiInfo(String key) { return mappings.get(key); } /** * 构建缓存map的key * * @param requestMethod 请求方法 * @param requestMapping 请求路径 * @return */ public static String buildMappingKey(String requestMethod, String requestMapping) { //TODO 判断 requestMapping 是否已 “/” 开头 if (!StringUtils.isEmpty(requestMapping) && !requestMapping.startsWith("/")) { requestMapping = "/" + requestMapping; } return requestMethod.toUpperCase() + ":" + requestMapping; } public void setRequestMappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping) { this.requestMappingHandlerMapping = requestMappingHandlerMapping; } public void setHandler(RequestHandler handler) { this.handler = handler; } public void setMagicApiService(ApiServiceProvider magicApiService) { this.magicApiService = magicApiService; } public List getApiInfos() { return apiInfos; } /** * 注册请求 */ public void registerAllMapping() { List list = magicApiService.listWithScript(); if (list != null) { apiInfos.addAll(list); for (ApiInfo info : list) { registerMapping(info, false); } } } /** * 根据请求方法和路径获取接口信息 * * @param method 请求方法 * @param requestMapping 请求路径 */ public ApiInfo getApiInfo(String method, String requestMapping) { return mappings.get(buildMappingKey(method, requestMapping)); } public void updateGroupPrefix(String oldGroupName, String newGroupName, String prefix) { for (ApiInfo info : apiInfos) { if (oldGroupName.equals(info.getGroupName())) { unregisterMapping(info.getId(), false); info.setGroupName(newGroupName); info.setGroupPrefix(prefix); registerMapping(info, false); } } } /** * 注册请求映射 * */ public void registerMapping(ApiInfo info, boolean delete) { // 先判断是否已注册,如果已注册,则先取消注册在进行注册。 if (mappings.containsKey(info.getId())) { ApiInfo oldInfo = mappings.get(info.getId()); logger.info("取消注册接口:{}", oldInfo.getName()); // 取消注册 mappings.remove(getMappingKey(info)); requestMappingHandlerMapping.unregisterMapping(getRequestMapping(oldInfo)); } logger.info("注册接口:{}", info.getName()); // 注册 RequestMappingInfo requestMapping = getRequestMapping(info); mappings.put(info.getId(), info); mappings.put(getMappingKey(info), info); requestMappingHandlerMapping.registerMapping(requestMapping, handler, method); if (delete) { // 刷新缓存 apiInfos.removeIf(i -> i.getId().equalsIgnoreCase(info.getId())); apiInfos.add(info); } } /** * 取消注册请求映射 */ public void unregisterMapping(String id, boolean delete) { ApiInfo info = mappings.remove(id); if (info != null) { logger.info("取消注册接口:{}", info.getName()); mappings.remove(getMappingKey(info)); requestMappingHandlerMapping.unregisterMapping(getRequestMapping(info)); if (delete) { //刷新缓存 apiInfos.removeIf(i -> i.getId().equalsIgnoreCase(info.getId())); } } } /** * 根据接口信息获取绑定map的key */ private String getMappingKey(ApiInfo info) { return buildMappingKey(info.getMethod(), getRequestPath(info.getGroupPrefix(), info.getPath())); } /** * 处理前缀 * * @param groupPrefix 分组前缀 * @param path 请求路径 */ public String getRequestPath(String groupPrefix, String path) { groupPrefix = groupPrefix == null ? "" : groupPrefix; while (groupPrefix.endsWith("/")) { groupPrefix = groupPrefix.substring(0, groupPrefix.length() - 1); } while (path.startsWith("/")) { path = path.substring(1); } path = groupPrefix + "/" + path; if (prefix != null) { path = prefix + (path.startsWith("/") ? path.substring(1) : path); } return path; } /** * 根据接口信息构建 RequestMappingInfo */ private RequestMappingInfo getRequestMapping(ApiInfo info) { return RequestMappingInfo.paths(getRequestPath(info.getGroupPrefix(), info.getPath())).methods(RequestMethod.valueOf(info.getMethod().toUpperCase())).build(); } }