项目接口信息汇总

项目接口信息汇总

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;
import com.sun.tools.javadoc.Main;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 项目接口信息汇总,包括项目名(作为表名)/模块名/接口URL/接口注释/开发人
 * 使用前提:1、引入依赖 org.apache.poi:poi-ooxml:4.1.2;
 *          2、引入tools.jar。
 * 使用限制:1、只扫描了controller包;
 *          2、接口URL必须写在注解的第一个参数里;
 *          3、只扫描了带有@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping注解的接口方法
 *          4、作者名根据类上的@author、@Author注解获取
 *
 * @author lingxiao
 * @create 2021-05-28 11:32
 */
@Slf4j
public class GetInterfaceInfoToExcel {
    /**
     * excel文件保存路径
     */
    private static final String SAVE_PATH = "D:/项目接口信息汇总.xlsx";

    /**
     * 项目地址
     */
    private static final List<String> SYSTEM_PATH = new ArrayList<>();

    /**
     * 保存类地址的list
     */
    public static List<String> resultPath = new ArrayList<>();

    static RootDoc rootDoc;

    public static class Doclet {
        public static boolean start(RootDoc rootDoc) {
            GetInterfaceInfoToExcel.rootDoc = rootDoc;
            return true;
        }
    }

    public static void main(String[] args) {
        init();
        SYSTEM_PATH.forEach(sp -> {
            resultPath.clear();
            getPath(new File(sp));
            // 截取项目名作为excel表名
            String systemName = sp.substring(sp.lastIndexOf("\\") + 1);
            resultPath.forEach(path -> saveInterfaceInfoToExcel(systemName, path));
        });
    }

    private static void init() {
        SYSTEM_PATH.add("D:\\codes\\aaa");
        SYSTEM_PATH.add("D:\\codes\\bbb");
        SYSTEM_PATH.add("D:\\codes\\ccc");
        SYSTEM_PATH.add("D:\\codes\\ddd");
    }

    /**
     * 获取项目中,所有controller包下面的类路径
     *
     * @param file 项目文件
     */
    private static void getPath(File file) {
        File[] files = file.listFiles();
        if (file.isDirectory() && files != null) {
            Arrays.stream(files).forEach(f -> {
                // 当文件夹名为controller。获取下面的类路径,保存到resultPath
                if (f.isDirectory()) {
                    File[] fs = f.listFiles();
                    if ("controller".equals(f.getName()) && fs != null) {
                        Arrays.stream(fs)
                                // 获取文件路径
                                .map(File::getPath)
                                // 过滤调target和test下的
                                .filter(p -> !p.contains("\\target\\") && !p.contains("\\test\\"))
                                .forEach(path -> resultPath.add(path));
                    } else {
                        getPath(f);
                    }
                }
            });
        }
    }

    /**
     * 获取接口信息保存到excel中
     *
     * @param systemName 系统名
     * @param javaPath   类路径
     */
    private static void saveInterfaceInfoToExcel(String systemName, String javaPath) {
        // 获取模块名
        String temp = javaPath.substring(javaPath.indexOf(systemName) + systemName.length() + 1);
        String modelName = temp.substring(0, temp.indexOf("\\"));

        String[] strs = new String[9];
        strs[0] = "-locale";
        strs[1] = "zh_CN";
        strs[2] = "-doclet";
        strs[3] = Doclet.class.getName();
        strs[4] = "-docletpath";
        strs[5] = Doclet.class.getResource("/").getPath();
        strs[6] = "-encoding";
        strs[7] = "UTF-8";
        strs[8] = javaPath;
        Main.execute(strs);
        ClassDoc[] classes = rootDoc.classes();
        for (ClassDoc classDoc : classes) {
            // 获取类上的开发人
            String rawCommentText = classDoc.getRawCommentText();
            if (rawCommentText.contains("@author")) {
                rawCommentText = rawCommentText.substring(rawCommentText.indexOf("@author") + 7);
                rawCommentText = authorFormat(rawCommentText);
            } else if (rawCommentText.contains("@Author")) {
                rawCommentText = rawCommentText.substring(rawCommentText.indexOf("@Author") + 7);
                rawCommentText = authorFormat(rawCommentText);
            } else {
                rawCommentText = "";
            }
            String author = rawCommentText;
            // 获取类上的注解,RequestMapping里面的URL
            AnnotationDesc[] annotations = classDoc.annotations();
            String classReqUrl = "";
            for (AnnotationDesc annotationDesc : annotations) {
                if ("RequestMapping".equals(annotationDesc.annotationType().name())
                        && annotationDesc.elementValues().length > 0) {
                    classReqUrl = annotationDesc.elementValues()[0].value().toString();
                }
            }
            // 获取方法上的信息
            MethodDoc[] methodDocs = classDoc.methods();
            for (MethodDoc methodDoc : methodDocs) {
                // 获取方法上的注解信息
                AnnotationDesc[] descs = methodDoc.annotations();
                String commentText = methodDoc.commentText();
                String reqUrl = "";
                for (AnnotationDesc desc : descs) {
                    // 获取方法上的URL
                    if ("RequestMapping".equals(desc.annotationType().name()) ||
                            "GetMapping".equals(desc.annotationType().name()) ||
                            "PostMapping".equals(desc.annotationType().name()) ||
                            "PutMapping".equals(desc.annotationType().name()) ||
                            "DeleteMapping".equals(desc.annotationType().name())) {
                        String value = desc.elementValues()[0].value().toString();
                        if (!value.contains(".")) {
                            reqUrl = value;
                        }
                        if (StringUtils.hasText(reqUrl) && !reqUrl.startsWith("/")) {
                            reqUrl = "/" + reqUrl;
                        }
                        // 与类上的URL拼接
                        reqUrl = classReqUrl + reqUrl;
                        // 去掉双引号与多余的斜杠
                        reqUrl = reqUrl.replace("\"", "");
                        while (reqUrl.contains("//")) {
                            reqUrl = reqUrl.replace("//", "/");
                        }
                    }
                    // 获取swagger作为注释
                    if ("ApiOperation".equals(desc.annotationType().name()) &&
                            !desc.elementValues()[0].value().toString().contains("."))  {
                        commentText = !StringUtils.hasText(commentText) ?
                                desc.elementValues()[0].value().value().toString() :
                                commentText + ";" + desc.elementValues()[0].value().value().toString();
                    }
                }
                // 接口URL不为空的,才保存到excel
                if (StringUtils.hasText(reqUrl)) {
                    List<String> sl = new ArrayList<>();
                    sl.add(modelName);
                    sl.add(reqUrl);
                    sl.add(commentText);
                    sl.add(author);
                    log.info(sl.toString());
                    log.info("类" + classDoc.name() + ",请求路径:" + reqUrl + ", 方法名:" + methodDoc.name() + ",开发人:"
                            + author + ",方法注释:" + commentText);
                    writeExcel(systemName, sl);
                }
            }
        }
    }

    /**
     * 去掉开发者名字外多余的部分
     *
     * @param rawCommentText 要处理的字符串
     * @return 处理好的字符串
     */
    private static String authorFormat(String rawCommentText) {
        if (rawCommentText.contains("\n")) {
            rawCommentText = rawCommentText.substring(0, rawCommentText.indexOf("\n"))
                    .replace(":", "").trim();
        } else {
            rawCommentText = rawCommentText.substring(0, rawCommentText.indexOf(" "))
                    .replace(":", "").trim();
        }
        if (rawCommentText.contains("by ")) {
            rawCommentText = rawCommentText.substring(rawCommentText.indexOf("by ") + 3).trim();
            rawCommentText = rawCommentText.substring(0, rawCommentText.indexOf(" "));
        }
        return rawCommentText;
    }

    /**
     * 写入excel
     *
     * @param tableName 表名
     * @param list      内容
     */
    private static void writeExcel(String tableName, List<String> list) {
        File file = new File(SAVE_PATH);
        XSSFWorkbook workbook = null;
        FileOutputStream stream = null;
        try {
            if (!file.exists()) {
                if (!file.createNewFile()) {
                    throw new IOException("创建excel文件失败!");
                }
                workbook = new XSSFWorkbook();
            } else {
                workbook = new XSSFWorkbook(new FileInputStream(file));
            }
            //创建工作表sheet
            Sheet sheet = workbook.getSheet(tableName);
            // 表不存在则创建
            if (sheet == null) {
                sheet = workbook.createSheet(tableName);
                Row firstRow = sheet.createRow(0);
                firstRow.createCell(0).setCellValue("模块");
                firstRow.createCell(1).setCellValue("接口URL");
                firstRow.createCell(2).setCellValue("功能描述");
                firstRow.createCell(3).setCellValue("开发人");
            }
            // 获取最后一行的行数
            int lastRowNum = sheet.getLastRowNum();
            Row row = sheet.createRow(lastRowNum + 1);
            for (int i = 0; i < list.size(); i++) {
                row.createCell(i).setCellValue(list.get(i));
            }
            stream = new FileOutputStream(file);
            workbook.write(stream);
            log.info("写入成功:" + list);
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (stream != null) {
                    stream.close();
                }
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值