《第一行代码 第3版》学习笔记——第十一章 网络技术

news2024/9/20 18:34:58

1 webview用法

class MainActivity : ComponentActivity() {
    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    AndroidView(factory = { context ->
                        WebView(context).apply {
                            webViewClient = object : WebViewClient() {
                                override fun shouldOverrideUrlLoading(
                                    view: WebView?,
                                    request: WebResourceRequest?
                                ): Boolean {
                                    try {
                                        if (url!!.startsWith("baiduboxapp://")) {
                                            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                                            startActivity(intent)
                                            return true
                                        }
                                    } catch (e: Exception) {
                                        return false
                                    }
                                    view?.loadUrl(url!!)
                                    return true
                                }
                            }
                            settings.javaScriptEnabled = true
                            loadUrl("https://www.baidu.com/")
                        }
                    })
                }
            }
        }
    }
}

Compose没有WebView控件,使用传统的WebView控件,创建一个WebViewClient对象,用于展示百度首页。loadUrl函数加载百度首页数据。javaScriptEnabled用于加载JavaScript样式
由于baidu有自定义scheme,所以这里做了特殊处理

2 使用http访问网络

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    color = MaterialTheme.colorScheme.background
                ) {
                    ShowHttp()
                }
            }
        }
    }
}

@Composable
fun ShowHttp() {
    var response by remember {
        mutableStateOf("")
    }
    LazyColumn {
        item {
            Button(
                onClick = {
                    thread {
                        var conn: HttpURLConnection? = null
                        try {
                            val res = StringBuilder()
                            val url = URL("https://www.baidu.com")
                            conn = url.openConnection() as HttpURLConnection
                            conn.connectTimeout = 8000
                            conn.readTimeout = 8000
                            val input = conn.inputStream
                            val reader = BufferedReader(InputStreamReader(input))
                            reader.use {
                                reader.forEachLine {
                                    res.append(it)
                                }
                            }
                            response = res.toString()
                            Log.i("TAG", "response = $response ")
                        } catch (e: Exception) {
                            e.printStackTrace()
                        } finally {
                            conn?.disconnect()
                        }
                    }
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "request")
            }
        }
        item {
            Button(
                onClick = {
                    thread {
                        try {
                            val client = OkHttpClient()
                            val request = Request.Builder()
                                .url("https://www.baidu.com")
                                .build()
                            val res = client.newCall(request).execute()
                            val responseData = res.body?.string()
                            if (responseData != null) {
                                response = responseData
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }
                    }
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "request from okhttp")
            }
        }
        item {
            Text(text = response)
        }
    }
}

这里创建两个按钮,一个数据展示的空间。两个按钮是两种使用http访问网络的方式,第一种是Java自带的HttpURLConnection相关的API,第二种是使用okhttp这个开源框架。
下面是访问baidu之后的打印界面
在这里插入图片描述

3 解析xml数据

网络上的数据经常使用xml或json进行传输,需要学习怎么对xml和json类型数据进行解析
这个使用pull和sax方式解析xml

class MainActivity : ComponentActivity() {
    private final val TAG = "MainActivity"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    XmlPage { sendRequestForXml() }
                }
            }
        }
    }

    private fun sendRequestForXml() {
        thread {
            try {
                val client = OkHttpClient()
                val request = Request.Builder()
                    .url("http://192.168.12.148:12345/get_data_xml")
                    .build()
                val response = client.newCall(request).execute()
                val responseData = response.body?.string()
                if (responseData != null) {
                    parseXmlDataWithPull(responseData)
                }
                if (responseData != null) {
                    parseXmlWithSax(responseData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun parseXmlDataWithPull(responseData: String) {
        try {
            val factory = XmlPullParserFactory.newInstance()
            val xmlPullparser = factory.newPullParser()
            xmlPullparser.setInput(StringReader(responseData))
            var eventType = xmlPullparser.eventType
            var id = ""
            var name = ""
            var version = ""
            while (eventType != XmlPullParser.END_DOCUMENT) {
                val nodeName = xmlPullparser.name
                when (eventType) {
                    XmlPullParser.START_TAG -> {
                        when (nodeName) {
                            "id" -> id = xmlPullparser.nextText()
                            "name" -> name = xmlPullparser.nextText()
                            "version" -> version = xmlPullparser.nextText()
                        }
                    }

                    XmlPullParser.END_TAG -> {
                        if ("app" == nodeName) {
                            Log.d(TAG, "id = $id, name = $name, version = $version")
                        }
                    }
                }
                eventType = xmlPullparser.next()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun parseXmlWithSax(responseData: String) {
        try {
            val factory = SAXParserFactory.newInstance()
            val xmlReader = factory.newSAXParser().xmlReader
            val handler = ContentHandler()
            xmlReader.contentHandler = handler
            xmlReader.parse(InputSource(StringReader(responseData)))
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

@Composable
fun XmlPage(
    sendRequest: () -> Unit
) {
    LazyColumn {
        item {
            Button(
                onClick = {
                    sendRequest()
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "GetXml")
            }
        }
    }
}

SAX方式解析需要继承DefaultHandler并重写其中的方法

class ContentHandler : DefaultHandler() {

    private var nodeName = ""
    private lateinit var id: StringBuilder
    private lateinit var name: StringBuilder
    private lateinit var version: StringBuilder

    override fun startDocument() {
        id = StringBuilder()
        name = StringBuilder()
        version = StringBuilder()
    }

    override fun startElement(
        uri: String,
        localName: String,
        qName: String,
        attributes: Attributes
    ) {
        nodeName = localName
    }

    override fun characters(ch: CharArray, start: Int, length: Int) {
        when (nodeName) {
            "id" -> id.appendRange(ch, start,  length)
            "name" -> name.appendRange(ch, start, length)
            "version" -> version.appendRange(ch, start, length)
        }
        Log.d("ContentHandler", "id = $id")
        Log.d("ContentHandler", "name = $name")
        Log.d("ContentHandler", "version = $version")
    }

    override fun endElement(uri: String?, localName: String?, qName: String?) {
        if ("app" == localName) {
            Log.d("endElement", "id = $id")
            Log.d("endElement", "name = $name")
            Log.d("endElement", "version = $version")
            Log.d("ContentHandler", "id is $id, name is $name, version is $version")
            id.setLength(0)
            name.setLength(0)
            version.setLength(0)
        }
    }

    override fun endDocument() {
    }
}

点击之后会打印

id = 1, name = Google Maps, version = 1.0
id = 2, name = Chrome, version = 2.1
id = 3, name = Google Play, version = 3.2

4 解析Json数据

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sendRequestForJson()
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {

                }
            }
        }
    }

    private fun sendRequestForJson() {
        thread {
            val client = OkHttpClient()
            val request = Request.Builder()
                .url("http://192.168.12.148:12345/get_data_json")
                .build()
            val response = client.newCall(request).execute()
            val responseData = response.body?.string()
            if (responseData != null) {
                parseJsonWithJsonObject(responseData)
                parseJsonWithGson(responseData)
            }
        }
    }

    private fun parseJsonWithJsonObject(responseData: String) {
        try {
            val jsonArray = JSONArray(responseData)
            for (i in 0 until jsonArray.length()) {
                val jsonObject = jsonArray.getJSONObject(i)
                val id = jsonObject.getString("id")
                val name = jsonObject.getString("name")
                val version = jsonObject.getString("version")
                Log.d(
                    "parseJsonWithJsonObject",
                    "id = ${id.trim()}, name = ${name.trim()}, version = ${version.trim()}"
                )
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun parseJsonWithGson(responseData: String) {
        val gson = Gson()
        val typeOf = object : TypeToken<List<App>>() {}.type
        val appList = gson.fromJson<List<App>>(responseData, typeOf)
        for (app in appList) {
            Log.d(
                "parseJsonWithGson", "id = ${app.id.trim()}, name = ${app.name.trim()} " +
                        ", version = ${app.version.trim()}"
            )
        }
    }
}

class App(val id: String, val name: String, val version: String)

使用JSONArray和Gson解析,Gson可以直接解析成对象。
打印如下

id = 5, name = Clash of Clans, version = 5.5
id = 6, name = Boom Beach, version = 7.0
id = 7, name = Clash Royale, version = 3.5
id = 5, name = Clash of Clans , version = 5.5
id = 6, name = Boom Beach , version = 7.0
id = 7, name = Clash Royale , version = 3.5

5 使用回调

由于网络请求是耗时的操作,在子线程中操作,无法准确知道结果什么时候返回,所以可以通过回调的方式来返回结果。

HttpCallbackListener

interface HttpCallbackListener {
    fun onFinish(response: String)
    fun onError(e: Exception)
}

HttpUtils

object HttpUtils {
    private const val TAG = "HttpUtils"
    fun sendHttpRequest(address: String, listener: HttpCallbackListener) {
        thread {
            var connect: HttpURLConnection? = null
            try {
                val response = StringBuilder()
                val url = URL(address)
                connect = url.openConnection() as HttpURLConnection
                connect.connectTimeout = 8000
                connect.readTimeout = 8000
                val inputStream = connect.inputStream
                val reader = BufferedReader(InputStreamReader(inputStream))
                reader.use {
                    reader.forEachLine {
                        response.append(it)
                    }
                }
                listener.onFinish(response.toString())
            } catch (e: Exception) {
                e.printStackTrace()
                listener.onError(e)
            } finally {
                connect?.disconnect()
            }
        }
    }

    fun sendHttpRequest(address: String, callback: okhttp3.Callback) {
        thread {
            val client = OkHttpClient()
            val request = Request.Builder()
                .url(address)
                .build()
            client.newCall(request).enqueue(callback)
        }
    }

    fun parseXmlWithPull(response: String): String {
        try {
            val factory = XmlPullParserFactory.newInstance()
            val parser = factory.newPullParser()
            parser.setInput(StringReader(response))
            var eventType = parser.eventType
            val responseData = StringBuilder()
            var id = ""
            var name = ""
            var version = ""
            while (eventType != XmlPullParser.END_DOCUMENT) {
                val nodeName = parser.name
                when (eventType) {
                    XmlPullParser.START_TAG -> {
                        when (nodeName) {
                            "id" -> id = nodeName
                            "name" -> name = nodeName
                            "version" -> version = nodeName
                        }
                    }

                    XmlPullParser.END_TAG -> {
                        if ("app" == nodeName) {
                            val text = "id = ${id.trim()}, name = ${name.trim()}," +
                                    " version = ${version.trim()}\n"
                            Log.d(TAG, text)
                            responseData.append(text)
                        }
                    }
                }
                eventType = parser.next()
            }
            return responseData.toString()
        } catch (e: Exception) {
            e.printStackTrace()
            return ""
        }
    }

    val localIpv4Address: String?
        get() {
            val en = NetworkInterface.getNetworkInterfaces()
            while (en.hasMoreElements()) {
                val netInterface = en.nextElement()
                val enIpAddress = netInterface.inetAddresses
                while (enIpAddress.hasMoreElements()) {
                    val inetAddress = enIpAddress.nextElement()
                    if (!inetAddress.isLoopbackAddress && inetAddress is Inet4Address) {
                        return inetAddress.hostAddress!!.toString()
                    }
                }
            }
            return null
        }
}

MainActivity

const val TAG = "MainActivity"

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    RequestPage()
                }
            }
        }
    }
}

@Composable
fun RequestPage() {
    var result by remember {
        mutableStateOf("")
    }
    LazyColumn {
        result = ""
        item {
            Button(
                onClick = {
                    val listener = object : HttpCallbackListener {
                        override fun onFinish(response: String) {
                            result = "HttpURLConnection data: \n"
                            result += HttpUtils.parseXmlWithPull(response)
                        }

                        override fun onError(e: Exception) {
                            Log.d(TAG, "onError: ")
                            result = "HttpURLConnection request failed"
                        }

                    }
                    val ip = HttpUtils.localIpv4Address
                    val url = "http://$ip:12345/get_data_xml"
                    HttpUtils.sendHttpRequest(url, listener)
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "request for xml with HttpURLConnection")
            }
        }
        item {
            Button(
                onClick = {
                    result = ""
                    val callback = object : Callback {
                        override fun onFailure(call: Call, e: IOException) {
                            Log.d(TAG, "onFailure: ")
                            result = "okhttp request failed"
                        }

                        override fun onResponse(call: Call, response: Response) {
                            result = "okhttp data: \n"
                            result += HttpUtils.parseXmlWithPull(response.body?.string().toString())
                        }
                    }
                    val ip = HttpUtils.localIpv4Address
                    val url = "http://$ip:12345/get_data_xml"
                    HttpUtils.sendHttpRequest(url, callback)
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "request for xml with okhttp")
            }
        }
        item {
            Text(text = result)
        }
    }
}

这里展示了HttpURLConnection和okhttp使用回调的方式,HttpURLConnection需要自己创建回调接口,okhttp则有自带的callback接口。

6 Retrofit

6.1 Retrofit使用

Retrofit基于以下几点设计:

  • 同一款应用程序中所发起的网络请求绝大多数指向的是同一个服务器域名
  • 服务器提供的接口通常是可以根据功能来归类的
  • 开发者肯定更加习惯于“调用一个接口,获取它的返回值”这样的编码方式
class App(val id: String, val name: String, val version: String)

创建一个App类用于存储数据,Retrofit可以通过Gson直接将xml数据解析成对象进行存储

interface AppService {
    @GET("get_data_json")
    fun getAppData(): Call<List<App>>
}

创建一个AppService 接口,定义一个函数做网络请求的入口,使用GET注解表示一个是get类型的请求,由于Retrofit可以设置baseurl,所以这里只需要设置相对的资源路径

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NetWorkDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    GetXmlData()
                }
            }
        }
    }
}

@Composable
fun GetXmlData() {
    var xmlData by remember {
        mutableStateOf("")
    }
    LazyColumn {
        item {
            Button(
                onClick = {
                    val ip = HttpUtils.localIpv4Address
                    val retrofit = Retrofit.Builder()
                        .baseUrl("http://$ip:12345/")
                        .addConverterFactory(GsonConverterFactory.create())
                        .build()
                    val appService = retrofit.create(AppService::class.java)
                    appService.getAppData().enqueue(object : Callback<List<App>> {
                        override fun onResponse(
                            call: Call<List<App>>,
                            response: Response<List<App>>
                        ) {
                            val result = StringBuilder()
                            val list = response.body()
                            if (list != null) {
                                for (app in list) {
                                    result.append(Gson().toJson(app).toString() + "\n")
                                }
                            }
                            xmlData = result.toString()
                        }

                        override fun onFailure(call: Call<List<App>>, t: Throwable) {
                            xmlData = "request failed"
                        }

                    })
                },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(text = "get xml data")
            }
        }
        item {
            Text(text = xmlData)
        }
    }
}

首先创建Retrofit对象,设置baseurl,并设置Gson作为转换工具。
然后创建AppService子类对象,调用getAppData方法,并调用enqueue开始发起网络请求。后面传入一个回调作为参数,请求的response返回后直接触发回调
请求后效果如下:
在这里插入图片描述

6.2 其他请求方式

如果需要复杂参数传递,可以参考

// GET http://example.com/<page>/get_data.json
interface ExampleService {
	@GET("{page}/get_data.json")
	fun getData(@Path("page") page: Int): Call<Data>
}

如果存在页面参数,可以通过传入一个int值并使用Path注解修饰

// GET http://example.com/get_data.json?u=<user>&t=<token>
interface ExampleService {
	@GET("get_data.json")
	fun getData(@Query("u") user: String, @Query("t") token: String): Call<Data>
}

这个是带参数查询的写法

// DELETE http://example.com/data/<id>
interface ExampleService {
@DELETE("data/{id}")
	fun deleteData(@Path("id") id: String): Call<ResponseBody>
}

这个是delete请求

// POST http://example.com/data/create {"id": 1, "content": "The description for this data."}
interface ExampleService {
	@POST("data/create")
	fun createData(@Body data: Data): Call<ResponseBody>
}

这个是post请求

// GET http://example.com/get_data.json
// User-Agent: okhttp
// Cache-Control: max-age=0
interface ExampleService {
	@Headers("User-Agent: okhttp", "Cache-Control: max-age=0")
	@GET("get_data.json")
	fun getData(): Call<Data>
}

这种是静态的Header中添加数据

interface ExampleService {
	@GET("get_data.json")
	fun getData(@Header("User-Agent") userAgent: String,
		@Header("Cache-Control") cacheControl: String): Call<Data>
}

这种是动态的Header中添加数据

6.3 最佳实践

val ip = HttpUtils.localIpv4Address
val retrofit = Retrofit.Builder()
    .baseUrl("http://$ip:12345/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
val appService = retrofit.create(AppService::class.java)

这段代码可以优化,创建一个ServiceCreator 类

object ServiceCreator {
    private const val BASE_URL = "http://192.168.12.148:12345"

    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
    inline fun <reified T> create(): T = create(T::class.java)
}

使用泛型,并创建一个内联函数,使用reified修饰,可以访问泛型的真实类型来进一步简化

// val appService = ServiceCreator.create(AppService::class.java)
val appService = ServiceCreator.create<AppService>()

没有加入inline函数可以调用上面的,加入inline之后,更为简化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1858396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

史上最全整合nacos单机模式整合哈哈哈哈哈

Nacos 是阿里巴巴推出的一个新开源项目&#xff0c;它主要是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos提供了一组简单易用的特性集&#xff0c;帮助用户快速实现动态服务发现、服务配置、服务元数据及流量管理。 Nacos 的关键特性包括&#x…

线程池概念、线程池的不同创建方式、线程池的拒绝策略

文章目录 &#x1f490;线程池概念以及什么是工厂模式&#x1f490;标准库中的线程池&#x1f490;什么是工厂模式&#xff1f;&#x1f490;ThreadPoolExecutor&#x1f490;模拟实现线程池 &#x1f490;线程池概念以及什么是工厂模式 线程的诞生是因为&#xff0c;频繁的创…

【Linux】Socket阻塞和非阻塞、同步与异步

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;Linux系列专栏&#xff1a;Linux基础 &#x1f525; 给大家…

20240623日志:大模型压缩-sliceGPT

context 1. 剪枝方案图释2. 正交矩阵Q 1. 剪枝方案图释 Fig. 1.1 剪枝方案 图中的阴影是表示丢弃掉这部分数据。通过引入正交矩阵 Q Q Q使 Q ⊤ Q Q Q ⊤ I \mathrm{Q}^\top\mathrm{Q}\mathrm{Q}\mathrm{Q}^\top\mathrm{I} Q⊤QQQ⊤I&#xff0c;来大量缩减 X X X的列数和 W …

[职场] 保险理赔工作简历自我评价范文 #媒体#经验分享#笔记

保险理赔工作简历自我评价范文 保险行业是指将通过契约形式集中起来的资金&#xff0c;用以补偿被保险人的经济利益业务的行业。下面是保险理赔工作简历自我评价范文&#xff0c;供大家参考。 保险公司工作自我评价1 我已在__保险公司工作_个年头。在同事和领导的热情帮忙下&…

query2doc:用大模型做query检索拓展

原文&#xff1a; 前沿重器[38] | 微软新文query2doc&#xff1a;用大模型做query检索拓展 比较主流的检索方案&#xff1a; 字面检索&#xff08;sparse&#xff0c;稀疏&#xff09;向量检索&#xff08;dense&#xff0c;稠密&#xff09; query对文档文段的召回&#xff…

【消息队列】六万字长文详细带你RabbitMQ从入门到精通

目录 1、基础篇1.1 为什么要用消息队列MQ1.2 什么是消息队列&#xff1f;1.3 RabbitMQ体系结构介绍1.4 RabbitMQ安装1.5 Hello World1.5.1 目标1.5.2 具体操作 1.6 RabbitMQ用法1.6.1 Work Queues1.6.2 Publish/Subscribe1.6.3 Routing1.6.4 Topics1.6.5 工作模式小结 2. 进阶篇…

维度建模中的事实表

在维度建模中&#xff0c;根据粒度划分&#xff0c;数据表主要分为维度表和事实表。而事实表又可以分为三种类型&#xff1a;事务型事实表、周期快照型事实表和累计快照型事实表。本文将详细介绍这三种事实表&#xff0c;并提供相应的代码示例。 目录 1. 事务型事实表示例 2. 周…

推荐系统三十六式学习笔记:原理篇.模型融合13|经典模型融合办法:线性模型和树模型的组合拳

目录 为什么要融合&#xff1f;“辑度组合”原理逻辑回归梯度提升决策树GBDT二者结合 总结 推荐系统在技术实现上一般划分为三个阶段&#xff1a;挖掘、召回、排序 。 为什么要融合&#xff1f; 挖掘的工作是对用户和物品做非常深入的结构化分析&#xff0c;各个角度各个层面…

硬盘监控和分析工具:Smartctl

文章目录 1. 概述2. 安装3. 使用4. smartctl属性信息介绍 1. 概述 Smartctl&#xff08;S.M.A.R.T 自监控&#xff0c;分析和报告技术&#xff09;是类Unix系统下实施SMART任务命令行套件或工具&#xff0c;它用于打印SMART自检和错误日志&#xff0c;启用并禁用SMRAT自动检测…

PR模板 | RGB特效视频标题模板Titles | MOGRT

RGB特效视频标题模板mogrt免费下载 4K分辨率&#xff08;38402160&#xff09; 支持任何语言 友好的界面 输入和输出动画 快速渲染 视频教程 免费下载&#xff1a;https://prmuban.com/39055.html 更多pr模板视频素材下载地址&#xff1a;https://prmuban.com

初见:AntDB智能运维“三剑客“之ADC

引言 6月15日&#xff0c;PostgreSQL数据库技术峰会广州站圆满落幕。峰会上&#xff0c;亚信安慧数据库智能运维产品负责人李志龙介绍了AntDB的6大数据库引擎和3大工具产品能力。 这里的3大工具分别指&#xff1a; AntDB数据库迁移工具包 MTK 数据库智能运维平台 ACC AntDB数据…

Modbus协议在工业自动化中的应用

Modbus协议介绍 Modbus是一种常用的工业现场总线通信协议,被广泛应用于工业自动化领域。它是一种简单、易实现的主从式通信协议,具有高度的可靠性和通用性。本文将从Modbus协议的基本概念、通信模式、数据格式、常见应用场景等方面进行全面介绍,并通过图文并茂的方式帮助读者更…

ardupilot开发 --- 视觉伺服 篇

风驰电掣云端飘&#xff0c;相机无法对上焦 视觉伺服分类视觉伺服中的坐标系成像模型推导IBVS推导参考文献 视觉伺服分类 控制量是在图像空间中推导得到还是在欧式空间中推导得到&#xff0c;视觉伺服又可以分类为基于位置(PBVS)和基于图像的(IBVS)视觉伺服。 视觉伺服中的坐…

关于docker存储overlay2相关问题

报错如下&#xff1a; 报错原因&#xff1a;使用rm -rf 清理overlay2导致的&#xff0c;非正常清理。 正常清理命令如下&#xff1a; # 清理Docker的所有构建缓存 docker builder prune# 删除旧于24小时的所有构建缓存 docker builder prune --filter "until24h"#删…

node.js环境安装以及Vue-CLI脚手架搭建项目教程

目录 ▐ vue-cli 搭建项目的优点 ▐ 安装node.js环境 ▐ 搭建vue脚手架项目 ▐ 项目结构解读 ▐ 常用命令 ▐ 创建组件 ▐ 组件路由 ▐ vue-cli 搭建项目的优点 传统的前端项目架构由多个html文件&#xff0c;且每个html文件都是相互独立的&#xff0c;导入外部组件时需…

wireshark常用过滤命令

wireshark常用过滤命令 wireshark抓包介绍单机单点&#xff1a;单机多点&#xff1a;双机并行&#xff1a; wireshark界面认识默认布局调整布局(常用)显示FCS错误 wireshark常见列Time回包数据报对应网络模型 wireshark基本操作结束抓包再次开始抓包 **wireshark常用过滤命令**…

【实物资料包】基于STM32智能台灯设计

【实物资料包】基于STM32智能台灯设计 需要资料的请在文章结尾获取哦~~~~&#xff08;如有问题私信我即可&#xff09; 1.介绍 1 添加wifi模块模块&#xff0c;可通过wifi模块APP或者手动按钮切换自动/手动模式 2 自动模式下&#xff0c;台灯可以感应是否有人落座&#xff0…

【BSCP系列第2期】XSS攻击的深度剖析和利用(文末送书)

文章目录 前言一、官方地址二、开始&#xff08;15个&#xff09;1&#xff1a;Lab: DOM XSS in document.write sink using source location.search inside a select element2&#xff1a;Lab: DOM XSS in AngularJS expression with angle brackets and double quotes HTML-e…

猫头虎分享已解决Bug:Array Index Out of Bounds Exception

&#x1f42f; 猫头虎分享已解决Bug&#xff1a;Array Index Out of Bounds Exception &#x1f42f; 摘要 大家好&#xff0c;我是猫头虎&#xff0c;今天我们要聊聊后端开发中经常遇到的一个问题&#xff1a;Array Index Out of Bounds Exception&#xff0c;即 java.lang.…