一個小應用獲取項目中調用的其他子模塊的接口列表


 

 

難得最近項目結束了,可以休息一下,但是領導突然給了我一個有點奇葩的任務。

我們項目是分成多個模塊的,我當前做的是其中一個模塊,領導讓我找出我這個模塊中用到其他模塊哪些接口,這些接口中哪些方法。

例如說:

我們service層經常會注入很多的service層接口,這些接口可能是自己模塊的,也有其他模塊的。

而我的任務就是找到我這個項目中引用的A模塊和B模塊的接口,以及調用了他們哪些方法。

 

 

 

這個任務着實是讓人頭疼啊,我的這個項目就有100多個文件,我總不能一個個文件翻吧。

 

雖然說我剛開始還真是這樣的,但是后面實在是不想繼續了。於是乎在摸魚中想到寫個小應用讓程序幫我找

 

想了下整體思路,其實也就四步。

  1. 遍歷所有java文件
  2. 獲取import springcloud_producer.dao.DeptMapper;紅色這串玩意
  3. 獲取private DeptMapper deptMapper;綠色這串玩意
  4. int resultNum = deptMapper.count(query);藍色這串玩意

然后返回不就ok了么,我真聰明。

 

至於怎么獲取,正則表達式不是很牛逼么。

 

全部都准備好了,那就直接開干。

 

附上代碼:

package springcloud_producer_8001;


import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.file.FileAlreadyExistsException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;



public class AppTest   {
    
    /** 用來保存引入的類全限定名 */
    private Set<String> classResult = new HashSet<String>();
    /** 用來保存引用的類的方法,包括普通方法和靜態方法名 */
    private Set<String> methodResult = new HashSet<String>();
    /**
     *     我們要找的目標包
     * */
    private List<String> searchPackages;
    
    
    /**
     *     構造函數
     *     @param searchPackages 我們要找的目標包
     * */
    public AppTest(List<String> searchPackages) {
        if(searchPackages == null || searchPackages.isEmpty()) {
            throw new IllegalArgumentException("searchPackages不能為空");
        }
        this.searchPackages = searchPackages;
    }


    
    /**
     *     獲取目標文件中引用的指定包內的類和使用的方法
     *     @param f 目標文件,如果是文件夾,則會遞歸處理
     * @throws Exception 
     * */
    public void parseAllUsedImportClassAndMethods(String path) throws Exception {
        File file = new File(path);
        // 獲取類和方法
        this.getAllUsedImportClassAndMethods(file);
        // 獲取方法的參數類型
        this.getMethodParams();
    }
    
    
    
    
    /**
     *     遞歸獲取java文件內容
     * */
    private void getAllUsedImportClassAndMethods(File f) throws Exception {
        if(f.isDirectory()) {
            // 如果是目錄,那就遞歸獲取java文件
            File[] listFiles = f.listFiles();
            for(File file :listFiles) {
                this.getAllUsedImportClassAndMethods(file);
            }
        }else {
            // 如果是.java結尾的文件就讀取
            if(f.getName().endsWith(".java")) {
                this.getFileText(f);
            }
        }
    }
    
    /**
     *     讀取文件內容
     * */
    private void getFileText(File file) throws Exception{
        FileReader reader = new FileReader(file);
        char[] buf = new char[1024];
        StringBuilder sb = new StringBuilder();
        while(reader.read(buf ) != -1) {
            sb.append(buf);
        }
        // 獲取引入的類
        Set<String> importClass = this.getImport(sb.toString());
        // 獲取引入的方法
        this.getMethods(sb.toString(), importClass);
        reader.close();
    }
    
    /**
     *     獲取import的類
     * */
    private Set<String> getImport(String fileText)  {
        StringBuilder sb = new StringBuilder();
        sb.append("import +?(");
        for(String packageStr :this.searchPackages) {
            sb.append(packageStr).append(".*?").append("|");
        }
        if(sb.charAt(sb.length() - 1) == '|') {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(") *;");
        Pattern p = Pattern.compile(sb.toString());
        Matcher m = p.matcher(fileText);
        Set<String> thisResult = new HashSet<String>();
        while(m.find()) {
            for(int i = 1; i <= m.groupCount(); i++) {
                String group = m.group(i);
                classResult.add(group);
                thisResult.add(group);
            }
        }
        return thisResult;
    }
    
    /**
     *     獲取調用的方法
     * */
    private void getMethods(String fileText,Set<String> importClass)  {
        // 普通方法
        for(String clasz: importClass) {
            String simpleClass = clasz.substring(clasz.lastIndexOf(".")+1);
            Pattern p = Pattern.compile("private +"+simpleClass+" +(.*?);");
            Matcher m = p.matcher(fileText);
            if(m.find()) {
                String fieldName = m.group(1);
                Pattern p2 = Pattern.compile(fieldName+"\\.([a-zA-Z]+?)\\(.*?\\)");
                Matcher m2 = p2.matcher(fileText);
                while(m2.find()) {
                    for(int i = 1; i <= m2.groupCount(); i++) {
                        String group = m2.group(i);
                        methodResult.add(clasz + "." + group);
                    }
                }
            }
        }
        // 靜態方法
        for(String clasz: importClass) {
            String simpleClass = clasz.substring(clasz.lastIndexOf(".")+1);
            Pattern p2 = Pattern.compile(simpleClass+"\\.([a-zA-Z]+?)\\(.*?\\)");
            Matcher m2 = p2.matcher(fileText);
            while(m2.find()) {
                for(int i = 1; i <= m2.groupCount(); i++) {
                    String group = m2.group(i);
                    methodResult.add(clasz + "." + group);
                }
            }
        }
    }
    
    
    /**
     *     獲取類方法的參數類型
     * */
    @SuppressWarnings("rawtypes")
    private void getMethodParams() {
        this.methodResult = this.methodResult.stream().sorted().map((methodStr)->{
            // 獲取方法的參數
            StringBuilder sb = new StringBuilder(methodStr);
            sb.append("(");
            int pointLastIndex = methodStr.lastIndexOf(".");
            String methodName = methodStr.substring(pointLastIndex+1);
            String className = methodStr.substring(0,pointLastIndex);
            try {
                Class<?> clasz = Class.forName(className);
                Method[] declaredMethods = clasz.getDeclaredMethods();
                for(Method method: declaredMethods) {
                    if(method.getName().equals(methodName)) {
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        for(Class p: parameterTypes) {
                            sb.append(p.getSimpleName()).append(" ,");
                        }
                        break;
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                return methodStr;
            }
            if(sb.charAt(sb.length()-1) == ',') {
                sb.deleteCharAt(sb.length()-1);
            }
            sb.append(")");
            return sb.toString();
        }).collect(Collectors.toSet());
    }
    
    /**
     *     導出
     *     @throws Exception 
     * */
    public void export(String path) throws Exception {
        File file = new File(path);
        if(file.exists()) {
            throw new FileAlreadyExistsException(path);
        }
        // 創建父目錄
        file.getParentFile().mkdirs();
        FileWriter fw = new FileWriter(file);
        
        fw.write("引用的類如下:\n");
        for(String clasz: this.classResult) {
            fw.write(clasz);
            fw.write("\n");
        }
        
        fw.write("\n使用的引用類的方法如下:\n");
        for(String method: this.methodResult) {
            fw.write(method);
            fw.write("\n");
        }
        fw.flush();
        fw.close();
    }
    
    /**
     *     導出
     *     @throws Exception 
     * */
    public void export(OutputStream out) throws Exception {
        
        out.write("引用的類如下:\n".getBytes(Charset.forName("utf-8")));
        for(String clasz: this.classResult) {
            out.write(clasz.getBytes(Charset.forName("utf-8")));
            out.write("\n".getBytes(Charset.forName("utf-8")));
        }
        
        out.write("\n使用的引用類的方法如下:\n".getBytes(Charset.forName("utf-8")));
        for(String method: this.methodResult) {
            out.write(method.getBytes(Charset.forName("utf-8")));
            out.write("\n".getBytes(Charset.forName("utf-8")));
        }
        out.flush();
        out.close();
    }
    
    
    /**
     *     測試
     * */
    public static void main(String[] args) throws Exception {
        AppTest test = new AppTest(Arrays.asList("springcloud_producer.service"));
        test.parseAllUsedImportClassAndMethods("D:\\workspace\\java_web\\springcloud-parent\\springcloud_producer\\src\\main\\java\\springcloud_producer");
        test.export(System.out);
        test.export("C:\\Users\\HongCheng\\Desktop\\2.txt");
    }
}

 

 

下面這個是我的運行效果:

 

 

不過要注意一下,因為會用到反射,所以這代碼最好放在你要搜索的項目里面,不然會導致反射失敗

 

不過idea應該有類似的功能,沒必要像我一樣做

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM