Spring 接口日志切片记录

1、注解

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

/**
 * @author 
 * @program 
 * @description 忽略统一响应注解定义
 * @packagename 
 * @date 
 **/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    /**
     * 模块
     */
    public String title() default "";
    public BusinessType businessType() default BusinessType.SELECT;
    /**
     * 是否保存请求的参数
     */
    public boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    public boolean isSaveResponseData() default true;

}

2、接口类型

public enum BusinessType {
    /**
     * 保存
     *
     */
    SAVE,
    /**
     * 删除
     *
     */
    DELETE,
    /**
     * 查询
     *
     */
    SELECT;


}

3、日志实体

@Data
@TableName("user_log")
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "用户日志", description = "用户日志")
public class UserLog implements Serializable {

    private static final long serialVersionUID = 1L;
    /**
     * 自增主键id
     */
    @TableId(value = "id", type = IdType.AUTO)
    @ApiModelProperty(value = "主键")
    private Long id;
    /**
     * 用户编号
     */
    @ApiModelProperty(value = "用户编号")
    private Long userNo;
    /**
     * 用户账号
     */
    @ApiModelProperty(value = "用户账号")
    private String userAccount;
    @ApiModelProperty(value = "客户端ID")
    private String clientId;
    /**
     * 用户名称
     */
    @ApiModelProperty(value = "用户名称")
    private String userName;
    /**
     * 操作方法
     */
    @ApiModelProperty(value = "操作方法")
    private String callMethod;
    /**
     * 操作结果
     */
    @ApiModelProperty(value = "操作结果")
    private String callResult;
    /**
     * 操作时间
     */
    @ApiModelProperty(value = "操作时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date operationTime;
    /**
     * 操作内容
     */
    @ApiModelProperty(value = "操作内容")
    private String operationContent;
    /**
     * 操作IP
     */
    @ApiModelProperty(value = "操作IP")
    private String operationIp;
    private String operationParam;
    private String operationResult;
    private String operationMsg;
    /**
     * 操作客户端
     */
    @ApiModelProperty(value = "操作客户端")
    private String operationClient;
    /**
     * 操作地理位置
     */
    @ApiModelProperty(value = "操作地理位置")
    private String operationAddress;
   
}

4、日志记录

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hierway.tool.utils.AddressUtils;
import com.hierway.tool.utils.RequestHeaderUtils;
import com.hierway.user.bo.OauthInfo;
import com.hierway.user.entity.UserLog;
import com.hierway.user.feign.IUserLogClient;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author 
 * @program 
 * @description 接口日志记录
 * @packagename 
 * @date 
 **/
@Aspect
@Component
@Slf4j
public class LogHandlerAspect {
    @Value("${spring.log-filter.enabled:true}")
    private Boolean enabled;
    @Value("${spring.log-filter.type:SAVE,DELETE}")
    private List filterType;
    @Resource
    private IUserLogClient userLogClient;
    private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 20, 60, TimeUnit.MINUTES,
            new SynchronousQueue(), new ThreadPoolExecutor.DiscardPolicy());
    /**
     * 切点
     */
    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
    {
        try {
            if(!enabled||!filterType.contains(controllerLog.businessType().toString())){
                return;
            }
            UserLog userLog = new UserLog();
            userLog.setOperationTime(new Date());
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            userLog.setCallMethod(className + "." + methodName);
            userLog.setOperationContent(controllerLog.title());
            // 是否需要保存request,参数和值
            if (controllerLog.isSaveRequestData())
            {
                userLog.setOperationParam("");
                // 获取参数的信息,传入到数据库中。
                Object[] params = joinPoint.getArgs();
                for (int i = 0; i < params.length; i++) {
                    Object param =  params[i];
                    userLog.setOperationParam(userLog.getOperationParam()+"参数"+i+":"+JSON.toJSONString(param)+";");
                }
            }
            // 是否需要保存response,参数和值
            if (controllerLog.isSaveResponseData() && jsonResult!=null)
            {
                userLog.setOperationResult(JSON.toJSONString(jsonResult));
            }

            userLog.setCallResult("成功");
            userLog.setOperationIp(RequestHeaderUtils.getIpAddr());
            userLog.setOperationClient(RequestHeaderUtils.getClient());
            userLog.setOperationAddress(AddressUtils.getAddresses(userLog.getOperationIp()));
            executor.execute(new Runnable() {
                @Override
                public void run() {
                  try {
                      userLogClient.create(userLog);
                  }catch (Exception ex){
                      log.error("保存用户日志失败",ex);
                  }

                }});
        }catch (Exception ex){
            log.error("请求日志失败",ex);
        }

    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e 异常
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
    {
        try {
            if(!enabled||!filterType.contains(controllerLog.businessType().toString())){
                return;
            }
        UserLog userLog = new UserLog();
        userLog.setOperationTime(new Date());
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        userLog.setCallMethod(className + "." + methodName);
        userLog.setOperationContent(controllerLog.title());
        // 是否需要保存request,参数和值
        if (controllerLog.isSaveRequestData())
        {
            userLog.setOperationParam("");
            // 获取参数的信息,传入到数据库中。
            Object[] params = joinPoint.getArgs();
            for (int i = 0; i < params.length; i++) {
                Object param =  params[i];
                userLog.setOperationParam(userLog.getOperationParam()+"参数"+i+":"+JSON.toJSONString(param)+";");
            }
        }
        userLog.setOperationMsg(e.getMessage());
      
        userLog.setCallResult("失败");
        userLog.setOperationIp(RequestHeaderUtils.getIpAddr());
        userLog.setOperationClient(RequestHeaderUtils.getClient());
        userLog.setOperationAddress(AddressUtils.getAddresses(userLog.getOperationIp()));
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    userLogClient.create(userLog);
                }catch (Exception ex){
                    log.error("保存用户日志失败",ex);
                }
            }});
        }catch (Exception ex){
            log.error("请求日志失败",ex);
        }
    }


}

5、请求头获取类

public class RequestHeaderUtils {

    public static String getClient(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String agent = request.getHeader("user-agent");
        StringTokenizer st = new StringTokenizer(agent,";");
        //得到用户的浏览器名
        st.nextToken();
        return agent;

    }

    public static String getIpAddr()
    {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if (request == null)
        {
            return null;
        }

        String ip = null;

        // X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
            // Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
            // WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
            // HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
            // X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        // 有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0)
        {
            ip = ipAddresses.split(",")[0];
        }

        // 还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
        {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
}

你可能感兴趣的:(java,spring,java,前端)