All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.schoolwow.quickapi.QuickAPI Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
package cn.schoolwow.quickapi;

import cn.schoolwow.quickapi.domain.*;
import cn.schoolwow.quickapi.handler.controller.AbstractControllerHandler;
import cn.schoolwow.quickapi.handler.entity.AbstractEntityHandler;
import cn.schoolwow.quickapi.util.QuickAPIConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class QuickAPI{
    private static Logger logger = LoggerFactory.getLogger(QuickAPI.class);
    public static QuickAPI newInstance(){
        return new QuickAPI();
    }

    private volatile APIDocument apiDocument;

    private QuickAPI(){
        if(null==apiDocument){
            synchronized (QuickAPI.class){
                if(null==apiDocument){
                    apiDocument = new APIDocument();
                }
            }
        }
    }

    /**
     * 指定文档标题
     * @param title 指定接口文档标题(唯一标识)
     * */
    public QuickAPI title(String title){
        apiDocument.title = title;
        return this;
    }

    /**
    * 设置文档描述
    * @param description 文档描述
    */
    public QuickAPI description(String description){
        apiDocument.description = description;
        return this;
    }

    /**
     * 扫描controller层
     * @param packageName 扫描Controller包
     * */
    public QuickAPI controller(String packageName){
        QuickAPIConfig.controllerPackageNameList.add(packageName);
        return this;
    }

    /**
     * 扫描controller层
     * @param clazz 扫描单个Controller类
     * */
    public QuickAPI controller(Class clazz){
        QuickAPIConfig.controllerClassList.add(clazz);
        return this;
    }

    /**Controller涉及的实体类层
     * @param packageName 扫描实体类包
     * */
    public QuickAPI entity(String packageName){
        QuickAPIConfig.entityPackageNameList.add(packageName);
        return this;
    }

    /**
     * Controller涉及的实体类层
     * @param clazz 扫描单个实体类
     * */
    public QuickAPI entity(Class clazz){
        QuickAPIConfig.entityClassList.add(clazz);
        return this;
    }

    /**
     * 接口路径前缀
     * @param prefix 接口路径前缀(context-path)
     * */
    public QuickAPI prefix(String prefix){
        apiDocument.prefix = prefix;
        return this;
    }

    /**
     * 文档路径地址
     * @param url 指定文档访问路径
     * */
    public QuickAPI url(String url){
        QuickAPIConfig.url = url;
        return this;
    }

    /**
     * 文档生成目录
     * @param directory 指定文档生成目录
     * */
    public QuickAPI directory(String directory){
        QuickAPIConfig.directory = directory;
        return this;
    }

    /**
     * Java源代码路径
     * @param sourcePath 指定java源代码所在目录
     * */
    public QuickAPI sourcePath(String sourcePath){
        QuickAPIConfig.sourcePath = sourcePath;
        return this;
    }

    /**
     * 忽略包名
     * @param ignorePackageName 要忽略的包名
     * */
    public QuickAPI ignorePackageName(String ignorePackageName){
        QuickAPIConfig.ignorePackageNameList.add(ignorePackageName);
        return this;
    }

    /**
     * 忽略类
     * @param ignoreClassName 要忽略的类名
     * */
    public QuickAPI ignoreClass(String ignoreClassName){
        QuickAPIConfig.ignoreClassList.add(ignoreClassName);
        return this;
    }

    /**
     * 扫描类过滤接口
     * @param predicate 函数式接口
     * */
    public QuickAPI filter(Predicate predicate){
        QuickAPIConfig.predicate = predicate;
        return this;
    }

    /**生成接口文档*/
    public QuickAPI generate(){
        //检测Java
        {
            File file = new File(QuickAPIConfig.sourcePath);
            if(!file.exists()){
                logger.warn("[源路径不存在]JavaDoc无法提取!请配置正确的源路径地址!当前源路径:{}",QuickAPIConfig.sourcePath);
            }
        }
        try {
            //生成API接口信息
            {
                apiDocument.date = new Date();
                apiDocument.apiControllerList = AbstractControllerHandler.apiControllerList;;
                apiDocument.apiEntityMap = AbstractEntityHandler.apiEntityMap;
                //生成json数据
                {
                    File file = new File(QuickAPIConfig.directory+QuickAPIConfig.url+"/api.json");
                    compareJSON(file,apiDocument);
                    String data = JSON.toJSONString(apiDocument, SerializerFeature.DisableCircularReferenceDetect);
                    generateFile(data,file);
                    QuickAPIConfig.jsonObject = data;
                }
                //生成swagger.json文件
                {
                    String data = generateSwagger(apiDocument);
                    File file = new File(QuickAPIConfig.directory+QuickAPIConfig.url+"/swagger.json");
                    generateFile(data,file);
                }
            }
            //复制静态资源文件
            {
                URL url = ClassLoader.getSystemResource("quickapi");
                switch(url.getProtocol()){
                    case "file":{

                    };break;
                    case "jar":{
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        JarFile jarFile = jarURLConnection.getJarFile();
                        Enumeration jarEntryEnumeration = jarFile.entries();
                        while(jarEntryEnumeration.hasMoreElements()){
                            JarEntry jarEntry = jarEntryEnumeration.nextElement();
                            if(
                                    jarEntry.getName().endsWith(".html")||
                                    jarEntry.getName().endsWith(".css")||
                                    jarEntry.getName().endsWith(".js")||
                                    jarEntry.getName().endsWith(".woff2")
                            ){
                                InputStream inputStream = jarFile.getInputStream(jarEntry);
                                String name = jarEntry.getName();
                                name = name.substring(name.indexOf("/"));
                                File file = new File(QuickAPIConfig.directory+QuickAPIConfig.url+name);
                                generateFile(inputStream,file);
                            }
                        }
                    };break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this;
    }

    /**上传到默认服务器*/
    public void upload() {
        upload("https://api.schoolwow.cn");
    }

    /**
     * 上传到服务器
     * @param host 服务器地址
     * */
    public void upload(String host) {
        upload(host,null);
    }
    /**
     * 上传到服务器
     * @param host 服务器地址
     * @param proxy http代理
     * */
    public void upload(String host, Proxy proxy) {
        if(QuickAPIConfig.jsonObject==null||QuickAPIConfig.jsonObject.isEmpty()){
            throw new IllegalArgumentException("请先调用generate()方法!");
        }
        StringBuilder sb = new StringBuilder();
        Scanner scanner = null;
        HttpURLConnection httpURLConnection = null;
        try {
            if(null==proxy){
                httpURLConnection = (HttpURLConnection) new URL(host+"/api/projectVersion/uploadAPI").openConnection();
            }else{
                httpURLConnection = (HttpURLConnection) new URL(host+"/api/projectVersion/uploadAPI").openConnection(proxy);
            }
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setRequestProperty("Content-Type","application/json; charset=utf-8");
            httpURLConnection.setConnectTimeout(10000);
            httpURLConnection.setReadTimeout(10000);
            httpURLConnection.setUseCaches(false);
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);
            byte[] bytes = QuickAPIConfig.jsonObject.getBytes();
            httpURLConnection.setFixedLengthStreamingMode(bytes.length);
            httpURLConnection.getOutputStream().write(bytes);
            httpURLConnection.getOutputStream().flush();
            httpURLConnection.connect();
            int statusCode = httpURLConnection.getResponseCode();

            if(statusCode==200){
                scanner = new Scanner(httpURLConnection.getInputStream());
            }else{
                scanner = new Scanner(httpURLConnection.getErrorStream());
            }
            while(scanner.hasNextLine()){
                sb.append(scanner.nextLine());
            }
            scanner.close();
            if(statusCode==200){
                logger.info("[上传成功]{}",sb.toString());
            }else{
                logger.warn("[上传失败]{}",sb.toString());
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(null!=scanner){
                scanner.close();
            }
        }
    }

    /**比较新老JSON文件,获取变更信息*/
    private void compareJSON(File file,APIDocument newAPIDocument) throws FileNotFoundException {
        if(!file.exists()){
            return;
        }
        Scanner scanner = new Scanner(file);
        StringBuilder builder = new StringBuilder();
        while(scanner.hasNextLine()){
            builder.append(scanner.nextLine());
        }
        scanner.close();
        APIDocument oldAPIDocument = JSON.parseObject(builder.toString()).toJavaObject(APIDocument.class);
        //比对API
        List oldAPIControllerList = oldAPIDocument.apiControllerList;
        List newAPIControllerList = newAPIDocument.apiControllerList;
        //提取变更列表
        APIHistory apiHistory = new APIHistory();
        for(APIController newAPIController:newAPIControllerList){
            if(!oldAPIControllerList.contains(newAPIController)){
                List newAPIList = newAPIController.apiList;
                for(API api:newAPIList){
                    apiHistory.addList.add(newAPIController.className+"#"+api.methods[0]+"_"+api.url);
                    logger.info("[新增接口]{} {} {}",api.name,api.methods[0],api.url);
                }
                continue;
            }
            for(APIController oldAPIController:oldAPIControllerList){
                if(newAPIController.className.equals(oldAPIController.className)){
                    List newAPIList = newAPIController.apiList;
                    List oldAPIList = oldAPIController.apiList;
                    for(API newAPI:newAPIList){
                        //判断是否新增
                        if(!oldAPIList.contains(newAPI)){
                            apiHistory.addList.add(newAPIController.className+"#"+newAPI.methods[0]+"_"+newAPI.url);
                            logger.info("[新增接口]{} {} {}",newAPI.name,newAPI.methods[0],newAPI.url);
                            continue;
                        }
                        //判断是否变更
                        for(API oldAPI:oldAPIList){
                            if(newAPI.equals(oldAPI)&&!Arrays.equals(newAPI.apiParameters,oldAPI.apiParameters)){
                                apiHistory.modifyList.add(newAPIController.className+"#"+newAPI.methods[0]+"_"+newAPI.url);
                                logger.info("[变更接口]{} {} {}",newAPI.name,newAPI.methods[0],newAPI.url);
                                break;
                            }
                        }
                    }
                    break;
                }
            }
        }
        //判断是否删除
        for(APIController oldAPIController:oldAPIControllerList){
            if(!newAPIControllerList.contains(oldAPIController)){
                List apiList = oldAPIController.apiList;
                for(API api:apiList){
                    apiHistory.deleteList.add(api);
                    logger.info("[删除接口]{} {} {}",api.name,api.methods[0],api.url);
                }
                continue;
            }
            for(APIController newAPIController:newAPIControllerList){
                if(oldAPIController.className.equals(newAPIController.className)){
                    List oldAPIList = oldAPIController.apiList;
                    List newAPIList = newAPIController.apiList;
                    for(API oldAPI:oldAPIList){
                        if(!newAPIList.contains(oldAPI)){
                            apiHistory.deleteList.add(oldAPI);
                            logger.info("[删除接口]{} {} {}",oldAPI.name,oldAPI.methods[0],oldAPI.url);
                        }
                    }
                    break;
                }
            }
        }
        if(!apiHistory.addList.isEmpty()||!apiHistory.modifyList.isEmpty()||!apiHistory.deleteList.isEmpty()){
            oldAPIDocument.apiHistoryList.add(0,apiHistory);
        }
        newAPIDocument.apiHistoryList = oldAPIDocument.apiHistoryList;
    }

    private String generateSwagger(APIDocument apiDocument){
        JSONObject o = new JSONObject();
        o.put("swagger","2.0");
        o.put("info",JSON.parseObject("{\"title\":\""+apiDocument.title+"\",\"version\":\"last\"}"));
        o.put("basePath","/");
        //添加tag
        {
            JSONArray tagArray = new JSONArray();
            for(APIController apiController:apiDocument.apiControllerList){
                tagArray.add(JSON.parseObject("{\"name\":\""+apiController.name+"\",\"description\":null}"));
            }
            o.put("tags",tagArray);
        }
        o.put("schemes",JSON.parseArray("[\"http\"]"));
        //添加path
        {
            JSONObject paths = new JSONObject();
            for(APIController apiController:apiDocument.apiControllerList){
                for(API api:apiController.apiList){
                    JSONObject p = new JSONObject();
                    p.put("tags",JSON.parseArray("[\""+apiController.name+"\"]"));
                    p.put("summary",api.name);
                    p.put("description",api.description);
                    //添加参数
                    {
                        JSONArray parameters = new JSONArray();
                        for(APIParameter apiParameter:api.apiParameters){
                            JSONObject q = new JSONObject();
                            q.put("name",apiParameter.name);
                            q.put("in",apiParameter.position);
                            q.put("required",apiParameter.required);
                            if(null==apiParameter.description){
                                q.put("description","");
                            }else{
                                q.put("description",apiParameter.description+("".equals(apiParameter.defaultValue)?"":",默认为"+apiParameter.defaultValue));
                            }
                            switch(apiParameter.requestType){
                                case "text":{
                                    q.put("type","string");
                                }break;
                                case "textarea":{
                                    q.put("name","root");
                                    p.put("consumes",JSON.parseArray("[\"application/json\"]"));
                                    JSONObject schema = new JSONObject();
                                    schema.put("$schema","http://json-schema.org/draft-04/schema#");
                                    schema.put("type","object");
                                    APIEntity apiEntity = apiDocument.apiEntityMap.get(apiParameter.type);
                                    if(null!=apiEntity){
                                        JSONObject fieldProperty = new JSONObject();
                                        if(null!=apiEntity.apiFields){
                                            for(APIField apiField:apiEntity.apiFields){
                                                fieldProperty.put(apiField.name,JSON.parseObject("{\"type\":\"string\",\"description\":\""+apiField.description+"\"}"));
                                            }
                                        }
                                        schema.put("properties",fieldProperty);
                                    }
                                    q.put("schema",schema);
                                }break;
                                case "file":{
                                    q.put("in","formData");
                                    q.put("type","file");
                                    q.put("description","上传的文件");
                                    p.put("consumes",JSON.parseArray("[\"multipart/form-data\"]"));
                                }break;
                            }
                            parameters.add(q);
                        }
                        p.put("parameters",parameters);
                    }
                    p.put("responses",JSON.parseObject("{\"200\":{\"description\":\"successful operation\",\"schema\":{}}}"));
                    paths.put(api.url,JSON.parseObject("{\""+api.methods[0].toLowerCase()+"\":"+p.toJSONString()+"}"));
                }
            }
            o.put("paths",paths);
        }
        return o.toJSONString();
    }

    private void generateFile(InputStream inputStream,File file) throws IOException {
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
        byte[] bytes = new byte[8192];
        int length=-1;
        while((length=inputStream.read(bytes,0,bytes.length))!=-1){
            fos.write(bytes,0,length);
        }
        fos.flush();
        fos.close();
    }

    private void generateFile(String data,File file) throws FileNotFoundException {
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        PrintWriter pw = new PrintWriter(file);
        pw.print(data);
        pw.flush();
        pw.close();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy