前言
目前已经实现日志和权限认证功能,配置起来可能麻烦点,但是注意版本问题时,其他的应该没什么问题。
此项目是用springboot+springsecurity+aop实现权限认证和日志功能的,请结合项目所需使用。
一、导入依赖?
<!--aop日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.6.6</version>
</dependency>
<!--获取浏览器信息工具-->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
二、编写配置
1.Log
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)//注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行
public @interface Log {
String value() default "";
}
2.AopLog
import cn.sms.util.LogUtils;
import cn.sms.core.security.SecurityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Description:LogAspect
* Date: 2022/4/19 9:51
* @Version: 1.0
*/
@Aspect
@Component // 开启组件扫描
@Slf4j
public class AopLog {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
ThreadLocal<Long> startTime = new ThreadLocal<>();
//定义切点(xxx修改成自己的log地址)
@Pointcut("@annotation(cn.xxx.aop.Log)")
public void aopWebLog() {
}
//使用环绕通知
@Around("aopWebLog()")
public Object myLogger(ProceedingJoinPoint pjp) throws Throwable {
startTime.set(System.currentTimeMillis());
//使用ServletRequestAttributes请求上下文获取方法更多
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String className = pjp.getSignature().getDeclaringTypeName();
String methodName = pjp.getSignature().getName();
//获取方法的@Log自定义内容
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Log myLog = method.getAnnotation(Log.class);
//使用数组来获取参数
Object[] array = pjp.getArgs();
ObjectMapper mapper = new ObjectMapper();
//执行函数前打印日志
log.info("调用前:{}:{},传递的参数为:{}", className, methodName, mapper.writeValueAsString(array));
log.info("URL:{}", request.getRequestURL().toString());
log.info("请求类型:{}", request.getMethod());
log.info("IP地址:{}", request.getRemoteAddr());
log.info("IP地址:{}", LogUtils.getIp(request));
log.info("浏览器:{}", LogUtils.getBrowser(request).equals("Unknown") ? LogUtils.getBrowser(request):"");
log.info("操作系统:{}", LogUtils.getOS(request).equals("Unknown") ? LogUtils.getOS(request):"");
log.info("用户姓名:{}", SecurityUtils.getCurrentUsername());
log.info("访问时间:{}", simpleDateFormat.format(new Date()));
log.info("方法注释:{}", myLog.value());
//调用整个目标函数执行
Object obj = pjp.proceed();
//执行函数后打印日志
log.info("调用后:返回值为:{}", mapper.writeValueAsString(obj));
log.info("耗时:{}ms", System.currentTimeMillis() - startTime.get());
调用service层添加日志方法
return obj;
}
}
3.LogUtils
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Description:IPUtil
* Date: 2022/4/19 11:15
* @Version: 1.0
*/
public class LogUtils {
private static final char SEPARATOR = '_';
private static final String UNKNOWN = "unknown";
/**
* 获取ip地址
*/
public static String getIp(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.getRemoteAddr();
}
String comma = ",";
String localhost = "127.0.0.1";
if (ip.contains(comma)) {
ip = ip.split(",")[0];
}
if (localhost.equals(ip)) {
// 获取本机真正的ip地址
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
return ip;
}
/**
* 获取浏览器信息
* @param request
* @return
*/
public static String getBrowser(HttpServletRequest request){
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
Browser browser = userAgent.getBrowser();
return browser.getName();
}
/**
* 获取系统
* @param request
* @return
*/
public static String getOS(HttpServletRequest request){
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
OperatingSystem os = userAgent.getOperatingSystem();
return os.getName();
}
/**
* 获取堆栈信息
*/
public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw);
return sw.toString();
}
}
}
三、使用
在controller的方法中使用 @Log("xxxxxxx") 注解