Personal project PowerOfLengedJxBrowser- Handling Js and Java interactions through annotations (2)

Annotation scanner design

Let's subdivide the design first.

1. Things to consider: how to save annotation objects and how to load dynamically imported jar packages

I defined a singleton class called AnnoRepertory to save the configuration and data required by the annotation scanner.

2. How do I know where the annotated class is?

Scanning the entire project recursively is definitely a bad idea. We can actively pass in the package name, tell the program which packages to scan, and speed up the program startup speed. Here I define a property in AnnoRepertory for configuration

3. We may package the code of some modules into jars or introduce third-party jars, how should they be handled?

I am so far-sighted that the module can be imported in the form of a jar package, similar to a plug-in, but the current solution is not perfect. Here I define an attribute in AnnoRepertory to save the jar package that needs to be dynamically introduced

4. How to save the declared and annotated class objects and methods?

Because the class object only produces one object after loading, similar to a singleton, I use List to save it. The method in the class is in the form of Map, the key is the name of the jspre+ method of the class object. For example, when JS calls "Index.test", the program directly goes to the Map to find whether the key exists, if it exists, call it, and if it does not exist, tell JS that there is no such method. I defined AnnoClass and AnnoMethod to save the related information of the class and method.

import java.util.List;
import java.util.Map;
 
/**
 * @Description:注解仓库对象
 * @author liuming
 */
public class AnnoRepertory {
     
    private final static AnnoRepertory annoRepertory=new AnnoRepertory();
     
    private AnnoRepertory() {}
    /**
     * 获取注解仓库实例
     * @return
     */
    public static AnnoRepertory getInstance() {
        return annoRepertory;
    }
     
    /** 注解扫描包配置,多个包以;号隔开  */
    private String scannerPackage;
    /**引入的jar文件列表*/
    private List<String> extraJars;
    /** 注解类对象集合 */
    private List<AnnoClass> annoClassList;
    /** 方法集合 */
    private Map<String,AnnoMethod> methodMap;
     
    /**
     * 方法集合
     * @return methodMap
     */
    public Map<String, AnnoMethod> getMethodMap() {
        return methodMap;
    }
    /**
     * 设置 方法集合
     * @param methodMap 方法集合
     */
    public void setMethodMap(Map<String, AnnoMethod> methodMap) {
        this.methodMap = methodMap;
    }
    /**
     * 注解类对象集合
     * @return annoClassList 注解类对象集合
     */
    public List<AnnoClass> getAnnoClassList() {
        return annoClassList;
    }
     
    /**
     * 设置 注解类对象集合
     * @param annoClassList 注解类对象集合
     */
    public void setAnnoClassList(List<AnnoClass> annoClassList) {
        this.annoClassList = annoClassList;
    }
    /** 
     * 获取注解扫描包配置,多个包以;号隔开 
     * @return scannerPackage 注解扫描包配置,多个包以;号隔开 
     */
    public String getScannerPackage() {
        return scannerPackage;
    }
    /** 
     * 设置注解扫描包配置,多个包以;号隔开 
     * @param scannerPackage 注解扫描包配置,多个包以;号隔开 
     */
    public void setScannerPackage(String scannerPackage) {
        this.scannerPackage = scannerPackage;
    }
    /**
     * 获取引入的jar文件列表
     * @return extraJars 引入的jar文件列表
     */
    public List<String> getExtraJars() {
        return extraJars;
    }
    /**
     * 设置 引入的jar文件列表
     * @param extraJars 引入的jar文件列表
     */
    public void setExtraJars(List<String> extraJars) {
        this.extraJars = extraJars;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "AnnoRepertory [scannerPackage=" + scannerPackage + ", annoClassList=" + annoClassList + "]";
    }
}
/**
 * @Description:注解类对象
 * @author liuming
 */
public class AnnoClass {
    /**类文件对象*/
    private Class<?> cls;
    /**类实例对象*/
    private Object obj;
    /**类实例名称,如果注解未指定,则用类名(小写开头)*/
    private String name;
    /**js函数名前缀,如果未指定,不使用前缀*/
    private String jspre;
    /**完整类名,包名.类名*/
    private String clsName;
     
    /**
     * 获取类文件对象
     * @return cls 类文件对象
     */
    public Class<?> getCls() {
        return cls;
    }
    /**
     * 设置 类文件对象
     * @param cls 类文件对象
     */
    public void setCls(Class<?> cls) {
        this.cls = cls;
    }
    /**
     * 获取 类实例对象
     * @return obj 类实例对象
     */
    public Object getObj() {
        return obj;
    }
    /**
     * 设置 类实例对象
     * @param obj 类实例对象
     */
    public void setObj(Object obj) {
        this.obj = obj;
    }
    /**
     * 获取 类实例名称,如果注解未指定,则用类名(小写开头)
     * @return name 类实例名称,如果注解未指定,则用类名(小写开头)
     */
    public String getName() {
        return name;
    }
    /**
     * 设置 类实例名称,如果注解未指定,则用类名(小写开头)
     * @param name 类实例名称,如果注解未指定,则用类名(小写开头)
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取 完整类名,包名.类名
     * @return clsName 完整类名,包名.类名
     */
    public String getClsName() {
        return clsName;
    }
    /**
     * 设置 完整类名,包名.类名
     * @param clsName 完整类名,包名.类名
     */
    public void setClsName(String clsName) {
        this.clsName = clsName;
    }
     
     
    /**
     * 获取 js函数名前缀,如果未指定,不使用前缀
     * @return jspre js函数名前缀,如果未指定,不使用前缀
     */
    public String getJspre() {
        return jspre;
    }
    /**
     * 设置 js函数名前缀,如果未指定,不使用前缀
     * @param jsname js函数名前缀,如果未指定,不使用前缀
     */
    public void setJspre(String jspre) {
        this.jspre = jspre;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "AnnoClass [cls=" + cls + ", obj=" + obj + ", name=" + name + ", clsName=" + clsName+", jspre="+jspre + "]";
    }
    public AnnoClass() {}
    /**
     * @param cls 类文件对象
     * @param obj 类实例对象
     * @param name 类实例名称,如果注解未指定,则用类名(小写开头)
     */
    public AnnoClass(Class<?> cls, Object obj, String name) {
        super();
        this.cls = cls;
        this.obj = obj;
        this.name = name;
    }
    /**
     * @param cls 类文件对象
     * @param obj 类实例对象
     * @param name 类实例名称,如果注解未指定,则用类名(小写开头)
     * @param clsName 完整类名,包名.类名
     */
    public AnnoClass(Class<?> cls, Object obj, String name, String clsName) {
        super();
        this.cls = cls;
        this.obj = obj;
        this.name = name;
        this.clsName = clsName;
    }
    /**
     *
     * @param cls 类文件对象
     * @param obj 类实例对象
     * @param name 类实例名称,如果注解未指定,则用类名(小写开头)
     * @param clsName 完整类名,包名.类名
     * @param jsname js对象名,如果未指定,浏览器不注入此JAVA对象
     */
    public AnnoClass(Class<?> cls, Object obj, String name, String clsName,String jspre) {
        super();
        this.cls = cls;
        this.obj = obj;
        this.name = name;
        this.clsName = clsName;
        this.jspre=jspre;
    }
}
import java.lang.reflect.Method;
import java.util.List;
 
/**
 * @Description:注解方法对象
 * @author liuming
 */
public class AnnoMethod {
     
    /**方法对象*/
    private Method method;
     
    /**方法注释*/
    private String desc;
     
    /**类对象*/
    private AnnoClass annoClass;
     
    /** 方法参数对象列表 */
    private List<MethodParam> methodParam;
 
    /**
     * method
     * @return method
     */
    public Method getMethod() {
        return method;
    }
 
    /**
     * 设置 method
     * @param method method
     */
    public void setMethod(Method method) {
        this.method = method;
    }
 
    /**
     * annoClass
     * @return annoClass
     */
    public AnnoClass getAnnoClass() {
        return annoClass;
    }
 
    /**
     * 设置 annoClass
     * @param annoClass annoClass
     */
    public void setAnnoClass(AnnoClass annoClass) {
        this.annoClass = annoClass;
    }
 
    /**
     * methodParam
     * @return methodParam
     */
    public List<MethodParam> getMethodParam() {
        return methodParam;
    }
 
    /**
     * 设置 methodParam
     * @param methodParam methodParam
     */
    public void setMethodParam(List<MethodParam> methodParam) {
        this.methodParam = methodParam;
    }
     
     
     
    /**
     * 获取 方法注释
     * @return desc 方法注释
     */
    public String getDesc() {
        return desc;
    }
 
    /**
     * 设置 方法注释
     * @param desc 方法注释
     */
    public void setDesc(String desc) {
        this.desc = desc;
    }
     
    /**
     * @param method
     * @param desc
     * @param annoClass
     * @param methodParam
     */
    public AnnoMethod(Method method, String desc, AnnoClass annoClass, List<MethodParam> methodParam) {
        super();
        this.method = method;
        this.desc = desc;
        this.annoClass = annoClass;
        this.methodParam = methodParam;
    }
 
    /**
     *
     */
    public AnnoMethod() {
        super();
    }
 
    /**
     * @param method
     * @param annoClass
     * @param methodParam
     */
    public AnnoMethod(Method method, AnnoClass annoClass, List<MethodParam> methodParam) {
        super();
        this.method = method;
        this.annoClass = annoClass;
        this.methodParam = methodParam;
    }
 
    /**
     * @param method
     * @param annoClass
     */
    public AnnoMethod(Method method, AnnoClass annoClass) {
        super();
        this.method = method;
        this.annoClass = annoClass;
    }
 
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "AnnoMethod [method=" + method + ", annoClass=" + annoClass + ", methodParam=" + methodParam + "]";
    }
}
/**
 * @Description: 方法参数
 * @author liuming
 */
public class MethodParam {
    /**参数类型*/
    private Class<?> cls;
    /**参数名*/
    private String name;
    /**
     * cls
     * @return cls
     */
    public Class<?> getCls() {
        return cls;
    }
    /**
     * 设置 cls
     * @param cls cls
     */
    public void setCls(Class<?> cls) {
        this.cls = cls;
    }
    /**
     * name
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置 name
     * @param name name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     *
     */
    public MethodParam() {
        super();
    }
    /**
     * @param cls
     * @param name
     */
    public MethodParam(Class<?> cls, String name) {
        super();
        this.cls = cls;
        this.name = name;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "MethodParam [cls=" + cls + ", name=" + name + "]";
    }
     
}

After completing the above operations, we have defined the required data structure.

Next, start writing the scanning program and load the required data. Get method parameter name uses Spring's LocalVariableTableParameterNameDiscoverer

/**
 * @Description: 注解扫描器
 *      
 * @author liuming
 */
public class AnnotationScanner {
     
    static URLClassLoader urlClassLoader= (URLClassLoader) ClassLoader.getSystemClassLoader();
     
    /**
     * Description:注解扫描入口
     * @author:liuming
     * @since 2017-12-4
     * @return void
     * @throws ScannerPackageNotFoundException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws UnsupportedEncodingException
     * @throws ClassNotFoundException
     * @throws InstantiationException
     */
    public static void scannerMain() throws ScannerPackageNotFoundException, IllegalArgumentException, IllegalAccessException, UnsupportedEncodingException, InstantiationException, ClassNotFoundException{
        AnnoRepertory aRepertory=AnnoRepertory.getInstance();
        if(StringUtils.isBlank(aRepertory.getScannerPackage())){
            throw new ScannerPackageNotFoundException("扫描路径未配置");
        }
        //解析所有需要扫描的包,获取类注解
        getScannerPackages(aRepertory.getScannerPackage());
        //扫描注解类中的所有方法
        analysisAnnoMethodField();
    }
     
    /**
     * Description:获取所有需要扫描的包列表
     * @author:liuming
     * @since 2017-12-4
     * @param packagePath 扫描包路径
     * @throws UnsupportedEncodingException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws ClassNotFoundException
     */
    public static void getScannerPackages(String packagePath) throws UnsupportedEncodingException, ClassNotFoundException, InstantiationException, IllegalAccessException{
        //获取一共要扫描多少包
        String[] packages=packagePath.split(";");
        //获取所有需要扫描的包
        List<String> fpg=new ArrayList<String>();
        for(int i=0;i<packages.length;i++){
            if(StringUtils.isBlank(packages[i])) continue;
            fpg.add(packages[i].replace(".","/"));
        }
        getScannerPackage(fpg);
    }
    /**
     * Description:递归获取所有的包,将*号转换成具体的包名,遍历里面的类
     * @author:liuming
     * @since 2017-12-4
     * @param pgs
     * @return List<String>
     * @throws UnsupportedEncodingException
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static void getScannerPackage(List<String> pgs) throws UnsupportedEncodingException, ClassNotFoundException, InstantiationException, IllegalAccessException{
        List<AnnoClass> annoClassList=new ArrayList<AnnoClass>();
        /***********************扫描指定jar包***********************/
        //获取包名的正则,用于jar扫描时做目录匹配
        List<String> regPgs=new ArrayList<String>();
        for(String pg:pgs) {
            regPgs.add(getPkgReg(pg));
        }
         
        List<String> jarList = AnnoRepertory.getInstance().getExtraJars();
        for(String jar:jarList) {
            try {
                JarFile jarFile=new JarFile(jar);
                Enumeration<JarEntry> entry = jarFile.entries();
                JarEntry jarEntry;
                while (entry.hasMoreElements()) {
                    jarEntry = entry.nextElement();
                    String name = jarEntry.getName();
                    if (name.charAt(0) == '/') {
                        name=name.substring(1);
                    }
                    for(String reg:regPgs) {
                        if(name.matches(reg)) {//匹配成功
                            System.out.println(jar+"扫描的类:"+name);
//                          System.out.println(name.matches(".*?\\$\\d+.*?"));
                            if(name.toLowerCase().endsWith(".class")  && !jarEntry.isDirectory()) {//如果是class文件,加载
                                AnnoClass ac = loadJsClass(name.replace("/",".").substring(0,name.length()-6));
                                if(ac!=null) annoClassList.add(ac);
                            }
                            break;
                        }
                    }
                     
                }
                jarFile.close();
            } catch (IOException e) {
//              e.printStackTrace();
                System.out.println(jar+"文件加载失败,跳过扫描...");
            }
        }
         
        /***********************扫描未在jar包的class**********************/
        for(String pg:pgs){
            analysisAnnoClass(pg,annoClassList);
        }
        AnnoRepertory.getInstance().setAnnoClassList(annoClassList);
    }
     
    /**
     * 扫描非jar包内的class,工程的bin目录
     * @author:liuming
     * @param pg
     * @param annoClassList
     * @throws UnsupportedEncodingException
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void analysisAnnoClass(String pg,List<AnnoClass> annoClassList) throws UnsupportedEncodingException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        int sindex=pg.indexOf("*");
        String pgPath=pg;
        if(sindex!=-1){//如果存在*号
            pgPath=pg.substring(0,sindex);
        }
         
        String protocol ="";//协议名称
        String filePath ="";//资源物理路径
        File file;//文件对象
        URL url = urlClassLoader.getResource(pgPath);
        if(url==null){
            return;
        }
         
        // 得到协议的名称
        protocol = url.getProtocol();
        if("file".equals(protocol)){
            filePath = URLDecoder.decode(url.getFile(), "UTF-8");
            file=new File(filePath);
            if(file.isDirectory()){//如果是目录才处理
                if(pg.indexOf("*")!=-1) {//获取当前包下所有目录,继续向下探查
                    for(File f:file.listFiles()){
                        if(f.isDirectory()){
                            analysisAnnoClass(pgPath+f.getName()+pg.substring(sindex+1), annoClassList);
                        }
                    }
                    return;
                }
                //获取所有的class文件
                 File[] fList=file.listFiles(new FileFilter() {
                     @Override
                     public boolean accept(File f) {
//                       System.out.println("扫描的文件:"+f.getAbsolutePath());
                         return !f.isDirectory() && f.getName().endsWith(".class");
                     }
                 });
                 if(fList!=null){
                     for(File f:fList){
                         AnnoClass ac = loadJsClass((pg+"/"+f.getName().substring(0,f.getName().length()-6)).replace("/","."));
                         if(ac!=null) annoClassList.add(ac);
                     }
                 }
            }
        }
    }
     
    /**
     * 扫描注解文件
     * @author:liuming
     * @param clsName Class名
     * @return
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static AnnoClass loadJsClass(String clsName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class<?> cls=Class.forName(clsName);
//       System.out.println("处理的类文件:"+cls);
         //获取类上的JsClass注解
         JsClass jsClass=cls.getAnnotation(JsClass.class);
         if(jsClass!=null) {
             System.out.println("扫描到的注解类:"+cls+"..."+clsName);
//           System.out.println("注解name:"+jsClass.name());
             String className=jsClass.name();
             if(StringUtils.isBlank(className)) {
//               System.out.println("扫描到的注解>>"+cls.getName());  // 包名.类名
                 className=cls.getSimpleName();
                 className=className.substring(0,1).toLowerCase()+className.substring(1);
    //               System.out.println(className);
             }
             return new AnnoClass(cls, cls.newInstance(), className,cls.getName(),jsClass.jspre());
         }
         return null;
    }
     
    /**
     * 获取包名的正则表达式
     * @author:liuming
     * @param pkg
     * @return
     */
    public static String getPkgReg(String pkg) {
        if(!pkg.endsWith("*") && !pkg.endsWith("/")) {
            pkg+="/";
        }
        if(pkg.endsWith("*")) {
            pkg=pkg.substring(0,pkg.length()-1)+"[^/]*?/[^/]*?";
        }else if(pkg.endsWith("/")) {
            pkg=pkg+"[^/]*?";
        }
        pkg=pkg.replace("/*/", "/[^/]*?/");
        return pkg;
    }
     
    /**
     * 解析注解类中的方法
     * @author:liuming
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    public static void analysisAnnoMethodField() throws IllegalArgumentException, IllegalAccessException {
        List<AnnoClass> annoClassList=AnnoRepertory.getInstance().getAnnoClassList();
        Map<String,AnnoMethod> methodMap=new HashMap<String,AnnoMethod>();
        if(annoClassList!=null && !annoClassList.isEmpty()) {
            for(AnnoClass annoClass:annoClassList) {
//              System.out.println(annoClass);
                //为类中含有@JsObject注解的字段注入实例,只能注入有@JsClass注解的对象,如果@JsObject标注的字段不是注解类对象集合中,抛出注入失败异常
                Field[] fields=annoClass.getCls().getDeclaredFields();
                if(fields.length>0) {
                    for(int i=0;i<fields.length;i++) {
                        fields[i].setAccessible(true);
                        JsObject jsObject=fields[i].getAnnotation(JsObject.class);
                        if(jsObject!=null) {
//                          System.out.println(fields[i].getGenericType().getTypeName());
                            //为属性赋值,以后根据需要做优化
                            for(AnnoClass ac:annoClassList) {
                                if(fields[i].getGenericType().getTypeName().equals(ac.getClsName())) {//如果与列表的类名一致
                                    fields[i].set(annoClass.getObj(), ac.getObj());
                                    break;
                                }
                            }
                        }
                    }
                }
                //解析含有@JsFunction注解的方法,获取方法中的参数
                Method[] methods=annoClass.getCls().getDeclaredMethods();
                if(methods.length>0) {
                    for(int i=0;i<methods.length;i++) {
                        methods[i].setAccessible(true);
                        JsFunction jsFunction=methods[i].getAnnotation(JsFunction.class);
                        if(jsFunction!=null) {//方法含有jsFunction注解
//                          System.out.println(jsFunction.name());//函数名
//                          System.out.println("方法名:"+methods[i].getName());//方法名,不需要
                            AnnoMethod annoMethod=new AnnoMethod(methods[i], annoClass);
                            //获取方法的所有参数
                            Class<?>[] paramClass=methods[i].getParameterTypes();
                            if(paramClass.length>0) {//存在参数
                                List<MethodParam> paramList=new ArrayList<MethodParam>();
                                //使用spring LocalVariableTableParameterNameDiscoverer获取参数名
                                ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
                                String[] pn=parameterNameDiscoverer.getParameterNames(methods[i]);
                                for(int j=0;j<paramClass.length;j++) {
//                                  System.out.println(paramClass[j]+"...."+pn[j]);
                                    paramList.add(new MethodParam(paramClass[j], pn[j]));
                                }
                                annoMethod.setMethodParam(paramList);
                            }
                            String funcName=(StringUtils.isNotBlank(annoClass.getJspre())?annoClass.getJspre()+".":"") + jsFunction.name();
                            System.out.println("扫描到的JS函数:"+funcName);
                            annoMethod.setDesc(jsFunction.desc());
                            methodMap.put(funcName,annoMethod);
                             
                        }
                    }
                }
            }
        }
         
        AnnoRepertory.getInstance().setMethodMap(methodMap);
    }
     
    /**
     *  根据JsClass注解的name获取扫描器保存的实体对象
     * @author:liuming
     * @param name
     * @return
     */
    public static Object getJsClassInstance(String name) {
        List<AnnoClass> annoClassList = AnnoRepertory.getInstance().getAnnoClassList();
        if(annoClassList!=null && !annoClassList.isEmpty()) {
            for(AnnoClass ac:annoClassList) {
                if(name.equals(ac.getName())) {
                    return ac.getObj();
                }
            }
        }
        return null;
    }
}

Next, write the entry program for JS and Java interaction. The logic is very simple. Find the method to be called according to the name of the passed-in function, first convert the passed-in parameter to a Json object, and then convert it to the type corresponding to the method parameter.

/**
 * @Description: JS与JAVA交互的处理类
 *              为何使用此类做JS交互?
 *              多次测试发现,在浏览器创建完window.document后调用JsObject的setProperty设置Java对象,在$(document).ready();方法中有时会出现对象未定义
 *              推测document加载与将Java对象载入JS上下文是同步进行的
 *              所以使用此类做JS与JAVA交互的总入口,尽量避免对象未定义的事情发生。另一个,也是为了方便js处理数据。
 *              网页上调用示例:Java.exec("test",JSON.stringify({data:\"测试\"})); 或者 Java.exec("test",{data:\"测试\"});
 *              绕了一圈,又绕回来了
 * @author liuming
 */
public class PoljbJsToJava {
    //gson对象
    Gson gson=new GsonBuilder().disableHtmlEscaping().serializeNulls().create();
     
    /**
     * 调用扫描到的Java方法
     * @author:liuming
     * @param funcName 函数名
     * @return
     */
    public String exec(String funcName) {
        return exec(funcName, "");
    }
    /**
     * 调用扫描到的Java方法
     * @author:liuming
     * @param funcName 函数名
     * @param jsObject 前端传入的JS对象
     * @return
     */
    public String exec(String funcName,JSObject jsObject) {
//      System.out.println(jsObject.toJSONString());
        return exec(funcName, jsObject.toJSONString());
    }
    /**
     * 调用扫描到的Java方法
     * @author:liuming
     * @param funcName 函数名
     * @param jsObject 前端传入的JSON字符串
     * @return
     */
    public String exec(String funcName,String params) {
        System.out.println("函数名:"+funcName);
        System.out.println("参数:"+params);
        try {
            AnnoMethod annoMethod = AnnoRepertory.getInstance().getMethodMap().get(funcName);
            if(annoMethod==null) {
                System.out.println("函数未在Java代码中声明,调用失败!");
                return gson.toJson(Message.error("函数未在Java代码中声明,调用失败!"));
            }
    //      System.out.println(annoMethod.getMethod().getReturnType());
            JsonObject jsonObject=null;
            if(StringUtils.isNotBlank(params)) {
                JsonParser jp=new JsonParser();
                jsonObject=jp.parse(params).getAsJsonObject();
            }
            //获取方法的参数列表
            List<MethodParam> methodParam = annoMethod.getMethodParam();
            Method method=annoMethod.getMethod();
            method.setAccessible(true);
            Object result=null;
            if(methodParam==null || methodParam.isEmpty()) {//不需要传递参数
                result=method.invoke(annoMethod.getAnnoClass().getObj());
    //          System.out.println(gson.toJson(result));
            }else {//对传入的参数进行处理
                Object[] objs=new Object[methodParam.size()];
                //遍历参数数组是否存在ho类型的参数,标记位置
                for(int i=0;i<methodParam.size();i++) {
                    MethodParam mp=methodParam.get(i);
                    if(jsonObject!=null && jsonObject.get(mp.getName())!=null) {
                        objs[i]=gson.fromJson(jsonObject.get(mp.getName()), mp.getCls());
                    }else {
                        objs[i]=null;
                    }
                }
                 
                result=method.invoke(annoMethod.getAnnoClass().getObj(),objs);
            }
            return gson.toJson(result);
        }catch(Exception e) {
            return gson.toJson(Message.error("程序异常:<br/>"+ToolUtil.getExceptionMessage(e)+"<br/><font color='red'>[一位优秀的程序员准备甩锅](๑>ڡ<)✿ </font>"));
        }
    }
     
}

Finally, when the script initialization action is executed, load this Java object, sample class:

public class XymScriptContextAdapter extends ScriptContextAdapter {
    /* (non-Javadoc)
     * @see com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter#onScriptContextCreated(com.teamdev.jxbrowser.chromium.events.ScriptContextEvent)
     */
    @Override
    public void onScriptContextCreated(ScriptContextEvent event) {
        System.out.println("注入公共脚本!");
        Browser browser = event.getBrowser();
        JSValue value = browser.executeJavaScriptAndReturnValue("window");
        value.asObject().setProperty("Java", new PoljbJsToJava());
    }
}

Set this adapter when creating the Browser object

browser.addScriptContextListener(new XymScriptContextAdapter());

Write a method to test on the front-end HTML page

Code: Omit, just make sense

Guess you like

Origin blog.csdn.net/xymmwap/article/details/108903043