个人项目PowerOfLengedJxBrowser-通过注解处理Js与Java交互(二)

注解扫描器设计

先细分一下设计。

1、需要考虑的事:注解对象如何保存,动态引入的jar包如何加载

我定义了一个叫AnnoRepertory的单例类,用于保存注解扫描器所需的配置和数据。

2、怎样知道声明了注解的类在哪里?

递归扫描整个项目肯定是下下策。我们可以主动传入包名,告知程序要扫描哪些包,加速程序启动速度。这里我在AnnoRepertory中定义一个属性做配置

3、我们可能会将某些模块的代码打包成jar或者引入第三方jar,它们该怎么处理?

我好高骛远的考虑可以将模块以jar包的形式导入,类似于插件,目前方案不完善。这里我在AnnoRepertory中定义一个属性,保存需要动态引入的jar包

4、声明注解的类对象和方法该怎样保存?

因为类对象在加载后只产生了一个对象,类似单例,我用List去保存。类中的方法则是用Map形式,键名为 类对象的jspre+方法的name。比如JS调用"Index.test",程序直接去Map中查找是否存在这个键,存在则调用,不存在则告诉JS没有这个方法。我定义了AnnoClass和AnnoMethod去保存类和方法的相关信息。

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 + "]";
    }
     
}

完成以上的操作,我们定义好了所需的数据结构。

接下来,开始写扫描程序,加载所需数据。获取方法参数名用到了spring的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;
    }
}

接下来写JS和Java交互的入口程序。逻辑很简单,根据传入的函数名找到要调用的方法,先把传入的参数转换成Json对象,再转换成方法参数对应的类型。

/**
 * @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>"));
        }
    }
     
}

最后,在脚本初始化动作执行时,载入此Java对象,示例类:

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());
    }
}

在创建Browser对象时设置此适配器

browser.addScriptContextListener(new XymScriptContextAdapter());

写个方法,在前端HTML页面测试

代码:略,言之有理即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值