注解掃描器設計
先細分一下設計,
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頁面測驗
代碼:略,言之有理即可
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/151189.html
標籤:其他
