需求
近来项目中有个新需求,审计记录中除了用户的访问地址还需要包含事件具体描述,项目是集成了swagger
的,开发时接口上都用@ApiOperation
写了接口说明,出于偷懒的心理尝试了一波根据url
反向查找类名,接口名,注解值,尝试之后甚是觉得不偷懒的搬砖工一定不是好的泥水匠。。。
实现思路
- 项目加载时获取所有的Controller类 - 路径 - 接口名 - 接口说明 - 接口发布说明到系统全局变量
- 日志记录时根据url获取接口发布说明
实现代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.method.HandlerMethod;
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 com.tbtech.common.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
@Service
public class InitUrlService implements InitializingBean, ServletContextAware{
public static List<HashMap<String, String>> urlList = new ArrayList<HashMap<String, String>>();
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
/**
* 获取url与类和方法的对应信息
*/
@Override
public void setServletContext(ServletContext servletContext) {
Map<RequestMappingInfo, HandlerMethod> handlerMethodsMap = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> item : handlerMethodsMap.entrySet()) {
HashMap<String, String> model = new HashMap<String, String>();
RequestMappingInfo info = item.getKey();
HandlerMethod method = item.getValue();
PatternsRequestCondition p = info.getPatternsCondition();
for (String url : p.getPatterns()) {
model.put("url", url); //路径
}
model.put("className", method.getMethod().getDeclaringClass().getName()); // 类名
ApiOperation apiOperation = method.getMethodAnnotation(ApiOperation.class);
if(apiOperation != null) {
model.put("apiOperationValue", apiOperation.value()); //接口说明
model.put("apiOperationnotes", apiOperation.notes()); //接口发布说明
}
RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition();
String type = methodsCondition.toString();
if (type != null && type.startsWith("[") && type.endsWith("]")) {
type = type.substring(1, type.length() - 1);
model.put("type", type); // 方法请求类型
}
urlList.add(model);
}
System.out.println("----反向加载URL完成----");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
}
/**
* 通过访问IP获取访问方法信息
* @param lookupPath
* @return
*/
public HashMap<String, String> findUrlByUrlList(String lookupPath){
for(HashMap<String, String> item : urlList) {
String url = item.getOrDefault("url", "");
if(!StringUtils.isBlank(url) && url.equals(lookupPath)) {
return item;
}
}
return null;
}
}
- 在插入操作记录的地方取出对应的url信息即可
HashMap<String, String> urlItem = initUrlService.findUrlByUrlList(url);
String apiOperationnotes = urlItem.getOrDefault("apiOperationnotes", "")
.end