通过AOP自定义注解实现日志管理
前言:
通过自定义注解和AOP结合的方式,实现日志的记录功能
大致流程:项目运行->用户操作调用业务处理类->通过自定义的注解(我理解为一个切点)->进入到AOP切面类(在这里可以获得业务处理类的类名,方法名,通过request获取操作者ip,自定义的操作名,时间等)->把获取的信息记入数据库实现日志的记录->记录成功后返回业务处理类,下面是代码。
1.spring-mvc配置文件
<!-- 6.开启注解AOP (前提是引入aop命名空间和相关jar包) -->
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"></aop:aspectj-autoproxy> <!-- 7.开启aop,对类代理强制使用cglib代理 -->
<aop:config proxy-target-class="true"></aop:config> <!-- 8.扫描 @Service @Component 注解-->
<context:component-scan base-package="com.bs" >
<!-- 不扫描 @Controller的类 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
2.自定义注解类
package com.bs.annotation; import java.lang.annotation.*; @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SysLog { String value() default "";
}
3.AOP切面类
package com.bs.aop; import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.Date;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.bs.annotation.SysLog;
import com.bs.basic.service.BsSysLogService; @Aspect
@Component
public class LogAspect { private static final String LOG_CONTENT = "[类名]:%s <br/>[方法]:%s <br>[参数]:%s <br/>[IP]:%s"; @Autowired
public BsSysLogService logService; @Around("@annotation(com.bs.annotation.SysLog)")
public Object saveLog(ProceedingJoinPoint joinPoint) throws Throwable{ DateFormat ddtf = DateFormat.getDateTimeInstance();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Object result = null;
String methodName = joinPoint.getSignature().getName();
Method method = currentMethod(joinPoint, methodName);
SysLog log = method.getAnnotation(SysLog.class);
String content =buildeContent(joinPoint, methodName, request); logService.insert(content,ddtf.format(new Date()),"-",log.value());
try{
result=joinPoint.proceed();
}catch(Exception exception){ }finally{
}
return result;
} /**
* 获取当前方法
* @param joinPoint
* @param methodName
* @return
*/
public Method currentMethod(ProceedingJoinPoint joinPoint,String methodName){
Method[] methods = joinPoint.getTarget().getClass().getMethods();
Method resultMethod = null;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
resultMethod = method;
break;
}
}
return resultMethod;
} /**
* 日志内容
* @param joinPoint
* @param methodName
* @param request
* @return
*/
public String buildeContent(ProceedingJoinPoint joinPoint, String methodName, HttpServletRequest request) {
String className = joinPoint.getTarget().getClass().getName();
Object[] params = joinPoint.getArgs();
StringBuffer bf = new StringBuffer();
if (params != null && params.length > 0) {
Enumeration<String> paraNames = request.getParameterNames();
while (paraNames.hasMoreElements()) {
String key = paraNames.nextElement();
bf.append(key).append("=");
bf.append(request.getParameter(key)).append("&");
}
if (StringUtils.isBlank(bf.toString())) {
bf.append(request.getQueryString());
}
}
return String.format(LOG_CONTENT, className, methodName, bf.toString(),getRemoteAddress(request));
} /**
*
* 获取请求客户端ip
*
* @param request
*
* @return ip地址
*
*/
public static String getRemoteAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
ip = request.getRemoteAddr();
}
return ip;
}
}
4.自定义注解配置在需要记录的业务处理类
@SysLog("删除场景")
@Override
public String deleteScene(String cmdValues) {
//业务逻辑....
}
@SysLog("更新场景")
@Override
public String updateScene(String value) {
//业务处理...
}
...
记录的日志是这样的
通过AOP自定义注解实现日志管理的更多相关文章
- spring AOP自定义注解 实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- (转)利用Spring AOP自定义注解解决日志和签名校验
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
- 【Spring】每个程序员都使用Spring(四)——Aop+自定义注解做日志拦截
一.前言 上一篇博客向大家介绍了Aop的概念,对切面=切点+通知 .连接点.织入.目标对象.代理(jdk动态代理和CGLIB代理)有所了解了.理论很强,实用就在这篇博客介绍. 这篇博客中,小编向大家介 ...
- spring boot aop 自定义注解 实现 日志检验 权限过滤
核心代码: package com.tran.demo.aspect; import java.lang.reflect.Method; import java.time.LocalDateTime; ...
- SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!
往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...
- spring AOP自定义注解方式实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- Spring aop+自定义注解统一记录用户行为日志
写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...
- redis分布式锁-spring boot aop+自定义注解实现分布式锁
接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...
随机推荐
- 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象
本文需要对C#里的LINQ.Lambda 表达式 .委托有一定了解. 在工作中,经常遇到需要对比两个集合的场景,如: 页面集合数据修改,需要保存到数据库 全量同步上游数据到本系统数据库 在这些场景中, ...
- Android RelativeLayout wrap_content 而且 child view 使用 layout_alignParentBottom 时 RelativeLayout 高度会占满屏幕
Android RelativeLayout wrap_content 而且 child view 使用 layout_alignParentBottom 时 RelativeLayout 高度会占满 ...
- solr 加载 停用/扩展词典
startup.bat 停止词典的效果
- linux源码安装的步骤
源码安装的过程中多多少少会遇到问题,在此仅简述一下安装的步骤,具体安装的过程中遇到的问题,具体解决. 安装步骤: 1.获取源码 name.gz 2.解包 tar -xvf name.gz (cd到包解 ...
- Orleans实战目录
一 项目结构 1> 接口项目 .net core类库 2> Grains实现项目 .net core类库 3> 服务Host .net core console applicatio ...
- charles重复发包工具/repeat
重复发包工具/repeat Charles 让你选择一个请求并重复,在测试后端接口的时候非常有用: Charles将请求重新发送到服务器,并将响应显示为新请求. 如果您进行后端更改并希望测试它们,用了 ...
- 全网最详细的实用的搜索工具【堪称比Everything要好】Listary软件的下载与安装(图文详解)
不多说,直接上干货! 但是呢,作为博主的我而言,一般不用免费版,喜欢用专业版,具体原因,你懂得. 下载,得到 需要破解安装包的,进 对应本平台的讨论和答疑QQ群:大数据和人工智能躺过的坑(总群)(16 ...
- 全网最详细的hive-site.xml配置文件里添加<name>hive.cli.print.header</name>和<name>hive.cli.print.current.db</name>前后的变化(图文详解)
不多说,直接上干货! 比如,你是从hive-default.xml.template,复制一份,改名为hive-site.xml 一般是 <configuration> <prope ...
- 编写自己的SpringBoot-starter
前言 我们都知道可以使用SpringBoot快速的开发基于Spring框架的项目.由于围绕SpringBoot存在很多开箱即用的Starter依赖,使得我们在开发业务代码时能够非常方便的.不需要过多关 ...
- Disruptor多个消费者不重复处理生产者发送过来的消息
1.定义事件事件(Event)就是通过 Disruptor 进行交换的数据类型. package com.ljq.disruptor; import java.io.Serializable; /** ...