全局API管理

matevip 2021-6-6 大约 2 分钟

# 一、全局API监听器

该监听器在 mate-starter-web 中实现,用于监听controller的api,完整的实现代码如下:

@Slf4j
public class RequestMappingScanListener implements ApplicationListener<ApplicationReadyEvent> {
	private static final AntPathMatcher pathMatch = new AntPathMatcher();
	private final Set<String> ignoreApi = new HashSet<String>();
	private final RedisService redisService;

	/**
	 * 构造方法
	 *
	 * @param redisService 注入redis
	 */
	public RequestMappingScanListener(RedisService redisService) {
		this.redisService = redisService;
		this.ignoreApi.add("/error");
		this.ignoreApi.add("/swagger-resources/**");
		this.ignoreApi.add("/v2/api-docs-ext/**");
		this.ignoreApi.add("/provider/**");
	}

	/**
	 * 默认事件
	 *
	 * @param event ApplicationReadyEvent
	 */
	@Override
	public void onApplicationEvent(@NotNull ApplicationReadyEvent event) {

		try {
			ConfigurableApplicationContext applicationContext = event.getApplicationContext();
			Environment env = applicationContext.getEnvironment();
			// 获取微服务模块名称
			String microService = env.getProperty("spring.application.name", "application");
			if (redisService == null || applicationContext.containsBean("resourceServerConfiguration")) {
				log.warn("[{}]忽略接口资源扫描", microService);
				return;
			}

			// 所有接口映射
			RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
			// 获取url与类和方法的对应信息
			Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
			List<Map<String, String>> list = new ArrayList<Map<String, String>>();
			for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
				RequestMappingInfo info = m.getKey();
				HandlerMethod method = m.getValue();
				if (method.getMethodAnnotation(ApiIgnore.class) != null) {
					// 忽略的接口不扫描
					continue;
				}
				// 请求路径
				PatternsRequestCondition p = info.getPatternsCondition();
				String urls = getUrls(p.getPatterns());
				if (isIgnore(urls)) {
					continue;
				}
				Set<MediaType> mediaTypeSet = info.getProducesCondition().getProducibleMediaTypes();
				for (MethodParameter params : method.getMethodParameters()) {
					if (params.hasParameterAnnotation(RequestBody.class)) {
						mediaTypeSet.add(MediaType.APPLICATION_JSON_UTF8);
						break;
					}
				}
				String mediaTypes = getMediaTypes(mediaTypeSet);
				// 请求类型
				RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition();
				String methods = getMethods(methodsCondition.getMethods());
				Map<String, String> api = Maps.newHashMap();
				// 类名
				String className = method.getMethod().getDeclaringClass().getName();
				// 方法名
				String methodName = method.getMethod().getName();
				String returnName = method.getReturnType().getParameterType().getName();
				if ($.isNotBlank(returnName)) {
					returnName = returnName.substring(returnName.lastIndexOf(StringPool.DOT) + 1, returnName.length());
				}
				// md5码
				String md5 = DigestUtils.md5DigestAsHex((microService + urls).getBytes());
				String name = "";
				String notes = "";
				String auth = "1";

				ApiOperation apiOperation = method.getMethodAnnotation(ApiOperation.class);
				if (apiOperation != null) {
					name = apiOperation.value();
					notes = apiOperation.notes();
				}
				// 判断是否需要权限校验
				PreAuth preAuth = method.getMethodAnnotation(PreAuth.class);
				if (preAuth != null) {
					auth = "0";
				}
				name = StringUtil.isBlank(name) ? methodName : name;
				api.put("name", name);
				api.put("notes", notes);
				api.put("path", urls);
				api.put("code", md5);
				api.put("className", className);
				api.put("methodName", methodName);
				api.put("method", methods);
				api.put("serviceId", microService);
				api.put("contentType", returnName);
				api.put("auth", auth);
				list.add(api);
			}
			// 放入redis缓存
			Map<String, Object> res = Maps.newHashMap();
			res.put("serviceId", microService);
			res.put("size", list.size());
			res.put("list", list);
			redisService.hset(MateConstant.MATE_API_RESOURCE, microService, res, 18000L);
			redisService.sSetAndTime(MateConstant.MATE_SERVICE_RESOURCE, 18000L, microService);
			log.info("资源扫描结果:serviceId=[{}] size=[{}] redis缓存key=[{}]", microService, list.size(), MateConstant.MATE_API_RESOURCE);
		} catch (Exception e) {
			log.error("error: {}", e.getMessage());
		}


	}

	private String getUrls(Set<String> urls) {
		StringBuilder stringBuilder = new StringBuilder();
		for (String url : urls) {
			stringBuilder.append(url).append(",");
		}
		if (urls.size() > 0) {
			stringBuilder.deleteCharAt(stringBuilder.length() - 1);
		}
		return stringBuilder.toString();
	}

	/**
	 * 是否是忽略的Api
	 *
	 * @param requestPath 请求地址
	 * @return boolean
	 */
	private boolean isIgnore(String requestPath) {
		for (String path : ignoreApi) {
			if (pathMatch.match(path, requestPath)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取媒体类型
	 *
	 * @param mediaTypes 类型SET集
	 * @return String
	 */
	private String getMediaTypes(Set<MediaType> mediaTypes) {
		StringBuilder stringBuilder = new StringBuilder();
		for (MediaType mediaType : mediaTypes) {
			stringBuilder.append(mediaType.toString()).append(",");
		}
		if (mediaTypes.size() > 0) {
			stringBuilder.deleteCharAt(stringBuilder.length() - 1);
		}
		return stringBuilder.toString();
	}

	/**
	 * 获取方法
	 *
	 * @param requestMethods 请求方法
	 * @return String
	 */
	private String getMethods(Set<RequestMethod> requestMethods) {
		StringBuilder stringBuilder = new StringBuilder();
		for (RequestMethod requestMethod : requestMethods) {
			stringBuilder.append(requestMethod.toString()).append(",");
		}
		if (requestMethods.size() > 0) {
			stringBuilder.deleteCharAt(stringBuilder.length() - 1);
		}
		return stringBuilder.toString();
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

# 二、启用监听器

/**
    * 资源扫描监听器类
    *
    * @return RequestMappingScanListener
    */
@Bean
@ConditionalOnMissingBean(RequestMappingScanListener.class)
public RequestMappingScanListener resourceAnnotationScan() {
    RequestMappingScanListener scan = new RequestMappingScanListener(redisService);
    log.info("资源扫描类.[{}]", scan);
    return scan;
}
1
2
3
4
5
6
7
8
9
10
11
12

目前此类在 mate-starter-web 模块下的 WebConfiguration 这个配置类中注册。

上次编辑于: 2021年6月8日 16:31
贡献者: matevip