需求
近來項目中有個新需求,審計記錄中除了用戶的訪問地址還需要包含事件具體描述,項目是集成了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