背景
生产环境有许多数据是保密的,需要对查看、导出、更新等操作。保存相关的日志信息。(记录操作人、IP地址、浏览器名称、操作模块、方法名称等)
功能实现
一、 自定义注解
/**
* 1.CONSTRUCTOR:用于描述构造器
* 2.FIELD:用于描述域
* 3.LOCAL_VARIABLE:用于描述局部变量
* 4.METHOD:用于描述方法
* 5.PACKAGE:用于描述包
* 6.PARAMETER:用于描述参数
* 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
* 1.SOURCE:在源文件中有效(即源文件保留)
* 2.CLASS:在class文件中有效(即class保留)
* 3.RUNTIME:在运行时有效(即运行时保留)
* 标注的方法为切点 用来记录日志
*/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogAnnotation {
/**
* 主模块
*/
public String mainModule() default "";
/**
* 子模块
*/
public String submodule() default "";
}
二、AOP
@Slf4j
@Aspect
@Component
public class DirectPayDataOperateAspect {
//指向自定义的注解接口,告诉切面类,只对使用该注解的方法才执行
@Pointcut("@annotation(com.huatek.figure.common.interfaces.LogAnnotation)")
public void loggableMethods() {
}
@Before("loggableMethods()")
public void logMethod(JoinPoint jp) {
String methodName = jp.getSignature().getName();
log.info("Executing method: " + methodName);
}
// 声明环绕通知
@Around("loggableMethods()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Long startTime = System.currentTimeMillis();
//要增强的方法的返回结果
Object ret = pjp.proceed();
// 获取request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
save(user,request,pjp);
Long endTime = System.currentTimeMillis();
log.info("总耗时{}m:响应数据{}", (endTime - startTime)/1000, JSON.toJSONString(ret));
return ret;
}
/**
* 保存操作
*
* @param user
* @param request
* @param pjp
*/
public void save(UserInfo user, HttpServletRequest request, ProceedingJoinPoint pjp) {
//1.操作人
//2.时间
//3.IP地址
//4.操作模块
//5.更新、插入
//6.浏览器
LogAnnotation logAnnotation = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(LogAnnotation.class);
log.info("日志信息:{}",JSON.toJSONString(logAnnotation));
//获取ip地址
String ipAddress = getIpAddress(request);
//获取浏览器名称及版本
String browserName = browserName(request);
//调用方法将数据保存到table表中
//添加日志,把request数据封装保存起来,根据项目需要存储即可
log.info("IP地址为:{},浏览器名称及版本:{},用户:{},操作模块:{},{}",ipAddress,browserName,user.getUserName(),logAnnotation.mainModule(),logAnnotation.submodule());
}
/**
* 获取浏览器名称及版本
* @param request
* @return
*/
public static String browserName(HttpServletRequest request){
String userAgent = request.getHeader("User-Agent");
UserAgent ua = UserAgent.parseUserAgentString(userAgent);
Browser browser = ua.getBrowser();
return browser.getName() + "-" + browser.getVersion(userAgent);
}
/**
* 获取IP地址
* @param request
* @return
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
三、功能测试
@RestController
public class ProjectFundController {
@LogAnnotation(mainModule = "主模块一",submodule = "子模块一")
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test() {
return "日志打印"
}
}