SpringBoot通过AOP保存操作日志

 

最近项目中遇到一个自己之前没有做过的小功能,即系统日志的查询,老板有事没事查看下手底下员工今天都做什么了呢?

思路:一:调接口时把操作信息保存到日志类中,这种感觉有点小low;

二:通过AOP实现保存操作日志信息,通过自定义的注解来具体实现,哪一个方法需要记录;

二(1.)首先,项目中需要引入AOP的jar包

<!-- aop -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

二(2.):首先自定义一个注解,详细说明都有

package org.asyware.radnor.model;

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

/**
 * 自定义行为日志注解
 * @author zl
 * @date 2018/12/05
 *
 */
@Target({ElementType.METHOD})//目标是方法
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Documented//文档生成时,该注解将被包含在javadoc中,可以去掉
public @interface LogAnnotation  {

	/**
	 * 
	 * action()解释说明:
	 * 这个是我们写注解时需要传入的参数值的名称,比如上述的用的是action,
	 * 那么我们在注解时就应该这样注解@LogAnnotation(action=”测试”),
	 * 当然如果你只有一个参数需要传的,那么建议各位使用value(),这样注解时会默认传入的,
	 * 这样我们就可以向其他注解一样@LogAnnotation(“测试”)。 
	 * targetType()解释说明:
	 * 自定义,我这边是分为create、delete、update、check
	 * @return
	 */
	String action() default "";
    String targetType() default "";
    String remark() default "";
}

二(3.)写个切面类(包含切入点、记录操作日志、获取方法的参数、获取客户端ip地址)

这块就把日志操作信息入库了

package org.asyware.radnor.conf;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.asyware.radnor.entity.Employee;
import org.asyware.radnor.entity.Log;
import org.asyware.radnor.model.LogAnnotation;
import org.asyware.radnor.repo.EmployeeRepo;
import org.asyware.radnor.repo.LogRepo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;


/**
 * 切面类
 * @author zl
 * @date 2018/12/05
 *
 */
@Aspect
@Component
public class LogAopAction {
	
	public static final String LOG_TARGET_TYPE="targetType";
    public static final String LOG_ACTION="action";
    public static final String LOG_REMARK="remark";
	
	private static final Logger logger  = LoggerFactory.getLogger(LogAopAction.class);

	@Autowired
    private LogRepo logRepo;
	@Autowired
	private EmployeeRepo employeeRepo;

    //切入点  @annotation(logAnnotation)需要你输入你实现的是哪个注解类。
    @Pointcut("@annotation(org.asyware.radnor.model.LogAnnotation)")
    public void pointCutMethod() {}
    
    
    /**
     * 记录操作日志
     * @param joinPoint
     */
    @Before("pointCutMethod()")//使用上面定义的切入点
    public void doServiceBefore(JoinPoint joinPoint) {
    	Long start = System.currentTimeMillis();
       Log log=new Log();//自己写的日志类
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
      //获取请求的参数
        String param = getParam(joinPoint);
        System.out.println("1111111111参数为"+param);
        Employee employee=employeeRepo.findOne(Integer.parseInt(param));
        if(employee==null) {
        	logger .warn("employee信息为空!");
        }else {
        	 log.setEmpId(employee.getId());
             log.setOperator(employee.getName());
             log.setIP(getCliectIp(request));
             System.out.println("000000000000IP:"+getCliectIp(request));
        }
      //下面开始获取 targetType,remark,action
        try {
            Map<String,String> map = getLogMark(joinPoint);
            log.setAction(map.get(LOG_ACTION));
            log.setTargetType(map.get(LOG_TARGET_TYPE));
            log.setRemark(map.get(LOG_REMARK));
            logRepo.save(log);
        }catch (ClassNotFoundException c){
            logger.error(c.getMessage());
        }catch (Exception e){
            logger.error("插入日志异常",e.getMessage());
        } 
    }
    
    
    /**
     * 方法参数
     * 
     * 最后一个参数必须是enpId,否则记录日志的时候会报错
     * @param joinPoint
     * @return
     */
    private String getParam(JoinPoint joinPoint){
        StringBuilder params = new StringBuilder();
        if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
            for ( int i = (joinPoint.getArgs().length-1); i < joinPoint.getArgs().length; i++) {    
                if(joinPoint.getArgs()[i].getClass() == Employee.class){
                    /*params.append(joinPoint.getArgs()[i].toString()).append(";");*/
                	params.append(joinPoint.getArgs()[i].toString());
                }else{
                    /*params.append(joinPoint.getArgs()[i]).append(";");*/
                    params.append(joinPoint.getArgs()[i]);
                }
           }    
       }    
       return params.toString();
    }

    
    private Map<String,String> getLogMark(JoinPoint joinPoint) throws ClassNotFoundException {
        Map<String,String> map = new HashMap<>();
        String methodName = joinPoint.getSignature().getName();
        String targetName = joinPoint.getTarget().getClass().getName();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        for (Method method : methods){
            if(method.getName().equals(methodName)){
            	LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);//注解类
                map.put(LOG_TARGET_TYPE,logAnnotation.targetType());//注解类中写的值
                map.put(LOG_ACTION,logAnnotation.action());
                map.put(LOG_REMARK,logAnnotation.remark());
            }
        }
        return map;
    }


    /**
     * 获取客户端ip地址
     * @param request
     * @return
     */
    public static String getCliectIp(HttpServletRequest request){
        String ip = request.getHeader("X-Real-IP");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值,第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        } else {
            return request.getRemoteAddr();
        }
    }

}

二(4.)最后在controller层中,在具体的方法上注入之前定义的注解,并写入此注解的属性信息,即就是通过注解把日志操作记录入库

package org.asyware.radnor.controller;

import org.asyware.radnor.entity.Custom;
import org.asyware.radnor.model.BaseResult;
import org.asyware.radnor.model.Constants;
import org.asyware.radnor.model.LogAnnotation;
import org.asyware.radnor.service.CustomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 客户
 * @author zl
 * @date 2018/12/04
 *
 */
@CrossOrigin
@Api(value="客户接口")
@RestController
@RequestMapping("/custom")
public class CustomController {
	
	@Autowired
	private  CustomService customService;
	
	
	/**
	 * 添加客户信息
	 * @LogAnnotation
	 * 在需要记录操作日志的controller层采用如上注解的方式就可以在操作时记录操作的日志了
	 * @param custom
	 * @return
	 */
	@ApiOperation(value="添加客户信息",notes="")
	@PostMapping("/insertInfo")
	@LogAnnotation(action="添加客户信息",targetType="create")
	public BaseResult insertInfo(@RequestBody Custom custom,
			@RequestParam("empId") Integer  empId) {
		try {
			return customService.insertInfo(custom,empId);
		} catch (Exception e) {
			e.printStackTrace();
			return new BaseResult(Constants.EXCEPTION_CODE,Constants.EXCEPTION_MSG);
		}
	}

}

最后,附上我之前参考别人的相关连接,https://blog.csdn.net/banjw_129/article/details/81316111https://blog.csdn.net/qq_35491812/article/details/81502764

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Stone.小小的太阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值