当前位置: 首页 > news >正文

Android Gradle开发与应用 (八) :Kotlin DSL

1. 前言

本文介绍了Gradle Kotlin DSL相关的一些知识点

2. DSL是什么

DSL是为特定领域设计的专门的语言,也就是设计了一门语言,然后解决某个特定的领域的特定问题。

2.1 举例说明

以下的这些都可以称之为DSL

  • 正则表达式 :用于文本处理的特定语言
  • SQL :用于数据库查询的领域特定语言
  • HTML : 用于描述网页结构的领域特定语言
  • CSS:用于描述网页样式的领域特定语言
  • Android XML布局 : 用于描述Android页面的领域特定语言

Gradle 中的 Groovy DSL 和 Kotlin DSL 就用来编写Gradle构建脚本的领域特定语言

像Kotlin它不仅可以做一些Android开发,还可以做后端,它不属于DSL,但是我们可以通过Kotlin的一些语法规则,来开发一些特定领域的DSL语言。

2.2 Kotlin DSL

Kotlin当中的DSL,使用高阶函数和一些Lambda表达式配合来进行编写的。

对于DSL没有明确的语法规定,只要能编写出一门语言,一种语法规则,解决特定领域的问题,那么他就可以称之为DSL

Gradle构建工具现在也使用Kotlin作为Gradle的主要编写语言了。

我们去创建KotlinGradle的时候,可以发现,它里面的内容和以前的Gradle没什么区别,但是语言上是用的Kotlin。

其实就是用Kotlin写了一个专门为Gradle使用的DSL

3. kotlin-dsl是什么

在用Kotlin编写的Gradle插件中,会有kotlin-dsl这一句

plugins {`java-gradle-plugin``kotlin-dsl`
}

我们点进去可以看到kotlin-dsl中间的-不是标准的kotlin语法,所以要加上``来做区分。

public val val PluginDependenciesSpec.`kotlin-dsl`: PluginDependencySpecget() = id("org.gradle.kotlin.kotlin-dsl") version "2.4.1"

也就是说 kotlin-dsl就是PluginDependencySpec的一个扩展属性。
其实就是相当于id("org.gradle.kotlin.kotlin-dsl") version "2.4.1"

所以如果把kotlin-dsl这行代码改为id("org.gradle.kotlin.kotlin-dsl") version "2.4.1",效果是一样的。

可以在Kotlin插件项目里,全局搜索org.gradle.kotlin.kotlin-dsl

3.1 kotlin-dsl插件的作用

提供Kotlin编写Gradle脚本的能力,从而可以替代传统的Groovy语言。

  • 使用Kotlin DSL的编程风格,可以使程序更加简单干净、直观简洁。这有助于提升开发效率,降低出错的可能性,并使得构建脚本更易于理解和维护。

  • 此外,Kotlin DSL还提供了强大的类型检查和智能代码补全功能,这些功能可以进一步提高开发者的编写体验。同时,由于Kotlin语言的强大功能,Kotlin DSL也支持更复杂的构建逻辑和更灵活的脚本编写方式。

4. groovy和kotlin的语法糖

4.1 apply plugin

4.1.1 groovy中的apply plugin
apply plugin : MyPlugin

等价于

apply([plugin : MyPlugin])

当方法的参数是一个map的时候,可以将方括号[]去掉

apply(plugin: MyPlugin)

当不引起歧义的时候,可以把圆括号去掉

apply plugin : MyPlugin
4.1.2 kotlin中的apply plugin
apply(plugin = "com.android.application")

实际上也是个函数调用

public fun org.gradle.api.plugins.PluginAware.apply(from: kotlin.Any? = COMPILED_CODE, plugin: kotlin.String? = COMPILED_CODE, to: kotlin.Any? = COMPILED_CODE): kotlin.Unit {  }

4.2 gradle和kotlin中的plugins

4.2.1 groovy中的plugins
plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'
}

本质是有一个plugins的方法,调用了一个闭包
实质上是

plugins({id('com.android.application').version('8.1.3').apply(false)
})
4.2.2 kotlin中的plugins
plugins {id("com.android.application") version "8.1.3" apply false
}

本质上也就是一个函数调用

public final fun plugins(block: org.gradle.kotlin.dsl.PluginDependenciesSpecScope.() -> kotlin.Unit): kotlin.Unit { /* compiled code */ }

id方法会返回一个PluginDependencySpecPluginDependencySpec中有versionapply方法

public interface PluginDependencySpec {PluginDependencySpec version(@Nullable String version);default PluginDependencySpec version(Provider<String> version) {return this.version((String)version.get());}PluginDependencySpec apply(boolean apply);
}
4.2.3 apply plugin 和 plugins的区别
  • plugins是Gradle较新的方式,用于声明性地应用插件。有更简洁的语法,更好的插件版本控制
  • 传统的apply方法机制则更加灵活,可以动态地加载和应用插件

现在一般情况下都用plugins即可,除非是要使用build.gradle中自己写的gradle插件,采用apply plugin进行引用。

5. Groovy DSL 和 Kotlin DSL的区别

5.1 gradle中,如下Groovy和Kotlin的写法为什么会有不同 ?

比如下面的这行代码 greeting.message = 'Hi from Gradle'the<GreetingPluginExtension>().message.set("Hi from Gradle")

Gradle 中,Groovy DSLKotlin DSL 提供了不同的语法和风格来配置构建脚本。这两种语言不同的写法来配置插件扩展,是由于这两种 DSL 在语法和设计哲学上的差异造成的。

首先,来看 Groovy DSL 的写法:

greeting.message = 'Hi from Gradle'

Groovy DSL 中,插件的扩展对象通常会被添加到项目的 extensions 集合中,并且可以直接通过扩展对象的名称(在这个例子中是 greeting)来访问。Groovy 语言允许直接对属性进行赋值操作,因此可以非常方便地通过点号 . 操作符来设置属性的值。

接下来,看 Kotlin DSL 的写法:

the<GreetingPluginExtension>().message.set("Hi from Gradle")

Kotlin DSL 中,由于 Kotlin 是一种静态类型语言,它提供了更严格的类型检查和更丰富的类型系统。因此,访问插件的扩展对象需要使用 the<T>() 函数,这个函数是 Gradle Kotlin DSL 提供的一个帮助函数,用于获取指定类型的扩展对象。这样做可以提供更好的类型安全,并且使代码更加清晰和易于理解。

另外,set 方法的使用也是 Kotlin 语言特性的体现。在 Kotlin 中,属性默认是不可变的(val),如果需要修改属性的值,通常需要提供一个 set 方法。虽然 Kotlin 也支持可变属性(var),但在 Gradle Kotlin DSL 的上下文中,使用 set 方法可能是为了遵循 Gradle API 的约定,或者是为了强调这是一个设置操作。

总结来说,Groovy DSLKotlin DSL 在语法和风格上的差异导致了配置插件扩展时的不同写法。Groovy DSL 提供了更加直接和简洁的语法,而 Kotlin DSL 则强调了类型安全和清晰的代码结构。这些差异使得两种 DSL 都有其独特的优点,开发者可以根据个人喜好和项目需求选择使用哪一种。

5.2 gradle中,tasks.register(‘xxx’)和task xxx这两种新建Task方式,有什么区别 ?

在Gradle中,tasks.register('xxx')task xxx这两种方式用于新建Task, 但它们之间存在一些区别:

  1. Groovy 和 Kotlin 语法:

    • task xxx 是 Groovy 语法,它使用 Groovy 闭包来配置任务。
    • tasks.register('xxx') 是 Kotlin 语法,它通过流式 API 调用来配置任务。
  2. 任务创建时机:

    • task xxx 是在配置文件(如 build.gradle)执行期间立即创建任务的。
    • tasks.register('xxx') 可以延迟任务的创建,直到需要时才注册到任务注册表中。
  3. 可读性和维护性:

    • task xxx 的语法更接近传统的 Gradle 构建脚本,对于熟悉早期版本的 Gradle 的用户来说可能更易读。
    • tasks.register('xxx') 提供了一种更一致和流畅的任务配置方式,与 Gradle 推向的 Kotlin DSL 相契合。
  4. API 兼容性:

    • task xxx 的语法可能会在未来的 Gradle 版本中被弃用,因为 Gradle 正在推动使用 Kotlin DSL。
    • tasks.register('xxx') 是当前推荐的方式,因为它与 Gradle 的 Kotlin DSL 兼容,并且有更好的未来兼容性保证。
  5. 任务名称:

    • task xxx 中的任务名称(‘xxx’)通常不包含引号。
    • tasks.register('xxx') 中的任务名称必须包含引号。
  6. 示例:

    • 使用 task xxx 语法创建一个名为 ‘myTask’ 的任务:
      task myTask {doLast {println 'Hello from myTask!'}
      }
      
    • 使用 tasks.register('xxx') 语法创建同样的任务:
      tasks.register('myTask') {doLast {println 'Hello from myTask!'}
      }
      

总的来说,虽然 task xxxtasks.register('xxx') 都可以用来创建新的任务,但是 tasks.register 是更现代、更灵活且未来兼容的方式。随着 Gradle 的发展,推荐使用 Kotlin 语法和 tasks.register 方法进行任务创建和配置。

6. 自定android闭包

使用Kotlin DSL模拟android闭包来实现一个myandroid的闭包,将MyAndroidBean传入。

首先创建一个MyAndroidBeanDefaultConfig 传参类

class MyAndroidBean {var namespace = ""var compileSdk = 0var myDefaultConfig = DefaultConfig()fun Project.myDefaultConfig(call: DefaultConfig.() -> Unit) {val defaultConfig = DefaultConfig()defaultConfig.call()}
}class DefaultConfig {var applicationId = ""var minSdk = 0var targetSdk = 0
}

然后实现一个自定义的myandroid闭包

fun Project.myandroid(call: MyAndroidBean.() -> Unit) {val myAndroidBean = MyAndroidBean()myAndroidBean.call()val defaultConfig = myAndroidBean.myDefaultConfig//打印传参println("namespace:${myAndroidBean.namespace}")println("namespace:${myAndroidBean.compileSdk}")println("applicationId:${defaultConfig.applicationId}")println("minSdk:${defaultConfig.minSdk}")println("targetSdk:${defaultConfig.targetSdk}")
}

进行调用

myandroid {namespace = "com.heiko.mytest"compileSdk = 34myDefaultConfig {applicationId = "com.heiko.mytest"minSdk = 21targetSdk = 34}
}

7. 其他

gradle中Kotlin和Groovy的差异 :
将 build 配置从 Groovy 迁移到 Kotlin | Android Studio | Android Developers (google.cn)
Gradle Kotlin DSL 入门

Android Gradle系列文章
Android Gradle 开发与应用 (一) : Gradle基础-氦客-CSDN博客
Android Gradle开发与应用 (二) : Groovy基础语法-CSDN博客
Android Gradle开发与应用 (三) : Groovy语法概念与闭包-CSDN博客
Android Gradle开发与应用 (四) : Gradle构建与生命周期-CSDN博客
Android Gradle开发与应用 (五): 基于Gradle 8.2,创建Gradle插件-CSDN博客
Android Gradle 开发与应用 (六) : 创建buildSrc插件和使用命令行创建Gradle插件-CSDN博客
Android Gradle 开发与应用 (七) : 实现打包自动复制文件插件
Android Gradle开发与应用 (八) :Kotlin DSL

相关文章:

Android Gradle开发与应用 (八) :Kotlin DSL

1. 前言 本文介绍了Gradle Kotlin DSL相关的一些知识点 2. DSL是什么 DSL是为特定领域设计的专门的语言&#xff0c;也就是设计了一门语言&#xff0c;然后解决某个特定的领域的特定问题。 2.1 举例说明 以下的这些都可以称之为DSL 正则表达式 :用于文本处理的特定语言SQ…...

phpstorm 快捷键

PHPstorm最常用的快捷键&#xff0c;提高开发效率 - 知乎 (zhihu.com) 四年精华PHP技术文章整理合集——PHP框架篇 (qq.com) 四年精华PHP技术文合集——微服务架构篇 (qq.com) Vue3 打印票据 预览的库&#xff1a;vue3打印解决方案&#xff1a;Vue-Plugin-HiPrint - 掘金 (j…...

浦大喜奔APP8.0智能升级,发力数字金融深化五大金融篇章服务

1. 浦大喜奔立足科技赋能持续迭代升级&#xff0c;筑牢用户体验护城河 浦发信用卡中心坚持数字科技与客户体验双轮驱动&#xff0c;以科技赋能发展&#xff0c;优化整体系统性能&#xff0c;全方位支撑浦大喜奔 APP提高线上客户服务能力与体验&#xff0c;积极服务民生消费&a…...

自然语言处理、大语言模型相关名词整理

自然语言处理相关名词整理 零样本学习&#xff08;zero-shot learning&#xff09;词嵌入&#xff08;Embedding&#xff09;为什么 Embedding 搜索比基于词频搜索效果好&#xff1f; Word2VecTransformer检索增强生成&#xff08;RAG&#xff09;幻觉采样温度Top-kTop-p奖励模…...

移动开发避坑指南——内存泄漏

在日常编写代码时难免会遇到各种各样的问题和坑&#xff0c;这些问题可能会影响我们的开发效率和代码质量&#xff0c;因此我们需要不断总结和学习&#xff0c;以避免这些问题的出现。接下来我们将围绕移动开发中常见问题做出总结&#xff0c;以提高大家的开发质量。本系列文章…...

太好玩了,我用 Python 做了一个 ChatGPT 机器人

毫无疑问&#xff0c;ChatGPT 已经是当下编程圈最火的话题之一&#xff0c;它不仅能够回答各类问题&#xff0c;甚至还能执行代码&#xff01; 或者是变成一只猫 因为它实在是太好玩&#xff0c;我使用Python将ChatGPT改造&#xff0c;可以实现在命令行或者Python代码中调用。…...

STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡

STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡 SD/MicroSD/TF卡是基于FLASH的一种常见非易失存储单元&#xff0c;由接口协议电路和FLASH构成。市面上由不同尺寸和不同容量的卡&#xff0c;手机领域用的TF卡实际就是MicroSD卡&#xff0c;尺寸比SD卡小&#xff0c;而电路和协…...

累积分布函数图(CDF)的介绍、matlab的CDF图绘制方法(附源代码)

在对比如下两个误差的时候&#xff0c;怎么直观地分辨出来谁的误差更低一点&#xff1f;&#xff1a; 通过这种误差时序图往往不容易看出来。 但是如果使用CDF图像&#xff0c;以误差绝对值作为横轴&#xff0c;以横轴所示误差对应的累积概率为纵轴&#xff0c;绘制曲线图&am…...

代码随想录算法训练营第四十一天|343.整数拆分、96不同的二叉搜索树

文档链接&#xff1a;https://programmercarl.com/ LeetCode343.整数拆分 题目链接&#xff1a;https://leetcode.cn/problems/integer-break/ 思路&#xff1a; j * (i - j) 是单纯的把整数拆分为两个数相乘&#xff0c;而j * dp[i - j]是拆分成两个以及两个以上的个数相乘…...

全量知识系统 程序详细设计之 统一资产模型(QA-SmartChat)

Q1. 下面我们聊聊整个全知系统的设计 的矩阵和函数&#xff0c;矩阵表示的是“活物”&#xff0c;分别 类似 一个基因的活性、一个实体的辨识度和某种特征的可区分度。 函数的可微、可积和可导性 则表示 运动的控制方式 在全知系统设计中&#xff0c;矩阵和函数是两个核心的组…...

已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法,亲测有效!!!

已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录 问题分析 报错原因 解决思路 解决方法 总结 在日常开发过程中&#xff0c;通过Spring框架提供的RestTemplat…...

内网渗透-Windows内网渗透

内网渗透-Windows内网渗透 文章目录 内网渗透-Windows内网渗透前言一、信息收集 1.1、SPN1.2、端口连接1.3、配置文件1.4、用户信息1.6、会话收集1.7、凭据收集 navicat&#xff1a;SecureCRT&#xff1a;Xshell&#xff1a;WinSCP&#xff1a;VNC: 1.8、DPAPI1.9、域信任1.10、…...

机器人方向控制中应用的磁阻角度传感芯片

磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响&#xff0c;可以达到高准确度与高效能&#xff0c;因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛&#xff0…...

如何在树莓派安装Nginx并实现固定公网域名访问本地静态站点

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…...

Ubuntu与主机windows共享文件夹

一、创建共享文件夹&#xff1a; 虚拟机->设置->选项->共享文件夹->总是启用->选择本地的共享文件夹&#xff08;如E&#xff1a;\Share&#xff09;->确定。 二、设置挂载&#xff1a; 首先赋予/etc/fstab文件可编辑的权限&#xff1b; sudo chmod 777 /…...

(四)C++自制植物大战僵尸游戏启动流程

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮&#xff08;本地Windows调试器&#xff09;进行项目启动。第一次启动项目需要编译项目中所有代码文件&#xff0c;编译生成需要一定的时间。不同性能的电…...

华为的AI战略地图上,才不是只有大模型

图片来源&#xff1a;pixabay© 钛媒体ToB深水区 图片来源&#xff1a;pixabay 大模型火热了一年&#xff0c;现在还没做AI化改造的企业&#xff0c;就像是工业革命浪潮伊始与火车赛跑的那辆马车。 最早的蒸汽火车缓慢又笨重&#xff0c;甚至铁轨上还预留了马匹行走的空…...

采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示

采用C#.Net JavaScript 开发的云LIS系统源码 二级医院应用案例有演示 一、系统简介 云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序&#xff0c;可协助区域内所有临床实验室相互协调并完成日常检验工作&#xff0c;对区域内的检验数据进行集中管理和共享&#xff0…...

Vue3(三):生命周期、路由、自定义hooks

这里终于明白了为什么一直有这个语法报错&#xff0c;就是在提示你哪里错的地方上方注释一行/*eslint-disable*/&#xff0c;之前一直警告这个错误感谢老师&#xff01; 一、vue2和vue3生命周期 还有一个问题就是父组件和子组件哪个先挂载完毕呢&#xff1f;答案是子组件先挂…...

UE4_导入内容_骨架网格体

FBX 导入支持 骨架网格体&#xff08;Skeletal Mesh&#xff09; 。这提供了一种简化的处理流程来将有动画的网格体从 3D应用程序中导入到虚幻引擎内&#xff0c;以便在游戏中使用。除了导入网格体外&#xff0c;如果需要&#xff0c;动画和变形目标都可以使用FBX格式 在同一文…...

第十五届蓝桥杯c++b组赛后复盘和真题展示

题目变成八道了&#xff0c;分数一百分可能&#xff0c;感觉拿奖难度还是很高 第一题是一个简单的握手问题 答案算出来1204&#xff0c;纯手写 第二题是 物理题 纯蒙&#xff0c;随便猜了个轨迹&#xff0c;答案具体忘了&#xff0c;最后是 .45 第三题暴力 第四题 我是傻逼…...

代码随想录 二叉树—二叉搜索树中的搜索

思路&#xff1a;当节点为空或者等于目标值&#xff0c;直接返回。由于是二叉搜索树&#xff0c;特点是左子树的值都小于根节点值&#xff0c;右子树的值均大于根节点&#xff0c;那么&#xff0c;左右子树的构建可以通过值的判断来递归调用。 c题解&#xff1a; /*** Defini…...

⑤-1 学习PID--什么是PID

​ PID 算法可以用于温度控制、水位控制、飞行姿态控制等领域。后面我们通过PID 控制电机进行说明。 自动控制系统 在直流有刷电机的基础驱动中&#xff0c;如果电机负载不变&#xff0c;我们只要设置固定的占空比&#xff08;电压&#xff09;&#xff0c;电机的速度就会稳定在…...

【OTA】STM32-OTA升级——持续更新

【OTA】STM32-OTA升级——持续更新 文章目录 前言一、ymodem串口协议1、Ymodem 协议2、PC3、蓝牙4、WIFI云平台 二、UDS车载协议1.UDS协议 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、ymodem串口协议 1、Ymodem 协议 STM32 Ymodem …...

java 字符集

ASCII 与 GBK ASCII:英文专用GBK:中文专用 万国码 unicode想要统一这个世界上所有的语言&#xff0c;所以创造了UTF-32但是使用32位&#xff0c;也就是4个字节&#xff0c;对于很多语言来说&#xff0c;过于奢侈&#xff0c;也会造成通信效率和存储效率变低 UTF-8 unicode 创造…...

Alibaba --- 如何写好 Prompt ?

如何写好 Prompt 提示工程&#xff08;Prompt Engineering&#xff09;是一项通过优化提示词&#xff08;Prompt&#xff09;和生成策略&#xff0c;从而获得更好的模型返回结果的工程技术。总体而言&#xff0c;其实现逻辑如下&#xff1a; &#xff08;注&#xff1a;示例图…...

用html写一个雨的特效

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>雨特效</title><link rel"stylesheet" href"./style.css"> </head> <body> <div id"wrap-textu…...

前端 接口返回来的照片太大 加载慢如何解决

现象 解决 1. 添加图片懒加载 背景图懒加载 对背景图懒加载做的解释 和图片懒加载不同&#xff0c;背景图懒加载需要使用 v-lazy:background-image&#xff0c;值设置为背景图片的地址&#xff0c;需要注意的是必须声明容器高度。 <div v-for"img in imageList&quo…...

003 传参

文章目录 传参http 状态码传参方式&#xff08;1&#xff09;URL请求参数 key 与 方法中的形参名一致&#xff08;2&#xff09;URL请求参数 key与RequestParam("id") 中的别名一致&#xff08;3&#xff09; 形参是POJO类&#xff0c;URL 参数 key 与pojo类的 set方…...

QT写Windows按键输出(外挂)

一、前言 玩游戏的时候遇到些枯燥无味反反复复的按鼠标键盘的情况时&#xff0c;就想写个外挂自动释放。刚好在学qt所以试验了下QT能不能对外输出按键与鼠标。 二、思路 qt中的按键鼠标全是输入&#xff0c;没有直接对外输出键盘鼠标指令的类&#xff0c;但是我们换个思路&…...

个人做购物商城网站会罚款吗/谷歌推广费用

IT-网站技术 泛域名 第一步&#xff1a;泛域名的解析 首先我要给大家讲一个故事&#xff1a;故事的内容是“泛域名”。从前啊&#xff0c;有个小朋友叫做“泛域名”&#xff0c;泛域名 是谁家的小孩呢&#xff1f;知道DOS 伯伯吗&#xff1f;唉&#xff5e;&#xff5e;对了&a…...

网站如何上传数据库/爱廷玖达泊西汀

通常我们都建议不要把mysql的datadir设置为文件系统的根目录&#xff0c;否则&#xff0c;show database的时候&#xff0c;会发现一个 奇怪的db: #mysql50#lostfoundmysql [localhost] {msandbox} (test) > SHOW DATABASES;---------------------| DATABASE |-------------…...

室内装修设计上海/深圳知名seo公司

二值化核心思想 设阈值&#xff0c;大于阈值的为0&#xff08;黑&#xff09;或255&#xff08;白&#xff09;&#xff0c;使图像成为黑白图。 阈值可固定&#xff0c;也可自适应阈值。 自适应阈值一般为一点像素与这点为中心的区域像素平均值或者高斯分布加权和的比较&#x…...

淄博网站建设铭盛信息/男生短期培训就业

实现步骤 使用uTools软件的“内网穿透”插件配置vue项目配置内网穿透插件参数 一、下载uTools软件并安装内网穿透插件&#xff0c;如下图所示&#xff1a; 二、配置vue项目参数 在webpack.dev.conf.js文件下配置相关参数。三、配置内网穿透插件参数&#xff0c;如下图&#x…...

自己做头像的网站非流光/贵阳百度推广电话

IoC控制反转设计原则——实现松耦合1.IoC设计原则1.1.控制程序流1.2.控制依赖对象的创建2.从典型的n层体系架构来理解IoCIOC是一种设计原则&#xff08;虽然&#xff0c;有很多人将它当成是一种设计模式&#xff09;&#xff0c;不是设计模式。它提供了高层级的设计指南&#x…...

h5企业网站源码下载/上海seo服务

Windows XP下装过Linux的人都知道&#xff0c;在Windows XP上装好Linux时&#xff0c;系统引导时会显示Linux引导管理界面&#xff0c;当我们某天把Linux删了后&#xff0c;却发现Linux引导管理界面还在&#xff0c;这时我们可以用以下的方法来删除它。 准备一张DOS启动盘和fd…...