java自定义注解记录日志
最近做了一个注解记录日志,经过反复打磨自觉比较严谨,同时也复习了自定义注解。现记录,方便以后调用。
导包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注解部分
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLogRecord {
String value() default "";
String describe() default "";
}
切面记录逻辑部分:
@Aspect
@Component
public class SysLogAspect {
private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class);
/**获取服务名称**/
@Value("${spring.application.name}")
private String serverName;
/**
* 与当前线程绑定避免多线程问题
*/
ThreadLocal<Long> currentTime = new ThreadLocal<>();
/**
* 匹配数字类型的字符串:在实际开发中把String类型转换成number类型要先判断能不用转
*/
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
/**保存日志接口**/
@Autowired
private ISysLogService iSysLogService;
@Pointcut("@annotation(com.sinux.cc.syslogs.util.annotation.SysLogRecord)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
currentTime.set(System.currentTimeMillis());
Object result = point.proceed();
Long consumeTime = System.currentTimeMillis() - currentTime.get();
currentTime.remove();
/**
* 从上下文环境获取request:
* 这里是获取response的写法:
* HttpServletResponse servletResponse =
* ((ServletServerHttpResponse) RequestContextHolder.getRequestAttributes()).getServletResponse();
*
*/
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//保存日志
saveSysLogs(point, consumeTime, result, request);
return result;
}
private void saveSysLogs(ProceedingJoinPoint point, Long consumeTime, Object result, HttpServletRequest request) throws Exception {
SysLog sl = new SysLog();
Map<String, Object> map = returnResult(point);
String ip = getIPAddress(request);
String broswer = getBroswer(request);
sl.setDescripe(map.get("descripe") == null ? "" : (String) map.get("descripe"));
sl.setOperation(map.get("value") == null ? "" : (String) map.get("value"));
sl.setMethod(map.get("menthodName") == null ? "" : (String) map.get("menthodName"));
sl.setIp(ip);
sl.setBroswer(broswer);
/**
* 用户名和id的获取,例如:shiro
* userName = ShiroUtils.getSysUser().getUserName()
* userId = ShiroUtils.getSysUser().getUserId();
* 这里写死
*/
sl.setUsername("cc");
sl.setUserId(7L);
sl.setCreateDate(new Date());
sl.setTime(consumeTime + " 毫秒");
/**
* 0代表成功,1代表失败
*/
sl.setOperateStatus(0);
sl.setParams(map.get("sb") == null ? "" : map.get("sb").toString());
sl.setReturnParams(result.toString());
sl.setServerName(serverName);
iSysLogService.saveSysLogInfo(sl);
}
/**
* 返回异常
*
* @param point
* @param e
*/
@AfterThrowing(pointcut = "logPointCut()", throwing = "e")
public void afterThrowing(JoinPoint point, Throwable e) {
Long t = System.currentTimeMillis() - currentTime.get();
currentTime.remove();
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).
getRequest();
saveErrorLogs(point, t, request, e);
}
private void saveErrorLogs(JoinPoint point, Long t, HttpServletRequest request, Throwable e) {
SysLog sl = new SysLog();
String ip = getIPAddress(request);
String broswer = getBroswer(request);
Map<String, Object> map = returnResult(point);
sl.setDescripe(map.get("descripe") == null ? "" : (String) map.get("descripe"));
sl.setOperation(map.get("value") == null ? "" : (String) map.get("value"));
sl.setMethod(map.get("menthodName") == null ? "" : (String) map.get("menthodName"));
sl.setIp(ip);
sl.setBroswer(broswer);
/**
* 用户名和id的获取,例如:shiro
* userName = ShiroUtils.getSysUser().getUserName()
* userId = ShiroUtils.getSysUser().getUserId();
* 这里写死
*/
sl.setUsername("cc");
sl.setUserId(7L);
sl.setCreateDate(new Date());
sl.setTime(t + " 毫秒");
/**
* 0代表成功,1代表失败
*/
sl.setOperateStatus(1);
sl.setParams(map.get("sb") == null ? "" : (String) map.get("sb"));
/**
* 错误信息
*/
sl.setReturnParams(e.getMessage());
sl.setServerName(serverName);
iSysLogService.saveSysLogInfo(sl);
}
public Map<String, Object> returnResult(JoinPoint point) {
Map<String, Object> map = new HashMap<>();
//方法签名
MethodSignature signature = (MethodSignature) point.getSignature();
//获取方法
Method method = signature.getMethod();
//获取方法上的注解
SysLogRecord sysLogRecord = method.getAnnotation(SysLogRecord.class);
if (sysLogRecord != null) {
//从注解中获取参数
map.put("value", sysLogRecord.value());
map.put("descripe", sysLogRecord.describe());
}
//组装成:类名.方法名()
String menthodName = point.getTarget().getClass().getName() + "." + signature.getName() + "()";
map.put("menthodName", menthodName);
/**
* 获取请求参数并遍历
*/
StringBuffer sb = new StringBuffer("{");
Object[] argsValue = point.getArgs();
String[] argsName = ((MethodSignature) point.getSignature()).getParameterNames();
if (null != argsValue) {
for (int i = 0; i < argsValue.length; i++) {
sb.append(" ").append(argsName[i]).append(":").append(argsValue[i]);
}
}
map.put("sb", sb.toString() + "}");
return map;
}
/**
*获取ip地址:这里考虑了多层中间件,如 网关、nginx等
**/
public static String getIPAddress(HttpServletRequest request) {
String ip = null;
//X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
//获取浏览器信息
/**
*导入了获取浏览器的包:
* <dependency>
* <groupId>eu.bitwalker</groupId>
* <artifactId>UserAgentUtils</artifactId>
* <version>1.21</version>
* </dependency>
***/
public String getBroswer(HttpServletRequest request) {
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
Browser browser = userAgent.getBrowser();
return browser.getName();
}
/**
* 判断字符串是不是数字类型
* 实际环境中userId 数字类型,需要先判断是不是数字类型在转换
* @param str
* @return
*/
public boolean isInteger(String str) {
return pattern.matcher(str).matches();
}
}
使用的时候加上注解,在写个value 和describe 不写就默认为空