前言
在项目开发过程中,我们经过会遇到各种各样的问题,我们会尽可能地做很多记录,以便事后对错误进行复查。一些通常的手段就是使用Log文件保存每天的后台请求日志。为了方便排查和做到可视化操作,楼主今日通过学习Spring AOP后,引用AOP实现记录每次API访问日志。该日志主要记录每次访问API成功的请求,配合 错误日志拦截器SystemExceptionHandler,就可以对每一次请求做日志管理了。以下是实现方式:
记录实体
/**
* 保存请求记录
* @author Kellan_Song
* @createTime 2019年4月4日
*/
@Entity
@Table(name="request_record")
public class RequestRecord implements Serializable {
private static final long serialVersionUID = 1L;
private Long id; //主键
private String request; //请求参数
private String response; //响应结果
private Date createTime; //访问时间
private String ip; //访问者ip
private String apiAdr; //请求地址
public RequestRecord() {
super();
}
public RequestRecord(String request, String response, Date createTime, String ip, String apiAdr) {
super();
this.request = request;
this.response = response;
this.createTime = createTime;
this.ip = ip;
this.apiAdr = apiAdr;
}
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name="request",columnDefinition="text COMMENT '请求参数'")
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
@Column(name="response",columnDefinition="text COMMENT '响应结果'")
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
@Column(name="create_time",columnDefinition="DATETIME COMMENT '请求时间')
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Column(name="ip",columnDefinition="varchar(255) COMMENT '访问者ip'")
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
@Column(name="api_adr",columnDefinition="varchar(255) COMMENT '访问接口api'")
public String getApiAdr() {
return apiAdr;
}
public void setApiAdr(String apiAdr) {
this.apiAdr = apiAdr;
}
}
AOP拦截记录
/**
* 请求记录拦截器
* @author Kellan_Song
* @createTime 2019年4月4日
*/
@Aspect
@Component
public class AopTest {
private final Logger logger = LoggerFactory.getLogger(AopTest.class);
@Autowired
RequestRecordDaoI requestRecordDao; //记录实体的dao层
@Pointcut("execution(public * com.xhwl.seven.controller..*Controller.*(..))")
public void pointCut(){}
@Around("pointCut()")
public Object arounds(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String classType = point.getTarget().getClass().getName();
Class<?> clazz = Class.forName(classType);
String clazzName = clazz.getName();
String methodName = point.getSignature().getName(); // 获取方法名称
Method[] methods = clazz.getMethods();
Annotation anno = null;
String request_str = null;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
//过滤只记录有@RequestMapping注解的方法
anno = method.getAnnotation(RequestMapping.class);
if (anno == null) return point.proceed();
if (anno != null) {
//封装请求参数
Map<String, Object> nameAndArgs = RequestUtils.getNameAndArgs(this.getClass(), clazzName, methodName, point.getArgs());
request_str = StringUtils.toJSONString(nameAndArgs);
logger.info("----请求参数 :" + request_str);
break;
}
}
}
//继续执行
Object o = point.proceed();
// 获取放回结果
String response_str = StringUtils.toJSONString(o);
logger.info("----请求结果 :" + response_str);
RequestRecord record = new RequestRecord(request_str, response_str, new Date(), request.getRemoteAddr(), request.getRequestURI());
requestRecordDao.save(record);
return o;
}
}
处理请求参数工具
/**
* 封装请求参数; 因为AOP无法直接获取请求参数的key值,所以需要使用javassist动态代理的方式放射获取参数的key值。
* @author Kellan_Song
* @createTime 2019年4月3日
*/
public class RequestUtils {
public static Map<String, Object> getNameAndArgs(Class<?> cls, String clazzName, String methodName, Object[] args)
throws NotFoundException {
Map<String, Object> nameAndArgs = new HashMap<String, Object>();
//实例化类型池对象
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(cls);
pool.insertClassPath(classPath);
//获取方法参数
CtClass cc = pool.get(clazzName);
CtMethod cm = cc.getDeclaredMethod(methodName);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if (attr == null) {
return nameAndArgs; //没有参数,返回空对象
}
//判断是否未静态方法
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < cm.getParameterTypes().length; i++) {
if (args[i] != null) {
//过滤文件类型、请求类型
if (args[i] instanceof MultipartFile || args[i] instanceof ServletRequest
|| args[i] instanceof ServletResponse) {
continue;
}
nameAndArgs.put(attr.variableName(i + pos), args[i]);// paramNames即参数名
}
}
return nameAndArgs;
}
}
版权声明:本文为q410654146原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。