1. 程式人生 > >Spring註解實現日誌記錄

Spring註解實現日誌記錄

之前總結寫了一篇通過XML配置的方式,切面程式設計實現日誌記錄的功能demo

http://blog.csdn.net/weiweiai123456/article/details/38561085

可參考http://blog.csdn.net/heirenheiren/article/details/36634497 ,講的是註解實現

現在實現一個通過註解方式實現的樣例:

一:準備

xml中需要開啟CGLIB動態代理

<!-- 啟用CGliB -->
	<aop:aspectj-autoproxy proxy-target-class="true"/>
切面程式設計----AOP,依賴的是代理,即JDK代理和CGLIB代理,而代理的實現依靠的是反射。

maven配置省...

二:註解類

SaveSysLog.java

package com.cooya.partner.metadata.entity.baseConfig;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 * Description: 儲存系統日誌註解介面
 *
 * @author suoww
 * @date 2017-2-8
 *
 */
@Retention(RetentionPolicy.RUNTIME)  //註解會在class中存在,執行時可通過反射獲取
@Target(ElementType.METHOD) //註解到方法
public @interface SaveSysLog {

    //呼叫方      1:嗨賺客戶端   2:支付寶   3:微信       4:錢寶     5:其他第三方
    int send() default 1; 
    
    //介面url(從二級目錄記起)
    String url();
    
    //介面型別(前臺,後臺)
    int type();
}
定義三個成員,這裡只能定義八種基本資料型別,分別是


byte-->Byte

short-->Short

int-->Integer

long-->Long

float-->Float

double-->Double

char-->Character

boolean-->Boolean

注意:只能是上述這些8種類型的變數

三:切面類

SysLogAspect.java

package com.cooya.partner.service.baseConfig;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;
import com.cooya.partner.constant.InterfaceTypeConst;
import com.cooya.partner.metadata.entity.baseConfig.PartnerSystemLog;
import com.cooya.partner.metadata.entity.baseConfig.SaveSysLog;
import com.cooya.partner.metadata.entity.user.PartnerUser;
import com.cooya.partner.metadata.mapper.baseConfig.PartnerSystemLogMapper;
import com.cooya.partner.permission.dto.ShiroUser;

/**
 * 
 * Description: 切面類記錄介面呼叫失敗日誌資訊
 *
 * @author suoww
 * @date 2017-2-8
 *
 */
@Aspect
@Component
public class SysLogAspect {
    
    public static final int CODE_SUCCESS = 0;
    
    private Logger logger = LoggerFactory.getLogger(SysLogAspect.class);
    
    @Resource
    private PartnerSystemLogMapper partnerSystemLogMapper;
    
    /**
     * 
     * Description: 定義切點名controllerAspect,此方法需要為空,只是標識切點和切面關係
     *
     * @author suoww
     * @date 2017-2-8
     */
    @Pointcut("@annotation(com.cooya.partner.metadata.entity.baseConfig.SaveSysLog)")
    public void controllerAspect(){}
    
    /**
     * 
     * Description:織入後增強 
     *
     * @param join
     * @author suoww
     * @throws Exception 
     * @date 2017-2-8
     */
    @AfterReturning(pointcut = "controllerAspect()", returning = "res")
    public void doAfter(JoinPoint joinPoint, Object res) throws Exception{
        //獲取反射引數
        logger.debug("---------------AfterReturning開始--------------");
        if(null == res){
            return;
        }
        Map<String, Object> map = Obj2Map(res);
        int code = (Integer)map.get("code");
        if(code == CODE_SUCCESS){
            return;
        }
        String message = (String)map.get("message");
        //類名
        String targetName = joinPoint.getTarget().getClass().getSimpleName();
        //得到方法名
        String methodName = joinPoint.getSignature().getName();
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        //入參key
        String[] parameterNames = ms.getParameterNames();
        //入參value
        Object[] arguments = joinPoint.getArgs();
        Method method = ms.getMethod();
        //方法的註解物件
        SaveSysLog logParam = method.getAnnotation(SaveSysLog.class);  
        /* logger.debug("SaveSysLog註解引數send:" + logParam.send());  
        logger.debug("SaveSysLog註解引數url:" + logParam.url()); 
        logger.debug("SaveSysLog註解引數type:" + logParam.type()); 
        logger.debug("targetName:" + targetName);
        logger.debug("methodName:" + methodName);
        logger.debug("ms:" + ms);
        logger.debug("arguments:" + JSONObject.toJSONString(arguments));
        logger.debug("parameterNames:" + JSONObject.toJSONString(parameterNames));
        logger.debug("method:" + JSONObject.toJSONString(method));*/
        
        //拼引數
        PartnerSystemLog sysLog = new PartnerSystemLog(); 
        //獲取使用者
        if(logParam.type() == InterfaceTypeConst.InterfaceType.APP){
            sysLog.setUserId(getAppUserId());
        }else{
            sysLog.setUserId(getMgrUserId());
        }
        sysLog.setSend(logParam.send());
        sysLog.setUrl(logParam.url());
        sysLog.setType(logParam.type());
        //入參字串
        StringBuffer jsonParamSb = new StringBuffer();
        for(int i = 0;i < parameterNames.length;i++){
            jsonParamSb.append(parameterNames[i]).append("=").append(JSONObject.toJSONString(arguments[i]));
            if(i != (parameterNames.length - 1)){
                jsonParamSb.append("&");
            }
        }
        //擷取返回json
        if(jsonParamSb.toString().length() <= 1000){
            sysLog.setJsonParam(jsonParamSb.toString());
        }else{
            sysLog.setJsonParam(jsonParamSb.toString().substring(0, 1000));
        }
        //出參
        sysLog.setJsonResult(JSONObject.toJSONString(res));
        StringBuffer remarkSb = new StringBuffer();
        remarkSb.append(targetName).append(".").append(methodName).append("報錯資訊:").append(message);
        //擷取remark
        if(remarkSb.toString().length() <= 1000){
            sysLog.setRemark(remarkSb.toString());
        }else{
            sysLog.setRemark(remarkSb.toString().substring(0, 1000)); 
        }
        sysLog.setCreateTime(new Date());
        sysLog.setUpdateTime(new Date());
        handleLog(sysLog);
        logger.debug("---------------AfterReturning結束--------------");
    }
    
    /**
     * 
     * Description: 非同步記錄介面呼叫失敗的日誌
     *
     * @param systemLog
     * @author suoww
     * @date 2017-2-8
     */
    @Async
    public void handleLog(PartnerSystemLog sysLog){
        //寫日誌
        int row = partnerSystemLogMapper.insertSelective(sysLog);
        logger.debug("------日誌寫入行數:" + row);
    } 
    
    /**
     * 
     * Description: 物件轉map
     *
     * @param obj
     * @return
     * @throws Exception
     * @author suoww
     * @date 2017-2-8
     */
    public Map<String,Object> Obj2Map(Object obj) throws Exception{
        Map<String,Object> map=new HashMap<String, Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }
    
    /**
     * 
     * Description: 獲取APP使用者ID
     *
     * @return
     * @author suoww
     * @date 2017-2-8
     */
    protected Long getAppUserId() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        if (null == session) {
            return null;
        }
        PartnerUser user = (PartnerUser) session.getAttribute("userInfo");
        if (null == user) {
            return null;
        }
        return user.getId();
    }
    
    /**
     * 
     * Description: 獲取Mgr的使用者ID
     *
     * @return
     * @author suoww
     * @date 2017-2-8
     */
    protected Long getMgrUserId(){
        ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
        return user.getId();
    }
}


@Aspect和@Component分別表示這是一個切面類、Spring要幫我例項化物件並管理


@Pointcut(XX) :使用SaveSysLog作為註解(annotation)的將作為切點,對應切面controllerAspect


[email protected] 表示切點後增強,即切入點的方法執行結束後,即執行切面中的增強程式碼,但是不會改變原切入點方法返回值。下面具體說明

2.pointcut="controllerAspect()" ,returning="res" 表示切點和切面對應關係,一個方法上可以有多個切面,指定順序

參考:http://blog.csdn.net/rainbow702/article/details/52185827

3.下面的是反射獲取的引數,類名,方法名,入參key,引數value,註解物件,方法返回值

四:呼叫

controller中呼叫

 /**
     * 
     * Description: 介面:查詢場次下商品
     *
     * @param channelId
     * @return
     * @author suoww
     * @date 2017-1-13
     */
    @RequestMapping("/queryGoodsUnderChannel")
    @ResponseBody
    @SaveSysLog(send=InterfaceTypeConst.SendType.HZ, url="/goods/api/queryGoodsUnderChannel.html", type=InterfaceTypeConst.InterfaceType.APP)
    public AjaxResult queryGoodsUnderChannel(@RequestParam(value = "channelId", required = true)Long channelId){
        try{
            List<PartnerChannelGoodsDto> list = partnerGoods2ChannelService.getChannelGoodsDto(channelId);
            logger.info("根據channelId:" + channelId + "獲取到的商品集合為" + JSONObject.toJSONString(list));
            return AjaxResult.success(list, "成功獲取頻道下商品");
        }catch(ResultCodeException e){
            e.printStackTrace();
            return AjaxResult.failed("校驗失敗:" + e.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            return AjaxResult.failed("系統異常:" + e.getMessage());
        }
    }

@SaveSysLog(send=InterfaceTypeConst.SendType.HZ, url="/goods/api/queryGoodsUnderChannel.html", type=InterfaceTypeConst.InterfaceType.APP)

這裡對應註解介面三個成員,send,url,type

queryGoodsUnderChannel 這個方法將整體作為一個切入點,結合@AfterReturning 在queryGoodsUnderChannel ()執行結束會,會進入到SysLogAspect.doAfter 執行一段程式碼,記錄日誌

五:測試

輸入http://localhost:8080/partner-app/goods/api/queryGoodsUnderChannel.html?channelId=17


  入參中channelId=17


引數可以對應。

總結:許可權控制,日誌記錄應該使用AOP,註解方式實際使用時候比XML配置方式要省事很多。

相關推薦

Spring註解實現日誌記錄

之前總結寫了一篇通過XML配置的方式,切面程式設計實現日誌記錄的功能demo http://blog.csdn.net/weiweiai123456/article/details/38561085 可參考http://blog.csdn.net/heirenheiren/

Spring Aop+註解實現日誌記錄

系統業務操作日誌記錄是每個系統必不可少的一部分,但通常的做法是在每個需要記錄日誌的地方,呼叫新增日誌的Service方法,這樣做主要是顯的麻煩。 我們可以使用Spring AOP結合註解來實現這一功能。 1、首先定義一個註解類,如下: @Target(

使用自定義註解+Spring AOP 實現日誌記錄

使用自定義註解+Spring切面 實現日誌記錄 在平常的專案程式設計中,我們會經常使用到日誌,用來記錄各種事件.但是,有些日誌記錄套路實在是太像了,我們不得不要寫很多遍. 比如在Spring中,我們要使用日誌記錄每個controller的訪問和結束時間,該怎

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

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

Spring AOP實現日誌記錄(Aspect)

一、Aop術語 切面(Aspect):在Spring AOP中,切面可以使用通用類或者在普通類中以@Aspect 註解(@AspectJ風格)來實現 連線點(Joinpoint):在Spring AOP中一個連線點代表一個方法的執行 通知(Advice):在切面的某個特定的連線點(Joinp

java動態代理詳解,並用動態代理和註解實現日誌記錄功能

動態代理的概念       動態代理是程式在執行過程中自動建立一個代理物件來代替被代理的物件去執行相應的操作,例如, 我們有一個已經投入執行的專案中有一個使用者DAO類UserDao用來對User物件進行資料庫的增刪改查操作,但是有一天,要求在對使用者的增刪改查操作時記錄相

使用Spring Aop自定義註解實現自動記錄日誌

百度加自己琢磨,以下親測有效,所以寫下來記錄,也方便自己回顧瀏覽加深印象之類,有什麼問題可以評論一起解決,不完整之處也請大佬指正,一起進步哈哈(1)首先配置檔案: <!-- 宣告自動為spring容器中配置@aspectj切面的bean建立代理 ,織入切面 --> <aop:

Spring Boot自定義註解+AOP實現日誌記錄

訪問Controller列印的日誌效果如下:*********************************Request請求*************************************** ClassName : com.xxx.app.xxx.a

spring Aspect 實現自定義註解日誌記錄,有時候註解類不起作用的原因分析

使用只要在controller的method上加上@ActionLog(actionGroup = "freeorder",actionType = "update",actionDesc = "操作",insertDb = true)其中insertDb 代表是否插入資料

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

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

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

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

spring 自定義註解實現日誌統一處理

需求:通過註解的方式 統一處理controller和service的日誌(實現上可能不太嚴謹,主要是實現流程)原理:先自定義註解。用aop切面攔截方法的使用,看是否有對應的自定義的註解,如果有,在切面中進行日誌的統一列印,可以獲取到加了註解方法的類名、方法名、引數。如果想每個

Spring MVC使用攔截器實現日誌記錄

spring記錄日誌有兩種,一種是通過AOP,另一種是通過攔截器interceptor,這裡選擇的是攔截器interceptor:  一、Interceptor實現類 SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來

spring boot集成aop實現日誌記錄

dst info pen reads image joinpoint 容器 asp call 1、pom依賴 <dependency> <groupId>org.springframework.boot</groupId&

python內置函數print輸出到文件,實現日誌記錄的功能

imp inpu 函數 rgs print top args txt war # bulid time 2018-6-22 import os import time def log(*args, **kwargs): # *kargs 為了通用 可不傳 ru

C#實現日誌記錄 支援按日期多檔案儲存

日誌記錄類LogHelper,支援按照日期儲存,儲存的資訊帶時間資訊,具體的日誌內容如下: 2016-12-08 23:56:45:787 [Notice]sadfsafasfffffffffffffffffffffffffffffffffffffffff 2016-12-08 2

Spring註解實現原理

先來說說註解是什麼: 註解顧名思義,就是類似於添加註釋,但是又不跟註釋完全一樣,因此,我們可以將它理解為將類或者方法與特定的資訊進行關聯。 那麼註解如何實現? 1、介面使用@interface定義。 2、通過繼承以下註解,實現功能:  元註解@Target,@Ret

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

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

spring註解 實現一個介面多個實現類的區分

相應的包 import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired

AOP之獲取Controller請求(Request)、返回(Response)引數、報錯資訊實現日誌記錄

需求:為系統中所有的提交,修改,刪除等等操作(除查詢以外的所有操作)做日誌記錄,記錄的內容包括:請求引數,返回引數,如果報錯就儲存報錯資訊。日誌要新增一個日誌型別。 方案:最好的選擇就是用註解標記切點,用AOP實現此需求。 一、準備 版本: J