springboot使用自定义注解实现日志记录功能

   有这么一个需求:记录controller的请求参数和响应结果到日志中。

   解决思路:写一个自定义注解,在需要记录的controller的方法上,加上该注解,通过注解来记录相关信息。

   解决方式:使用AOP来解决,通过返回通知来获取返回结果信息。

   解决步骤:

1、在pom.xml中引入AOP的依赖


	org.springframework.boot
	spring-boot-starter-aop
	2.2.2.RELEASE

2、定义枚举类,针对方法参数制定枚举类型

public enum ParamTypeEnum {
    PARAM_BEAN("bean","bean"),//bean类型
    PARAM_KAK_JSON("k1-v1,k2-v2,...,json","kak_json"),//k-v键值对和json串混合类型
    PARAM_KAK_MAP("k1-v1,k2-v2,...,map","kak_map"),//k-v键值对和map混合类型
    PARAM_KAK("k1-v1,k2-v2,...","kak"),//k-v键值对类型
    PARAM_MAP("map","map"),//map类型
    PARAM_JSON("json","json");//json类型

    private String name;
    private String code;

    public String getName() {
        return this.name;
    }

    public String getCode() {
        return this.code;
    }

    private ParamTypeEnum(String name, String code){
        this.name = name;
        this.code = code;
    }
}

3、定义自定义注解

//以下3个元注解的作用,自行百度即可
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ManagerLog {
    /**
     * 参数类型,一共6种
     * 1、json
     * 2、map
     * 3、K-V键值对
     * 4、K-V键值对 与 json 混合
     * 5、K-V键值对 与 map 混合
     * 6、bean
     * @return
     */
    ParamTypeEnum paramType();

    /**
     * 参数为混合参数时使用,标记map/json所在的参数位置,从0开始计数
     * @return
     */
    int mulIndex() default -1;

    /**
     * json是否为嵌套json,仅支持2级
     * @return
     */
    boolean mulJson() default false;

    /**
     * 举例:{"data":{"a":1,"b":2}}
     * 嵌套json的key
     * @return
     */
    String childJsonName() default "data";
}

4、AOP实现

@Aspect
@Component
public class ManagerLogAspect {

    @Resource
    private KafkaManagerLogSenderUtil kafkaManagerLogSenderUtil;//将日志信息发送到kafka

    @Pointcut("@annotation(com.chineseall.admin.annotation.ManagerLog)")
    public void annotationPointCut() {
    }

    @AfterReturning(returning = "result",value = "annotationPointCut()&&@annotation(managerLog)")
    public Object afterReturn(JoinPoint point, Object result, ManagerLog managerLog) {
        try{
            //获取参数类型枚举
            ParamTypeEnum paramTypeEnum = managerLog.paramType();
            //json
            if (ParamTypeEnum.PARAM_JSON.getCode().equals(paramTypeEnum.getCode())){
                String jsonStr = (String) point.getArgs()[0];
                dealJson(point,result,managerLog,jsonStr);
            }
            //map
            else if (ParamTypeEnum.PARAM_MAP.getCode().equals(paramTypeEnum.getCode())){
                dealMap(point,result,managerLog);
            }
            //k-v键值对
            else if (ParamTypeEnum.PARAM_KAK.getCode().equals(paramTypeEnum.getCode())){
                dealKak(point,result,managerLog);
            }
            //k-v键值对 与 json 混合
            else if (ParamTypeEnum.PARAM_KAK_JSON.getCode().equals(paramTypeEnum.getCode())){
                dealKakAndJson(point,result,managerLog);
            }
            //k-v键值对 与 map 混合
            else if (ParamTypeEnum.PARAM_KAK_MAP.getCode().equals(paramTypeEnum.getCode())){
                dealKakAndMap(point,result,managerLog);
            }
            else if (ParamTypeEnum.PARAM_BEAN.getCode().equals(paramTypeEnum.getCode())){
                String jsonStr = JSONObject.toJSONString(point.getArgs()[0]);
                dealJson(point,result,managerLog,jsonStr);
            }
        }catch (Exception e){
            System.out.println("ManagerLogAspect切面记录日志时发生错误!"+e.getMessage());
            log.error("ManagerLogAspect切面记录日志时发生错误!"+e.getMessage());
        }
        return result;
    }

    /**
     * 发送消息至kafka
     * @param desc
     * @throws Exception
     */
    private void sendMsg(String desc) throws Exception{
        

        kafkaManagerLogSenderUtil.sendManagerMsg(desc);
    }

   
    /**
     * 处理参数类型为k1-v1,k2-v2,...,map的数据
     * @param point
     * @param result
     * @param managerLog
     * @throws Exception
     */
    private void dealKakAndMap(JoinPoint point, Object result, ManagerLog managerLog) throws Exception{
       
        int index = managerLog.mulIndex();
        if (index==-1){
            throw new Exception("在@ManagerLog注解中,未标明map的位置");
        }
        Object[] args = point.getArgs();
        String targetValue = null;
        Map map = (Map)point.getArgs()[index];
        String[] paramNames = getParamNames(point);

        StringBuilder sb = new StringBuilder();
        sb.append("#managerLog#\n执行了如下操作:\n");
        
        for (int i=0;i entry : jsonObject.entrySet()){
                sb.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
            }
        }
        //追加执行结果
        appendResult(sb,result,targetParamName);
        
        sendMsg(sb.toString());
    }

    /**
     * 处理参数类型为k-v的数据
     * @param point
     * @param result
     * @param managerLog
     */
    private void dealKak(JoinPoint point, Object result, ManagerLog managerLog) throws Exception{
        
        StringBuilder sb = new StringBuilder();
        sb.append("#managerLog#\n执行了如下操作:\n");
        
        Object[] args = point.getArgs();
        String[] paramNames = getParamNames(point);
        for (int i=0;i map = (Map)point.getArgs()[0];
        StringBuilder sb = new StringBuilder();
        sb.append("#managerLog#\n执行了如下操作:\n");
        
        if (map != null){
            for (String key : map.keySet()){
                sb.append(key).append(":").append(map.get(key).toString()).append("\n");
                
            }
        }
        //追加执行结果
        appendResult(sb,result,targetParamName);
        
        sendMsg(sb.toString());
    }


    /**
     * 处理参数类型为json的数据
     * @param point
     * @param result
     * @param managerLog
     */
    private void dealJson(JoinPoint point, Object result, ManagerLog managerLog,String jsonStr) throws Exception{
        

        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        if (managerLog.mulJson()){
            jsonObject = jsonObject.getJSONObject(managerLog.childJsonName());
        }
        StringBuilder sb = new StringBuilder();
        sb.append("#managerLog#\n执行了如下操作:\n");
       
        if (jsonObject != null){
            for (Map.Entry entry : jsonObject.entrySet()){
                sb.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
                
            }
        }
        //追加执行结果
        appendResult(sb,result,targetParamName);
        
        
        sendMsg(sb.toString());
    }

    /**
     * 获取执行结果
     * @param sb
     * @param result
     * @return
     */
    private String appendResult(StringBuilder sb,Object result){
        return appendResult(sb,result,null);
    }

//targetParamName和targetParamValue是业务相关的东西,不需要关注
    /**
     * 获取执行结果
     * @param sb
     * @param result
     * @param targetParamName
     * @return
     */
    private String appendResult(StringBuilder sb,Object result,String targetParamName){
        String targetValue = "-1";
        try {
            sb.append("执行的结果如下:\n");
            ReturnMsg returnMsg = (ReturnMsg)result;
            if (null != returnMsg) {
                if (returnMsg.getCode() == 0) {
                    sb.append(returnMsg.getData());

                    if (targetParamName != null){
                        try {
                            //从执行结果中获取targetParamName对应的值
                            targetValue = getTargetValue(returnMsg,targetParamName);
                        }catch (Exception e){
                            System.out.println("从执行结果中获取targetParamName对应的值异常"+e.getMessage());
                            targetValue = "-1";
                        }
                    }
                } else {
                    sb.append(!StringUtils.isEmpty(returnMsg.getException()) ? returnMsg.getException() : returnMsg.getMsg());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取执行结果发生异常"+e.getMessage());
        }
        return targetValue;
    }

    /**
     * 从执行结果中获取targetParamName对应的值
     * @param returnMsg
     * @param targetParamName
     * @return
     */
    private String getTargetValue(ReturnMsg returnMsg,String targetParamName){
        String targetValue = "0";
        String jsonString = JSONObject.toJSONString(returnMsg.getData());
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        for (Map.Entry entry : jsonObject.entrySet()){
            if (targetParamName.equals(entry.getKey())){
                targetValue = entry.getValue().toString();
            }
        }
        return targetValue;
    }
}

6、在controller的方法上添加该自定义注解

    @ManagerLog(paramType = ParamTypeEnum.PARAM_JSON)
    @PostMapping("/single")
    public ReturnMsg singleBook(@RequestBody String body) throws Exception{
    } 
  

 

你可能感兴趣的:(spring,boot)