1. 程式人生 > >SpringAOP攔截Controller,Service實現日誌管理(自定義註解的方式)

SpringAOP攔截Controller,Service實現日誌管理(自定義註解的方式)

         首先我們為什麼需要做日誌管理,在現實的上線中我們經常會遇到系統出現異常或者問題。這個時候就馬上開啟CRT或者SSH連上伺服器拿日子來分析。受網路的各種限制。於是我們就想為什麼不能直接在管理後臺檢視報錯的資訊呢。於是日誌管理就出現了。

         其次個人覺得做日誌管理最好的是Aop,有的人也喜歡用攔截器。都可以,在此我重點介紹我的實現方式。

         Aop有的人說攔截不到Controller。有的人說想攔AnnotationMethodHandlerAdapter截到Controller必須得攔截org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter。

首先Aop可以攔截到Controller的,這個是毋容置疑的其次須攔截AnnotationMethodHandlerAdapter也不是必須的。最起碼我沒有驗證成功過這個。我的Spring版本是4.0.3。

         Aop之所以有的人說攔截不到Controller是因為Controller被jdk代理了。我們只要把它交給cglib代理就可以了。

第一步定義兩個註解:

package com.annotation;  
  
import java.lang.annotation.*;  
  
/** 
 *自定義註解 攔截Controller 
 */  
  
@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public  @interface SystemControllerLog {  
  
    String description()  default "";  
  
  
}  
  
package com.annotation;  
  
import java.lang.annotation.*;  
  
/** 
 *自定義註解 攔截service 
 */  
  
@Target({ElementType.PARAMETER, ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public  @interface SystemServiceLog {  
  
    String description()  default "";  
  
  
}  
第二步建立一個切點類:
package com.annotation;  
  
import com.model.Log;  
import com.model.User;  
import com.service.LogService;  
import com.util.DateUtil;  
import com.util.JSONUtil;  
import com.util.SpringContextHolder;  
import com.util.WebConstants;  
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.*;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.stereotype.Component;  
import org.springframework.web.context.request.RequestContextHolder;  
import org.springframework.web.context.request.ServletRequestAttributes;  
import javax.annotation.Resource;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpSession;  
import java.lang.reflect.Method;  
  
/** 
 * 切點類 
 * @author tiangai 
 * @since 2014-08-05 Pm 20:35 
 * @version 1.0 
 */  
@Aspect  
@Component  
public  class SystemLogAspect {  
    //注入Service用於把日誌儲存資料庫  
    @Resource  
     private LogService logService;  
    //本地異常日誌記錄物件  
     private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);  
  
    //Service層切點  
    @Pointcut("@annotation(com.annotation.SystemServiceLog)")  
     public  void serviceAspect() {  
    }  
  
    //Controller層切點  
    @Pointcut("@annotation(com.annotation.SystemControllerLog)")  
     public  void controllerAspect() {  
    }  
  
    /** 
     * 前置通知 用於攔截Controller層記錄使用者的操作 
     * 
     * @param joinPoint 切點 
     */  
    @Before("controllerAspect()")  
     public  void doBefore(JoinPoint joinPoint) {  
  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();  
        //讀取session中的使用者  
        User user = (User) session.getAttribute(WebConstants.CURRENT_USER);  
        //請求的IP  
        String ip = request.getRemoteAddr();  
         try {  
            //*========控制檯輸出=========*//  
            System.out.println("=====前置通知開始=====");  
            System.out.println("請求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));  
            System.out.println("請求人:" + user.getName());  
            System.out.println("請求IP:" + ip);  
            //*========資料庫日誌=========*//  
            Log log = SpringContextHolder.getBean("logxx");  
            log.setDescription(getControllerMethodDescription(joinPoint));  
            log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            log.setType("0");  
            log.setRequestIp(ip);  
            log.setExceptionCode( null);  
            log.setExceptionDetail( null);  
            log.setParams( null);  
            log.setCreateBy(user);  
            log.setCreateDate(DateUtil.getCurrentDate());  
            //儲存資料庫  
            logService.add(log);  
            System.out.println("=====前置通知結束=====");  
        }  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中的使用者  
        User user = (User) session.getAttribute(WebConstants.CURRENT_USER);  
        //獲取請求ip  
        String ip = request.getRemoteAddr();  
        //獲取使用者請求方法的引數並序列化為JSON格式字串  
        String params = "";  
         if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {  
             for ( int i = 0; i < joinPoint.getArgs().length; i++) {  
                params += JSONUtil.toJsonString(joinPoint.getArgs()[i]) + ";";  
            }  
        }  
         try {  
              /*========控制檯輸出=========*/  
            System.out.println("=====異常通知開始=====");  
            System.out.println("異常程式碼:" + e.getClass().getName());  
            System.out.println("異常資訊:" + e.getMessage());  
            System.out.println("異常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));  
            System.out.println("請求人:" + user.getName());  
            System.out.println("請求IP:" + ip);  
            System.out.println("請求引數:" + params);  
               /*==========資料庫日誌=========*/  
            Log log = SpringContextHolder.getBean("logxx");  
            log.setDescription(getServiceMthodDescription(joinPoint));  
            log.setExceptionCode(e.getClass().getName());  
            log.setType("1");  
            log.setExceptionDetail(e.getMessage());  
            log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
            log.setParams(params);  
            log.setCreateBy(user);  
            log.setCreateDate(DateUtil.getCurrentDate());  
            log.setRequestIp(ip);  
            //儲存資料庫  
            logService.add(log);  
            System.out.println("=====異常通知結束=====");  
        }  catch (Exception ex) {  
            //記錄本地異常日誌  
            logger.error("==異常通知異常==");  
            logger.error("異常資訊:{}", ex.getMessage());  
        }  
         /*==========記錄本地異常日誌==========*/  
        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

在例項化ApplicationContext的時候需要加上

Xml程式碼 
  1. <!-- 啟動對@AspectJ註解的支援 -->  
  2. <aop:aspectj-autoproxy/>  

 在呼叫Controller的時候AOP發揮作用所以在SpringMVC的配置檔案里加上

Xml程式碼 
  1. <!--通知spring使用cglib而不是jdk的來生成代理方法 AOP可以攔截到Controller->  
  2. <aop:aspectj-autoproxy proxy-target-class="true" />  

 第四步使用

Controller層的使用

Java程式碼

/** 
    * 刪除使用者 
    * 
    * @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;  
   }  

效果圖

使用者操作:



 異常





文章來源http://itindex.net/detail/50710-springaop-controller-service

相關推薦

SpringAOP攔截Controller,Service實現日誌管理(定義註解方式)

         首先我們為什麼需要做日誌管理,在現實的上線中我們經常會遇到系統出現異常或者問題。這個時候就馬上開啟CRT或者SSH連上伺服器拿日子來分析。受網路的各種限制。於是我們就想為什麼不能直接在管理後臺檢視報錯的資訊呢。於是日誌管理就出現了。          其次

SpringAOP攔截Controller,Service實現日誌管理(定義註解方式)(轉載)

http://langgufu.iteye.com/blog/2235556   首先我們為什麼需要做日誌管理,在現實的上線中我們經常會遇到系統出現異常或者問題。這個時候就馬上開啟CRT或者SSH連上伺服器拿日子來分析。受網路的各種限制。於是我們就想為什麼不能直接在

Spring AOP攔截Service實現日誌管理(定義註解方式)

最近專案中用到AOP方式進行Service操作方法日誌管理,特為之記! 1、先說理論和採用的方法 採用註解的方式,其中包括以下註解:@Aspect(類註解)和@AfterReturning(方法註解),其中需要用的Maven庫如下: "org.aspectj:aspect

Spring AOP 基於註解實現日誌記錄+定義註解

一、寫一個自定義註解        註解中包括配置方法所在模組名稱,以及功能名稱,當然我們在註解裡可以自定義。import java.lang.annotation.Documented; import java.lang.annotation.ElementType; im

使用Spring AOP定義註解方式實現使用者操作日誌記錄

1,開發環境 作業系統:Windows 7 JDK:1.8.0_161 Eclipse:Mars.2 Release (4.5.2) 2,自定義註解類UserLog @Target({ElementType.PARAMETER, ElementType.METHOD}) @R

springboot aop 定義註解方式實現一套完善的日誌記錄(完整原始碼)

一:功能簡介 本文主要記錄如何使用aop切面的方式來實現日誌記錄功能。 主要記錄的資訊有: 操作人,方法名,引數,執行時間,操作型別(增刪改查),詳細描述,返回值。 二:專案結構圖 三:MAVEM依賴 本專案有兩個pom檔案,父類的pom檔案主要作用是對子類pom檔案依賴的版本號進行統一管理。 1.最外層

註解Annotation實現原理與定義註解例子

什麼是註解? 對於很多初次接觸的開發者來說應該都有這個疑問?Annontation是Java5開始引入的新特徵,中文名稱叫

使用定義註解方式配合spring讀取配置檔案

一、使用@interface關鍵字來標識為註解類:@Target({ ElementType.TYPE })@Retention( RetentionPolicy.RUNTIME )@Componentpublic @interface Config {}@Target({

Spring AOP 定義註解實現日誌管理

目錄 一、配置檔案 二、新建一個日誌實體類Log 三、編寫 service 層 四、編寫 service 層的實現 serviceimpl 五、自定義註解類 六、編寫切面類 七、spring + aop 需要的 jar 包 部落格的程式碼是基於 SSM 環境編寫的

spring-AOP+定義註解實現日誌管理註解方式實現

一、場景 後臺管理系統中,管理員作業系統時生成日誌儲存在資料庫中。 二、實現 1、jar包依賴 <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency&

《SpringBoot學習篇》(5)AOP+定義註解實現日誌管理

用到的AOP註解:@Aspect  @Pointcut  @After 首先看一下如何呼叫自定義註解: @MyLog(module="老師模組", method="查詢全部") @RequestMapping("/all") public List

springAOP定義註解實現細粒度許可權控制管理

IOC與AOP無疑是spring的核心,提供了非常強大的功能,這兩個思想為我們開發帶來了巨大的方便。 這裡我們aop簡單實現一些許可權控制,用到的aop提供的環繞通知,至於spring提供了那些通知,大家可以自行百度。 <bean id="privilegeAspec

spring實現service日誌管理

現在為了便於管理系統,配置一個日誌表,當用戶登入系統以及對系統資料進行增刪改操作時要將使用者的資訊存入到資料庫 //1.自定義註解 package com.zipx.util.systemlog; import java.lang.annotation.Documented

定義註解實現日誌管理

首先定義一個註解: @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface LogAnnotation { //模組

Spring AOP定義註解實現系統日誌記錄管理

package com.kilomob.powernetwork.managerweb.annotation; import java.lang.reflect.Method; import java.net.InetAddress; import java.util.Arrays; import java

【Spring MVC攔截器+logback日誌+定義註解實現使用者鑑權登陸和訪問日誌記錄

摘要說明: 專案中經常這樣的需要  1. 登陸鑑權:比如使用者瀏覽器發出某個請求的時候我們需要判斷這個使用者是否已經登陸,也就是cookie中是否有他的登陸資訊。 2. 訪問日誌記錄:使用者訪問請求的時候我們有必要記錄訪問者的身份資訊以及訪問了哪個url,請求引數是什麼,這

SSH開發 | 配合定義註解 和 Stratus攔截器,實現 方法級粒度 用戶鑒權

struts OS action gin 所有 具體實現 getmethod red nal 1.提要   本文是 小小商城-SSH版的 細節詳解系列 之一,項目 github:https://github.com/xenv/S-mall-ssh 本文代碼大部分在 gith

SpringVC 攔截器+定義註解 實現權限攔截

json.js 加載 bean media tar attr esp 權限 encoding 1.springmvc配置文件中配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://w

ssm springaop 定義註解日誌資料到資料庫

弄得過程中出現過好多問題。(報錯時候切入方法不正常執行,) 1、需要導的包:slf4j-log4j12-1.6.2.jar  slf4j-api-1.6.2.jar  (這兩個jar包版本最好保持一致,之前我使用不同版本報錯) aspectjweaver-1.6

springboot AOP 實現日誌管理

本文使用註解進行spring AOP的實現。 1.AOP的基本概念 (1)Aspect(切面):通常是一個類,裡面可以定義切入點和通知 (2)JointPoint(連線點):程式執行過程中明確的點,一般是方法的呼叫 (3)Advice(通知):AOP在特定的切入點上執