import com.google.common.collect.Lists;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @date 2021-05-06
*/
@Component
public class TestInitializer implements ApplicationContextAware, InitializingBean {
// 一个方法可以对应多个uri
public static Map<String,List<String>> methodUriMap = new HashMap();
// 一个uri也可以对应多个方法,不过这里不支持,只支持一个uri对应一个方法
public static Map<String,String> uriMethodMap = new HashMap();
@Override
public void afterPropertiesSet() throws Exception {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMapping.class, true, false);
List<HandlerMapping> handlerMappingList = matchingBeans.values().stream().filter(handlerMapping -> handlerMapping instanceof RequestMappingHandlerMapping).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(handlerMappingList)) {
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) handlerMappingList.get(0);
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> requestMappingInfoHandlerMethodEntry : handlerMethods.entrySet()) {
RequestMappingInfo requestMappingInfo = requestMappingInfoHandlerMethodEntry.getKey();
HandlerMethod mappingInfoValue = requestMappingInfoHandlerMethodEntry.getValue();
RequestMethodsRequestCondition methodCondition = requestMappingInfo.getMethodsCondition();
Set<String> requestTypes = new HashSet<>();
if(!CollectionUtils.isEmpty(methodCondition.getMethods())){
// get、post、PUT... 配置(没有配置的说明都支持)
requestTypes = methodCondition.getMethods().stream().map(RequestMethod::name).collect(Collectors.toSet());
}
PatternsRequestCondition patternsCondition = requestMappingInfo.getPatternsCondition();
if(CollectionUtils.isEmpty(patternsCondition.getPatterns())) {
continue;
}
// 完整的uri配置(有可能是这种 /api/project/audit/ip/{projectName}/{env} )
Set<String> requestUrls = patternsCondition.getPatterns();
// @RequestMapping 里面配置 params、headers、produces、consumes导致存在多个相同uri#method的,遇到直接忽略;这里只支持一个uri对应一个方法
List<String> uriList = Lists.newArrayList();
for(String requestUrl:requestUrls){
if(CollectionUtils.isEmpty(requestTypes)) {
// 说明 get、post、PUT... 都支持
for(RequestMethod requestMethod:RequestMethod.values()){
String uriIdentity = requestUrl+"#"+ requestMethod.name();
if(uriMethodMap.containsKey(uriIdentity)){
// 配置 params、headers、produces、consumes导致存在多个相同uri#method的,遇到直接忽略;这里只支持一个uri对应一个方法
String tempMethodIdentity = uriMethodMap.get(uriIdentity);
List<String> tempUriList = methodUriMap.get(tempMethodIdentity);
tempUriList.remove(uriIdentity);
if(CollectionUtils.isEmpty(tempUriList)){
methodUriMap.remove(tempMethodIdentity);
}
uriMethodMap.remove(uriIdentity);
}else{
uriList.add(uriIdentity);
}
}
}else{
requestTypes.forEach(requestType -> {
String uriIdentity = requestUrl+"#"+ requestType;
if(uriMethodMap.containsKey(uriIdentity)){
// 配置 params、headers、produces、consumes导致存在多个相同uri#method的,遇到直接忽略;这里只支持一个uri对应一个方法
String tempMethodIdentity = uriMethodMap.get(uriIdentity);
List<String> tempUriList = methodUriMap.get(tempMethodIdentity);
tempUriList.remove(uriIdentity);
if(CollectionUtils.isEmpty(tempUriList)){
methodUriMap.remove(tempMethodIdentity);
}
uriMethodMap.remove(uriIdentity);
}else{
uriList.add(uriIdentity);
}
});
}
}
if(CollectionUtils.isEmpty(uriList)){
continue;
}
String controllerName = mappingInfoValue.getBeanType().toString();
String requestMethodName = mappingInfoValue.getMethod().getName();
Class<?>[] methodParamTypes = mappingInfoValue.getMethod().getParameterTypes();
StringBuilder methodIdentity = new StringBuilder(controllerName).append(".").append(requestMethodName);
methodIdentity.append("(");
for(Class<?> methodParamType:methodParamTypes){
methodIdentity.append(methodParamType.getName());
}
methodIdentity.append(")");
// 存入map
methodUriMap.put(methodIdentity.toString(),uriList);
uriList.forEach(uri-> uriMethodMap.put(uri,methodIdentity.toString()));
}
}
}
}