aop 实现Java日志功能

aop 是一个强大的..,思路很简单,就是在进入到一个方法时,获取到进入前,中,后,环绕。这四个状态时的这个方法的属性。我们可以利用它来实现日志功能,可以保证日志模块到业务代码最小化的侵入(就只有一个注解)。在请求每次进到一个controller时,获取到它的请求方法,用户信息,异常等信息记录到数据库里。

1.第一步 自定义一个@Log注解,标记到你要记录日志的controller上面。我的注解有三个参数,分别是事件类型,操作类型,描述。可以在切面里面获取到他们分别标记在控制层上面的值。


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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    String eventType() default "";
    String operationType() default "";
    String description() default "";
    
}

2.第二部 标记到你要记录日志的controller上面,如下,参数可以自定义内容,在切面里面获取。

    /**
	 * @Title gettq
	 * @Date 2019年8月7日 上午11:25:55
	 * @author liunn
	 * @Description 天气
	 * @param request
	 * @param entity
	 * @return
	 * @throws Exception
	 */
	@Log(eventType="1",operationType="3",description="天气")
	@RequestMapping(value = "/gettq", method = { RequestMethod.POST })
	public @ResponseBody JSONObject gettq(HttpServletRequest request,
			@ModelAttribute(" entity ") Entity entity) throws Exception {

	}


3.第三步,切面获取值,写入到数据库中

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
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.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.sgcc.zcqsm.reshandover.annotation.Log;
import com.sgcc.zcqsm.reshandover.config.AppProperties;
import com.sgcc.zcqsm.reshandover.entity.PageEntity;
import com.sgcc.zcqsm.reshandover.service.IWebsService;
import com.sgcc.zcqsm.reshandover.service.LogService;
import com.sgcc.zcqsm.reshandover.util.DataUtil;
import com.sgcc.zcqsm.reshandover.util.ResponseInfo;
import com.sgcc.zcqsm.util.ContextHolderUtils;
import com.sgcc.zcqsm.util.JsonUtil;
import com.sgcc.zcqsm.util.ToolUtil;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Aspect
@Order(5)
@Component
@EnableConfigurationProperties(AppProperties.class)
public class LogAspect {
//	private Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	@Autowired
	private RedisTemplate<Object,Object> redisTemplate;
	@Autowired
	private LogService logService;	
	@Autowired
	private IWebsService iWebsService;
	@Autowired
    ObjectMapper objectMapper;
	@Autowired
	private AppProperties appProperties;
	private ThreadLocal<Date> startTime = new ThreadLocal<Date>();
	
	@Pointcut("@annotation(com.sgcc.zcqsm.reshandover.annotation.Log)") 
	public void pointcut() {

    }
	
    /**
     * 前置通知,在Controller层操作前拦截
     *
     * @param joinPoint 切入点
     */
    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) {
  //  	logger.info("进入["+joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()+"]方法里面");
        // 获取当前调用时间
        startTime.set(new Date());
    }

    /**
     * 正常情况返回
     *
     * @param joinPoint 切入点
     * @param rvt       正常结果
     */
    @AfterReturning(pointcut = "pointcut()")
    public void doAfter(JoinPoint joinPoint) throws Exception {
    	//1正常
//    	logger.info("退出["+joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()+"]方法");
        handleLog(joinPoint, null,1);
    }

    /**
     * 异常信息拦截
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) throws Exception {
    	//0 失败
 //   	logger.info("退出["+joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()+"]方法");
        handleLog(joinPoint, e,0);
    }
    
    @Async
    private void handleLog(final JoinPoint joinPoint, final Exception e,int eventResultCode) throws Exception{
        if(isOpen()) {
    	// 获得注解
        Method method = getMethod(joinPoint);
        Log log = getAnnotationLog(method);
        if (log == null) {
            return;
        }
      
        HttpServletRequest request = ToolUtil.getRequest();
        String lrrName=request.getHeader("userId");
//        Date now = new Date();
//        // 操作数据库日志表
//        ErpLog erpLog = new ErpLog();
//        erpLog.setErrorCode(0);
//        erpLog.setIsDeleted(0);
//        // 请求信息        
//        erpLog.setType(ToolUtil.isAjaxRequest(request) ? "Ajax请求" : "普通请求");
//        erpLog.setTitle(log.value());
//        erpLog.setHost(request.getRemoteHost());
//        erpLog.setUri(request.getRequestURI().toString());
        erpLog.setHeader(request.getHeader(HttpHeaders.USER_AGENT));
//        erpLog.setHttpMethod(request.getMethod());
//        erpLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//        
//        
//        // 请求的方法参数值
//        Object[] args = joinPoint.getArgs();
//        // 请求的方法参数名称
//        LocalVariableTableParameterNameDiscoverer u= new LocalVariableTableParameterNameDiscoverer();
//        String[] paramNames = u.getParameterNames(method);
//        if (args != null && paramNames != null) {
//            StringBuilder params = new StringBuilder();
//            params = handleParams(params, args, Arrays.asList(paramNames));
//            erpLog.setParams(params.toString());
//        }
//        String retString = JsonUtil.bean2Json(rvt);
//        erpLog.setResponseValue(retString.length() > 5000 ? JsonUtil.bean2Json("请求参数数据过长不与显示") : retString);
//        if (e != null) {
//            erpLog.setErrorCode(1);
//            erpLog.setErrorMessage(e.getMessage());
//        }
//        Date stime = startTime.get();
//        erpLog.setStartTime(stime);
//        erpLog.setEndTime(now);
//        erpLog.setExecuteTime(now.getTime() - stime.getTime());
//        erpLog.setUsername(MySysUser.loginName());
//        HashMap<String, String> browserMap = ToolUtil.getOsAndBrowserInfo(request);
//        erpLog.setOperatingSystem(browserMap.get("os"));
//        erpLog.setBrower(browserMap.get("browser"));
//        erpLog.setId(IdUtil.simpleUUID());
//        logService.insertSelective(erpLog);
        if (e != null) {
        	iWebsService.saveCwrz(DataUtil.returnExceptionLx(e), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), "程序报错:"+DataUtil.returnExceptionInfo(e), lrrName);
        }
        //日志信息记录到数据库中
        logService.saveLog(lrrName, Integer.parseInt(log.eventType()), Integer.parseInt(log.operationType()),eventResultCode, log.description(),request.getRemoteAddr());
    }
    } 
    
    /**
     * 是否存在注解,如果存在就获取
     */
    private Log getAnnotationLog(Method method) {
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }

    private Method getMethod(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method;
        }
        return null;
    }

    private StringBuilder handleParams(StringBuilder params, Object[] args, List paramNames) throws JsonProcessingException {
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof Map) {
                Set set = ((Map) args[i]).keySet();
                List list = new ArrayList();
                List paramList = new ArrayList<>();
                for (Object key : set) {
                    list.add(((Map) args[i]).get(key));
                    paramList.add(key);
                }
                return handleParams(params, list.toArray(), paramList);
            } else {
                if (args[i] instanceof Serializable) {
                    Class<?> aClass = args[i].getClass();
                    try {
                        aClass.getDeclaredMethod("toString", new Class[]{null});
                        // 如果不抛出NoSuchMethodException 异常则存在 toString 方法 ,安全的writeValueAsString ,否则 走 Object的 toString方法
                        params.append("  ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i]));
                    } catch (NoSuchMethodException e) {
                        params.append("  ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i].toString()));
                    }
                } else if (args[i] instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) args[i];
                    params.append("  ").append(paramNames.get(i)).append(": ").append(file.getName());
                } else {
                    params.append("  ").append(paramNames.get(i)).append(": ").append(args[i]);
                }
            }
        }
        return params;
    }
    
    
    private boolean isOpen() {
    	String logOpen=appProperties.getLogOpen();
    	if(getRedis("requestPrivateKey")==null||getRedis("requestPrivateKey")=="") {
    		String requestPrivateKey =appProperties.getFilterPwd();
    		setRedis("requestPrivateKey",requestPrivateKey);
    	}
    	if(getRedis("SessionOutTimeStr")==null||getRedis("SessionOutTimeStr")=="") {
    		 String SessionOutTimeStr =appProperties.getSessionOutTime();
    		setRedis("SessionOutTimeStr",SessionOutTimeStr);
    	}

    	if(logOpen.equals("true")) {
    		return true;
    	}else {
    		return false;
    	}
    }
	private void setRedis(String rkey,Object ObjectStr) {

		redisTemplate.opsForValue().set(rkey, ObjectStr, 1L, TimeUnit.DAYS);

	
	}
	private Object getRedis(String rkey) {
		
		Object rObject =redisTemplate.opsForValue().get(rkey);
	
		return rObject;		
	}
    
}

这里面 需要注意的是

    @Pointcut("@annotation(com.sgcc.zcqsm.reshandover.annotation.Log)") 

这个注解的值是Log自定义注解的位置,也就是它的包名加类名。

handleLog这个方法是实现日志写入数据库的地方,可以根据实际情况写日志属性。这里面分别对应异常日志,和业务日志。

这时候,日志就实现了。至于怎么写入数据库,持久层。这个简单,不会的话自行百度。

AppProperties是一个自定义的配置文件类。这个也不难。里面配置是否开启日志。sm2公钥。会话超时。


import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Configuration
@ConfigurationProperties(prefix = "app", ignoreInvalidFields = false)
@PropertySource("classpath:app.properties")
@Component
public class AppProperties {
	private String logOpen;
	private String sessionOutTime;
	private String filterPwd;
	public String getLogOpen() {
		return logOpen;
	}

	public void setLogOpen(String logOpen) {
		this.logOpen = logOpen;
	}

	public String getSessionOutTime() {
		return sessionOutTime;
	}

	public void setSessionOutTime(String sessionOutTime) {
		this.sessionOutTime = sessionOutTime;
	}

	public String getFilterPwd() {
		return filterPwd;
	}

	public void setFilterPwd(String filterPwd) {
		this.filterPwd = filterPwd;
	}
	
}

app.properties 

app.logOpen=true
app.sessionOutTime=30
app.filterPwd=216c9f564c4b1891864b4b35d05db181864832802f6addf95e7651d28a988184

这里面有一些工具类。我把他们粘贴出来。


import com.google.common.collect.Maps;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;

public class ToolUtil {

    /**
     * 获取客户端的ip信息
     *
     * @param request
     * @return
     */
    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
     
        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknow".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
       
        return ip;
    }

    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

    /**
     * 获取request
     */
    public static HttpServletRequest getRequest() {
        return getRequestAttributes().getRequest();
    }

    /**
     * 获取response
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }

    /**
     * 获取session
     */
    public static HttpSession getSession() {
        return getRequest().getSession();
    }

    /**
     * 是否是Ajax异步请求
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.indexOf("application/json") != -1) {
            return true;
        }
        String xRequestedWith = request.getHeader("X-Requested-With");
        if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
            return true;
        }
        String uri = request.getRequestURI();
        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
            return true;
        }
        String ajax = request.getParameter("__ajax");
        if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
            return true;
        }
        return false;
    }

    /**
     * 获取操作系统,浏览器及浏览器版本信息
     *
     * @param request
     * @return
     */
    public static HashMap<String, String> getOsAndBrowserInfo(HttpServletRequest request) {
        HashMap<String, String> map = Maps.newHashMap();
        String browserDetails = request.getHeader("User-Agent");
        String userAgent = browserDetails;
        String user = userAgent.toLowerCase();

        String os = "";
        String browser = "";

        //=================OS Info=======================
        if (userAgent.toLowerCase().contains("windows")) {
            os = "Windows";
        } else if (userAgent.toLowerCase().contains("mac")) {
            os = "Mac";
        } else if (userAgent.toLowerCase().contains("x11")) {
            os = "Unix";
        } else if (userAgent.toLowerCase().contains("android")) {
            os = "Android";
        } else if (userAgent.toLowerCase().contains("iphone")) {
            os = "IPhone";
        } else {
            os = "UnKnown, More-Info: " + userAgent;
        }
        //===============Browser===========================
        if (user.contains("edge")) {
            browser = (userAgent.substring(userAgent.indexOf("Edge")).split(" ")[0]).replace("/", "-");
        } else if (user.contains("msie")) {
            String substring = userAgent.substring(userAgent.indexOf("MSIE")).split(";")[0];
            browser = substring.split(" ")[0].replace("MSIE", "IE") + "-" + substring.split(" ")[1];
        } else if (user.contains("safari") && user.contains("version")) {
            browser = (userAgent.substring(userAgent.indexOf("Safari")).split(" ")[0]).split("/")[0]
                    + "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
        } else if (user.contains("opr") || user.contains("opera")) {
            if (user.contains("opera")) {
                browser = (userAgent.substring(userAgent.indexOf("Opera")).split(" ")[0]).split("/")[0]
                        + "-" + (userAgent.substring(userAgent.indexOf("Version")).split(" ")[0]).split("/")[1];
            } else if (user.contains("opr")) {
                browser = ((userAgent.substring(userAgent.indexOf("OPR")).split(" ")[0]).replace("/", "-"))
                        .replace("OPR", "Opera");
            }

        } else if (user.contains("chrome")) {
            browser = (userAgent.substring(userAgent.indexOf("Chrome")).split(" ")[0]).replace("/", "-");
        } else if ((user.contains("mozilla/7.0")) || (user.contains("netscape6")) ||
                (user.contains("mozilla/4.7")) || (user.contains("mozilla/4.78")) ||
                (user.contains("mozilla/4.08")) || (user.contains("mozilla/3"))) {
            browser = "Netscape-?";

        } else if (user.contains("firefox")) {
            browser = (userAgent.substring(userAgent.indexOf("Firefox")).split(" ")[0]).replace("/", "-");
        } else if (user.contains("rv")) {
            String IEVersion = (userAgent.substring(userAgent.indexOf("rv")).split(" ")[0]).replace("rv:", "-");
            browser = "IE" + IEVersion.substring(0, IEVersion.length() - 1);
        } else {
            browser = "UnKnown, More-Info: " + userAgent;
        }
        map.put("os", os);
        map.put("browser", browser);
        return map;
    }
}

猜你喜欢

转载自blog.csdn.net/liuno0/article/details/110518290
今日推荐