游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

自定义注解妙用,一行代码搞定用户操作日志记录,你学会了吗?

  1。简介
  我在使用spring完成项目的时候需要完成记录日志,我开始以为Spring的AOP功能,就可以轻松解决,半个小时都不用,可是经过一番了解过后,发现一般的日志记录,只能记录一些简单的操作,例如表名、表名称等记录不到。
  这个时侯就用到了自定义注解,把想要记录的内容放在注解中,通过切入点来获取到注解参数,然后将参数插入数据库记录2。SpringAOP
  对于SpringAop的基本介绍大家可以看看:
  https:blog。csdn。netyjt520557articledetails84833508
  这里是为了方便大家理解如何实现给大家解释一下2。1。关于SpringAOP的一些术语切面(Aspect):在SpringAOP中,切面可以使用通用类或者在普通类中以Aspect注解(AspectJ风格)来实现连接点(Joinpoint):在SpringAOP中一个连接点代表一个方法的执行通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括around、before和after等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。通知类型前置通知(Before):在某连接点(joinpoint)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)返回后通知(AfterReturning):在某连接点(joinpoint)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回抛出异常后通知(AfterThrowing):方法抛出异常退出时执行的通知后通知(After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)环绕通知(Around):包围一个连接点(joinpoint)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行2。2。SpringAOP配置有两种风格:XML风格采用声明形式实现SpringAOPAspectJ风格采用注解形式实现SpringAOP3。首先自定义注解
  定义一个日志描述和一个表名这里根据需要自定义注解packagecom。ywj。log;importjava。lang。annotation。;ClassNameCrmlogAOP日志记录自定义注解类Target({ElementType。PARAMETER,ElementType。METHOD})Retention(RetentionPolicy。RUNTIME)DocumentedpublicinterfaceSystemCrmlog{日志描述对于什么表格进行了什么操作Stringdescription()default;操作了的表名returnStringtableName()default;}3。1。定义切面类,从切入点获取注解信息保存到数据库
  对于一些可能碰到的问题我在方法的注释里都有解决办法,大家注意一下,这里我对于方法报错也有处理方法
  这里是对于切面类里使用到的两个类解释:
  AspectJ使用org。aspectj。lang。JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org。aspectj。lang。ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。我们先来了解一下这两个接口的主要方法:1)JoinPointjava。lang。Object〔〕getArgs():获取连接点方法运行时的入参列表;SignaturegetSignature():获取连接点的方法签名对象;java。lang。ObjectgetTarget():获取连接点所在的目标对象;java。lang。ObjectgetThis():获取代理对象本身;2)ProceedingJoinPoint
  ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:java。lang。Objectproceed()throwsjava。lang。Throwable:通过反射执行目标对象的连接点处的方法;java。lang。Objectproceed(java。lang。Object〔〕args)throwsjava。lang。Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。packagecom。ywj。log;importcom。fasterxml。jackson。databind。ObjectMapper;importcom。ywj。log。biz。SyslogBiz;importcom。ywj。log。dao。SyslogDao;importcom。ywj。login。biz。SysUserBiz;importcom。ywj。login。dao。SysUserDao;importcom。ywj。login。dao。SysrighDao;importorg。aspectj。lang。JoinPoint;importorg。aspectj。lang。annotation。;importorg。springframework。stereotype。Component;importorg。springframework。web。context。request。RequestAttributes;importorg。springframework。web。context。request。RequestContextHolder;importorg。springframework。web。context。request。ServletRequestAttributes;importjavax。servlet。http。HttpServletRequest;importjava。lang。reflect。Method;importjava。text。SimpleDateFormat;importjava。util。Arrays;importjava。util。Date;importjava。util。List;importjava。util。Map;ClassNameSystemLogAspectAuthorAdministratorDescribe定义切入面类AspectComponentpublicclassSystemLogAspect{注解Pointcut切入点定义出一个或一组方法,当执行这些方法时可产生通知指向你的切面类方法由于这里使用了自定义注解所以指向你的自定义注解Pointcut(annotation(com。ywj。log。SystemCrmlog))publicvoidcrmAspect(){}抛出异常后通知(AfterThrowing):方法抛出异常退出时执行的通知注意在这里不能使用ProceedingJoinPoint不然会报错ProceedingJoinPointisonlysupportedforaroundadvicethrowing注解为错误信息paramjoinPointparamexAfterThrowing(valuecrmAspect(),throwingex)publicvoidafterThrowingMethod(JoinPointjoinPoint,Exceptionex)throwsException{HttpServletRequesthttpServletRequestgetHttpServletRequest();获取管理员用户信息WebUtilwebUtilnewWebUtil();MapString,ObjectuserwebUtil。getUser(httpServletRequest);CrmLogMessagelognewCrmLogMessage();获取需要的信息StringcontextgetServiceMthodDescription(joinPoint);Stringusrname;Stringrolename;if(user!null){usrnameuser。get(usrname)。toString();rolenameuser。get(rolename)。toString();}管理员姓名log。setUserName(usrname);角色名log。setUserRole(rolename);日志信息log。setContent(usrnamecontext);设置参数集合log。setRemarks(getServiceMthodParams(joinPoint));设置表名log。setTableName(getServiceMthodTableName(joinPoint));操作时间SimpleDateFormatsifnewSimpleDateFormat(yyyyMMddHH:mm:ss);log。setDateTime(sif。format(newDate()));设置ip地址log。setIp(httpServletRequest。getRemoteAddr());设置请求地址log。setRequestUrl(httpServletRequest。getRequestURI());执行结果log。setResult(执行失败);错误信息log。setExString(ex。getMessage());将数据保存到数据库SyslogDaosysLogDaonewSyslogDao();sysLogDao。addSyslog(log);}返回后通知(AfterReturning):在某连接点(joinpoint)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回方法执行完毕之后注意在这里不能使用ProceedingJoinPoint不然会报错ProceedingJoinPointisonlysupportedforaroundadvicecrmAspect()指向需要控制的方法returning注解返回值paramjoinPointparamreturnValue返回值throwsExceptionAfterReturning(valuecrmAspect(),returningreturnValue)publicvoiddoCrmLog(JoinPointjoinPoint,ObjectreturnValue)throwsException{HttpServletRequesthttpServletRequestgetHttpServletRequest();获取管理员用户信息WebUtilwebUtilnewWebUtil();MapString,ObjectuserwebUtil。getUser(httpServletRequest);CrmLogMessagelognewCrmLogMessage();StringcontextgetServiceMthodDescription(joinPoint);Stringusrname;Stringrolename;if(user!null){usrnameuser。get(usrname)。toString();rolenameuser。get(rolename)。toString();}管理员姓名log。setUserName(usrname);角色名log。setUserRole(rolename);日志信息log。setContent(usrnamecontext);设置参数集合log。setRemarks(getServiceMthodParams(joinPoint));设置表名log。setTableName(getServiceMthodTableName(joinPoint));操作时间SimpleDateFormatsifnewSimpleDateFormat(yyyyMMddHH:mm:ss);log。setDateTime(sif。format(newDate()));设置ip地址log。setIp(httpServletRequest。getRemoteAddr());设置请求地址log。setRequestUrl(httpServletRequest。getRequestURI());if(returnValue!null){if(returnValueinstanceofList){Listls(List)returnValue;if(ls。size()0){log。setResult(执行成功);}else{log。setResult(执行成功);}}elseif(returnValueinstanceofBoolean){Booleanfalg(Boolean)returnValue;if(falg){log。setResult(执行成功);}else{log。setResult(执行失败);}}elseif(returnValueinstanceofInteger){Integeri(Integer)returnValue;if(i0){log。setResult(执行成功);}else{log。setResult(执行失败);}}else{log。setResult(执行成功);}}将数据保存到数据库SyslogDaosysLogDaonewSyslogDao();sysLogDao。addSyslog(log);}获取自定义注解里的日志描述paramjoinPointreturn返回注解里面的日志描述throwsExceptionprivateStringgetServiceMthodDescription(JoinPointjoinPoint)throwsException{类名StringtargetNamejoinPoint。getTarget()。getClass()。getName();方法名StringmethodNamejoinPoint。getSignature()。getName();参数Object〔〕argumentsjoinPoint。getArgs();通过反射获取示例对象ClasstargetClassClass。forName(targetName);通过实例对象方法数组Method〔〕methodstargetClass。getMethods();Stringdescription;for(Methodmethod:methods){判断方法名是不是一样if(method。getName()。equals(methodName)){对比参数数组的长度Class〔〕clazzsmethod。getParameterTypes();if(clazzs。lengtharguments。length){获取注解里的日志信息descriptionmethod。getAnnotation(SystemCrmlog。class)。description();break;}}}returndescription;}获取自定义注解里的表名paramjoinPointreturn返回注解里的表名字throwsExceptionprivateStringgetServiceMthodTableName(JoinPointjoinPoint)throwsException{类名StringtargetNamejoinPoint。getTarget()。getClass()。getName();方法名StringmethodNamejoinPoint。getSignature()。getName();参数Object〔〕argumentsjoinPoint。getArgs();通过反射获取示例对象ClasstargetClassClass。forName(targetName);通过实例对象方法数组Method〔〕methodstargetClass。getMethods();表名StringtableName;for(Methodmethod:methods){判断方法名是不是一样if(method。getName()。equals(methodName)){对比参数数组的长度Class〔〕clazzsmethod。getParameterTypes();if(clazzs。lengtharguments。length){获取注解里的表名tableNamemethod。getAnnotation(SystemCrmlog。class)。tableName();break;}}}returntableName;}获取json格式的参数用于存储到数据库中paramjoinPointreturnthrowsExceptionprivateStringgetServiceMthodParams(JoinPointjoinPoint)throwsException{Object〔〕argumentsjoinPoint。getArgs();ObjectMapperomnewObjectMapper();returnom。writeValueAsString(arguments);}获取当前的request这里如果报空指针异常是因为单独使用spring获取request需要在配置文件里添加监听listenerlistenerclassorg。springframework。web。context。request。RequestContextListenerlistenerclasslistenerreturnpublicHttpServletRequestgetHttpServletRequest(){RequestAttributesraRequestContextHolder。getRequestAttributes();ServletRequestAttributessra(ServletRequestAttributes)ra;HttpServletRequestrequestsra。getRequest();returnrequest;}}
  每个切面传递的数据的都不一样,最终决定,获取切面的所有参数,转成json字符串,保存到数据库中。相关类:
  日志信息类packagecom。ywj。log;ClassNameCrmLogMessageAuthorAdministratorDescribe数据库日志类publicclassCrmLogMessage{privateIntegerlogid;日志idprivateStringUserName;管理员姓名privateStringUserRole;管理员角色privateStringContent;日志描述privateStringRemarks;参数集合privateStringTableName;表格名称privateStringDateTime;操作时间privateStringresultValue;返回值privateStringip;ip地址privateStringrequestUrl;请求地址privateStringresult;操作结果privateStringExString;错误信息publicCrmLogMessage(){}OverridepublicStringtoString(){returnCrmLogMessage{logidlogid,UserNameUserName,UserRoleUserRole,ContentContent,RemarksRemarks,TableNameTableName,DateTimeDateTime,resultValueresultValue,ipip,requestUrlrequestUrl,resultresult,ExStringExString};}publicCrmLogMessage(Integerlogid,StringuserName,StringuserRole,Stringcontent,Stringremarks,StringtableName,StringdateTime,StringresultValue,Stringip,StringrequestUrl,Stringresult,StringexString){this。logidlogid;UserNameuserName;UserRoleuserRole;Contentcontent;Remarksremarks;TableNametableName;DateTimedateTime;this。resultValueresultValue;this。ipip;this。requestUrlrequestUrl;this。resultresult;ExStringexString;}publicStringgetExString(){returnExString;}publicvoidsetExString(StringexString){ExStringexString;}publicIntegergetLogid(){returnlogid;}publicvoidsetLogid(Integerlogid){this。logidlogid;}publicStringgetUserName(){returnUserName;}publicvoidsetUserName(StringuserName){UserNameuserName;}publicStringgetUserRole(){returnUserRole;}publicvoidsetUserRole(StringuserRole){UserRoleuserRole;}publicStringgetContent(){returnContent;}publicvoidsetContent(Stringcontent){Contentcontent;}publicStringgetRemarks(){returnRemarks;}publicvoidsetRemarks(Stringremarks){Remarksremarks;}publicStringgetTableName(){returnTableName;}publicvoidsetTableName(StringtableName){TableNametableName;}publicStringgetDateTime(){returnDateTime;}publicvoidsetDateTime(StringdateTime){DateTimedateTime;}publicStringgetResultValue(){returnresultValue;}publicvoidsetResultValue(StringresultValue){this。resultValueresultValue;}publicStringgetIp(){returnip;}publicvoidsetIp(Stringip){this。ipip;}publicStringgetRequestUrl(){returnrequestUrl;}publicvoidsetRequestUrl(StringrequestUrl){this。requestUrlrequestUrl;}publicStringgetResult(){returnresult;}publicvoidsetResult(Stringresult){this。resultresult;}}
  用来获取登录用户信息的帮助类:packagecom。ywj。log;importcom。base。web。BaseAction;importjavax。servlet。http。HttpServletRequest;importjava。util。Map;ClassNameWebUtilAuthorAdministratorDescribe日志帮助类用来获取session中的用户信息来存入数据库publicclassWebUtil{从session中获取到用户对象returnpublicMapString,ObjectgetUser(HttpServletRequestrequest){MapString,Objectattributenull;if(request!null){Objectuserrequest。getSession()。getAttribute(Constans。USERKEY);attribute(MapString,Object)user;}returnattribute;}}
  在你的springcontext。xml中配置!启动对AspectJ注解的支持!自动扫描包路径!你需要刚才的切面类的包路径context:componentscanbasepackagecom。ywj。log!你需要注解方法的包路径context:componentscanbasepackagecom。。。biz。impl
  然后在你需要记录的方法上加上注解SystemCrmlog(description进行了登录操作,tableNameConstans。USERTABLENAME)
  效果这里表名使用了常量类
  对于一些表的信息可以写一个常量类
  然后执行登录操作数据库记录为:

我科学家研发二氧化碳高效转化新机制来源:人民网人民日报本报合肥12月16日电(记者徐靖)近日,中国科学技术大学教授曾杰与电子科技大学教授夏川、中国科学院大连化学物理研究所研究员肖建平合作,基于固态电解质开……特斯拉扩充中国公关团队,招聘范围十大城市,网友终于想通了扩大公关招聘规模,不需要公关的特斯拉终于想通了?8月16日,特斯拉招聘的官方公号发布一则名为特斯拉职能部门最新职位汇总的推文,在这些招聘岗位中,除了较为常规的财务、人力资……苹果手机可以用多少年?2021年用iPhone7是什么体验?iPhone7大家好,我是指尖,今天跟大家聊聊,2021年我在用iPhone7做什么事情,以及为什么用它。这部手机是我在2017年年底买的,2020年双十一后退居二……你现在用的什么手机?再换机还用这个品牌的吗?谢邀!其实因为过去一年半之间,因为职业属性的机缘巧合,让我连续使用了两代vivoX系列的产品,包括上一代的vivoX50Pro以及这一代的vivoX60Pro,而现在,v……技术100自研,芯片算力超过苹果A15,OPPO能否成第二个看到一些键盘X在那里酸我就真忍不住了,在这群人眼中,除了华为自研芯片是正统外,MOV三家搞科研、搞芯片都是面子工程,各种冷嘲热讽。反正在这群人眼中,不管怎么做都是错的。说……iPhone更新有两种常规方法,一是在iTunes更新,二是感谢您的阅读!【苹果手机到底是ios更新好,还是OTA线上更新好?】最近很多人问我iphone手机应该怎么样去更新,特别是全新的IOS14系统,我们是通过手机直接线……储能风口与硬核技术双重加持南网科技即将登陆科创板本报见习记者张军兵随着首次公开发行价格的确定,南网科技(688248。SH)距正式登陆科创板仅一步之遥。12月9日,南网科技披露发行公告称,本次公开发行股票数量为8……供应链称苹果或将削减新iPhoneSE产量市场预期不乐观【手机中国新闻】来自供应链消息,苹果可能会在下个季度削减新iPhoneSE的产量,预计削减达到20,很快苹果又在近期通知多家供应商,生产订单减少约200万至300万部。其主要原……Android12正式发布,设计大改亮点十足最近几天,科技圈最万众期待的是什么,那莫过于是GoogleIO2021大会了。2020年由于疫情影响,取消了GoogleIO大会。而这次转为线上举办。作为Googl……微信聊天语音记录会在腾讯服务器保存多久?微信的文字和语音聊天记录都是保存在手机本地的。你用一段时间微信就会发现微信的体积越来越大,有好几个G,这全部都是微信的聊天记录。微信所有的聊天记录都是通过腾讯的服务器进行……FileJuicerv4。71一款Mac平台用于提取文件包内FileJuicer是一款Mac平台用于提取文件包内容的工具,是一款异常强大的提取文件包内容的实用办公工具。可提取word、ppt等档案中的图片文件,显然也可提取PDF文件中的……iOS12还有这些隐藏小技巧?iPhone这下买值了!【PConline资讯】距离iOS12发布已经有一段时间了,iOS12经过精心设计、系统性能优化以及各种新增功能,如今已经深受果粉们的爱戴,目前有80以上的苹果设备正在使用iO……
我的NAS机箱进化史截止换代至乔思伯N1本内容来源于什么值得买APP,观点仅代表作者本人作者:licrosse标题图饮品与本文内容无关;仅做比例展示用途购买理由之前玩过几款NAS机箱和ITX机箱,主要遗憾……为什么现在越来越多人讨厌阿里了?但凡只要是淘宝天猫、阿里巴巴卖家,就没有不厌恶阿里巴巴的。淘宝店0流量,流量全靠推广,30万销售额,你没有个3万推广费是做不到的,除非外站推广。但是做生意的也都知道,现在……美商海盗船发布HS80RGBWIRELESS高品质无线游戏耳美商海盗船宣布,推出旗下全新的高品质无线游戏耳机:HS80RGBWIRELESS。新产品搭载了美商海盗船的SLIPSTREAM低延迟无线传输技术,在外观上也采用了全新的设计,同……你能接受苹果公司iOS15扫描用户相册这一行为吗?隐私一直是一个被很多人关注的话题,但一个残酷的现实就是在这个网络普及的时代,我们的隐私都在以某一种方式被其他人所看到。以安卓手机为例,某些APP动不动就要求获取联络人、短信等读……每月300元高温补贴,为啥发不下来?多位外卖骑手没收到!平台广东暑热天气持续,按照当地有关规定,6月至10月应当为户外劳动者发放高温津贴。然而,近日广州多名外卖小哥却反映,外卖平台承诺的高温补贴,一直没有发放。家住广州天河区的郑先……懂大众的都买斯柯达?20万级别的B级车,这2款难道不香?文车魔王原创随着生活的进步,对于绝大多数的家庭来说B级车也再不是遥不可及的梦想了。相对于A级和C级车,很明显B级车的性价比更高。今天就为大家推荐这2款极具性价比的2。0T……九阳神功DC评凯音C9在武侠世界里,《九阳神功》是一本令天下武林人士心驰神往的武功秘籍。它上面记载了至刚至阳的内功心法。大成之后可以易筋洗髓,使人百毒不侵。亦能让人驱使真气护体,成就金刚不坏之躯。而……世界上最贵的冰块,近3000的价格,遭到土豪们争相竞购世界上最贵的冰块,堪称冰界爱马仕,啾咪啾咪!和发兔去看看就是它,来自美国一家专业的制冰公司GlceLuxuryIce,冰块每块周长6厘米,晶莹剔透毫无任何杂质,每包50个……国内农业和国外差距在哪?中国院士一语道破真相,这一步很关键中国是农业大国,不是农业强国。尽管从相关数据来看,2019年中国农业GDP达到1。02万亿美元左右,是全世界唯一一个农业产值突破万亿美元的国家。可高额的农业产值背后,农业从业人……你的SIM卡密码设置了吗?简单几步,手机丢失不慌张随着信息技术的飞速发展,中国手机支付用户规模持续增长。截止2020年3月,中国手机网络支付用户规模为76508万人,较2019年上半年增加14381万。移动支付已深入绑定个人生……微信支付宝已用自家打车替代滴滴移动支付网消息:大概从昨天开始,滴滴出行已从微信支付交通出行一栏消失。同时,在微信小程序、支付宝小程序中均无法搜索到该小程序。不过对于此前在微信、支付宝使用过滴滴出行小程……广州可怕!人脸识别时一定要穿衣服,摄像头拍到的可能不止是脸你以为识别的只是一张脸,殊不知上半身全照进去了,互联网社死随时随地都可以发生这两天人脸识别一定要穿上衣服话题火上热搜!不穿衣服人脸识别被看光光?网友质疑平台侵权……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网