SpringMVC自定义注解的方式AOP实现 日志管理

来源:互联网 发布:淘宝在哪看总消费金额 编辑:程序博客网 时间:2024/05/16 14:41

第一步定义两个注解:

SystemControllerLog.java

package com.annotation;        import java.lang.annotation.*;        /**   *自定义注解 拦截Controller   */        @Target({ElementType.PARAMETER, ElementType.METHOD})    @Retention(RetentionPolicy.RUNTIME)    @Documented    public  @interface SystemControllerLog {            String description()  default "";            } 
SystemServiceLog.java 
package com.annotation;        import java.lang.annotation.*;        /**   *自定义注解 拦截service   */        @Target({ElementType.PARAMETER, ElementType.METHOD})    @Retention(RetentionPolicy.RUNTIME)    @Documented    public  @interface SystemServiceLog {            String description()  default "";            }


第二步创建一个切点类:

</pre><p><pre name="code" class="java">package com.cm.contract.controller.annotation;import java.lang.reflect.Method;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import com.cm.contract.common.CMConstant;import com.cm.contract.model.companyinfo.CMcompany;import com.cm.contract.model.customerinfo.CMcustomer;import com.cm.contract.model.jurinfo.CMjurisdiction;import com.cm.contract.model.loginfo.CMlog;import com.cm.contract.model.userinfo.CMuser;import com.cm.contract.service.loginfo.LogService;import com.cm.contract.utill.CommonUtill;import com.cm.contract.utill.DateUtils;/** * 自定义切点类 *  * @author FENGWEI * @date 2016-6-17 */@Aspect@Componentpublic class SystemLogAspect {// 注入service 用于把热值保存数据库@Resourceprivate LogService logService;// 本地异常日志记录对象private static final Log logger = LogFactory.getLog(SystemLogAspect.class);// Service层切点@Pointcut("@annotation(com.cm.contract.controller.annotation.SystemServiceLog)")public void serviceAspect() {logger.info("service 日志记录方式启动!");}// Contorller层切点@Pointcut("@annotation(com.cm.contract.controller.annotation.SystemControllerLog)")public void controllerAspect() {logger.info("controller 日志记录方式启动!");}// 前置通知 用于拦截contorller层记录 日志的操作@Before("controllerAspect()")public void doBefore(JoinPoint joinPoint) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 读取session中的用户CMuser user = (CMuser) request.getSession().getAttribute(CMConstant.LOGINUSER);// 请求的IPString ip = CommonUtill.getIp();try {// *========控制台输出=========*//logger.info("=====前置通知开始=====");logger.info("请求方法:"+ (joinPoint.getTarget().getClass().getName() + "."+ joinPoint.getSignature().getName() + "()"));logger.info(joinPoint.getTarget().getClass().getName());//获取用户请求方法的参数String params = "";//参数组Object[] methodParams = joinPoint.getArgs();//获取description值 判断请求的方法String methodRemark = getControllerMethodDescription(joinPoint);//如果参数为对象 则CMjurisdiction jur=(CMjurisdiction) methodParams[0];--方式  如果参数为ModelMap 则直接获取参数if (methodParams != null && methodParams.length > 0) {for (int i = 0; i < methodParams.length; i++) {if (methodRemark.equals("添加权限")) {CMjurisdiction jur=(CMjurisdiction) methodParams[0];params=" 名称:"+jur.getJurname();}if (methodRemark.equals("修改权限")) {CMjurisdiction jur=(CMjurisdiction) methodParams[0];params=" ID:"+jur.getJurid();}if (methodRemark.equals("添加部门")) {String orgname = request.getParameter("addName");params=" 名称:"+orgname;}if (methodRemark.equals("删除部门")) {String currId = request.getParameter("treeId");params=" ID:"+currId;}if (methodRemark.equals("修改部门")) {String orgid = request.getParameter("editId");params=" ID:"+orgid;}if (methodRemark.equals("添加客户")) {CMcustomer cus=(CMcustomer) methodParams[0];params=" 名称:"+cus.getCustomername();}if (methodRemark.equals("修改客户")) {String customerid = request.getParameter("customerid");params=" ID:"+customerid;}if (methodRemark.equals("删除客户")) {String customerid = request.getParameter("id");params=" ID:"+customerid;}if (methodRemark.equals("添加公司")) {CMcompany com=(CMcompany) methodParams[0];params=" 名称:"+com.getCompanyname();}if (methodRemark.equals("编辑公司")) {String companyid = request.getParameter("companyid");params=" ID:"+companyid;}if (methodRemark.equals("上传公司文件")) {String companyid = request.getParameter("companyid");params=" 公司ID:"+companyid;}if (methodRemark.equals("删除公司关联文件")) {String fileid = request.getParameter("fileid");params=" 文件ID:"+fileid;}if (methodRemark.equals("下载公司关联文件")) {String fileid = request.getParameter("fileid");params=" 文件ID:"+fileid;}if (methodRemark.equals("数据库手动备份")) {String fileName = "合同管理系统bak";String date = DateUtils.doFindDate();fileName += "[" + date + "]";params="  :"+fileName+".zip";}if (methodRemark.equals("启动数据库定时备份")) {String bakFileName = request.getParameter("bakFileName");String date = DateUtils.doFindDate();bakFileName += "[" + date + "]";params="  :"+bakFileName+".zip";}if (methodRemark.equals("执行定时备份")) { String bakFileName=methodParams[0].toString();params="  :"+bakFileName+".zip";}if (methodRemark.equals("还原数据库")) {String backid = request.getParameter("backid");params="  ID:"+backid;}}}String type="4";//日志类型(0:客户,1:公司,2:合同,3:成本,4:其它,5:数据库操作)方便查询页面显示//公司添加的日志if (joinPoint.getThis().getClass().toString().contains("CompanyController")) {type="1";}if (joinPoint.getThis().getClass().toString().contains("CustomerController")) {type="0";}if (joinPoint.getThis().getClass().toString().contains("BakRecoverController")) {type="5";}logger.info(joinPoint.getSignature());logger.info("方法描述:"+ getControllerMethodDescription(joinPoint));logger.info("请求人:" + user.getUsername());logger.info("请求IP:" + ip);logger.info("请求參數:" + params);// *========数据库日志=========*//CMlog log = new CMlog();log.setContent("用户: "+user.getUsername() +" "+getControllerMethodDescription(joinPoint)+": "+params +"成功!");log.setTitle(getControllerMethodDescription(joinPoint));log.setLogtype("0"); // 日志类型 业务日志log.setUserip(ip);log.setUsername(user.getLoginname());log.setLogtime(DateUtils.dateTimeStr());log.setType(type);log.setUserid(user.getUserid());// 保存数据库logService.insert(log);logger.info("=====前置通知结束=====");} catch (Exception e) {// 记录本地异常日志logger.error("==前置通知异常==异常信息:{}");logger.error(e.getMessage());}}/** * 异常通知 用于拦截service层记录异常日志 *  * @param joinPoint * @param e */@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();HttpSession session = request.getSession();// 读取session中的用户CMuser user = (CMuser) request.getSession().getAttribute(CMConstant.LOGINUSER);// 获取请求ipString ip = CommonUtill.getIp();//获取用户请求方法的参数String params = "";try {//参数组Object[] methodParams = joinPoint.getArgs();//获取description值 判断请求的方法String methodRemark = getControllerMethodDescription(joinPoint);//如果参数为对象 则CMjurisdiction jur=(CMjurisdiction) methodParams[0];--方式  如果参数为ModelMap 则直接获取参数if (methodParams != null && methodParams.length > 0) {for (int i = 0; i < methodParams.length; i++) {if (methodRemark.equals("添加权限")) {CMjurisdiction jur=(CMjurisdiction) methodParams[0];params=" 名称:"+jur.getJurname();}if (methodRemark.equals("修改权限")) {CMjurisdiction jur=(CMjurisdiction) methodParams[0];params=" ID:"+jur.getJurid();}if (methodRemark.equals("添加部门")) {String orgname = request.getParameter("addName");params=" 名称:"+orgname;}if (methodRemark.equals("删除部门")) {String currId = request.getParameter("treeId");params=" ID:"+currId;}if (methodRemark.equals("修改部门")) {String orgid = request.getParameter("editId");params=" ID:"+orgid;}if (methodRemark.equals("添加客户")) {CMcustomer cus=(CMcustomer) methodParams[0];params=" 名称:"+cus.getCustomername();}if (methodRemark.equals("修改客户")) {String customerid = request.getParameter("customerid");params=" ID:"+customerid;}if (methodRemark.equals("删除客户")) {String customerid = request.getParameter("id");params=" ID:"+customerid;}if (methodRemark.equals("添加公司")) {CMcompany com=(CMcompany) methodParams[0];params=" 名称:"+com.getCompanyname();}if (methodRemark.equals("编辑公司")) {String companyid = request.getParameter("companyid");params=" ID:"+companyid;}if (methodRemark.equals("上传公司文件")) {String companyid = request.getParameter("companyid");params=" 公司ID:"+companyid;}if (methodRemark.equals("删除公司关联文件")) {String fileid = request.getParameter("fileid");params=" 文件ID:"+fileid;}if (methodRemark.equals("下载公司关联文件")) {String fileid = request.getParameter("fileid");params=" 文件ID:"+fileid;}if (methodRemark.equals("数据库手动备份")) {String fileName = "合同管理系统bak";String date = DateUtils.doFindDate();fileName += "[" + date + "]";params="  :"+fileName+".zip";}if (methodRemark.equals("启动数据库定时备份")) {String bakFileName = request.getParameter("bakFileName");String date = DateUtils.doFindDate();bakFileName += "[" + date + "]";params="  :"+bakFileName+".zip";}if (methodRemark.equals("执行定时备份")) { String bakFileName=methodParams[0].toString();params="  :"+bakFileName+".zip";}if (methodRemark.equals("还原数据库")) {String backid = request.getParameter("backid");params="  ID:"+backid;}}}/* ========控制台输出========= */logger.info("=====异常通知开始=====");logger.info("异常代码:" + e.getClass().getName());logger.info("异常信息:" + e.getMessage());logger.info("异常方法:"+ (joinPoint.getTarget().getClass().getName() + "."+ joinPoint.getSignature().getName() + "()"));logger.info("方法描述:" + getServiceMthodDescription(joinPoint));logger.info("请求人:" + user.getUsername());logger.info("请求IP:" + ip);logger.info("请求参数:" + params);/* ==========数据库日志========= */CMlog log = new CMlog();log.setContent("用户: "+user.getUsername() +" "+getControllerMethodDescription(joinPoint) +"异常!");log.setTitle(getControllerMethodDescription(joinPoint));log.setLogtype("2"); // 日志类型 业务日志log.setUserip(ip);log.setUsername(user.getUsername());// log.setUserip(CommonUtill.getIp());log.setLogtime(DateUtils.dateTimeStr());log.setOther1(params);// 保存数据库logService.insert(log);logger.info("=====异常通知结束=====");} catch (Exception ex) {// 记录本地异常日志logger.error("异常信息:{}");logger.error(ex.getMessage());}/* ==========记录本地异常日志========== */logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}");logger.error(joinPoint.getTarget().getClass().getName()+ joinPoint.getSignature().getName() + e.getClass().getName()+ e.getMessage() + params);}/** * 获取注解中对方法的描述信息 用于service层注解 *  * @param joinPoint *            切点 * @return 方法描述 * @throws Exception */public static String getServiceMthodDescription(JoinPoint joinPoint)throws Exception {// 获取目标类名String targetName = joinPoint.getTarget().getClass().getName();// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取相关参数Object[] arguments = joinPoint.getArgs();// 生成类对象Class targetClass = Class.forName(targetName);// 获取该类的方法Method[] methods = targetClass.getMethods();String description = "";for (Method method : methods) {if (method.getName().equals(methodName)) {Class[] clazzs = method.getParameterTypes();if (clazzs.length == arguments.length) {description = method.getAnnotation(SystemServiceLog.class).description();break;}}}return description;}/** * 获取注解中对方法的描述信息 用于Controller层注解 *  * @param joinPoint *            切点 * @return 方法描述 * @throws Exception */public static String getControllerMethodDescription(JoinPoint joinPoint)throws Exception {// 获取目标类名String targetName = joinPoint.getTarget().getClass().getName();// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取相关参数Object[] arguments = joinPoint.getArgs();// 生成类对象Class targetClass = Class.forName(targetName);// 获取该类的方法Method[] methods = targetClass.getMethods();String description = "";for (Method method : methods) {if (method.getName().equals(methodName)) {Class[] clazzs = method.getParameterTypes();if (clazzs.length == arguments.length) {description = method.getAnnotation(SystemControllerLog.class).description();break;}}}return description;}}

 

第三步把Controller的代理权交给cglib

spring-mvc.xml配置

<aop:aspectj-autoproxy proxy-target-class="true" />  

第四步使用

Controller层的使

/**     * 删除用户     *     * @param criteria 条件     * @param id       id     * @param model    模型     * @return 数据列表     */     @RequestMapping(value = "/delete")     //此处为记录AOP拦截Controller记录用户操作     @SystemControllerLog(description = "删除用户")      public String del(Criteria criteria, String id, Model model, HttpSession session) {          try {             User user = (User) session.getAttribute(WebConstants.CURRENT_USER);              if ( null != user) {                  if (user.getId().equals(id)) {                     msg = "您不可以删除自己!";                     criteria = userService.selectByCriteriaPagination(criteria);                 }  else {                     //删除数据并查询出数据                     criteria = userService.delete(id, criteria);                     msg = "删除成功!";                 }             }         }  catch (Exception e) {             msg = "删除失败!";         }  finally {             model.addAttribute("msg", msg);             model.addAttribute("criteria", criteria);         }         //跳转列表页          return "user/list";     }  
 Service层的使用
/**     * 按照分页查询     * @param criteria     * @return     */     //此处为AOP拦截Service记录异常信息。方法不需要加try-catch     @SystemServiceLog(description = "查询用户")      public Criteria<User> selectByCriteriaPagination(Criteria<User> criteria)     {         criteria.getList().get(0).getAccount();         //查询总数          long total=userMapper.countByCriteria(criteria);         //设置总数         criteria.setRowCount(total);         criteria.setList(userMapper.selectByCriteriaPagination(criteria));          return  criteria;     }  

运行错误常遇到的错误解决:无法找到元素 'aop:aspectj-autoproxy' 的声明

异常:

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from class path resource [e_aop_anno/bean.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 30; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'aop:aspectj-autoproxy' 的声明。    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243)    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)    at e_aop_anno.App.testUserDao(App.java:10)    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:606)    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)Caused by: org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 30; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'aop:aspectj-autoproxy' 的声明。    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:458)    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3237)    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1917)    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:746)    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379)    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2786)    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)    at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:388)    ... 37 more
解决方式:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    **xmlns:aop="http://www.springframework.org/schema/aop"**    xsi:schemaLocation="        http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">      <!-- 开启注解扫描-->      <context:component-scan base-package="controller所在的路径"></context:component-scan>
<pre name="code" class="html" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 26px;"> <context:component-scan base-package="service所在的路径"></context:component-scan>
<!-- 开启Aop注解扫描 --> <!-- 不管怎样设置,Aop在目标对象没有实现接口的情况下会使用cglib代理,在实现接口的情况下会使用jdk动态代理 --><aop:aspectj-autoproxy proxy-target-class="true" /> </beans>

引入Aop的名称空间,还要在xsi:schemaLocation中加入aop的xsd文件 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd 
这两个是必须要有的,缺一不可 
由此可以看出,在使用Spring Aop时,不仅需要引入Aop的名称空间,还有引入相应的xsd文件


0 0
原创粉丝点击