1. 程式人生 > >Spring_AOP 記錄系統關鍵操作日誌用法

Spring_AOP 記錄系統關鍵操作日誌用法

解決 ati rgs pad tope reads 匿名 ava syslog

問題:

  系統需要記錄用戶的關鍵操作日誌,以便後期的系統維護,方便的查看問題,及時排除

分析:

  (1)保存字段:作為一個日誌記錄功能,首先數據庫新建一張表保存用戶的操作關鍵字段,

          用戶名,ip,操作描述,時間,日誌id

  (2)采用技術:

      第一種:新建一個日誌業務實現,在操作發生時進行聯動

          缺點是耦合太緊密,無用代碼增多,後期代碼臃腫,改動時地方分散,不利於維護

      第二種:使用spring 的 aop 技術進行切面切入

          由於本身系統結構不規範,參數,方法名沒有一致的樣式,使用正則匹配方法名不是很方便

          本身日誌記錄也只是記錄關鍵操作,api全部切入的話,就不需要這個功能了

          必須有針對性的記錄關鍵操作日誌

      第三種:使用spring 的 aop 技術切到自定義註解上,針對不同註解標誌進行參數解析,記錄日誌

          缺點是要針對每個不同的註解標誌進行分別取註解標誌,獲取參數進行日誌記錄輸出

         

解決:

  由於本身系統的不規範,個人技術能力的欠缺,目前采用第三種辦法進行關鍵日誌的記錄

  (1)首先新建 註解類【MethodLog】

package org.triber.portal.service.logAop;

import java.lang.annotation.*;

/**
 * 日誌切面註解
 
*/ @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MethodLog { String remark() default ""; String operType() default "0"; // String desc() default ""; }

  (2)新建切面實現類【LogService】

package org.triber.portal.service.logAop;

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.triber.common.helper.StringUtil; import org.triber.common.helper.UserUtil; import org.triber.common.model.menu.MenuModel; import org.triber.common.model.user.User; import org.triber.portal.dao.mapper.operateLog.OperateLogMapper; import org.triber.portal.model.area.Area; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Calendar; /** * 日誌切面實現 */ @Component @Aspect public class LogService { @Autowired private OperateLogMapper dao; public LogService() { System.out.println("Aop"); } /** * 切點 */ @Pointcut("@annotation(org.triber.portal.service.logAop.MethodLog)") public void methodCachePointcut() { } /** * 切面 * * @param point * @return * @throws Throwable */ @Around("methodCachePointcut()") public Object around(ProceedingJoinPoint point) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E"); Calendar ca = Calendar.getInstance(); String operDate = df.format(ca.getTime()); String ip = getIp(request); User user = UserUtil.getCurrentUser(request); String loginName; String name; if (user != null) { loginName = user.getLoginName(); } else { loginName = "匿名用戶"; } String methodRemark = getMthodRemark(point); String methodName = point.getSignature().getName(); String packages = point.getThis().getClass().getName(); if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 如果是CGLIB動態生成的類 try { packages = packages.substring(0, packages.indexOf("$$")); } catch (Exception ex) { ex.printStackTrace(); } } String operatingcontent = ""; Object[] method_param = null; Object object; try { method_param = point.getArgs(); //獲取方法參數 // String param=(String) point.proceed(point.getArgs()); object = point.proceed(); } catch (Exception e) { // 異常處理記錄日誌..log.error(e); throw e; } Syslog sysLog = new Syslog(); sysLog.setOptId(org.triber.common.util.StringUtil.getRandNum(11)); sysLog.setLoginId(user.getLoginId()); sysLog.setLoginName(loginName); sysLog.setIpAddress(ip); sysLog.setMethodName(packages + "." + methodName); sysLog.setMethodRemark(methodRemark); sysLog.setOptDate(operDate); /** * 用戶操作 */ if("新增用戶".equals(methodRemark)){ HttpServletRequest req = (HttpServletRequest) method_param[0]; sysLog.setOperatingcontent("新增用戶: 用戶名為 " + req.getParameter("userName")); } if("刪除用戶".equals(methodRemark)){ String loginId = (String) method_param[1]; sysLog.setOperatingcontent("刪除用戶: 用戶id為 " + loginId); } if("修改用戶".equals(methodRemark)){ HttpServletRequest req = (HttpServletRequest) method_param[0]; sysLog.setOperatingcontent("修改用戶: 用戶名為 " + req.getParameter("loginName")); } /** * 角色操作 */ if("新增角色".equals(methodRemark)){ HttpServletRequest req = (HttpServletRequest) method_param[0]; sysLog.setOperatingcontent("新增角色: 角色名為 " + req.getParameter("roleDesc")); } if("刪除角色".equals(methodRemark)){ String roleId = (String) method_param[1]; sysLog.setOperatingcontent("新增角色: 角色id為 " + roleId); } if("修改角色".equals(methodRemark)){ HttpServletRequest req = (HttpServletRequest) method_param[0]; sysLog.setOperatingcontent("修改角色: 角色名為 " + req.getParameter("roleDesc")); } /** * 菜單操作 */ if("新增菜單".equals(methodRemark)){ MenuModel menuModel = (MenuModel) method_param[0]; sysLog.setOperatingcontent("新增菜單: 菜單名為 " + menuModel.getMenuName()); } if("刪除菜單".equals(methodRemark)){ String menuId = (String) method_param[0]; sysLog.setOperatingcontent("刪除菜單: 菜單id為 " + menuId); } if("修改菜單".equals(methodRemark)){ MenuModel menuModel = (MenuModel) method_param[0]; sysLog.setOperatingcontent("修改菜單: 菜單名為 " + menuModel.getMenuName()); } /** * 部門操作 */ if("新增部門".equals(methodRemark)){ String deptDesc = (String) method_param[1]; sysLog.setOperatingcontent("新增部門: 部門名為 " + deptDesc); } if("修改部門".equals(methodRemark)){ String deptDesc = (String) method_param[2]; sysLog.setOperatingcontent("修改部門: 部門名為 " + deptDesc); } /** * 地區操作 */ if("新增地區".equals(methodRemark)){ Area area = (Area) method_param[0]; sysLog.setOperatingcontent("新增地區: 地區名為 " + area.getAreaDscr().trim()); } if("刪除地區".equals(methodRemark)){ String areaId = (String) method_param[0]; sysLog.setOperatingcontent("刪除地區: 地區id為 " + areaId); } if("修改地區".equals(methodRemark)){ Area area = (Area) method_param[0]; sysLog.setOperatingcontent("修改地區: 地區名為 " + area.getAreaDscr().trim()); } /** * 機構操作 */ if("新增機構".equals(methodRemark)){ String isAdd = (String) method_param[1]; if(isAdd.equals("1")){ String addOrgDscrPancy = (String) method_param[5]; sysLog.setOperatingcontent("新增機構: 機構名為 " + addOrgDscrPancy); }else{ String addOrgDscrPancy = (String) method_param[5]; sysLog.setOperatingcontent("修改機構: 機構名為 " + addOrgDscrPancy); } } if("刪除機構".equals(methodRemark)){ String orgId = (String) method_param[3]; sysLog.setOperatingcontent("刪除機構: 機構id為 " + orgId); } /** * 空參數 */ if("".equals(methodRemark) || null == methodRemark){ sysLog.setOperatingcontent("操作參數: " + method_param[0]); } dao.saveSysLog(sysLog); // System.out.println("日誌實體:"+sysLog.getLoginName()+sysLog.getMethodRemark()+sysLog.getOperatingcontent()); return object; } /** * 方法異常時調用 * * @param ex */ public void afterThrowing(Exception ex) { System.out.println("afterThrowing"); System.out.println(ex); } /** * 獲取方法中的中文備註 * * @param joinPoint * @return * @throws Exception */ public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] method = targetClass.getMethods(); String methode = ""; for (Method m : method) { if (m.getName().equals(methodName)) { Class[] tmpCs = m.getParameterTypes(); if (tmpCs.length == arguments.length) { MethodLog methodCache = m.getAnnotation(MethodLog.class); if (methodCache != null) { methode = methodCache.remark(); } break; } } } return methode; } /** * 獲取請求ip * * @param request * @return */ public static String getIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { int index = ip.indexOf(","); if (index != -1) { return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip.substring(0, index); } else { return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } } ip = request.getHeader("X-Real-IP"); if (StringUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { return ip; } return request.getRemoteAddr().equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } }

  (3)新建日誌實體【Syslog】

package org.triber.portal.service.logAop;

import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;

/**
 * 操作日誌實體類
 */
public class Syslog implements Serializable{

    @Setter@Getter private String optId;
    @Setter@Getter private String loginId;
    @Setter@Getter private String loginName;
    @Setter@Getter private String ipAddress;
    @Setter@Getter private String methodName;
    @Setter@Getter private String methodRemark;
    @Setter@Getter private String operatingcontent;
    @Setter@Getter private String optDate;
    //模糊條件
    @Setter@Getter private String serchCondition;
}

  (4)日誌切入【添加註解標誌即可】

 /**
     * 刪除金融機構
     * @param request
     * @param response
     * @param operateVersionId 機構版本
     * @param orgId 機構iD
     * @param orgLvl 機構層級
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "delOrgByFlagAndOrgId", method = RequestMethod.POST, produces = {"application/json"})
    @MethodLog(remark = "刪除機構")
    public String delOrgByFlagAndOrgId(HttpServletRequest request,
                                     HttpServletResponse response,
                                     @RequestParam(value = "operateVersionId", required = false) String operateVersionId,
                                     @RequestParam(value = "orgId", required = false) String orgId,
                                     @RequestParam(value = "orgLvl", required = false) String orgLvl) throws Exception{
        orgService.delOrgByFlagAndOrgId(areaIdPrefix,orgId, orgLvl, operateVersionId);
        return "0";
    }

  (5)maven註入aop依賴

<!--spring切面aop依賴-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

在application.properties文件裏加這樣一條配置
spring.aop.auto=true

在springboot項目裏加這兩條配置即可,就可以開啟aop功能

總結:

  至此,大功告成,可以開始加註解標誌,獲取參數,記錄關鍵信息,輸出日誌了。。。

  

Spring_AOP 記錄系統關鍵操作日誌用法