springMVC自定义注解,用AOP来实现日志记录的方法
程序员文章站
2023-12-13 12:03:34
需求背景
最近的一个项目,在项目基本完工的阶段,客户提出要将所有业务操作的日志记录到数据库中,并且要提取一些业务的关键信息(比如交易单号)体现在日志中。
为了保证工期,...
需求背景
最近的一个项目,在项目基本完工的阶段,客户提出要将所有业务操作的日志记录到数据库中,并且要提取一些业务的关键信息(比如交易单号)体现在日志中。
为了保证工期,在查阅了资料以后,决定用aop+自定义注解的方式来完成这个需求。
准备工作
自定义注解需要依赖的jar包有 aspectjrt-xxx.jar ,aspectjweaver-xxx.jar,xxx代表版本号。
自定义注解
在项目下单独建立了一个log包,来存放日志相关的内容
**.common.log.annotation //自定义注解存放位置 **.common.log.aop //aop工具类存放位置
在annotation包下面新建自定义注解类:
package **.common.log.annotation; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; @target({ elementtype.method }) @retention(retentionpolicy.runtime) public @interface xxxoperatelog { /** * 操作类型描述 * @return */ string operatetypedesc() default ""; /** * 操作类型 * @return */ long operatetype() default -1; /** * 模块编码 * @return */ string moudlecode() default "m30"; /** * 模块名称 * @return */ string moudlename() default "xx模块"; /** * 业务类型 * @return */ string busstype() default ""; /** * 业务类型描述 * @return */ string busstypedesc() default ""; }
在aop包下新建xxxoperatelogaop
package **.common.log.aop; import ** ;//省略 @aspect @component public class xxxoperatelogaop{ @autowired systemlogservice systemlogservice; httpservletrequest request = null; logger logger = loggerfactory.getlogger(xxxoperatelogaop.class); threadlocal<long> time = new threadlocal<long>(); //用于生成操作日志的唯一标识,用于业务流程审计日志调用 public static threadlocal<string> tag = new threadlocal<string>(); //声明aop切入点,凡是使用了xxxoperatelog的方法均被拦截 @pointcut("@annotation(**.common.log.annotation.xxxoperatelog)") public void log() { system.out.println("我是一个切入点"); } /** * 在所有标注@log的地方切入 * @param joinpoint */ @before("log()") public void beforeexec(joinpoint joinpoint) { time.set(system.currenttimemillis()); info(joinpoint); //设置日志记录的唯一标识号 tag.set(uuid.randomuuid().tostring()); request= ((servletrequestattributes) requestcontextholder.getrequestattributes()).getrequest(); } @after("log()") public void afterexec(joinpoint joinpoint) { methodsignature ms = (methodsignature) joinpoint.getsignature(); method method = ms.getmethod(); logger.debug("标记为" + tag.get() + "的方法" + method.getname() + "运行消耗" + (system.currenttimemillis() - time.get()) + "ms"); } //在执行目标方法的过程中,会执行这个方法,可以在这里实现日志的记录 @around("log()") public object aroundexec(proceedingjoinpoint pjp) throws throwable { object ret = pjp.proceed(); try { object[] orgs = pjp.getargs(); systemlog valuereturn = null; for (int i = 0; i < orgs.length; i++) { if(orgs[i] instanceof systemlog){ valuereturn = (systemlog) orgs[i]; } } if(valuereturn==null){ valuereturn = new systemlog(); } if(valuereturn!=null&&request!=null){ methodsignature ms = (methodsignature) pjp.getsignature(); method method = ms.getmethod(); //获取注解的操作日志信息 xxxoperatelog log = method.getannotation(xxxoperatelog.class); string businesstype = log.busstype(); string businessdesc = log.busstypedesc(); hashmap requestmap = servletutils.getparameterstohashmap(request) ; //从参数中寻找业务类型 if(businesstype.equals("")) { object objbusinesstype = requestmap.get("business_type"); businesstype = objbusinesstype == null ? "" : objbusinesstype.tostring(); } //从执行结果的申请单中找业务类型 object apply = request.getattribute("apply") ; if(apply != null){ jsonobject obj = jsonfactory.tojsonabstractentity(apply); if(obj != null) { valuereturn.setotherdesc("申请单号:"+obj.getstring("apply_no")); if(businesstype.equals("")) { businesstype = obj.getstring("business_type"); } } } //从方法的执行过程参数中找业务类型(一般是手动设置) if(businesstype.equals("")) { businesstype = (string) request.getattribute("business_type"); businesstype = businesstype == null ? "" : businesstype; } if(!businesstype.equals("") && businessdesc.equals("")) { businessdesc = xxxsysconstant.business_type.getname(businesstype); } valuereturn.setbusstype(xxxsysconstant.business_type.getnumber(businesstype)); valuereturn.setbusstypedesc(businessdesc); valuereturn.setmoudlecode(log.moudlecode()); valuereturn.setmoudlename(log.moudlename()); valuereturn.setoperateresult(xxxsysconstant.yesorno.yes); valuereturn.setoperatetype(log.operatetype()); valuereturn.setinputuserid(((usercontext)webutils.getsessionattribute(request, "xxxusercontext")).getsysuser().getid()); valuereturn.setoperatetypedesc(log.operatetypedesc()); valuereturn.setrequestip(getremotehost(request)); valuereturn.setrequesturl(request.getrequesturi()); valuereturn.setserverip(request.getlocaladdr()); valuereturn.setuids(tag.get()); //保存操作日志 systemlogservice.savesystemlog(valuereturn); }else{ logger.info("不记录日志信息"); } //保存操作结果 } catch (exception e) { e.printstacktrace(); } return ret; } //记录异常日志 @afterthrowing(pointcut = "log()",throwing="e") public void doafterthrowing(joinpoint joinpoint, throwable e) { try { info(joinpoint); object[] orgs = joinpoint.getargs(); systemlog valuereturn = null; for (int i = 0; i < orgs.length; i++) { if(orgs[i] instanceof systemlog){ valuereturn = (systemlog) orgs[i]; } } if(valuereturn==null){ valuereturn = new systemlog(); } if(valuereturn!=null&&request!=null){ methodsignature ms = (methodsignature) joinpoint.getsignature(); method method = ms.getmethod(); xxxoperatelog log = method.getannotation(xxxoperatelog.class); string businesstype = log.busstype(); string businessdesc = log.busstypedesc(); if(businesstype.equals("")) { object objbusinesstype = servletutils.getparameterstohashmap(request).get("business_type"); businesstype = objbusinesstype == null ? "" : objbusinesstype.tostring(); businessdesc = xxxsysconstant.business_type.getname(businesstype); } valuereturn.setbusstype(xxxsysconstant.business_type.getnumber(businesstype)); valuereturn.setbusstypedesc(businessdesc); valuereturn.setmoudlecode(log.moudlecode()); valuereturn.setmoudlename(log.moudlename()); valuereturn.setoperatetype(log.operatetype()); valuereturn.setoperatetypedesc(log.operatetypedesc()); valuereturn.setinputuserid(((usercontext)webutils.getsessionattribute(request, "xxxusercontext")).getsysuser().getid()); valuereturn.setoperateresult(xxxsysconstant.yesorno.no); string errmes = e.getmessage(); if(errmes!=null && errmes.length()>800){ errmes = errmes.substring(0, 800); } valuereturn.seterrormessage(errmes); valuereturn.setrequestip(getremotehost(request)); valuereturn.setrequesturl(request.getrequesturi()); valuereturn.setserverip(request.getlocaladdr()); valuereturn.setuids(tag.get()); systemlogservice.savesystemlog(valuereturn); }else{ logger.info("不记录日志信息"); } } catch (exception e1) { e1.printstacktrace(); } } private void info(joinpoint joinpoint) { logger.debug("--------------------------------------------------"); logger.debug("king:\t" + joinpoint.getkind()); logger.debug("target:\t" + joinpoint.gettarget().tostring()); object[] os = joinpoint.getargs(); logger.debug("args:"); for (int i = 0; i < os.length; i++) { logger.debug("\t==>参数[" + i + "]:\t" + os[i].tostring()); } logger.debug("signature:\t" + joinpoint.getsignature()); logger.debug("sourcelocation:\t" + joinpoint.getsourcelocation()); logger.debug("staticpart:\t" + joinpoint.getstaticpart()); logger.debug("--------------------------------------------------"); } /** * 获取远程客户端ip * @param request * @return */ private string getremotehost(javax.servlet.http.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(); } return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } }
修改配置文件spring-mvc.xml,添加如下配置
<!-- 开启aop拦截 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <mvc:annotation-driven /> <!-- 定义spring描述bean的范围 --> <context:component-scan base-package="**.common.log" > <context:include-filter type="annotation" expression="org.springframework.stereotype.controller"/> </context:component-scan>
需要注意的是,上述配置必须放在同一个xml文件里面,要么spring-mvc.xml,要么spring-context.xml,否则可能不生效,暂时还未查明是为什么。
注解的使用
@xxxoperatelog( busstype=xxxsysconstant.business_type.yyyy ,busstypedesc="业务类型描述" ,operatetype = xxxsysconstant.logoperatetype.query ,operatetypedesc = "操作描述" ) @requestmapping(value = "/**/**/queryxxxxx4datagrid.json", method = requestmethod.post) public void queryxxxxx4datagrid(httpservletrequest request, httpservletresponse arg1, model model, writer writer) { logger.info("==========验票查询(出库)交易信息 开始====================="); try { //do something for business } catch (systemexception se) { throw se; } catch (businessexception be) { throw be; } catch (exception e) { throw new systemexception(e); } }
以上这篇springmvc自定义注解,用aop来实现日志记录的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。