MappingHandlerMapping.java 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package org.ssssssss.magicapi.config;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.util.StringUtils;
  5. import org.springframework.web.bind.annotation.RequestMethod;
  6. import org.springframework.web.context.request.NativeWebRequest;
  7. import org.springframework.web.context.request.RequestAttributes;
  8. import org.springframework.web.context.request.ServletWebRequest;
  9. import org.springframework.web.servlet.HandlerMapping;
  10. import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
  11. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
  12. import org.ssssssss.magicapi.provider.ApiServiceProvider;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.lang.reflect.Method;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.concurrent.ConcurrentHashMap;
  21. /**
  22. * 请求映射
  23. */
  24. public class MappingHandlerMapping {
  25. /**
  26. * 已缓存的映射信息
  27. */
  28. private static Map<String, ApiInfo> mappings = new ConcurrentHashMap<>();
  29. private static Logger logger = LoggerFactory.getLogger(MappingHandlerMapping.class);
  30. /**
  31. * spring中的请求映射处理器
  32. */
  33. private RequestMappingHandlerMapping requestMappingHandlerMapping;
  34. /**
  35. * 请求处理器
  36. */
  37. private RequestHandler handler;
  38. /**
  39. * 请求到达时处理的方法
  40. */
  41. private Method method = RequestHandler.class.getDeclaredMethod("invoke", HttpServletRequest.class, HttpServletResponse.class, Map.class, Map.class);
  42. /**
  43. * 接口信息读取
  44. */
  45. private ApiServiceProvider magicApiService;
  46. /**
  47. * 统一接口前缀
  48. */
  49. private String prefix;
  50. /**
  51. * 缓存已映射的接口信息
  52. */
  53. private List<ApiInfo> apiInfos = Collections.synchronizedList(new ArrayList<>());
  54. public MappingHandlerMapping() throws NoSuchMethodException {
  55. }
  56. public void setPrefix(String prefix) {
  57. this.prefix = prefix;
  58. }
  59. /**
  60. * 根据request获取对应的接口信息
  61. */
  62. public static ApiInfo getMappingApiInfo(HttpServletRequest request) {
  63. NativeWebRequest webRequest = new ServletWebRequest(request);
  64. // 找到注册的路径
  65. String requestMapping = (String) webRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
  66. // 根据请求方法和路径获取接口信息
  67. return getMappingApiInfo(buildMappingKey(request.getMethod(), requestMapping));
  68. }
  69. /**
  70. * 根据绑定的key获取接口信息
  71. */
  72. public static ApiInfo getMappingApiInfo(String key) {
  73. return mappings.get(key);
  74. }
  75. /**
  76. * 构建缓存map的key
  77. *
  78. * @param requestMethod 请求方法
  79. * @param requestMapping 请求路径
  80. * @return
  81. */
  82. public static String buildMappingKey(String requestMethod, String requestMapping) {
  83. //TODO 判断 requestMapping 是否已 “/” 开头
  84. if (!StringUtils.isEmpty(requestMapping) && !requestMapping.startsWith("/")) {
  85. requestMapping = "/" + requestMapping;
  86. }
  87. return requestMethod.toUpperCase() + ":" + requestMapping;
  88. }
  89. public void setRequestMappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping) {
  90. this.requestMappingHandlerMapping = requestMappingHandlerMapping;
  91. }
  92. public void setHandler(RequestHandler handler) {
  93. this.handler = handler;
  94. }
  95. public void setMagicApiService(ApiServiceProvider magicApiService) {
  96. this.magicApiService = magicApiService;
  97. }
  98. public List<ApiInfo> getApiInfos() {
  99. return apiInfos;
  100. }
  101. /**
  102. * 注册请求
  103. */
  104. public void registerAllMapping() {
  105. List<ApiInfo> list = magicApiService.listWithScript();
  106. if (list != null) {
  107. apiInfos.addAll(list);
  108. for (ApiInfo info : list) {
  109. registerMapping(info, false);
  110. }
  111. }
  112. }
  113. /**
  114. * 根据请求方法和路径获取接口信息
  115. *
  116. * @param method 请求方法
  117. * @param requestMapping 请求路径
  118. */
  119. public ApiInfo getApiInfo(String method, String requestMapping) {
  120. return mappings.get(buildMappingKey(method, requestMapping));
  121. }
  122. public void updateGroupPrefix(String oldGroupName, String newGroupName, String prefix) {
  123. for (ApiInfo info : apiInfos) {
  124. if (oldGroupName.equals(info.getGroupName())) {
  125. unregisterMapping(info.getId(), false);
  126. info.setGroupName(newGroupName);
  127. info.setGroupPrefix(prefix);
  128. registerMapping(info, false);
  129. }
  130. }
  131. }
  132. /**
  133. * 注册请求映射
  134. *
  135. */
  136. public void registerMapping(ApiInfo info, boolean delete) {
  137. // 先判断是否已注册,如果已注册,则先取消注册在进行注册。
  138. if (mappings.containsKey(info.getId())) {
  139. ApiInfo oldInfo = mappings.get(info.getId());
  140. logger.info("取消注册接口:{}", oldInfo.getName());
  141. // 取消注册
  142. mappings.remove(getMappingKey(info));
  143. requestMappingHandlerMapping.unregisterMapping(getRequestMapping(oldInfo));
  144. }
  145. logger.info("注册接口:{}", info.getName());
  146. // 注册
  147. RequestMappingInfo requestMapping = getRequestMapping(info);
  148. mappings.put(info.getId(), info);
  149. mappings.put(getMappingKey(info), info);
  150. requestMappingHandlerMapping.registerMapping(requestMapping, handler, method);
  151. if (delete) { // 刷新缓存
  152. apiInfos.removeIf(i -> i.getId().equalsIgnoreCase(info.getId()));
  153. apiInfos.add(info);
  154. }
  155. }
  156. /**
  157. * 取消注册请求映射
  158. */
  159. public void unregisterMapping(String id, boolean delete) {
  160. ApiInfo info = mappings.remove(id);
  161. if (info != null) {
  162. logger.info("取消注册接口:{}", info.getName());
  163. mappings.remove(getMappingKey(info));
  164. requestMappingHandlerMapping.unregisterMapping(getRequestMapping(info));
  165. if (delete) { //刷新缓存
  166. apiInfos.removeIf(i -> i.getId().equalsIgnoreCase(info.getId()));
  167. }
  168. }
  169. }
  170. /**
  171. * 根据接口信息获取绑定map的key
  172. */
  173. private String getMappingKey(ApiInfo info) {
  174. return buildMappingKey(info.getMethod(), getRequestPath(info.getGroupPrefix(), info.getPath()));
  175. }
  176. /**
  177. * 处理前缀
  178. *
  179. * @param groupPrefix 分组前缀
  180. * @param path 请求路径
  181. */
  182. public String getRequestPath(String groupPrefix, String path) {
  183. groupPrefix = groupPrefix == null ? "" : groupPrefix;
  184. while (groupPrefix.endsWith("/")) {
  185. groupPrefix = groupPrefix.substring(0, groupPrefix.length() - 1);
  186. }
  187. while (path.startsWith("/")) {
  188. path = path.substring(1);
  189. }
  190. path = groupPrefix + "/" + path;
  191. if (prefix != null) {
  192. path = prefix + (path.startsWith("/") ? path.substring(1) : path);
  193. }
  194. return path;
  195. }
  196. /**
  197. * 根据接口信息构建 RequestMappingInfo
  198. */
  199. private RequestMappingInfo getRequestMapping(ApiInfo info) {
  200. return RequestMappingInfo.paths(getRequestPath(info.getGroupPrefix(), info.getPath())).methods(RequestMethod.valueOf(info.getMethod().toUpperCase())).build();
  201. }
  202. }