根据bean的注解生成接口文档表格

前言

前一阵写了几个接口,需要给别人出一份接口文档。总觉手写挺麻烦的。看了一下接口入参的bean每个属性都有类似@notNull这样的注解,这种注解是用于接口调用时自动进行校验时用的。想了一下干脆通过扫描接口的参数的这些注解来生成一个文档。于是就写了一个工具类,来生成一个表格形式的接口文档。这个工具不需要启动spring,简单配置两三个参数,直接运行main方法就可以生成。


代码

用于扫描包的工具类:

 package com.zbj.finance.member.api.excel;

import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * 
 * @author txf 扫描包的工具类
 */
public class ScannerUtils {

    public static Set<String> scanBasePackage(String basePackageName) {
        String packageDirName = basePackageName.replace(".", "/");
        URL url = Thread.currentThread().getContextClassLoader()
                .getResource(packageDirName);
        System.out.println("文件路径:" + url);
        File targetFile = new File(url.getFile());
        if (!targetFile.exists() || targetFile.isFile()) {
            throw new RuntimeException(basePackageName + "不是一个包名或者该包名不存在");
        }
        Set<String> classNames = new HashSet<String>();
        getAllClass(targetFile, basePackageName, classNames);
        return classNames;

    }

    /**
     * 得到所有在parentFile目录下的class文件名称
     * 
     * @param parentFile
     * @param classNames
     * @param basePackageName
     */
    private static void getAllClass(File parentFile, String basePackageName,
            Set<String> classNames) {

        File[] files = parentFile.listFiles();
        for (File file : files) {
            String path = file.getPath();
            if (file.isFile()) {

                if (path.endsWith(".class")) {
                    classNames.add(basePackageName
                            + "."
                            + path.substring(path.lastIndexOf('\\') + 1,
                                    path.lastIndexOf('.')));
                }
            } else {
                basePackageName = basePackageName
                        + path.substring(path.lastIndexOf('\\') + 1);
                getAllClass(file, basePackageName, classNames);
            }
        }
    }
}

用于生成Excel组装数据的对象:

package com.zbj.finance.member.api.excel;

import java.util.List;

/**
 * 
 * @author txf
 *  用于生成sheet的装入数据的对象
 */
public class ExcelSheet {

private String sheetName;

    private String note;

    private String classPath;

    private String requestName;

    private String responseName;

    private List<String> head;

    private List<List<String>> requestDatas;

    private List<List<String>> responseDatas;

    public String getRequestName() {
        return requestName;
    }

    public void setRequestName(String requestName) {
        this.requestName = requestName;
    }

    public String getResponseName() {
        return responseName;
    }

    public void setResponseName(String responseName) {
        this.responseName = responseName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public String getClassPath() {
        return classPath;
    }

    public void setClassPath(String classPath) {
        this.classPath = classPath;
    }

    public String getSheetName() {
        return sheetName;
    }

    public void setSheetName(String sheetName) {
        this.sheetName = sheetName;
    }

    public List<String> getHead() {
        return head;
    }

    public void setHead(List<String> head) {
        this.head = head;
    }

    public List<List<String>> getRequestDatas() {
        return requestDatas;
    }

    public void setRequestDatas(List<List<String>> requestDatas) {
        this.requestDatas = requestDatas;
    }

    public List<List<String>> getResponseDatas() {
        return responseDatas;
    }

    public void setResponseDatas(List<List<String>> responseDatas) {
        this.responseDatas = responseDatas;
    }

}

生成用于生成Excel的data对象:

package com.zbj.finance.member.api.excel;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.web.doc.annotation.ApidocElement;
import javax.web.doc.annotation.ApidocInterface;
import javax.web.doc.annotation.ApidocService;

/**
 * 
 * @author txf
 *  生成用于生成Excel的data对象
 *
 */
public class ExcelDataCreater {

    private String basePackageName;

    public ExcelDataCreater(String basePackageName) {
        super();
        this.basePackageName = basePackageName;
    }

    public List<ExcelSheet> createExcelData(){

        //扫描包
        Set<String> classNames = ScannerUtils.scanBasePackage(basePackageName);

        for(String str : classNames){
            System.out.println("扫描到类:" + str);
        }
        //获取拥有对应注解的类
        List<Class<?>> excelClass = new ArrayList<Class<?>>();
        for(String str : classNames){

            Class<?> c = null;

            try {
                c = Class.forName(str);
            } catch (ClassNotFoundException e) {
                System.out.println("获取类失败:" + str);
            }

            ApidocService apidocService = c.getAnnotation(ApidocService.class);
            if(apidocService != null){
                System.out.println("含注解@ApidocService的类:" + str);
                excelClass.add(c);
            }
        }

        //这里固定head的名称
        List<String> head = new ArrayList<String>();
        head.add("参数名");
        head.add("类型");
        head.add("是否必输");
        head.add("长度");
        head.add("描述");

        List<ExcelSheet> ess = new ArrayList<ExcelSheet>();
        for(Class<?> c : excelClass){
            ApidocService apidocService = c.getAnnotation(ApidocService.class);
            String classAnnotValue = apidocService.value();

            //获取该类下所有包含@ApidocInterface注解的方法
            for(Method method : c.getMethods()){
                ApidocInterface apidocInterface = method.getAnnotation(ApidocInterface.class);
                if(apidocInterface != null){
                    String methodAnnotValue = apidocInterface.value();
                    ExcelSheet es = new ExcelSheet();
                    //放入固定值head
                    es.setHead(head);
                    //类名 + 方法名 = 一个sheetes.setSheetName(c.getSimpleName() + "." + method.getName());
                    //获取说明
                    String note = classAnnotValue + "——" + methodAnnotValue;
                    es.setNote(note);
                    //获取类名
                    String classPath = c.getName();
                    es.setClassPath(classPath + "." + method.getName());
                    //获取方法参数对象
                    Class<?>[] parameters = method.getParameterTypes();
                    //目前接口就一个对象,所以获取第一个
                    Class<?> parrameterClass = parameters[0];
                    //放入请求参数的内容
                    es.setRequestName(parrameterClass.getName());
                    es.setRequestDatas(createDatas(parrameterClass));
                    //放入返回参数的内容
                    Class<?> responseClass = method.getReturnType();
                    es.setResponseName(responseClass.getName());
                    es.setResponseDatas(createDatas(responseClass));
                    ess.add(es);
                }
            }

        }

        return ess;
    }

    private List<List<String>> createDatas(Class<?> c){

        List<List<String>> datas = new ArrayList<List<String>>();

        for(Field filed : c.getDeclaredFields()){
            //只记录有@ApidocElement注解的属性
            ApidocElement apidocElement = filed.getAnnotation(ApidocElement.class);
            if(apidocElement != null){
                //一个属性的详细信息对应一个list
                List<String> data = new ArrayList<String>();
                data.add(filed.getName());
                data.add(filed.getType().getSimpleName());
                data.add(String.valueOf(apidocElement.required()));
                data.add(apidocElement.minLen() + "-" + apidocElement.maxLen());
                data.add(apidocElement.value());
                datas.add(data);
            }
        }
        return datas;
    }

}

生成Excel的工具类:

package com.zbj.finance.member.api.excel;

import org.apache.poi.hssf.util.HSSFColor;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.util.CellRangeAddress;

/**
 * Created by txf
 *  生成Excel的工具
 */
public class ExcelCreater {

    public static void createExcel(List<ExcelSheet> sheets, String filePath, String fileName) throws Exception{
        HSSFWorkbook book = new HSSFWorkbook();
        for(ExcelSheet excelSheet : sheets){
            createSheet(book, excelSheet);
        }
        creatFile(filePath, fileName);
        File file = new File(filePath + "/" +fileName + ".xls");
        OutputStream os = null;
        os = new FileOutputStream(file);
        book.write(os);
    }

    private static void createSheet(HSSFWorkbook book, ExcelSheet excelSheet){
        try {
            HSSFSheet sheet = book.createSheet(excelSheet.getSheetName());
            HSSFCellStyle style = book.createCellStyle();
            HSSFFont font = book.createFont();
            setFont(font);
            setStyle(style, font);

//          加载合并的说明行第一行;起始行,结束行,起始列,结束列
            CellRangeAddress callRangeAddress = new CellRangeAddress(0,0,1,excelSheet.getHead().size() - 1);
            sheet.addMergedRegion(callRangeAddress);
            sheet.addMergedRegion(callRangeAddress);
            sheet.addMergedRegion(callRangeAddress);
            //第一行是说明
            HSSFRow row0 = sheet.createRow(0);
            row0.createCell(0).setCellValue("说明:");
            row0.createCell(1).setCellValue(excelSheet.getNote());
            //第二行是接口名
            HSSFRow row1 = sheet.createRow(1);
            row1.createCell(0).setCellValue("接口名称:");
            row1.createCell(1).setCellValue(excelSheet.getClassPath());

            //内容开始行
            int dataIndex = 3;
            //内容的第一行是,请求参数名
            sheet.addMergedRegion(callRangeAddress);
            HSSFRow row2 = sheet.createRow(dataIndex);
            row2.createCell(0).setCellValue("请求参数名:");
            row2.createCell(1).setCellValue(excelSheet.getRequestName());

            dataIndex++;
            //填充表头header
            HSSFRow row = sheet.createRow(dataIndex);

            int headIndex = 0;
            for(String headStr : excelSheet.getHead()){
                HSSFCell cell = row.createCell(headIndex);
                cell.setCellValue(headStr);
                headIndex++;
            }

            int dataRow = dataIndex + 1;
            for(List<String> datas : excelSheet.getRequestDatas()){
                HSSFRow rowcol = sheet.createRow(dataRow);//index:第几行
                //定义列数
                int dataCol = 0;
                for(String str : datas){
                    HSSFCell cell = rowcol.createCell(dataCol);//第几列:从0开始
                    cell.setCellValue(str);
                    dataCol++;
                }
                dataRow++;
            }

            dataRow++;

            //写入返回参数
            sheet.addMergedRegion(callRangeAddress);
            HSSFRow row3 = sheet.createRow(dataRow);
            row3.createCell(0).setCellValue("返回参数名:");
            row3.createCell(1).setCellValue(excelSheet.getResponseName());
            dataRow++;
            //填充表头header
            HSSFRow rowTow = sheet.createRow(dataRow);

            int headIndex2 = 0;
            for(String headStr : excelSheet.getHead()){
                HSSFCell cell = rowTow.createCell(headIndex2);
                cell.setCellValue(headStr);
                headIndex2++;
            }
            dataRow++;
            for(List<String> datas : excelSheet.getResponseDatas()){
                HSSFRow rowcol = sheet.createRow(dataRow);//index:第几行
                //定义列数
                int dataCol = 0;
                for(String str : datas){
                    HSSFCell cell = rowcol.createCell(dataCol);//第几列:从0开始
                    cell.setCellValue(str);
                    dataCol++;
                }
                dataRow++;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void setStyle(HSSFCellStyle style, HSSFFont font) {
        //样式设置

        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);

        style.setFont(font);
    }

    private static void setFont(HSSFFont font) {

        font.setColor(HSSFColor.VIOLET.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

    }

    private static void creatFile(String filePath, String fileName) {
        File folder = new File(filePath);
        //文件夹路径不存在
        if (!folder.exists() && !folder.isDirectory()) {
            System.out.println("文件夹路径不存在,创建路径:" + filePath);
            folder.mkdirs();
        } else {
            System.out.println("文件夹路径存在:" + filePath);
        }

        // 如果文件不存在就创建
        File file = new File(filePath + fileName);
        if (!file.exists()) {
            System.out.println("文件不存在,创建文件:" + filePath + fileName);
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("文件已存在,文件为:" + filePath + fileName);
        }
    }

}

main方法:

package com.zbj.finance.member.api.excel;

/**
 * 
 * @author txf
 *  直接运行,生成Excel文档
 */
public class CreateExcelFile {

    public static void main(String[] args) throws Exception {
        ExcelDataCreater edc = new ExcelDataCreater("com.xxx.xxxx.xxx.api.service");
        ExcelCreater.createExcel(edc.createExcelData(), "C:/excel", "接口文档");
    }

}

其中一个用于接口入参的bean:

package com.zbj.finance.member.api.domains;

import javax.web.doc.AbstractResponse;
import javax.web.doc.annotation.ApidocElement;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import com.zbj.finance.member.api.domains.BalanceResponse.BalanceResponseBuilder;
import com.zbj.finance.member.api.enums.BusinessStatus;

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DrawMoneyRequest extends AbstractResponse{

    @ApidocElement(value = "主网用户编号",minLen = 1, maxLen = 11)
    Integer userId;
    @ApidocElement(value = "产品业务代码",minLen = 1, maxLen = 36)
    String bizCode;
    @ApidocElement(value = "订单标题",minLen = 1, maxLen = 255)
    String title;
    @ApidocElement(value = "外部订单号",minLen = 1, maxLen = 100)
    String orderID;
    @ApidocElement(value = "放款金额",minLen = 1, maxLen = 9)
    String amount;
    @ApidocElement(value = "银行卡号",minLen = 1, maxLen = 25)
    String bankAccountNo;

}

生成Excel文档图

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值