springboot 启动项目打印接口列表的实现

 更新时间:2021年9月11日 16:00  点击:2193

springboot 启动项目打印接口列表

环境

  • springboot 2.3.2.RELEASE

修改配置文件

logging:
  level:
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: trace

结果:

在这里插入图片描述

Springboot项目添加接口入参统一打印

需求:要求接口被调用时要打印被调用方法名,以及入参情况,参数格式化时选择fastjson

注:使用fastjson序列化时脱敏,建议入参统一使用自定义的对象类型作为入参

如果不需要参数脱敏,直接使用增强中相关代码,并去除参数脱敏相关代码即可

新建注解,用于实现参数打印功能的增强

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamInfo {
    /**
     * 取消统一打印参数
     * 默认为false统一打印
     * 如需自定义参数打印 请赋值为true
     */
    boolean unPrint() default false;
    /**
     * 需要脱敏的字段,如密码等
     */
    String[] fields() default {};
}

自定义序列化规则

/**
 * 序列化过滤器:值替换
 *
 */
public class ReplaceFieldFilter implements ValueFilter {
    /**
     * 需要进行替换的属性名和替换值
     * key:属性名
     * value:替换值
     */
    private Map<String, Object> fieldMap;
    public ReplaceFieldFilter() {
    }
    public ReplaceFieldFilter(Map<String, Object> fieldMap) {
        this.fieldMap = fieldMap;
    }
    @Override
    public Object process(Object o, String name, Object value) {
        if(!CollectionUtils.isEmpty(fieldMap)){
            Iterator<Map.Entry<String, Object>> iterator = fieldMap.entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String, Object> next = iterator.next();
                if(next.getKey().equalsIgnoreCase(name)){
                    return next.getValue();
                }
            }
        }
        return value;
    }
    public Map<String, Object> getFieldMap() {
        return fieldMap;
    }
    public void setFieldMap(Map<String, Object> fieldMap) {
        this.fieldMap = fieldMap;
    }
    /**
     * 传入需要脱敏的字段名,序列化时格式化为 * 号
     */
    public ReplaceFieldFilter(String... fields) {
        String str = "******";
        fieldMap = new HashMap<>(4);
        for (String field : fields) {
            fieldMap.put(field, str);
        }
    }
}

写参数打印增强,这里选择环绕增强

@Component
@Aspect
//表示增强的执行顺序,如果多个增强,数值小的先被执行
@Order(0)
public class ParamInfoAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(ParamInfoAspect.class);
    @Around("execution(* com.service.impl.*.*(..))")
    public Object printParam(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String requestId = RandomStringUtils.randomAlphanumeric(16);
        Object returnValue = null;
        try {
            Object[] args = joinPoint.getArgs();
            // 获取方法对象
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            //通过注解获取脱敏字段,之后初始化fieldMap,完成字段脱敏
            ParamInfo annotation = method.getAnnotation(ParamInfo.class);
            Map<String, Object> fieldMap = new HashMap<>(4);
            fieldMap.put("password", "******");
            if (annotation != null) {
                //获取需要脱敏的字段名数组
                String[] fields = annotation.fields();
                for (String field : fields) {
                    fieldMap.put(field, "******");
                }
            }
            String param;
            //参数整合,多字段入参整合为对象,单个对象入参格式不变
            if (args.length > 1 || (args.length == 1 && args[0].getClass() == String.class)) {
                Map<String, Object> paramMap = new LinkedHashMap<>();
                String[] parameterNames = signature.getParameterNames();
                for (int i = 0; i < parameterNames.length; i++) {
                    paramMap.put(parameterNames[i], args[i]);
                }
                param = "[" + JSON.toJSONString(paramMap, new ReplaceFieldFilter(fieldMap)) + "]";
            } else {
                param = JSON.toJSONString(args, new ReplaceFieldFilter(fieldMap));
            }
            String methodName = method.getName();
            LOGGER.info("method:[{}], parameter:{}, requestId:[{}]", methodName, param, requestId);
            returnValue = joinPoint.proceed();
            return returnValue;
        } catch (Exception e) {
            LOGGER.error("system is error:", e);
   //可在这里定义程序异常时的错误返回值
            returnValue = ErrorCode.SYSTEM_ERROR;
            return returnValue;
        } finally {
            LOGGER.info("request cost:{}ms, requestId:[{}]", System.currentTimeMillis() - startTime, requestId);
            LOGGER.info("returnValue:[{}], requestId:[{}]", returnValue, requestId);
        }
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • 解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题

    这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28
  • js实现浏览器打印功能的示例代码

    这篇文章主要介绍了js如何实现浏览器打印功能,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-15
  • c# 三种方法调用WebService接口

    这篇文章主要介绍了c# 三种方法调用WebService接口的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-07
  • SpringBoot实现excel文件生成和下载

    这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
  • 详解springBoot启动时找不到或无法加载主类解决办法

    这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
  • vue接口请求加密实例

    这篇文章主要介绍了vue接口请求加密实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-12
  • SpringBoot集成Redis实现消息队列的方法

    这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • js实现列表按字母排序

    这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
  • 解决Springboot get请求是参数过长的情况

    这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • Spring Boot项目@RestController使用重定向redirect方式

    这篇文章主要介绍了Spring Boot项目@RestController使用重定向redirect方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02
  • Springboot+TCP监听服务器搭建过程图解

    这篇文章主要介绍了Springboot+TCP监听服务器搭建过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-28
  • springBoot 项目排除数据库启动方式

    这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
  • javaScript年份下拉列表框内容为当前年份及前后50年

    javascript下拉列表框,内容为当前年份及前后50年,默认选择为当前年份 复制代码 代码如下: <script language="javascript" type="text/javascript"> window.onload=function(){ //设置年份的选择 var myDate= new Date(...2014-05-31
  • Python 列表(List)的底层实现原理分析

    这篇文章主要介绍了Python 列表(List)的底层实现原理分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
  • C#简单了解接口(Interface)使用方法

    这篇文章主要介绍了C#简单了解接口(Interface)使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-12-08
  • 详解SpringBoot之访问静态资源(webapp...)

    这篇文章主要介绍了详解SpringBoot之访问静态资源(webapp...),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-14
  • SpringBoot接口接收json参数解析

    这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
  • easyUI下拉列表点击事件使用方法

    这篇文章主要为大家详细介绍了easyUI下拉列表点击事件的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-05-22
  • springboot中使用@Transactional注解事物不生效的坑

    这篇文章主要介绍了springboot中使用@Transactional注解事物不生效的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
  • C# Rx的主要接口深入理解

    这篇文章主要介绍了C# Rx的主要接口深入理解的相关资料,需要的朋友可以参考下...2020-06-25