使用Spring AOP自定义注解在controller记录用户行为日志

想记录用户行为日志有多种方式,在controller层用注解是比较简单的方式,在需要记录日志的方法前添加注解,就可以自动存入相关参数写入日志表。

实现分为3步。

1、添加SPRING AOP的必要POM文件 

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

2、自定义注解,实现用户日志AOP类

2.1 声明注解类,参数为调用接口的描述

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserLog {
    //操作模块描述
    String value() default "";
}

2.2 实现AOP类(Utils.getIpAddr获取IP地址,网上有很多例子,fUserLogService.addLog往数据库新增日志代码就不贴了)

@Aspect
@Component
public class UserLogAspect {
    @Autowired
    RedisAPPTool redisAPPTool;
    @Autowired
    FUserLogService fUserLogService;

    static FUser fUser=new FUser();
    static {
        fUser.setFid(0);
        fUser.setFnickname("游客");
        fUser.setFusername("游客");
    }

    @Pointcut("@annotation(com.jinhua.app.annotation.UserLog)")
    public void annotationPointcut() {

    }

    @AfterReturning(value = "@annotation(userLog)")
    public void  doAround(JoinPoint joinPoint,UserLog userLog){
        //获取方法名(是方法名不是RequestMapping)
        String methodName = joinPoint.getSignature().getName();
        //获取所有参数和参数值
        Map<String,Object> map=this.getNameAndValue(joinPoint);
        //将所有参数转成JSON保存(最好加密一下,我这里没加密)
        JSONObject json = new JSONObject(map);
        BaseController baseController=(BaseController)joinPoint.getThis();

        System.out.println("userLog:" + methodName + "--"+userLog.value()+"--"+
                Utils.getIpAddr(baseController.getRequest())+"--"+ json.toString());

        if(map.get("uid")!=null) {
            Integer uid = Integer.parseInt(map.get("uid").toString());
            FUser user = null;
            //通过UID获取TOKEN
            String token=redisAPPTool.getToken(uid);
            if(token!=null) {
                //通过TOKEN获取用户信息
                user=redisAPPTool.getUserByToken(token);
                if (user == null) {
                    user = fUser;
                }
                //用户日志
                FUserLog fUserLog=new FUserLog();
                //用户ID
                fUserLog.setFuserid(uid);
                //访问接口方法名
                fUserLog.setFmodule(methodName);
                //类型
                fUserLog.setFtype(FUserLogEnum.LOG_TYPE_OPERATION);
                //接口描述
                fUserLog.setFdescription(userLog.value());
                //参数JSON
                fUserLog.setFjosn(json.toString());
                //IP地址
                fUserLog.setFip(Utils.getIpAddr(baseController.getRequest()));
                //插入
                //fUserLogService.addLog(fUserLog);
            }
        }
        else
        {
            System.out.println("私有接口错误!IP:"+Utils.getIpAddr(baseController.getRequest())+",Time:"+Utils.getCurTimeString()+",JOSN:"+json.toString());
        }
        //UserLog log = method.getAnnotation(UserLog.class);
    }

    /**
     * 获取参数Map集合
     * @param joinPoint
     * @return
     */
    private Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramNames.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        return param;
    }


}

3、在controller方法上添加日志注解

3.1 方法前添加“@UserLog”

@Controller
public class QuAndAnController extends BaseController{

    @Autowired
    FQuestionService fQuestionService;

/**
     * 添加回答
     * @param fquid
     * @param fcontext
     * @param fpraise
     * @param uid
     * @param time
     * @param sign
     * @return
     */
    @UserLog
    @RequestMapping("insertAn")
    @ResponseBody
    public String insertAn(
            @RequestParam(value = "fquid") Long fquid,
            @RequestParam(value = "fcontext") String fcontext,
            @RequestParam(value = "fpraise") Integer fpraise,
            @RequestParam(value = "uid") int uid,
            @RequestParam(value = "time") Long time,
            @RequestParam(value = "sign") String sign
    ) {
        //验证TOKEN开始
        FUser user = null;
        try {
            user = checkAPI(uid, sign, time);
        } catch (Exception e) {
            e.printStackTrace();
            return "失败";
        }
        if (user == null) {
            return "失败";
        }
        //验证TOKEN结束
        
        int result = 0;
        /*FAnswer fAnswer = new FAnswer();
        //问题ID
        fAnswer.setFquid(fquid);
        //回答内容
        fAnswer.setFcontext(Utils.filterXSS(fcontext));
        //回答ID
        fAnswer.setFuid(uid);
        //赞
        fAnswer.setFpraise(0);
        
        try {
            result = fQuestionService.insertAn(fAnswer);
        } catch (Exception e) {
            e.printStackTrace();
        }*/

        if (result == 1) {
            return "成功";
        } else {
            return "失败";
        }
    }
}

 

相关实体和工具类

/**
 * 所有controller的父类
 */
public class BaseController {
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected HttpSession session;
    @Autowired
    RedisAPPTool redisAPPTool;

    @ModelAttribute
    public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
        this.session = request.getSession();
    }

    //验证私有接口
    public FUser checkAPI(Integer uid, String sign,Long time) throws Exception {
        String token=redisAPPTool.getToken(uid);
        if(!redisAPPTool.apiRate(token)){
            throw new Exception("访问太快,请稍后在试");
        }
        if(Math.abs(System.currentTimeMillis()-time)> FRedisEnum.API_TIME
                || !APICheck.checkAPI(request,sign,token)){
            throw new Exception("签名有误");
        }
        FUser user=redisAPPTool.getUserByToken(token);
        if(user==null || uid!=user.getFid()){
            throw new Exception("失败,验证录失效,请重新登录");
        }
        return user;
    }

    public HttpServletRequest getRequest()
    {
        return this.request;
    }
}

@Component
public class RedisAPPTool {
    @Autowired
    RedisTool redisTool;
    /**
     * 获取登录用户信息
     *
     * @param token 登录token
     * @return
     */
    public FUser getUserByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        String json = redisTool.getString(token);
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        JSONObject obj = JSON.parseObject(json);
        Object resultStr = obj.get("extObject");
        if (resultStr == null) {
            return null;
        }
        return JSON.parseObject(resultStr.toString(), FUser.class);
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public String getToken(Integer uid) {
        if (StringUtils.isEmpty(uid)) {
            return null;
        }
        String token = redisTool.getString(FRedisEnum.ACCOUNT_LOGIN_KEY+uid);
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        return token;
    }

    /**
     * 访问频率限制
     *
     * @param token 登录token
     * @return
     */
    public boolean apiRate(String token) {
        if (StringUtils.isEmpty(token)) {
            return false;
        }
        String json = redisTool.getString(FRedisEnum.API_RATE+token);
        if (StringUtils.isEmpty(json)) {
            redisTool.set(FRedisEnum.API_RATE+token,true,3*1000L);
            return true;
        }else {
            return false;
        }
    }
}

public class FUserLog implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long fid;
    private Integer ftype;
    private String fmodule;
    private String fdescription;
    private String fip;
    private String fjosn;
    private Integer fuserid;
    private Date fcreatetime;
    
    public FUserLog() {
    }

    public Long getFid() {
        return fid;
    }

    public void setFid(Long fid) {
        this.fid = fid;
    }

    public Integer getFtype() {
        return ftype;
    }

    public void setFtype(Integer ftype) {
        this.ftype = ftype;
    }

    public String getFmodule() {
        return fmodule;
    }

    public void setFmodule(String fmodule) {
        this.fmodule = fmodule;
    }

    public String getFdescription() {
        return fdescription;
    }

    public void setFdescription(String fdescription) {
        this.fdescription = fdescription;
    }

    public String getFip() {
        return fip;
    }

    public void setFip(String fip) {
        this.fip = fip;
    }

    public String getFjosn() {
        return fjosn;
    }

    public void setFjosn(String fjosn) {
        this.fjosn = fjosn;
    }

    public Integer getFuserid() {
        return fuserid;
    }

    public void setFuserid(Integer fuserid) {
        this.fuserid = fuserid;
    }

    public Date getFcreatetime() {
        return fcreatetime;
    }

    public void setFcreatetime(Date fcreatetime) {
        this.fcreatetime = fcreatetime;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值