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

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之后,更为简化

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GandCrab5.2勒索病毒复现

GandCrab第一代勒索病毒首次出现于2018年1月&#xff0c;后面经历了五个大版本的更新迭代&#xff0c;该系列病毒特征是采用RSAAES加密算法&#xff0c;从算法上分析解密难度较大&#xff0c;会将系统中的大部分文件加密为随机后缀名的文件&#xff0c;然后对用户进行勒索。本实…

国内邮件推送如何避免拦截?内容优化技巧?

国内邮件推送的平台怎么选择&#xff1f;如何提高邮件推送效果&#xff1f; 邮件营销是企业与客户沟通的重要方式&#xff0c;但在国内邮件推送过程中&#xff0c;邮件被拦截的问题屡见不鲜。为了确保邮件能够顺利送达目标用户&#xff0c;AokSend将探讨一些有效的策略&#x…

【亲测好用】神级PSAI插件大揭秘:三款创成式修图神器,让你解放双手

PsBeta被停用后&#xff0c;小编一直想找到能够平替PsBeta创成式填充功能的插件。 功夫不负有心&#xff0c;终于被我找到啦&#xff0c;现在就给大家揭秘这三款宝藏修图神器&#xff0c;希望能够帮到大家。 1.插件名称&#xff1a;Starai 无需科学上网&#xff0c;还自带提示…

wireshark常用过滤命令

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

乐鑫云方案研讨会回顾|ESP RainMaker® 引领创业潮,赋能科创企业

近日&#xff0c;乐鑫信息科技 (688018.SH) ESP RainMaker 云生态方案线下研讨会和技术沙龙在深圳成功举办&#xff0c;吸引了众多来自照明电工、新能源、安防、宠物等垂类领域的客户与合作伙伴。活动现场&#xff0c;与会嘉宾围绕产品研发、测试认证、品牌构建、跨境电商等多维…

揭秘循环购:消费即收益,如何助力商家月销百万?

大家好&#xff0c;我是吴军&#xff0c;今天要和大家分享一种颠覆性的商业模式——循环购。你是否听说过“消费1000送2000”这样的促销活动&#xff1f;是不是觉得太不可思议&#xff0c;商家岂不是在“送钱”&#xff1f;别急&#xff0c;让我为你揭开这背后的秘密。 循环购&…

路由器ARP和ARP-proxy(华为)

#交换设备 路由器ARP和ARP-proxy(华为) 当一个广播域中的主机想要访问另外一个广播域的主机时&#xff0c;会广播ARP报文&#xff0c;询问目标IP地址所对应的MAC地址&#xff0c;默认情况下&#xff0c;arp记录是设备自动生成的&#xff0c;但是这样会容易受到ARP欺骗攻击&am…

基础入门篇 | YOLOv10 项目【训练】【验证】【推理】最简单教程 | YOLOv10必看 | 最新更新,直接打印 FPS,mAP50,75,95

文章目录 训练 --train.py推理 --detect.py验证 --val.py不训练,只查看模型结构/参数量/计算量 --test.pyYOLOv10 是基于 YOLOv8 项目的改进版本,目前已经被 YOLOv8 项目合并,所以两个算法使用方法完全一致~ 今天我给大家展示一种非常方便的使用过程,包含【训练】【验证】…

盘立方期货Kdj幅图指标公式源码

盘立方期货Kdj幅图指标公式源码&#xff1a; N:250; WR1:100-100*(HHV(HIGH,N)-CLOSE)/(HHV(HIGH,N)-LLV(LOW,N)),DOT,COLORLIGHTGREEN; EW:EMA(WR1,5); STICKLINE(WR1<20,WR1,20,1,0),COLORYELLOW; STICKLINE(WR1>80,WR1,80,1,0),COLORYELLOW; RSV:(CLOSE-LLV(LOW…

2024CICE电博会·以“链主”企业为核心,推动产业链协同发展

随着全球科技日新月异的发展&#xff0c;消费电子产业已成为推动经济增长、改善人民生活的重要力量。中国国际消费电子博览会&#xff08;简称CICE电博会&#xff09;自2001年创办以来&#xff0c;已经走过了二十余个春秋&#xff0c;凭借其独特的地理位置优势、专业的组织策划…

MAC Address

文章目录 1. 前言2. MAC Address2.1 MAC 地址格式2.2 Locally Administered MAC Address2.3 MAC 单播 和 多播 3. 参考资料 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. MAC Address 2.1 MA…

《2024云安全资源池 能力指南》

《2024云安全资源池 能力指南》这份报告不仅梳理了云安全资源池的发展历程,还深入探讨了其在当前云计算环境下的重要性和必要性。报告详细分析了云安全资源池的市场需求、技术架构、关键技术以及行业应用案例,为政企用户提供了全面的云安全解决方案。通过资料收集、问卷调研、企…

0624_ARM1

思维导图&#xff1a;

揭秘红酒酿造魔法:看葡萄如何华丽变身酿成

红酒&#xff0c;这一液体中的诗篇&#xff0c;从葡萄园中的翠绿到酒窖里的深沉&#xff0c;每一滴都蕴含着大自然的恩赐与酿酒师的智慧。今天&#xff0c;就让我们一起揭开红酒酿造的神秘面纱&#xff0c;探寻从葡萄到佳酿的魔法之旅&#xff0c;并特别聚焦在备受赞誉的雷盛红…

java安全必学之Javassist 学习

Javassist 学习 环境搭建 这个非常简单&#xff0c;只需要你自己加一个依赖 <!-- https://mvnrepository.com/artifact/javassist/javassist --><dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><versi…

光伏能源圈

2021年&#xff0c;新型电力系统之下&#xff0c;中国已形成了两网五大六小的电力新格局&#xff1a; 两大电网&#xff1a;国家电网、南方电网 五大电力央企&#xff1a;国家能源投资集团、中国华能集团、中国华电集团、中国大唐集团、国家电力投资集团。 六小豪门&#xf…

使用Leaflet和瓦片地图实现离线地图的技术指南

引言 在现代的Web应用中&#xff0c;地图服务扮演着越来越重要的角色。然而&#xff0c;在一些特殊环境下&#xff0c;如偏远地区或网络环境不稳定的情况下&#xff0c;依赖在线地图服务可能会受到限制。因此&#xff0c;实现离线地图功能成为了一个重要的需求。本文将介绍如何…

MoonBit 周报 Vol.46:支持32位无符号整数!

MoonBit 更新 支持了 32 位无符号整数 let num 100U // 32位无符号整数的字面量需要后缀U在 wasm 后端导出返回值类型为 Unit 的函数时&#xff0c;之前导出函数的类型中会有 (result i32)&#xff0c;现在 MoonBit 编译器会自动生成一个没有返回值 wrapper 函数&#xff0c…

【漏洞复现】通天星CMSV6车载定位监控平台 point_manage/merge SQL注入致RCE

0x01 产品简介 通天星CMSV6车载定位监控平台拥有以位置服务、无线3G14G视频传输、云存储服务为核心的研发团队&#xff0c;专注于为定位、无线视频终端产品提供平台服务&#xff0c;通天星CMSV6产品覆盖车载录像机、单兵录像机、网络监控摄像机、行驶记录仪等产品的视频综合平…