首页 文章 精选 留言 我的

精选列表

搜索[项目实战],共10013篇文章
优秀的个人博客,低调大师

OpenHarmony项目实战:智能体重秤

一、简介 本demo基于OpenHarmony3.1Beta版本开发,该样例能够接入数字管家应用,通过数字管家应用监测体重秤上报数据,获得当前测量到的体重,身高,并在应用端形成一段时间内记录的体重值,以折线图的形式表现出来,根据计算的BMI值来提醒当前身体健康状态,推送健康小知识。 1.交互流程 交互图 如上图所示,智能体重称整体方案原理图可以大致分成:智能体重称设备、数字管家应用、云平台三部分。智能体重称通过MQTT协议连接华为IOT物联网平台,从而实现命令的接收和属性上报。 关于智能设备接入华为云IoT平台的详细细节可以参考 连接IOT云平台指南;智能设备同数字管家应用之间的设备模型定义可以参考profile . 2.实物简介 如上图示,左边为全志xr806模组,右边为超声波测距模块,echo脚连接PA19,Triq脚连接PA20,Vcc脚连接5V电源,Gnd脚接地, 如上图示,右边为称重模块,clk脚接PB15,dt脚接PB14,vcc脚接5V,gnd脚接地,称重传感器红色线接E+,黑色线接E-,白色线接A-,绿色线接A+ 左边xr806模块左下角k1按键,长按k1按键不放,同时上电,4-5秒后松开按键,可以清除已保存得配网信息 xr806模块,在设备正常工作后,按k1按键,可以初始化当前得重量为0,高度为0 二、 快速上手 1.硬件准备 全志xr806模组 hcsr04超声波模块 hx711称重模块带支架托盘 预装HarmonyOS手机一台 2、环境准备 参照文档:XR806快速上手指导文档 3、编译前准备 设备侧代码下载 具体仓库地址:https://gitee.com/openharmony-sig/knowledge_demo_smart_home/ 下载方式:使用git 命令下载,指令如下(用户也可以根据需要将该仓库fork到自己的目录下后进行下载) cd ~ git clone git@gitee.com:openharmony-sig/knowledge_demo_smart_home.git 代码拷贝 cp -rfa ~/knowledge_demo_smart_home/dev/team_x ~/openharmony/vendor/ cp -rfa ~/knowledge_demo_smart_home/dev/third_party/iot_link ~/openharmony/third_party/ SOC代码下载替换 当前官方soc代码由于DHCP暂未适配,所以暂时不支持AP模式,这时需要下载并替换之前SOC代码。如果官方soc代码已修复该问题,可忽略此步骤。 git clone https://gitee.com/moldy-potato-chips/xr806_-ap_mode.git mv ~/openharmony/device/soc/allwinner ~/allwinner.org // 不建议直接删除, cp -raf xr806_-ap_mode ~/openharmony/device/soc/allwinner 整合并修改完成后的目录结构如下图 修改文件 修改编译依赖 打开 device/soc/allwinner/xradio/xr806/BUILD.gn,添加应用依赖(deps字段): module_group(module_name) { modules = [ "src", "project", "include", ] configs = [ ":SdkLdCconfig", ] deps = [ "//vendor/team_x/smart_weight_scale/demo_smart_weight_scale:smart_weight_scale" ] } 修改编译方式 将demo依赖的库编译方式(static_library)修改为(source_set): 具体依赖查看demo_smart_weight_scale目录下的BUILD.gn: deps = [ "../../common/iot_wifi_xradio:iot_wifi", "../../common/iot_cloud:iot_cloud", "//third_party/cJSON:cjson", "../../common/iot_boardbutton_xradio:iot_boardbutton", "../../common/iot_boardled_xradio:iot_boardled_xradio", ] 其中//third_party/cJSON目录下的BUILD.gn建议参照下面的修改: source_set("cJSON") { sources = [ "cJSON.c", "cJSON_Utils.c", ] ldflags = [ "-lm" ] } third_party/iot_link目录下的各级使用到的BUILD.gn也需要将编译方式修改为source_set,或者将所有需要编译的文件放在iot_link目录的BUILD.gn中,如下: source_set("iot_link") { sources = [ "link_log/link_log.c", "link_misc/link_random.c", "link_misc/link_ring_buffer.c", "link_misc/link_string.c", "network/dtls/dtls_al/dtls_al.c", "network/dtls/mbedtls/mbedtls_port/dtls_interface.c", "network/dtls/mbedtls/mbedtls_port/mbed_port.c", "network/dtls/mbedtls/mbedtls_port/timing_alt.c", "network/mqtt/mqtt_al/mqtt_al.c", "network/mqtt/paho_mqtt/port/paho_mqtt_port.c", "network/mqtt/paho_mqtt/port/paho_osdepends.c", "network/mqtt/paho_mqtt/paho/MQTTClient-C/src/MQTTClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectServer.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTDeserializePublish.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTFormat.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTPacket.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSerializePublish.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeServer.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeServer.c", "oc_mqtt/oc_mqtt_al/oc_mqtt_al.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile_package.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_event.c", "oc_mqtt/oc_mqtt_tiny_v5/oc_mqtt_tiny.c", "oc_mqtt/oc_mqtt_tiny_v5/hmac.c", "queue/queue.c", ] cflags = [ "-Wno-unused-variable" ] cflags += [ "-Wno-unused-but-set-variable" ] cflags += [ "-Wno-sign-compare" ] cflags += [ "-Wno-unused-parameter" ] cflags += [ "-Wno-unused-function" ] ldflags = [ "-Wl,-rpath-link=//device/xradio/xr806/xr_skylark/lib" ] ldflags += [ "-lmbedtls" ] include_dirs = [ "inc", "link_log", "link_misc", "queue", "oc_mqtt/oc_mqtt_tiny_v5", "oc_mqtt/oc_mqtt_profile_v5", "oc_mqtt/oc_mqtt_al", "network/dtls/mbedtls/mbedtls_port", "network/mqtt/paho_mqtt/port", "network/mqtt/paho_mqtt/paho/MQTTClient-C/src", "network/mqtt/paho_mqtt/paho/MQTTPacket/src", "//third_party/mbedtls/include/", "//third_party/mbedtls/include/", "//third_party/cJSON", "//kernel/liteos_m/components/cmsis/2.0", "//device/xradio/xr806/xr_skylark/include/net/mbedtls-2.2.0/", ] defines = [ "MQTTCLIENT_PLATFORM_HEADER=paho_osdepends.h", "WITH_DTLS", "MBEDTLS_AES_ROM_TABLES", "MBEDTLS_CONFIG_FILE=\"los_mbedtls_config_dtls.h\"", "CONFIG_DTLS_MBEDTLS_CERT", "CONFIG_DTLS_MBEDTLS_PSK", "CFG_MBEDTLS_MODE=PSK_CERT", "CONFIG_OC_MQTT_TINY_ENABLE=1" ] } 修改iot_link中的部分文件1.third_party/iot_link/network/mqtt/paho_mqtt/port/paho_mqtt_port.c 测试发现,当fd为0的时候,在执行recv时会立马返回-1,因此做下面规避操作。 static int __socket_connect(Network *n, const char *host, int port) { ... int tmpfd = socket(AF_INET,SOCK_STREAM,0); // to skip fd = 0; fd = socket(AF_INET,SOCK_STREAM,0); if(fd == -1) { return ret; } close(tmpfd); // to skip fd = 0; ... } 系统setsockopt函数未适配,因此需要做下面的修改: static int __socket_read(void *ctx, unsigned char *buf, int len, int timeout) { int fd; int ret = 0; #if 0 struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== uf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } if(0 != setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&timedelay,sizeof(struct timeval))) { return ret; //could not support the rcv timeout } int bytes = 0; while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); printf("[%s|%s|%d]fd = %d, rc = %d\n", __FILE__,__func__,__LINE__, fd, rc); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } return bytes; #else int bytes = 0; fd_set fdset; struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== buf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } timedelay.tv_sec = 2; FD_ZERO(&fdset); FD_SET(fd, &fdset); ret = select(fd + 1, &fdset, NULL, NULL, &timedelay); if (ret > 0) { while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); // printf("[%s|%s|%d]fd = %d, rc = %d, errno=%d(%s)\n", __FILE__,__func__,__LINE__, fd, rc,errno, strerror(errno)); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } } return bytes; #endif } 2.third_party/iot_link/network/dtls/mbedtls/mbedtls_port/dtls_interface.c 在文件顶部添加打印函数定义以及添加mbedtls_calloc以及mbedtls_free的定义,否则编译会提示错误: #define MBEDTLS_LOG LINK_LOG_DEBUG #ifndef mbedtls_calloc #define mbedtls_calloc calloc #endif #ifndef mbedtls_free #define mbedtls_free free #endif 系统部分mbedtls接口不一致,固需要注释部分接口代码: mbedtls_ssl_context dtls_ssl_new(dtls_establish_info_s *info, char plat_type) { ... if (info->psk_or_cert == VERIFY_WITH_PSK) { /* if ((ret = mbedtls_ssl_conf_psk(conf, info->v.p.psk, info->v.p.psk_len, info->v.p.psk_identity, strlen((const char *)info->v.p.psk_identity))) != 0) { MBEDTLS_LOG("mbedtls_ssl_conf_psk failed: -0x%x", -ret); goto exit_fail; } */ } ... } int dtls_shakehand(mbedtls_ssl_context *ssl, const dtls_shakehand_info_s *info) { ... if (MBEDTLS_SSL_IS_CLIENT == info->client_or_server) { ret = mbedtls_net_connect(server_fd, info->u.c.host, info->u.c.port, info->udp_or_tcp); if( 0 != ret) { ret = MBEDTLS_ERR_NET_CONNECT_FAILED; goto exit_fail; } } else { //server_fd = (mbedtls_net_context*)atiny_net_bind(NULL, info->u.s.local_port, MBEDTLS_NET_PROTO_UDP); ///< --TODO ,not implement yet } ... } void dtls_init(void) { (void)mbedtls_platform_set_calloc_free(calloc, free); (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); } 在iot_link/network/dtls/mbedtls/mbedtls_port/mbed_port.c文件中的dtls_imp_init()函数中,也需要注释掉未实现的接口,否则编译报错: int dtls_imp_init(void) { int ret =-1; // (void)mbedtls_platform_set_calloc_free(calloc, free); // (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); ret = dtls_al_install(&s_mbedtls_io); return ret; } 3.在文件iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.c中添加对应timersub和timeradd的实现(系统中未实现该函数): // add this for "timersub" && "timeradd" #ifndef timersub #define timersub(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec - (t)->tv_sec, \ ((a)->tv_usec = (s)->tv_usec - (t)->tv_usec) < 0 && \ ((a)->tv_usec += 1000000, (a)->tv_sec--) ) #endif #ifndef timeradd #define timeradd(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec + (t)->tv_sec, \ ((a)->tv_usec = (s)->tv_usec + (t)->tv_usec) >= 1000000 && \ ((a)->tv_usec -= 1000000, (a)->tv_sec++) ) #endif 4.编译中会有部分头文件提示找不到,这个时候直接将其注释即可 (iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.h): #define INVALID_SOCKET SOCKET_ERROR // #include <sys/socket.h> #include <sys/param.h> #include <sys/time.h> // #include <netinet/in.h> // #include <netinet/tcp.h> // #include <arpa/inet.h> // #include <netdb.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #endif #if defined(WIN32) #include <Iphlpapi.h> #else // #include <sys/ioctl.h> // #include <net/if.h> #endif 5.因为弱引用导致无法链接相关符号,因此需要注释以下几个文件中的弱引用。 文件一 third_party/iot_link/network/dtls/dtls_al/dtls_al.c #if 0 __attribute__((weak)) int dtls_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement dtls by yourself####",__FUNCTION__); return -1; } #endif extern int dtls_imp_init(void); 文件二 third_party/iot_link/network/mqtt/mqtt_al/mqtt_al.c #if 0 __attribute__((weak)) int mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement mqtt by yourself####",__FUNCTION__); return -1; } #endif extern int mqtt_imp_init(void); 文件三 third_party/iot_link/oc_mqtt/oc_mqtt_al/oc_mqtt_al.c #if 0 __attribute__ ((weak)) int oc_mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement oc mqtt by yourself####",__FUNCTION__); return 0; } __attribute__ ((weak)) int oc_mqtt_demo_main(void) { LINK_LOG_WARN("Please implement the oc mqtt v5 demo yourself"); return -1; } #endif extern int oc_mqtt_demo_main(void); 修改GPIO查找方式 因为GPIO框架修改了设备驱动注册的管脚号,导致应用无法根据HCS的引脚操作对应的GPIO,此问题已经提issue,如果该问题已解决,可以忽略此步骤。 打开drivers/framework/support/platform/src/gpio/gpio_manager.c,将cntlr->start = start;注释即可。 static int32_t GpioManagerAdd(struct PlatformManager *manager, struct PlatformDevice *device) { uint16_t start; struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device); if ((start = GpioCntlrQueryStart(cntlr, &manager->devices)) >= GPIO_NUM_MAX) { PLAT_LOGE("GpioCntlrAdd: query range for start:%d fail:%d", cntlr->start, start); return HDF_ERR_INVALID_PARAM; } // cntlr->start = start; DListInsertTail(&device->node, &manager->devices); PLAT_LOGI("%s: start:%u count:%u", __func__, cntlr->start, cntlr->count); return HDF_SUCCESS; } 将对应的驱动文件复制到drvier对应目录: 因为主仓代码中未将对应的驱动文件合并到driver/adpater/platform对应的目录下,固需要手动将文件拷贝到对应目录。若主仓已合入,可忽略此步骤。 // 拷贝gpio驱动 cp -af device/soc/allwinner/xradio/drivers/gpio/gpio_xradio.* driver/adpater/platform/gpio // 修改driver/adpater/platform/gpio/BUILD.gn文件,加上gpio_xradio的编译 hdf_driver(module_name) { sources = [] if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) { sources += [ "gpio_bes.c" ] } if (defined(LOSCFG_SOC_COMPANY_ALLWINNER)) { sources += [ "gpio_xradio.c" ] } include_dirs = [ "." ] } 为了节省ram资源,可以把无用的资源先关闭,如关闭内部codec,将 device/soc/allwinner/xradio/xr806/project/prj_config.h中的PRJCONF_INTERNAL_SOUNDCARD_EN设置为0,如下: /* Xradio internal codec sound card enable/disable */ #define PRJCONF_INTERNAL_SOUNDCARD_EN 0 4、代码编译 #首先可以查看一下hb的版本,如果hb版本为0.4.4版本就不需要更新。 查看hb版本 hb --version 更新hb, 以下指令需要在openharmony SDK根目录执行 pip3 uninstall ohos_build pip3 install build/li 编译命令: hb set // 如果是第一次编译,Input code path 命令行中键入"./" 指定OpenHarmony工程编译根目录后 回车, 如下图所示,使用键盘上下键选中wifi_skylark hb build // 如果需要全量编译,可以添加-f 选项 生成的固件保存在out/xradio/smart_weight_scale目录下 5、固件烧录 参照文档:XR806快速上手指导文档 6、设备配网 在设备上电前需准备好安装了数字管家应用的HarmonyOS手机,详情见数字管家应用开发, 并在设置中开启手机的NFC功能; 写设备NFC标签,详细操作见设备NFC标签指导文档; 烧录完成后,上电。开发者在观察开发板上状态LED灯以8Hz的频率闪烁时,将手机上半部靠近开发板NFC标签处(无NFC标签的可用NFC贴纸替代); 碰一碰后手机将自动拉起数字管家应用并进入配网状态; 配网过程中需要 连接设备的AP热点,然后填写需要配置的wifi的密码; 最后点击配置,手机会将ssid以及对应的密码通过AP热点发送到设备。 本文整理自:https://bbs.aw-ol.com/topic/1116/ 作者@budbool

优秀的个人博客,低调大师

Docker部署JavaWeb项目实战(转)

摘要:本文主要讲了如何在Ubuntu14.04 64位系统下来创建一个运行Java web应用程序的Docker容器。 一、下载镜像、启动容器 1、下载镜像 先查看镜像 [html] view plain copy dockerimages 记住这个Image ID,下面我们启动容器需要用到它。如果看到以上输出,说明您可以使用“oursuer/ubuntu”这个镜像了,或将其称为仓库(Repository),该镜像有一个名为“14.04”的标签(Tag),此外还有一个名为1f879014f4d2 的镜像 ID(可能您所看到的镜像 ID 与此处的不一致,那是正常现象,因为这个数字是随机生成的)。此外,我们可以看到该镜像只有188.4 MB,非常小巧,而不像虚拟机的镜像文件那样庞大。现在镜像已经有了,我们下面就需要使用该镜像,来启动容器。 2、启动容器容器是在镜像的基础上来运行的,一旦容器启动了,我们就可以登录到容器中,安装自己所需的软件或应用程序。既然镜像已经下载到本地,那么如何才能启动容器呢?只需使用以下命令即可启动容器: [plain] view plain copy dockerrun-i-t-v/download/:/mnt/software/1f879014f4d2/bin/bash 这条命令比较长,我们稍微分解一下,其实包含以下三个部分: [html] view plain copy dockerrun<相关参数><镜像ID><初始命令> 如果看到以上输出,说明您可以使用“docker.cn/docker/centos”这个镜像了,或将其称为仓库(Repository),该镜像有一个名为“centos6”的标签(Tag),此外还有一个名为“25c5298b1a36 ”的镜像 ID(可能您所看到的镜像 ID 与此处的不一致,那是正常现象,因为这个数字是随机生成的)。此外,我们可以看到该镜像只有 215.8 MB,非常小巧,而不像虚拟机的镜像文件那样庞大。 现在镜像已经有了,我们下面就需要使用该镜像,来启动容器。 [plain] view plain copy 其中,相关参数包括: -i:表示以“交互模式”运行容器 -t:表示容器启动后会进入其命令行 -v:表示需要将本地哪个目录挂载到容器中,格式:-v<宿主机目录>:<容器目录> 假设我们的所有安装程序都放在了宿主机的/download/目录下,现在需要将其挂载到容器的/mnt/software/目录下。 需要说明的是,不一定要使用“镜像 ID”,也可以使用“仓库名:标签名”,例如:oursuer/ubuntu:14.04。 初始命令表示一旦容器启动,需要运行的命令,此时使用“/bin/bash”,表示什么也不做,只需进入命令行即可。 退出容器使用Ctrl+d或输入exit 如果退出容器后,可以再次使用命令(注意,得先运行docker run之后然后被stop掉的容器才可以使用如下命令) [plain] view plain copy dockerstart容器ID 其中容器ID。使用命令docker ps -a来看,如下: 然后再次启动已启动过但现在是关闭的容器 [plain] view plain copy dockerstartsick_mestorf 这个命令只会启动容器,不会进入容器。要进入容器得用命令 [plain] view plain copy dockerattach容器ID或容器名 如下: 二、安装相关软件 首先先将JDK和tomcat的安装包.gz文件放在外面的/download文件夹下 然后再次启动容器。进入容器 然后看看是否有安装包。发现两个都在了,下面可以安装了 1、JDK安装 直接使用 [plain] view plain copy cd/usr mkdirjava cdjava mkdirjdk cd/mnt/software/ tarzxvfjdk-8u65-linux-x64.gz-C/usr/java/jdk 这里直接接文件解压到/usr/java/jdk目录,如下 配置环境变量输入: [plain] view plain copy vi/etc/profile 或 添加如下内容: [plain] view plain copy #setjavaenvironment exportJAVA_HOME=/usr/java/jdk/jdk1.8.0_65 exportJRE_HOME=/usr/java/jdk/jdk1.8.0_65/jre exportCLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$JAVA_HOME:$PATH 注意此处改成对应的jdk的目录,并且要以root用户来做修改,否则无法保存 保存后执行: [plain] view plain copy source/etc/profile 验证安装: 输入: [plain] view plain copy java-version 如果出现如下内容,说明安装成功 2、tomcat安装 直接解压 [html] view plain copy cd/usr/java mkdirtomcat tarzxvf-C/usr/java/tomcat 配置环境 进入到上面的tomcat的bin文件夹下: 打开 [plain] view plain copy visetclasspath.sh 或 [plain] view plain copy geditsetclasspath.sh 添加如下内容: [plain] view plain copy exportJAVA_HOME=/usr/java/jdk/jdk1.8.0_65 exportJRE_HOME=/usr/java/jdk/jdk1.8.0_65/jre 保存即可。 然后退回到bin目录下: 执行: [plain] view plain copy ./startup.sh 说明tomcat启动成功 或者使用如下命令查看: 三、配置容器启动环境变量 (上面的JDK配置环境变量可以不要,但是这里的一定要写!!!!!!!!!!因为这里是设置容器启动时加载的环境变量) 1、设置环境变量首先,编辑.bashrc文件 [plain] view plain copy vi~/.bashrc 然后,在该文件末尾添加如下配置: [plain] view plain copy exportJAVA_HOME=/usr/java/jdk/jdk1.8.0_65 exportJRE_HOME=/usr/java/jdk/jdk1.8.0_65/jre exportCLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$JAVA_HOME:$PATH 最后,需要使用source命令,让环境变量生效: [plain] view plain copy source~/.bashrc 2、编写运行脚本 我们需要编写一个运行脚本,当启动容器时,运行该脚本,启动 Tomcat,具体过程如下:首先,创建运行脚本: [html] view plain copy vi/root/run.sh 然后,编辑脚本内容如下: [html] view plain copy #!/bin/bash source~/.bashrc sh/usr/java/tomcat/apache-tomcat-7.0.68/bin/catalina.shrun 注意:这里必须先加载环境变量,然后使用 Tomcat 的运行脚本来启动 Tomcat 服务。 最后,为运行脚本添加执行权限: [html] view plain copy chmodu+x/root/run.sh 3、退出容器 当以上步骤全部完成后,可使用exit或ctrl+d命令,退出容器。 随后,可使用如下命令查看正在运行的容器: docker ps 此时,您应该看不到任何正在运行的程序,因为刚才已经使用exit命令退出的容器,此时容器处于停止状态,可使用如下命令查看所有容器: docker ps -a 输出如下内容: 记住以上CONTAINER ID(容器 ID),随后我们将通过该容器,创建一个可运行 Java Web 的镜像。 四、创建 Java Web 镜像 使用以下命令,根据某个“容器 ID”来创建一个新的“镜像”: [plain] view plain copy dockercommit89a47b5b749elin_javaweb:0.1 该容器的 ID 是“89a47b5b749e”,所创建的镜像名是“lin_javaweb:0.1”,随后可使用镜像来启动 Java Web 容器。 这是创建成功后 同样可以查看下镜像 五、启动 Java Web 容器 有必要首先使用docker images命令,查看当前所有的镜像: 可见,此时已经看到了最新创建的镜像“lin_javaweb:0.1”,其镜像 ID 是“4487bd38df06”。正如上面所描述的那样,我们可以通过“镜像名”或“镜像 ID”来启动容器,与上次启动容器不同的是,我们现在不再进入容器的命令行,而是直接启动容器内部的 Tomcat 服务。此时,需要使用以下命令: [plain] view plain copy dockerrun-d-p58080:8080--namejavaweblin_javaweb:0.1/root/run.sh 稍作解释: [html] view plain copy -d:表示以“守护模式”执行/root/run.sh脚本,此时Tomcat控制台不会出现在输出终端上。 -p:表示宿主机与容器的端口映射,此时将容器内部的8080端口映射为宿主机的58080端口,这样就向外界暴露了58080端口,可通过Docker网桥来访问容器内部的8080端口了。 --name:表示容器名称,用一个有意义的名称命名即可。 关于 Docker 网桥的内容,需要补充说明一下。实际上 Docker 在宿主机与容器之间,搭建了一座网络通信的桥梁,我们可通过宿主机 IP 地址与端口号来映射容器内部的 IP 地址与端口号, 在一系列参数后面的是“镜像名”或“镜像 ID”,怎么方便就怎么来。最后是“初始命令”,它是上面编写的运行脚本,里面封装了加载环境变量并启动 Tomcat 服务的命令。 当运行以上命令后,会立即输出一长串“容器 ID”,我们可通过docker ps命令来查看当前正在运行的容器。 在浏览器中,输入以下地址,即可访问 Tomcat 首页:http://127.0.0.1:58080/ 或者 http://localhost:58080/注意:这里使用的是宿主机的 IP 地址,与对外暴露的端口号 58080,它映射容器内部的端口号 8080。 http://blog.csdn.net/evankaka/article/details/50722788

优秀的个人博客,低调大师

Android项目实战(三十五):多渠道打包

多渠道打包: 可以理解为:同时发布多个渠道的apk。分别上架不同的应用商店。这些apk带有各自渠道的标签,用于统计分析各个商店的下载次数等数据。 实现步骤 一、添加友盟渠道标签 添加位置:app目录下的 AndroidManifest.xml文件 添加语句: <!--多渠道打包--> <meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/> 示例: 二、添加渠道 添加几个,打包的时候就可以生成几个相应渠道的包 添加位置:app目录下的build.gradle文件 android{ ... } 内 添加代码: productFlavors { xiaomi {} qihu360 {} baidu {} wandoujia {} } productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } 示例: 三、签名信息配置 上面打出的包都是未签名的。上架需要签名包。 实现: app目录下 android{ ... } 中添加 signingConfigs{ ... } 相关 。 四、指定签名为release 添加位置:app目录下build.gradle文件 android{ ... } 内 添加代码: signingConfig signingConfigs.release 五、gradle 实现多渠道打包 测试: 可以看到outputs --> app 中多了各个渠道的release.apk 包

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册