java怎么运用切面编程生成日志

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java怎么运用切面编程生成日志相关的知识,希望对你有一定的参考价值。

参考技术A 1.首先创建一个自定义注解拦截Controller类,代码如下
/**
* 自定义注解 拦截Controller
*/
@Target( ElementType.PARAMETER, ElementType.METHOD )
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLog
String desc() default "";//标示默认打印空

2.创建一个打印日志的切面类,引入切面注解@Aspect,
新建方法代码如下:
// Controller层切点
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void recordLog()

@Around("recordLog()")
public Object around(ProceedingJoinPoint pjp) throws Throwable
// ExPatternParser.initLogger();
long start = System.currentTimeMillis();
Object[] args = pjp.getArgs();
String remark = this.getControllerMethodDescription(pjp);
Object retVal = null;
try
retVal = pjp.proceed();
catch (Throwable e)
// TODO Auto-generated catch block
logger.error("请求失败" + e.toString(),e);
remark = remark + "。Exception Cause By " + e.toString();
throw e;
finally
long end = System.currentTimeMillis();
long cost = end - start;
//打印访问日志
// Controller中所有方法的参数,前两个分别为:Request,Response
if(args != null && args.length > 0)
Object o = args[0];
if(o instanceof HttpServletRequest)
HttpServletRequest request = (HttpServletRequest) args[0];
PrintLog.visit(request, cost,remark);



return retVal;

/**
* 获取注解中对方法的描述信息 用于Controller层注解
* @param joinPoint切点
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(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[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods)
if (method.getName().equals(methodName))
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length)
ControllerLog controllerLog = method.getAnnotation(ControllerLog.class);
if(controllerLog !=null)
description =
controllerLog.desc();


break;



return description;


3.然后在每个Controller类上加上注解:
@ControllerLog(desc = "要 打印的日志内容")
参考技术B 切面编程你说的是不是spring中的切面如果是这样的话就不需要用静态的了,直接配置一下就好了,或者直接在这个方法上面写注解也行本回答被提问者采纳

切面编程(操作日志)

自定义注解

import java.lang.annotation.*;
 
/**
 * @author wzm
 */
//注解会在class中存在,运行时可通过反射获取
@Retention(RetentionPolicy.RUNTIME)
//目标是方法
@Target({ElementType.METHOD, ElementType.PARAMETER})
//表示是否将注解信息添加在java文档中
@Documented
public @interface Log {
 
    //这个用户所做的是什么操作
    String value() default "未标注操作";
 
    /**
     * 1 2 3 4 / 增 删 改 查
     * 0 未设置
     * @return int
     */
    int type() default 0;
 
}
 

切面类

SysLogAspect.java

import com.thyc.fabric.annotation.Log;
import com.thyc.fabric.common.utils.IpUtil;
import com.thyc.fabric.entity.business.OperationLogger;
import com.thyc.fabric.service.business.OperationLoggerService;
import com.thyc.fabric.shiro.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
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 javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
 
/**
 * @author wzm
 */
@Aspect
@Component
@Slf4j
public class SysLogAspect {
 
    @Autowired
    private OperationLoggerService operationLoggerService;
 
    public SysLogAspect() {
    }
 
    private static OperationLogger operationLogger = new OperationLogger();
 
    /**
     * 注解切点
     */
    @Pointcut("@annotation(com.thyc.fabric.annotation.Log)")
    public void pointCut() {
    }
 
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjd) throws Throwable {
        Object object = null;
        try {
            // 开始执行时间
            long starTime = System.currentTimeMillis();
            object = pjd.proceed();
 
            // 获取request
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = null;
            if (servletRequestAttributes != null) {
                request = servletRequestAttributes.getRequest();
            }
            if (request != null) {
                // 通过token解析操作用户
                String token = (String) SecurityUtils.getSubject().getPrincipal();
                if (token != null) {
                    String username = JWTUtil.getUsername(token);
                    operationLogger.setCreator(username);
                }
                // 获取访问端(web android ios)
                operationLogger.setAccessType(request.getHeader("accessType"));
 
            }
            MethodSignature methodName1 = (MethodSignature) pjd.getSignature();
            Method method = methodName1.getMethod();
 
            //method方法上面的注解
            Annotation[] annotations = method.getAnnotations();
            boolean flag = false;
            for (Annotation annotation : annotations) {
                if (Log.class.equals(annotation.annotationType())) {
                    flag = true;
                }
            }
            if (flag) {
                // 类名
                String className = pjd.getTarget().getClass().getName();
                operationLogger.setLogClassName(className);
 
                // 操作描述
                String operation = method.getAnnotation(Log.class).value();
                operationLogger.setOperationContent(operation);
 
                // 操作类型
                Integer operationType = method.getAnnotation(Log.class).type();
                operationLogger.setOperationType(operationType);
 
                // ip地址
                String ip = IpUtil.getIp(request);
                operationLogger.setRemoteIpAddress(ip);
 
                // 城市信息
                String cityInfo = IpUtil.getCityInfo(ip);
                operationLogger.setCityInfo(cityInfo);
 
                // 设置方法名
                operationLogger.setLogMethodName(method.getName());
 
                Signature signature = pjd.getSignature();
                MethodSignature methodSignature = (MethodSignature) signature;
                String[] argNames = methodSignature.getParameterNames();
 
                // 如果有参数
                if (argNames.length > 0) {
                    // 参数名列表
                    List<String> paramNameList =
                            new ArrayList<>(Arrays.asList(methodSignature.getParameterNames()).subList(0, argNames.length));
 
                    // 参数类型
                    List<String> paramTypeList = new ArrayList<>();
                    Parameter[] parameters = method.getParameters();
                    for (Parameter parameter : parameters) {
                        String paramType = parameter.getType().getName();
                        paramTypeList.add(paramType);
                    }
 
                    // 参数的值
                    List<Object> paramValueList = new ArrayList<>();
                    Object[] params = pjd.getArgs();
                    Collections.addAll(paramValueList, params);
 
                    operationLogger.setParamsTypeList(paramTypeList.toString());
                    operationLogger.setParamsNameList(paramNameList.toString());
                    operationLogger.setParamsValueList(paramValueList.toString());
                } else {
                    // 没有参数的话就都设置为none
                    operationLogger.setParamsTypeList("none");
                    operationLogger.setParamsNameList("none");
                    operationLogger.setParamsValueList("none");
                }
            }
            // 设置异常信息
            operationLogger.setExceptionInfo(null);
 
            // 执行时间 = 执行结束时间 - 开始时间 (单位:毫秒)
            long execTime = System.currentTimeMillis() - starTime;
            operationLogger.setExecTime(String.valueOf(execTime));
        } catch (Exception e) {
            operationLogger.setExceptionInfo(e.getMessage());
            operationLoggerService.addLogger(operationLogger);
            throw e;
        }
        log.info("[" + operationLogger.getRemoteIpAddress() + "][" + operationLogger.getOperationContent() + "]["
                + operationLogger.getLogClassName() + " - " + operationLogger.getLogMethodName() + "]" + " - "
                + (StringUtils.isNotBlank(operationLogger.getExecTime()) ? operationLogger.getExecTime() : "0") + "ms");
 
        // 录入数据库
        operationLoggerService.addLogger(operationLogger);
        // 执行方法,获取返回参数
        return object;
    }
}

 

service层

OperationLoggerService.java
import com.baomidou.mybatisplus.service.IService;
import com.thyc.fabric.common.exception.BaseException;
import com.thyc.fabric.entity.business.OperationLogger;
 
/**
* 操作日志记录 Service层
*
* @author wzm
* @version 1.0
*/
public interface OperationLoggerService extends IService<OperationLogger> {
 
    /**
     * 添加日志(配置了aop切面)
     *
     * @param operationLogger log
     * @throws BaseException e
     */
    void addLogger(OperationLogger operationLogger) throws BaseException;
}
 
OperationLoggerServiceImpl.java
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.thyc.fabric.common.exception.BaseException;
import com.thyc.fabric.dao.business.OperationLoggerMapper;
import com.thyc.fabric.entity.business.OperationLogger;
import com.thyc.fabric.service.business.OperationLoggerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
import javax.annotation.Resource;
import java.util.Date;
 
/**
 * 操作日志记录 ServiceImpl层
 *
 * @author wzm
 * @version 1.0
 */
@Service
@Slf4j
public class OperationLoggerServiceImpl extends ServiceImpl<OperationLoggerMapper, OperationLogger> implements OperationLoggerService {
 
    @Resource
    private OperationLoggerMapper operationLoggerMapper;
 
    /**
     * 添加日志(配置了aop切面)
     *
     * @param operationLogger 日志对象
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void addLogger(OperationLogger operationLogger) throws BaseException {
        //尚未添加logger实体和dao
        try {
            operationLogger.setCreateTime(new Date());
            int result = operationLoggerMapper.insert(operationLogger);
            //操作成功
            if (result < 1) {
                log.warn("新增日志失败");
            }
        } catch (Exception e) {
            //手动回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BaseException(e.getMessage());
        }
    }
 
}
 

Dao层

OperationLoggerMapper.java
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.thyc.fabric.entity.business.OperationLogger;
import com.thyc.fabric.vo.business.LogVO;
 
import java.util.List;
 
/**
* @author wzm
*/
public interface OperationLoggerMapper extends BaseMapper<OperationLogger> {
 
    /**
     * 查询操作日志
     *
     * @param type 日志类型
     * @param star 开始时间
     * @param end  截止时间
     * @return list vo
     * @author wzh
     * @date 2019/9/29 0029 17:53
     */
    List<LogVO> queryLogList(Integer type, String star, String end);
}
 
OperationLoggerMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.thyc.fabric.dao.business.OperationLoggerMapper">
 
    <resultMap id="OperationLoggerMap" type="com.thyc.fabric.entity.business.OperationLogger">
        <result column="id" property="id" />
        <result column="operation_content" property="operationContent" />
        <result column="operation_type" property="operationType" />
        <result column="log_class_name" property="logClassName" />
        <result column="log_method_name" property="logMethodName" />
        <result column="params_type_list" property="paramsTypeList" />
        <result column="params_name_list" property="paramsNameList" />
        <result column="params_value_list" property="paramsValueList" />
        <result column="exception_info" property="exceptionInfo" />
        <result column="remote_ip_address" property="remoteIpAddress" />
        <result column="access_type" property="accessType" />
        <result column="exec_time" property="execTime" />
        <result column="city_info" property="cityInfo" />
        <result column="creator" property="creator" />
        <result column="modifier" property="modifier" />
        <result column="create_time" property="createTime" />
        <result column="modify_time" property="modifyTime" />
        <result column="valid" property="valid" />
    </resultMap>
 
    <select id="queryLogList" resultType="com.thyc.fabric.vo.business.LogVO">
        select
        log.id as logId,
        u.nick_name as nickName,
        log.operation_type as typeId,
        log.operation_content as `desc`,
        log.remote_ip_address as ip,
        log.log_class_name as className,
        log.log_method_name as methodName,
        log.exception_info as exceptionInfo,
        log.create_time as createTime
        from
        t_operation_logger as log
        inner join t_sys_user as u
        on u.id = log.user_id
        where  log.valid = 1 AND u.valid = 1
        <if test="type != null">
            AND log.operation_type = #{type}
        </if>
        <if test="type == null">
            AND log.operation_type <![CDATA[!=]]> 4
        </if>
        <if test="star != null and end != null">
            AND DATE_FORMAT(log.create_time,‘%Y-%m-%d‘) BETWEEN STR_TO_DATE(#{star},‘%Y-%m-%d‘) AND STR_TO_DATE(#{end},‘%Y-%m-%d‘)
        </if>
        order by log.create_time desc
    </select>
</mapper>
 

日志实体类

实体类:
import com.baomidou.mybatisplus.annotations.TableField;
import com.thyc.fabric.entity.BaseEntity;
import com.baomidou.mybatisplus.annotations.TableName;
import lombok.Data;
import java.io.Serializable;
 
/**
 *
 * @author wzm
 */
@TableName("t_operation_logger")
@Data
public class OperationLogger extends BaseEntity<OperationLogger>{
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 操作内容
     */
    @TableField("operation_content")
    private String operationContent;
    /**
     * 操作类型( 0-未设置, 1-新增, 2-删除, 3-修改, 4-查询, 5-登录, 6-登出, 7-转账)
     */
    @TableField("operation_type")
    private Integer operationType;
    /**
     * 类名
     */
    @TableField("log_class_name")
    private String logClassName;
    /**
     * 方法名
     */
    @TableField("log_method_name")
    private String logMethodName;
    /**
     * 参数类型列表
     */
    @TableField("params_type_list")
    private String paramsTypeList;
    /**
     * 参数名称列表
     */
    @TableField("params_name_list")
    private String paramsNameList;
    /**
     * 参数值列表
     */
    @TableField("params_value_list")
    private String paramsValueList;
    /**
     * 异常信息
     */
    @TableField("exception_info")
    private String exceptionInfo;
    /**
     * 远程IP地址
     */
    @TableField("remote_ip_address")
    private String remoteIpAddress;
    /**
     * 访问类型(0-web, 1-android, 2-ios)
     */
    @TableField("access_type")
    private String accessType;
    /**
     * 执行时间
     */
    @TableField("exec_time")
    private String execTime;
    /**
     * 城市信息
     */
    @TableField("city_info")
    private String cityInfo;
 
    @Override
    protected Serializable pkVal() {
        return this.id;
    }
 
}

 

控制层

注解加到方法是以记录该接口的行为。
@PostMapping("oss_file_uploader")
@Log(value = "oss文件上传", type = 1)
@ApiOperation(value = "oss文件上传", notes = "文件上传接口", produces = "application/json")
public ApiResult ossUploadFile(@RequestParam(value = "file") MultipartFile file) throws BusinessException {
    return commonService.ossUploadFile(file);
}

 

以上是关于java怎么运用切面编程生成日志的主要内容,如果未能解决你的问题,请参考以下文章

什么是面向切面编程

3.AOP面向切面编程

3.AOP面向切面编程

如何理解spring中的切面和过滤

spring入门面向切面编程

Spring 运用 pointcut 和 advisor 对特定的方法进行切面编程