通过Swagger拉去所有接口,记录用户操作日志

Swagger接口获取到的数据格式:
我们主要关注paths属性

{
    "swagger": "2.0",
    "info": {
        "description": "Admin-api",
        "version": "2.0",
        "title": "简书 接口文档"
    },
    "host": "localhost:8081",
    "basePath": "/",
    "tags": [{
        "name": "数据统计相关",
        "description": "Statistic Controller"
    }, {
        "name": "文章管理",
        "description": "Article Controller"
    }, {
        "name": "用户安全",
        "description": "Admin Controller"
    }, {
        "name": "用户管理",
        "description": "User Controller"
    }],
    "paths": {
        "/statistic/dataFinanceOverView": {
            "get": {
                "tags": ["数据统计相关"],
                "summary": "财务数据概览",
                "operationId": "dataFinanceOverViewUsingGET",
                "produces": ["*/*"],
                "parameters": [{
                    "name": "Authorization",
                    "in": "header",
                    "description": "令牌",
                    "required": false,
                    "type": "string"
                }, {
                    "name": "endDate",
                    "in": "query",
                    "description": "结束日期",
                    "required": true,
                    "type": "string"
                }, {
                    "name": "startDate",
                    "in": "query",
                    "description": "开始日期",
                    "required": true,
                    "type": "string"
                }],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/DataFinanceOverView",
                            "originalRef": "DataFinanceOverView"
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                },
                "deprecated": false
            }
        },
        "/statistic/dataOperateOverView": {
            "get": {
                "tags": ["数据统计相关"],
                "summary": "运营数据概览",
                "operationId": "dataOperateOverViewUsingGET",
                "produces": ["*/*"],
                "parameters": [{
                    "name": "Authorization",
                    "in": "header",
                    "description": "令牌",
                    "required": false,
                    "type": "string"
                }, {
                    "name": "endDate",
                    "in": "query",
                    "description": "结束日期",
                    "required": true,
                    "type": "string"
                }, {
                    "name": "startDate",
                    "in": "query",
                    "description": "开始日期",
                    "required": true,
                    "type": "string"
                }],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/DataOperateOverView",
                            "originalRef": "DataOperateOverView"
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                },
                "deprecated": false

            }
        }
    }
}

我们只需要三个值

{
    "paths": {
        "/statistic/dataFinanceOverView": {
            "get": {
                "tags": ["数据统计相关"],
                "summary": "财务数据概览"
            }
        }
    }
}

最终解析后得到的数据格式

[{
    "modelName": "数据统计相关",
    "method": "/statistic/financeStatisticInfoView",
    "methodName": "财务统计"
}, {
    "modelName": "数据统计相关",
    "method": "/statistic/operationReport",
    "methodName": "运营报表"
}, {
    "modelName": "数据统计相关",
    "method": "/statistic/userStatisticsInfoView",
    "methodName": "用户统计"
}]

Swagger工具类

import com.aliyuncs.utils.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import vip.shuashua.repayment.utils.HttpUtils;
import vip.shuashua.repayment.utils.RedisKey;

import java.io.IOException;
import java.util.*;

/**
 * 通过Swagger获取所有接口方法,缓存至Redis
 * Created by LiuJingWei on 2019-09-26.
 */
@Component
public class AdminSwaggerAllMethod implements ApplicationRunner {

    private Logger logger = LoggerFactory.getLogger(AdminSwaggerAllMethod.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    // http://localhost:8081/v2/api-docs
    @Value("${swagger.get.all.method.url}")
    private String SWAGGER_PATH;

    @Override
    public void run(ApplicationArguments args) {
        if (redisTemplate.hasKey(RedisKey.WEB_SWAGGER_ALL_METHOD.getKey())) {
            redisTemplate.delete(RedisKey.WEB_SWAGGER_ALL_METHOD.getKey());
        }
        String swaggerAllMethodJson = getSwaggerAllMethod();
        if (StringUtils.isNotEmpty(swaggerAllMethodJson)) {
            redisTemplate.opsForValue().set(RedisKey.WEB_SWAGGER_ALL_METHOD.getKey(), swaggerAllMethodJson);
            logger.info(String.format("动态通过Swagger解析所有接口方法成功!并加入Redis缓存key:%s,value:%s", RedisKey.WEB_SWAGGER_ALL_METHOD.getKey(), swaggerAllMethodJson));
        } else {
            logger.error("动态通过Swagger解析所有接口方法失败!");
        }
    }

    /**
    * 获取Swagger所有接口方法
    * # 这里注意一点,我们只获取了GET、POST方法
    */
    public String getSwaggerAllMethod(){
        try {
            List<Map<String,Object>> swaggerAllMethod = new ArrayList<>();
            ObjectMapper objectMapper = new ObjectMapper();
            String swaggerJson = HttpUtils.get(SWAGGER_PATH, null, 3000, 3000, "UTF-8");
            Map<String, Object> swaggerMap = objectMapper.readValue(swaggerJson, Map.class);
            LinkedHashMap<String, Object> pathsMap = (LinkedHashMap<String, Object>) swaggerMap.get("paths");// 所有方法
            pathsMap.entrySet().stream().forEach(s -> {
                String method = s.getKey();
                LinkedHashMap<String, Object> methodMode = ((LinkedHashMap<String, Object>) pathsMap.get(s.getKey()));// 所有請求方式GET、POST等
                methodMode.entrySet().stream()
                        .filter(model -> "get".equals(model.getKey()) || "post".equals(model.getKey()))
                        .forEach(m -> {
                            LinkedHashMap<String, Object> methodBody = (LinkedHashMap<String, Object>) methodMode.get(m.getKey());
                            String methodName = (String) methodBody.get("summary");
                            methodBody.entrySet().stream()
                                    .filter(tags -> "tags".equals(tags.getKey()))// tags里是??槊?                                    .forEach(tags -> {
                                        ArrayList<Object> tagList = (ArrayList<Object>) tags.getValue();
                                        String modeName = (String) tagList.get(0);
                                        Map<String, Object> swaggerMethod = new HashMap<>();
                                        swaggerMethod.put("method", method);
                                        swaggerMethod.put("modelName", modeName);
                                        swaggerMethod.put("methodName", methodName);
                                        swaggerAllMethod.add(swaggerMethod);
                                    });
                        });
            });

            return objectMapper.writeValueAsString(swaggerAllMethod);
        } catch (IOException e) {
            logger.error("通过Swagger解析所有接口异常",e);
            return null;
        }
    }

}

ApplicationRunner 接口中的run方法是在项目启动成功后执行的

数据存入Redis中,然后就可以使用过滤器,拦截每次请求后,使用方法名做对比,获取接口中文描述啦。

这里推荐继承Spring的OncePerRequestFilter,重写doFilterInternal方法
可以获取到请求参数以及相应参数列表,加上方法名以及中文描述,基本满足操作日志记录的要求

后面有空会把整体代码上传至github中...

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,938评论 6 13
  • 需求: 为客户端同事写接口文档的各位后端同学,已经在各种场合回忆了使用自动化文档工具前手写文档的血泪史.我的故事却...
    _Lyux阅读 4,693评论 0 2
  • 今天技术总监说:小明,我们本次3.0改造,使用swagger2.0作为前后端分离的接口规范,它可以一键生成前后端的...
    coder小明阅读 3,404评论 4 12
  • 2019年3月11日,星期一,晴。(柔者处上之大学历练——连载第295篇) 连续两天的生病无奈也让我中止了两天的早...
    枫郁樰阅读 224评论 0 2
  • 1、因为早起,我们才能获得安静的时间,以便对未来和当下做出检视与安排,活在要事第一。 2、因为早起,所以需要早睡。...
    smile_ddbc阅读 190评论 0 0