一,使用aop记录方法调用日志
1)使用注解与aop做方法调用日志,只需要把注解添加在要记录的方法上就可以,不会影响代码结构
2)实现思路 数据库表建立>>配置需要环境>>自定义注解>>定义切点与操作(包含处理逻辑)>>添加注解
二,配置环境
1)在原来的项目pom文件中添加以下aop需要的依赖
<springframework>4.0.5.RELEASE</springframework> <aspectj>1.8.5</aspectj> <!-- Spring AOP --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${springframework}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj}</version> </dependency>
2)springmvc配置
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
<!-- 启动AspectJ支持 只对扫描过的bean有效 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <!-- 指定Sping组件扫描的基本包路径 --> <context:component-scan base-package="com.bjsxt.portl"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
三,自定义注解
1)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志记录
* @author heyuan***
* @date: 2017年11月22日 上午11:41:57
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
String name() default ""; //用于写方法作用
}
四,定义切点与操作
1)
@Aspect @Component public class SeriveLogAop { @Resource private OperationLogMapper operationLogMapper; @Pointcut("@annotation(com.bjsxt.portal.annotation.SeriveLog)") public void SeriveLogAopqd() { System.out.println("---------->切点"); } @After("SeriveLogAopqd()") public void Afters(JoinPoint joinPoint) { OperationLog operationLog = new OperationLog(); User user = new User(); StringBuffer arg = new StringBuffer(); Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; ++i) { System.out.println(" ==>参数[" + i + "]: " + args[i].toString()); arg.append(args[i].toString()); } Signature signature = joinPoint.getSignature(); String signa = signature.toString(); MethodSignature ms = (MethodSignature)joinPoint.getSignature(); Method method = ms.getMethod(); String name = ((SeriveLog)method.getAnnotation(SeriveLog.class)).name(); String name2 = method.getName(); HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); user.setuUsername("无登录人"); String host = request.getRemoteHost(); String username = user.getuUsername(); String time = Time.getTime(); operationLog.setoIp(host); operationLog.setuUsername(username); operationLog.setoTime(time); operationLog.setoMethodname(name2); operationLog.setoExplain(name); operationLog.setoFullpath(signa); operationLog.setoParameter(arg.toString()); this.operationLogMapper.addOperationLogs(operationLog); } }
五,在需要记录的方法上添加@Log(name="方法描述"
)
六,常用知识
注解:
@Before – 目标方法执行前执行 前置通知 JoinPoint joinPoint
@After – 目标方法执行后执行 后置通知
@AfterReturning – 目标方法返回后执行,如果发生异常不执行
@AfterThrowing – 异常时执行 异常通知
@Around – 在执行上面其他操作的同时也执行这个方法 环绕通知 ProceedingJoinPoint pjp 执行方法:pjp.proceed(); 要返回pjp
joinPoint:方法 joinPoint.getKind() // method-execution joinPoint.getTarget().toString()// 获取连接点所在的目标对象; com.xxx.portal.service.impl.UserServiceImpl@a269a21 joinPoint.getArgs() //获取连接点方法运行时的入参列表; System.out.println("Args:"); for(int i=0;i<os.length;i++){ System.out.println(" ==>参数["+i+"]: "+os[i].toString()); } joinPoint.getSignature() //获取连接点的方法签名对象;String com.bjsxt.portal.service.impl.UserServiceImpl.getUser(User,HttpServletRequest,HttpSession) joinPoint.getSourceLocation() // org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@161b0ee2 joinPoint.getStaticPart() // execution(String com.xxx.portal.service.impl.UserServiceImpl.getUser(User,HttpServletRequest,HttpSession)) MethodSignature ms=(MethodSignature) joinPoint.getSignature(); Method method=ms.getMethod(); method.getAnnotation(Log.class).name(); //method.getAnnotation(Log.class).name() 获取操作名(@log(name="内容")) method.getName(); //获取当前执行方法名
常用方法:
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
request.getSession();
request.getHost();//获取ip
异常名称: e.getClass().toString()
网络参考资料 @Aspect @Component public class LogAop { ThreadLocal<Long> time=new ThreadLocal<Long>(); ThreadLocal<String> tag=new ThreadLocal<String>(); //切点 @Pointcut("@annotation(com.bjsxt.portal.annotation.Log)") public void logqd() { System.out.println("---------->切点"); } /** * 在所有标注@Log的地方切入 * @param joinPoint * 前置通知 */ @Before("logqd()") public void beforeExec(JoinPoint joinPoint){ time.set(System.currentTimeMillis()); tag.set(UUID.randomUUID().toString()); info(joinPoint); MethodSignature ms=(MethodSignature) joinPoint.getSignature(); Method method=ms.getMethod(); //method.getAnnotation(Log.class).name() 获取操作名(@log(name="内容")) System.out.println(method.getAnnotation(Log.class).name()+"标记"+tag.get()); } /** *后置通知 */ @After("logqd()") public void afterExec(JoinPoint joinPoint){ MethodSignature ms=(MethodSignature) joinPoint.getSignature(); Method method=ms.getMethod(); System.out.println("标记为"+tag.get()+"的方法"+method.getName()+"运行消耗"+(System.currentTimeMillis()-time.get())+"ms"); } /** *环绕通知 */ @Around("logqd()") public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("前"); Object proceed = pjp.proceed(); System.out.println("后"); return proceed; } private void info(JoinPoint joinPoint){ System.out.println("--------------------------------------------------"); System.out.println("King: "+joinPoint.getKind()); System.out.println("Target: "+joinPoint.getTarget().toString()); Object[] os=joinPoint.getArgs(); System.out.println("Args:"); for(int i=0;i<os.length;i++){ System.out.println(" ==>参数["+i+"]: "+os[i].toString()); } System.out.println("Signature: "+joinPoint.getSignature()); System.out.println("SourceLocation: "+joinPoint.getSourceLocation()); System.out.println("StaticPart: "+joinPoint.getStaticPart()); System.out.println("--------------------------------------------------"); } } /** * 异常通知 *@descript *@param point *@version 1.0 */ @AfterThrowing(pointcut = "controllerAspect()", throwing = "e") public void doAfterThrowing(JoinPoint point, Throwable e) { LogFormMap logForm = new LogFormMap(); Map<String, Object> map = null; String user = null; String ip = null; try { ip = SecurityUtils.getSubject().getSession().getHost(); } catch (Exception ee) { ip = "无法获取登录用户Ip"; } try { map=getControllerMethodDescription(point); // 登录名 user = SecurityUtils.getSubject().getPrincipal().toString(); if (Common.isEmpty(user)) { user = "无法获取登录用户信息!"; } } catch (Exception ee) { user = "无法获取登录用户信息!"; } logForm.put("accountName",user); logForm.put("module",map.get("module")); logForm.put("methods","<font color="red">执行方法异常:-->"+map.get("methods")+"</font>"); logForm.put("description","<font color="red">执行方法异常:-->"+e+"</font>"); logForm.put("actionTime","0"); logForm.put("userIP",ip); try { logMapper.addEntity(logForm); } catch (Exception e1) { e1.printStackTrace(); } }