spidermonkeys_嵌入式开发网站

spidermonkeys_嵌入式开发网站
利用SpiderMonkey进行嵌入式开发——学习总结
关键词:SpiderMonkey                                          利用SpiderMonkey进行嵌入式开发——学习总结许峰2007/07/30最近在学习javascript引擎SpiderMonkey,学了一个星期了,终于有点眉目,现将学习经验记录下来,已被后用。
一下将逐步记录我学习的过程。1、下载源文件以及编译
在 http://ftp.mozilla

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

利用SpiderMonkey进行嵌入式开发——学习总结

关键词: SpiderMonkey                                          
利用SpiderMonkey进行嵌入式开发——学习总结
许峰 2007/07/30
最近在学习javascript引擎SpiderMonkey,学了一个星期了,终于有点眉目,现将学习经验记录下来,已被后用。

一下将逐步记录我学习的过程。
1、下载源文件以及编译

在 
http://ftp.mozilla.org/pub/mozilla.org/js/ 下面有一个文件js-1.60.tar.gz, 这个就是SpiderMonkey的源代码

将源码下载后,解压缩。比如我下载到 /home/xufeng/work/jsEngine 下面,解压后就产生一个文件夹js,源文件全部在js/src中,进入js/src,进行编译(请参考README)。

以上所用的命令有:

$tar xvzf js-1.60.tar.gz

$cd js/src

$make -f Makefile.ref
2.运行一个实例程序

编译过后就会生成javascript引擎的静态库和动态库,分别是libjs.a和libjs.so,在js/src/Linux_All_DBG.OBJ/目录下面.进入这个目录就可以看见.如果要使用javascript引擎,只要在头文件中包含jsapi.h 同时在编译的时候链接这些库就可以了.

在Linux_ALL_DBG.OBJ目录下面还有一个可执行程序 js, 运行这个程序将产生类似shell的东西,可以在下面运行javascript代码.
3.利用javascript引擎进行嵌入式开发

先写一个最简单的程序,用来执行一段javascript代码(javascript代码也是很简单).这个程序也基本上展示了最主要的几个API.

程序如下:

/**

 *程序 test1.c

 *执行一段javascript代码 

 */

  

#include “jsapi.h”

/* EXIT_FAILURE and EXIT_SUCCESS */

#include “stdlib.h”

/* strlen */

#include “string.h”
static void usage();
int main(int argc,const char* argv[])

{

    /* pointer to our runtime object */

    if(argc!=2){

            usage();

            exit(-1);

    }

    JSRuntime *runtime = NULL;

    /* pointer to our context */

    JSContext *context = NULL;

    /* pointer to our global JavaScript object */

    JSObject *global = NULL;
    /* script to run (should return 100) */

    const char *script = argv[1];

    /* JavaScript value to store the result of the script */

    jsval rval;
    /* create new runtime, new context, global object */

    if ((!(runtime = JS_NewRuntime(1024L * 1024L)))

        || (!(context = JS_NewContext(runtime, 8192)))

        || (!(global = JS_NewObject(context, NULL, NULL, NULL)))

        )

        return EXIT_FAILURE;

    /* set global object of context and initialize standard ECMAScript

     *      objects (Math, Date, …) within this global object scope */

    if (!JS_InitStandardClasses(context, global))

         return EXIT_FAILURE;
    /* now we are ready to run our script */

    if (!JS_EvaluateScript(context, global, script, strlen(script), “script”, 1, &rval))

         return EXIT_FAILURE;
    printf(“the script’s result is /n%d/n”,JSVAL_TO_INT(rval));
    /* clean up */

    JS_DestroyContext(context);

    JS_DestroyRuntime(runtime);

    JS_ShutDown();

    return EXIT_SUCCESS;

}
void usage()

{

        printf(“example1 script_content/n”);

        printf(“for example:./example1 /”var a=1;b=2;a+b/”/n”);

}

/**

 *程序结束

 */

以上程序写好以后就要编译了,编译的时候要注意增加一些编译参数。这里我写了一个简单的Makefile

########################################################################################################

ROSS_COMPILE_PREFIX =

CROSS_COMPILE_PATH   =

CC      =  $(CROSS_COMPILE_PREFIX)gcc

CFLAGS  = -DXP_UNIX -DJS_THREADSAFE -g -O0 -Wall -W -pedantic -std=c99 -I$(HOME)/work/jsEngine/js/src/

LDFLAGS = -L$(HOME)/work/jsEngine/js/src/Linux_All_DBG.OBJ/

LIBS = -ljs

DFLAGS  =  -g -DDEBUG

CLINK  = -c -o

RM  = rm -f

CFILES = test1.c
OBJ  = $(patsubst %.c,%.o, $(CFILES))

EXECUTABLE = $(patsubst %.c,%, $(CFILES))

DEPENDENCY = $(patsubst %.c,%.d, $(CFILES))
all: $(DEPENDENCY) $(EXECUTABLE)
indent :

        find -name ‘*.[ch]’|xargs indent -kr -cli4 -i4 -nut

doc:

        doxygen

include $(DEPENDENCY)

%: %.o

        $(CC) $< $(LIBS) -o $@ $(LDFLAGS)

%.o: %.c

        $(CC) -c $< -o$@ $(CFLAGS)

%.d: %.c

        $(CC) -MM $(CFLAGS) $< >$@.$$$$;/

        sed ‘s,/($*/)/.o:,/1.o 
$@:,g’ < 
$@.$$$$ > 
$@;/

        $(RM) 
$@.$$$$;

clean:

        $(RM) $(EXECUTABLE) *.o *.bak *.c~ *.h~ *.d

########################################################################################################
需要注意的是CFLAGS和DFLAGS,针对自己的路径要做修改。

-ljs — 链接的时候增加libjs.so库 

-DXP_UNIX — 告诉编译器define XP_UNIX,使得javascript引擎知道操作系统是Unix或类似于Unix系统(这个参数是必需的,否则编译出错,我就在这里碰了跟头) 

-O0 — 不让编译器进行优化
有了以上步骤就可以进行编译运行了。初步的工作已经完成。
执行javascript代码的主要过程有:

1. 创建一个Runtime, API为 JS_NewRuntime()

2. 创建一个Context, API为 JS_NewContext()

3. 创建一个对象Object, API为 JS_NewObject()

4. 初始化全局对象 JS_InitStandardClasses()

5. 执行javascript代码 JS_EvaluateScript()

6. 销毁上下文Context JS_DestroyContext()

7. 销毁Runtime JS_DestroyRuntime()

以上就是主要的过程, 接下来的一些深入的工作都是基于此的.
4. 利用javascript引擎来解析一个javascript文件

在上面的程序中,javascript语句是当作命令行参数传给程序的, 有点的时候觉得不太方便, 于是将所有的javascript写道一个文件中, 然后解析这个文件, 执行语句. 执行一个文件中的javascript语句一般有两种方法:其一是定义FILE *fp, 利用 fp 将这个文件所有字节读出来,然后作为字符串传递给JS_EvaluateScript() API,得到结果;第二种是先编译这个js文件,然后再执行已经编译的文件。以下将给出这两种方法的实例。
方法一:

/**

 *程序 test2.c

 *利用FILE *fp文件指针执行js文件的代码

 */

#include “jsapi.h”
JSClass global_class = 

{

    “global”,

 0,

 JS_PropertyStub, 

 JS_PropertyStub,

 JS_PropertyStub, 

 JS_PropertyStub,

 JS_EnumerateStub, 

 JS_ResolveStub,

 JS_ConvertStub, 

 JS_FinalizeStub,

 JSCLASS_NO_OPTIONAL_MEMBERS

};

int main()

{

    JSString* jss;

    char buf[5120];

    int len;

    jsval rval;

    JSRuntime *rt;

    JSContext *cx;

    JSObject *globalObj;

    

    rt = JS_NewRuntime(1024L*1024L);

    if (!rt)return -1;

    cx = JS_NewContext(rt, 8L*1024L);

    if (!cx)return -1;

    

    if (!(globalObj = JS_NewObject (cx, &global_class, NULL, NULL)))return -1;

    JS_InitStandardClasses (cx, globalObj);

    

    FILE* fp;

 if (!(fp = fopen (“test.js”, “r”)))return -1;

    len = fread (buf, 1, 5120, fp);

    fclose (fp);

    if (len <= 0)return -1;

 JS_EvaluateScript (cx, globalObj, buf, len, “”, 1, &rval);

 jss = JS_ValueToString (cx, rval);

 fprintf(stdout, “The result is: %s/n”, JS_GetStringBytes(jss));

 JS_DestroyContext(cx);

 JS_DestroyRuntime(rt);

 return 0;

}
/**

 *程序结束

 */

javascript文件内容如下:

/**

 *test.js

 */

var i = 1;

var j = 2;

i+j;

/**

 *End

 */
好了,运行这个程序,将得到如下结果:

The result is: 3
方法二:

/**

 *程序 test3.c

 *先编译js文件,再执行文件

 */

/* EXIT_FAILURE and EXIT_SUCCESS */

#include “stdlib.h”

/* strlen */

#include “string.h”

/* get SpiderMonkey API declarations */

#include “sys/types.h”

#include “sys/stat.h”

#include “jsapi.h”
/*Function prototypes definition*/

JSBool JsFileExecute(JSContext *ctx, const char *file);

int usage(const char *progname);
JSClass JsGlobalObjectClass = {

 “System”,

 0,

 JS_PropertyStub,

 JS_PropertyStub,

 JS_PropertyStub,

 JS_PropertyStub,

 JS_EnumerateStub,

 JS_ResolveStub,

 JS_ConvertStub,

 JS_FinalizeStub,

 JSCLASS_NO_OPTIONAL_MEMBERS

};
int main(int argc, char **argv)

{

 JSRuntime *rt = NULL;

 JSContext *ctx = NULL;

 JSObject *obj = NULL;

 char *file = NULL;

 if (argc < 2)

 {

  usage(argv[0]);

 }

 else

 {

  file = argv[1];

 }

    

    rt = JS_NewRuntime(1024L*1024L);

    if(!rt)

    {

     printf(“Runtime created failed./n”);

     return -1;

 }

    ctx = JS_NewContext(rt, 8L*1024L);

    if(!ctx)

    {

     printf(“Context created failed./n”);

     JS_DestroyRuntime(rt);

     return -1;

 }

 obj = JS_NewObject(ctx, &JsGlobalObjectClass, NULL, NULL);

    if(!obj)

    {

     printf(“Object created failed./n”);

     JS_DestroyContext(ctx);

     JS_DestroyRuntime(rt);

     return -1;

 }

 JS_InitStandardClasses(ctx, obj);
 if(JsFileExecute(ctx, file))

    {

     printf(“File execute successfully./n”);

 }

 else

 {

     printf(“File execute failed./n”);

 }

 return 0;

}
int usage(const char *progname)

{

 printf(“Usage: %s <file>/n”, progname);

 exit(-1);

}
JSBool JsFileExecute(JSContext *ctx, const char *file)

{

    JSScript *script = NULL;

    JSString *jss;

    JSBool retval;

    jsval ret;

    JSObject *global = JS_GetGlobalObject(ctx);

    

    script = JS_CompileFile(ctx, global, file);

    if(script == NULL)

    {

     return JS_FALSE;

 }

 retval = JS_ExecuteScript(ctx, global, script, &ret);

 jss = JS_ValueToString (ctx, ret);

 printf(“The result is: %s/n”, JS_GetStringBytes(jss));

 JS_DestroyScript(ctx, script);

    return retval;

}

/**

 *End

 */

这种方法先是用JS_CompileFile() API来编译文件,得到一个script,然后再JS_ExecuteScript() 来运行script,我觉得这种方法更加好一些。

运行的时候,js文件还是用的test.js,其源码同上。
5. 在程序中增加类

javascript是面向对象的,一个类常有构造函数、属性和方法等,在下面的程序中我们构建一个类,并逐步增加类的属性和方法。   

在如下程序中,定义了一个PeopleClass类,然后用

static JSFunctionSpec PeopleMethods[] = {

    {“print”, PeoplePrint, 0, 0, 0},

 {NULL}

};

来定义类的方法,如果有更多的方法也可以在这里定义,其中 “print” 是将在javascript中采用的方法名,PeoplePrint是在程序中实现的类的方法,后面的参数请参考API说明。

/**

 *程序 test4.c

 */
#include “stdio.h”

#include “jsapi.h”
static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);

JSBool JsFileExecute(JSContext *ctx, const char *file);

int usage(const char *progname);
typedef struct

{

    char name[16];

    char addr[64];

    char tel[10];

}PeopleInfo;

static PeopleInfo pinfo={“xufeng”, “Chongqing”, “123456”};
JSClass global_class = {

     “global”,

  0,

  JS_PropertyStub, 

  JS_PropertyStub,

  JS_PropertyStub, 

  JS_PropertyStub,

  JS_EnumerateStub, 

  JS_ResolveStub,

  JS_ConvertStub, 

  JS_FinalizeStub,

  JSCLASS_NO_OPTIONAL_MEMBERS

};
static JSClass PeopleClass = {

  “people”,

  0,

  JS_PropertyStub,

  JS_PropertyStub,

  JS_PropertyStub,

  JS_PropertyStub,

  JS_EnumerateStub,

  JS_ResolveStub,

  JS_ConvertStub, 

  JS_FinalizeStub,

  JSCLASS_NO_OPTIONAL_MEMBERS

};
static JSFunctionSpec PeopleMethods[] = {

    {“print”, PeoplePrint, 0, 0, 0},

 {NULL}

};

int main(int argc, char **argv)

{

 JSRuntime *rt;

    JSContext *cx;

    JSObject *globalObj,*PeopleObj;

    char *file = NULL;

 if (argc < 2)

 {

  usage(argv[0]);

 }

 else

 {

  file = argv[1];

 }

    

 rt = JS_NewRuntime(1024L*1024L);

    if (!rt)return -1;

    cx = JS_NewContext(rt, 8L*1024L);

    if (!cx)return -1;

    

    if (!(globalObj = JS_NewObject (cx, &global_class, NULL, NULL)))return -1;

    JS_InitStandardClasses (cx, globalObj);

    

    PeopleObj = JS_DefineObject (cx, globalObj, “people”, &PeopleClass, 0, JSPROP_ENUMERATE);

 JS_DefineFunctions (cx,PeopleObj, PeopleMethods);

    if(JsFileExecute(cx, file))

    {

     printf(“File execute successfully./n”);

 }

 else

 {

     printf(“File execute failed./n”);

 }

 JS_DestroyContext(cx);

 JS_DestroyRuntime(rt);

 return 0;

}
static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)

{

    fprintf(stdout,”My Name is %s./nMy Addr is %s./nMy telephone is %s/n”, pinfo.name, pinfo.addr, pinfo.tel);

    return JS_TRUE;

}

JSBool JsFileExecute(JSContext *ctx, const char *file)

{

    JSScript *script = NULL;

    JSBool retval;

    jsval ret;

    JSObject *global = JS_GetGlobalObject(ctx);

    

    script = JS_CompileFile(ctx, global, file);

    if(script == NULL)

    {

     return JS_FALSE;

 }

 retval = JS_ExecuteScript(ctx, global, script, &ret);

 JS_DestroyScript(ctx, script);

    return retval;

}

int usage(const char *progname)

{

 printf(“Usage: %s <file>/n”, progname);

 exit(-1);

}

/**

 *End

 */

运行的时候,在javascript中增加对象的使用,修改后的test.js内容如下:

/**

 *javascript start

 */

people.print();

/**

 *END

 */    

编译后运行:./test4 test.js

程序将会产生如下结果:

My Name is xufeng.

My Addr is Chongqing.

My telephone is 123456

File execute successfully.
接下来我们增加类的属性,增加属性以及定义属性的Getter和Setter函数。

程序如下:

/**

 *程序 test5.c

 *增加对象的属性

 *增加错误报警函数  

 */ 

#include “stdio.h”

#include “stdlib.h”

#include “jsapi.h”

#include “sys/types.h”

#include “sys/stat.h”
enum PEOPLE {NAME, ADDRESS, TEL};

static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);

static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);

static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);

static void JsErrorHandler(JSContext *ctx, const char *msg, JSErrorReport *er);

int usage(const char *progname);

JSBool JsFileExecute(JSContext *ctx, const char *file);
typedef struct

{

    char name[16];

    char addr[64];

    char tel[10];

}PeopleInfo;

static PeopleInfo pinfo={“xufeng”, “Chongqing”, “123456”};
JSClass global_class = {

     “global”,

  0,

  JS_PropertyStub, 

  JS_PropertyStub,

  JS_PropertyStub, 

  JS_PropertyStub,

  JS_EnumerateStub, 

  JS_ResolveStub,

  JS_ConvertStub, 

  JS_FinalizeStub,

  JSCLASS_NO_OPTIONAL_MEMBERS

};
static JSClass PeopleClass = {

  “people”,

  0,

  JS_PropertyStub,

  JS_PropertyStub,

  GetPeopleProperty, 

  SetPeopleProperty,

  JS_EnumerateStub,

  JS_ResolveStub,

  JS_ConvertStub, 

  JS_FinalizeStub,

  JSCLASS_NO_OPTIONAL_MEMBERS

};
static JSPropertySpec PeopleProperties[] = {

 {“name”, NAME, JSPROP_ENUMERATE},

 {“address”, ADDRESS, JSPROP_ENUMERATE},

 {“tel”, TEL, JSPROP_ENUMERATE},

 {NULL}

};

static JSFunctionSpec PeopleMethods[] = {

    {“print”, PeoplePrint, 0, 0, 0},

 {NULL}

};

int main(int argc, char **argv)

{

    JSRuntime *rt;

    JSContext *cx;

    JSObject *globalObj,*PeopleObj;

    char *file = NULL;

 if (argc < 2)

 {

  usage(argv[0]);

 }

 else

 {

  file = argv[1];

 }

 rt = JS_NewRuntime(1024L*1024L);

    if (!rt)return -1;

    cx = JS_NewContext(rt, 8L*1024L);

    if (!cx)return -1;

    JS_SetErrorReporter(cx, JsErrorHandler);

    

    if (!(globalObj = JS_NewObject (cx, &global_class, NULL, NULL)))return -1;

    JS_InitStandardClasses (cx, globalObj);

    

    PeopleObj = JS_DefineObject (cx, globalObj, “people”, &PeopleClass, 0, JSPROP_ENUMERATE);

 JS_DefineProperties (cx,PeopleObj, PeopleProperties);

 JS_DefineFunctions (cx,PeopleObj, PeopleMethods);

    if(JsFileExecute(cx, file))

    {

     printf(“File execute successfully./n”);

 }

 else

 {

     printf(“File execute failed./n”);

 }

 JS_DestroyContext(cx);

 JS_DestroyRuntime(rt);

 return 0;

}
static void JsErrorHandler(JSContext *ctx, const char *msg, JSErrorReport *er)

{

    printf(“JS Error: %s/nFile: %s:%u/n”, msg, er->filename, er->lineno);

}
static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp)

{

    if (JSVAL_IS_INT(id)) {

        switch (JSVAL_TO_INT(id)) {

            case NAME:

                *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,pinfo.name));

                break;

            case ADDRESS:

                *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,pinfo.addr));

                break;

            case TEL:

             *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,pinfo.tel));

                break;

        }

    }

    return JS_TRUE;

}
static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp)

{

    if (JSVAL_IS_INT(id)) {

        switch (JSVAL_TO_INT(id)) {

            case NAME:

                strncpy(pinfo.name, JS_GetStringBytes(JS_ValueToString(cx, *vp)), 15);

                break;

            case ADDRESS:

                strncpy(pinfo.addr, JS_GetStringBytes(JS_ValueToString(cx, *vp)), 63);

                break;

            case TEL:

             strncpy(pinfo.tel, JS_GetStringBytes(JS_ValueToString(cx, *vp)), 9);

                break;

        }

    }

    return JS_TRUE;

}
static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)

{

    fprintf(stdout,”My Name is %s./nMy Addr is %s./nMy telephone is %s/n”, pinfo.name, pinfo.addr, pinfo.tel);

    return JS_TRUE;

}
int usage(const char *progname)

{

 printf(“Usage: %s <file>/n”, progname);

 exit(-1);

}

JSBool JsFileExecute(JSContext *ctx, const char *file)

{

    JSScript *script = NULL;

    JSBool retval;

    jsval ret;

    JSObject *global = JS_GetGlobalObject(ctx);

    

    script = JS_CompileFile(ctx, global, file);

    if(script == NULL)

    {

     return JS_FALSE;

 }

 retval = JS_ExecuteScript(ctx, global, script, &ret);

 JS_DestroyScript(ctx, script);

    return retval;

}

/**

 *END

 */

接下来修改test.js,修改后如下:

/**

 *javascript start

 */

people.print();

people.name = “John”;

people.address = “Beijing”;

people.tel = “00099988”;

people.print();

/**

 *END

 */

编译运行 ./test5 test.js 得到如下结果:

My Name is xufeng.

My Addr is Chongqing.

My telephone is 123456

My Name is John.

My Addr is Beijing.

My telephone is 00099988

File execute successfully.
注意:在上面程序中增加了一个错误报警函数 JsErrorHandler(),然后 JS_SetErrorReporter(cx, JsErrorHandler);设置这个ErrorReporter,只要编译javascript出错了,这个函数就会运行,打印出出错的位置。
工作就做到了这里,希望对你有点用处。  
附:
将ECMAScript值转换为本地值,一般采用以下函数:

JS_ValueToNumber, JS_ValueToInt32, JS_ValueToECMAInt32, JS_ValueToECMAUint32,

JS_ValueToBoolean, JS_ValueToUint16, JS_ValueToString, JS_ValueToObject,

JS_ValueToFunction
将本地值转化为ECMAScript值,一般采用以下函数:

JS_NewNumberValue, JS_NewJS_NewStringCopyZ, JS_UCStringCopyZ, JS_NewArrayObject

and macros from the …_TO_JSVAL family: BOOLEAN_TO_JSVAL, STRING_TO_JSVAL,

OBJECT_TO_JSVAL
内存使用:

可以设置两种内存使用限制。通过JS_NewRuntime可以限制每个runtime堆的大小,通过JS_NewContext可以限制每个

context栈的大小。
利用spidermonkey来执行一个javascript文件有两种方法,第一种是将这个文件读出来然后作为字符串传递给spidermonkey,第二种是告诉spidermonkey去编译这个文件,然后再执行已经编译的文件。
本文来自ChinaUnix博客,如果查看原文请点:
http://blog.chinaunix.net/u1/35985/showart_410091.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181399.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 开通阿里云短信服务

    开通阿里云短信服务阿里云短信服务1,阿里云用户权限操作1.1、找到后台放在个人头像上面选择AccessKey管理1.2、选择子用户1.3、创建用户组1.4、给用户组添加权限然后就可以看到你的权限里面多了一个sms的短信权限1.5、创建用户注意!注意!注意点击确认后只可以看到一次密码返回就看不到了注意!注意!注意点击确认后只可以看到一次密码返回就看不到了注意!注意!注意点击确认后只可以看到一次密码返回就看不到了1.6、把用户加入到用户组2、开通阿里云短信服务

    2022年10月28日
  • 获取textview行数

    获取textview行数如果我们想获取TextView内容的行数,TextView没有提供现成的api供我们使用,需要我们自己获取。这里提供一个间接的方法,通过StaticLayout来间接获取行数。下面是代码:publicstaticintgetTextViewLines(TextViewtextView,inttextViewWidth){intwidth=textViewWidt…

    2022年10月29日
  • spring boot vue跨域_vue怎么解决跨域问题

    spring boot vue跨域_vue怎么解决跨域问题一、什么是跨域在springboot+vue前后端分离项目中,请求资源的端口号,域名(ip地址)不同。二、跨域的解决方案1、springboot后端处理:在每个controller上加上@CrossOrigin注解或在controller的基类上添加@CrossOrigin注解,其他controller类加上@Controller即可。2、在vue前端进行处理:通过代理的方式访问后端接口。…

  • oracle函数的创建

    oracle函数的创建函数和存储过程有一定的相似之处,函数用于返回特定的数据,当建立函数时,在函数头部就会包含return字句,而在函数体内必须包含return语句返回的数据,可以使用createfunction来创建函数。案例1输入雇员的姓名,返回雇员的年薪。创建函数:createorreplacefunctionc_hs1(srnamevarchar2)returnnumber …

  • pycharm虚拟环境与本地环境区别_pycharm自带python吗

    pycharm虚拟环境与本地环境区别_pycharm自带python吗    Python的版本众多,在加上适用不同版本的PythonPackage。这导致在同时进行几个项目时,对库的依赖存在很大的问题。这个时候就牵涉到对Python以及依赖库的版本管理,方便进行开发,virtualenv就是用来解决这个问题的。下面介绍使用PyCharm创建VirtualEnvironment的方法。    PyCharm可以使用virtualenv中的功能来创建虚拟环境。Py…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号