1.Log注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解可以放在controller类上,但是只有 modular 参数有效;
//该注解也可以放在controller类的方法上,如果只有方法上有Log注解,那么只会解析该注解上的信息,
//如果类和方法上都有Log注解,且方法上的 modular参数 不是默认值,那么以方法上的 modular 参数为准,否则以类上的 modular 参数为准;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/** 方法模块 */
String modular() default "";
/** 功能描述 */
String describe() default "";
}
2.日志信息封装DTO
import lombok.Data;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* @ClassName LogMessage
* @Description: 日志数据封装
* @Author Jiajiajia
* @Version V1.0
**/
@Data
@ToString
public class LogMessage {
//操作人id
private Long operationUserId;
//操作人
private String operationUser;
//操作模块
private String modular;
//具体方法描述
private String describe;
//来源计算机ip地址
private String ip;
//操作状态
private byte state;
//请求类型
private String type;
//执行时间
private LocalDateTime createTime=LocalDateTime.now();
//其他信息
private String message;
public void setState(State state){
this.state=state.getState();
}
/**
* 操作状态的枚举类
*/
public enum State{
SUCCESS((byte)0),ERROR((byte)1);
private byte state;
State(byte state){
this.state=state;
}
public byte getState(){
return state;
}
}
}
3.注解解析
利用反射技术,获取注解所在类的类信息,方法信息,和注解信息
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
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.net.InetAddress;
import java.net.UnknownHostException;
/**
* @ClassName AopTest
* @Author Jiajiajia
* @Version V1.0
**/
@Aspect
@Component
public class LogAopAdapter {
/**
* 如果同步操作那就在这里注入dao层,在doAfter或throwing方法中将message对象插入数据库;
* 如果异步操作,那就在doAfter或throwing方法中将message对象放入阻塞队列异步执行,或者使用mq,
* 或者使用springboot的异步事件等;
*/
// @Resource
// private LogAopDao logAopDao;
@Pointcut("@annotation(com.test.Log)")
public void log(){}
/**
* 前置通知
* @param joinPoint
* @throws Throwable
*/
@Before("log()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
}
/**
* 后置通知
* @param joinPoint
* @throws Throwable
*/
@After("log()&&@annotation(logMessage)")
public void doAfter(JoinPoint joinPoint,Log logMessage)throws Throwable{
LogMessage message = getMessage(joinPoint,logMessage);
message.setState(LogMessage.State.SUCCESS);
System.out.println(message);
}
/**
* 异常通知
* @param joinPoint
* @param ex
* @throws Exception
*/
@AfterThrowing(value="log()&&@annotation(logMessage)", throwing="ex")
public void throwing(JoinPoint joinPoint,Log logMessage,Exception ex) throws Exception{
LogMessage message = getMessage(joinPoint,logMessage);
message.setMessage(ex.getMessage());
message.setState(LogMessage.State.ERROR);
System.out.println(message);
}
private LogMessage getMessage(JoinPoint joinPoint,Log mlog)throws Exception{
LogMessage message=new LogMessage();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
message.setType(request.getMethod());
message.setIp(getUserRealIp(request));
Signature signature = joinPoint.getSignature();
Class c=signature.getDeclaringType();
if(!"".equals(mlog.describe())){
message.setDescribe(mlog.describe());
}
if(!"".equals(mlog.modular())){
message.setModular(mlog.modular());
}else{
Log clog=(Log)c.getAnnotation(Log.class);
if(clog!=null){
if(!"".equals(clog.modular())){
message.setModular(clog.modular());
}
}
}
return message;
}
/**
* 获取源主机ip地址
* @param request
* @return
* @throws UnknownHostException
*/
public static String getUserRealIp(HttpServletRequest request) throws UnknownHostException {
String ip;
if (request.getHeader("x-forwarded-for") == null) {
ip = request.getRemoteAddr();
} else {
ip = request.getHeader("x-forwarded-for");
}
if ("127.0.0.1".equals(ip)) {
ip = InetAddress.getLocalHost().getHostAddress();
}
return ip;
}
}
4.测试代码
测试代码
@Log(modular = "测试模块")
@RestController
public class TestController {
@GetMapping("test")
@Log(describe = "测试描述")
public String test(){
if(true){
//手动抛异常
throw new Exception("异常");
}
return "test";
}
}