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
- SpringMVC自定义注解的方式AOP实现 日志管理
- Spring AOP 自定义注解方式实现实现日志管理
- spring AOP自定义注解方式实现日志管理
- spring AOP自定义注解方式实现日志管理
- spring AOP自定义注解方式实现日志管理 详解
- spring AOP自定义注解方式实现日志管理
- spring AOP自定义注解方式实现日志管理
- aop:aspectj-autoproxy, SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- Spring AOP拦截Service实现日志管理(自定义注解的方式)
- spring自定义注解实现AOP日志管理
- aop注解方式实现全局日志管理
- aop注解方式实现日志管理
- Spring MVC AOP通过自定义注解方式拦截Controller等实现日志管理
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- springMVC自定义注解,用AOP来实现日志记录
- Android Studio里面的Build.gradle的详细配置说明
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
- mybatis学习笔记(二)增删改查
- android webview中调用了js的时候混淆失效问题
- HTTP状态码
- SpringMVC自定义注解的方式AOP实现 日志管理
- Android Studio常用快捷键说明
- Cannot find or open the PDB file
- Oracle学习01【持续更新】
- Bugtags 2016-06-16 更新内容
- 数据库数据根据每个字段的排名
- HTML滚动文字代码 marquee标签
- Mysql新建用户和数据库并授权
- 勒布朗法则