【Android】 网络技术

news2024/12/27 13:40:31

前言

本文用于记录Android网络技术的使用, 包括我们如何发起一条HTTP请求、解析XML、JOSN格式的数据以及最好用的网络库Retrofit。

使用HTTP协议访问网络

关于HTTP协议的工作原理,我们只需要知道客户端向服务器发起一条HTTP请求,服务器接收到请求之后会返回一些数据给客户端,然后客户端再对这些数据进行解析和处理。接下来我们将实现一下手动发送HTTP请求。

使用HttpURLConnection

我们先来大致了解一下使用HttpURLConnection发送HTTP请求的步骤:

  • 获取HttpURLConnection实例,一般都是先new出一个URL对象并将目标网站传入,然后调用openConnection()方法即可获得实例
Url url=new URL("http://www.baidu.com");
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
  • 设置HTTP请求所使用的方法。常用方法有GET和POST。GET表示希望从服务器那获取数据,POST表示希望提交数据给服务器。
connection.setRequestMethod("GET");
  • 一些其他设置,如设置连接超时、读取超时毫秒数、服务器希望得到的消息头等
  • 调用getInputStream()方法获取服务器返回的输入流,接下来我们就可以对输入流进行读取
InputStream in=connection.getInputStream();
  • 最后调用disconnect()方法将这个HTTP连接关闭
connection.disconnect();

实例

向百度首页发起一条HTTP请求,返回它的HTML代码

  • activity_main,包括发送请求的按钮和展示返回数据的文本框
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/send_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Request"/>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/response_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </ScrollView>
</LinearLayout>
  • MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button sendRequest=(Button) findViewById(R.id.send_request);
        responseText=(TextView) findViewById(R.id.response_text);
        sendRequest.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if(view.getId()==R.id.send_request){
            sendRequestWithHttpURLConnection();
        }
    }
    private void sendRequestWithHttpURLConnection(){
        //开启线程发送网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection=null;
                BufferedReader reader=null;
                try {
                    //向百度的首页发起一条HTTP请求
                    URL url=new URL("https://www.baidu.com");
                    connection=(HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    InputStream in=connection.getInputStream();
                    //下面对获取到的输入流(服务器返回的流)进行读取
                    reader=new BufferedReader(new InputStreamReader(in));
                    StringBuilder response=new StringBuilder();
                    String line;
                    while((line=reader.readLine())!=null){
                        response.append(line);
                    }
                    showResponse(response.toString());
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    if(reader!=null){
                        try {
                            reader.close();
                        }catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                    if(connection!=null){
                        //关闭HTTP连接
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
    private void showResponse(final String response){
        //因为Android不允许在子线程更新UI,所有我们使用runOnUiThread方法将线程切换为主线程
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //将结果显示到界面上
                responseText.setText(response);
            }
        });
    }
}

这里主要注意一下showResponse()方法中的runOnUiThread()方法,它可以将线程由子线程切换为主线程。

  • 最后别忘了申请一下网络权限
<uses-permission android:name="android.permission.INTERNET"/>

POST请求

想要发送POST请求,只需将setRequestMethod的参数改为POST,并在获取输入流之前把要提交的数据写出即可。例如我们要向服务器提交用户名和密码,可以写成:

connection.setRequestMethod("POST");
DataOutputStream out=new DataOutputStream(connection.getOutputStream());
//数据与数据之间用&分隔开
out.writeBytes("username=admin&password=123456);

使用OkHttp

OkHttp是一个可以代替原生HttpURLConnection发送HTTP请求的网络通信库。可用于简化我们发送HTTP的步骤。下面我们来简单梳理一下其基本步骤:

  • 首先使用前必须添加其依赖
implementation ("com.squareup.okhttp3:okhttp:4.9.0")
  • 创建一个OkHttpClient实例
OkHttpClient client=new OkHttpClient();
  • 要想发送HTTP请求,我们需要创建一个Request对象(目标网站为百度首页),注意此时请求并未发送
Request request=new Request.Builder()
    .url("http://www.baidu.com")
    .build();
  • 调用OkHttpClient的newCall()方法来创建一个Call对象并调用它的execute()方法来发送请求并获取服务器返回的数据
Response response=client.newCall(request).execute();
  • 获取具体的返回内容
String responseData=response.body().string();

POST请求

  • 我们需要先构建出一个RequestBody对象来存放待提交的数据
RequestBody requestBody=new FormBody.Builder()
    .add("username","admin")
    .add("password","123456")
    .build();
  • 接着在构建出一个Request对象并将待提交的数据传入
Request request=new Request.Builder()
    .url("http://www.baidu.com")
    .post(requestBody)
    .build();

最后就和GET请求一样调用execute()方法来发送请求并获取服务器返回的数据即可。

实例

这里我们就直接在上面的代码进行改造,将上面点击按钮的sendRequestWithHttpURLConnection()方法换为:

sendRequestWithOkHttp();

接着实现这个方法:

	//使用OkHttp发送请求
    private void sendRequestWithOkHttp(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //构建OkHttpClient实例
                    OkHttpClient client=new OkHttpClient();
                    //构建Request对象并将目标网址传入
                    Request request=new Request.Builder()
                            .url("https://www.baidu.com")
                            .build();
                    //调用execute()方法发送请求并接收返回的数据
                    Response response=client.newCall(request).execute();
                    //将返回的数据解析成字符串
                    String responseData=response.body().string();
                    //将返回的信息显示在屏幕上
                    showResponse(responseData);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }).start();
    }

解析XML格式数据

数据在网络上传输通常有两种方式XML和JSON,这两种数据分别具有其自己的结构规格和语义,当我们获取到这种数据时,我们要对其进行解析从而取出我们想要的那部分内容,接下来我们先来介绍Pull解析XML格式数据。

Pull解析方式

首先你要确保你已经下载好Tomcat并做好相关配置并将Tomcat启动起来,接下来我们来自定义一段XML格式的数据(这段数据我是定义在D:\Apache\apache-tomcat-8.5.95\webapps\AndroidStudy这个路径下的):

<apps>
	<app>
		<id>1</id>
		<name>Google Maps</name>
		<version>1.0</version>
	</app>
	<app>
		<id>2</id>
		<name>Chrome</name>
		<version>2.1</version>
	</app>
	<app>
		<id>3</id>
		<name>Google Play</name>
		<version>2.3</version>
	</app>
</apps>

接下来我们可以打开浏览器看看是不是没问题,我的Tomcat端口是9000(可以在conf\server.xml文件中修改端口号),所以我输入localhost:9000/AndroidStudy/get_data.xml会显示出以下内容:

在这里插入图片描述

接下来我们就可以去对这些定义好的数据进行解析,我们接着在上面写好的代码上进行修改

  • 首先构造Request对象时url我们要指定为访问本机IP地址,你打开控制台查一下本机电脑IP,如下所示
.url("http://192.168.??.???:9000/AndroidStudy/get_data.xml")
  • 接着实现一个parseXMLWithPull对返回的数据进行解析
	//Pull解析数据
    private void parseXMLWithPull(String xmlData){
        try {
            XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
            //使用XmlPullParserFactory来创建出XmlPullParser实例
            XmlPullParser xmlPullParser=factory.newPullParser();
            //将服务器返回的数据设置进XmlPullParser就可以开始进行解析了
            xmlPullParser.setInput(new StringReader(xmlData));
            //通过getEventType()就可以得到当前的解析事件
            int eventType=xmlPullParser.getEventType();
            String id="";
            String name="";
            String version="";
            //!=XmlPullParser.END_DOCUMENT表示解析工作还未完成
            while(eventType!=XmlPullParser.END_DOCUMENT){
                String nodeName=xmlPullParser.getName();
                switch (eventType){
                    //开始解析某个节点,将数据取出
                    case XmlPullParser.START_TAG:{
                        if("id".equals(nodeName)){
                            id=xmlPullParser.nextText();
                        } else if ("name".equals(nodeName)) {
                            name=xmlPullParser.nextText();
                        } else if ("version".equals(nodeName)) {
                            version=xmlPullParser.nextText();
                        }
                        break;
                    }
                    //完成解析某个节点,将数据打印
                    case XmlPullParser.END_TAG:{
                        if("app".equals(nodeName)){
                            Log.d("MainActivity","id is "+id);
                            Log.d("MainActivity","name is "+name);
                            Log.d("MainActivity","version is "+version);
                        }
                        break;
                    }
                    default:
                        break;
                }
                eventType=xmlPullParser.next();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

注意:我们需要在AndroidManifest.xml的<application>标签中加入以下一行代码,不然程序会出现问题

android:usesCleartextTraffic="true"

接着启动程序点击按钮解析出来的数据就打印出来了。

解析JSON数据

接下来学习如何解析JSON格式的数据,首先说一下JSON相比XML的优势——JSON的体积更小,在网络传输的时候可以更省流量。但同时它的缺点是语义性较差,不如XML看起来直观

在解析之前,我们和前面一样,新建一个get_data.json文件,接下来访问localhost:9000/AndroidStudy/get_data.json,如下所示:

在这里插入图片描述

使用JSONObject

  • 和上面一样,构造url时传入自己数据源的url
.url("http://192.168.??.???:9000/AndroidStudy/get_data.json")
  • 接着实现一个parseJSONWithJSONObject()方法对返回的数据进行解析
	//使用JSONObject解析JSON格式的数据
    private void parseJSONWithJSONObject(String jsonData){
        try {
            JSONArray jsonArray=new JSONArray(jsonData);
            for(int i=0;i<jsonArray.length();i++){
                JSONObject jsonObject=jsonArray.getJSONObject(i);
                String id=jsonObject.getString("id");
                String version=jsonObject.getString("version");
                String name=jsonObject.getString("name");
                Log.d("MainActivity","id is "+id);
                Log.d("MainActivity","name is "+name);
                Log.d("MainActivity","version is "+version);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

我们前面定义的是一个JSON数组,所以这里我们先将服务器返回的数据传到一个JSONArray对象中,接着遍历JSONArray对象,这里我们使用JSONObject来接收遍历出来的元素,接着取出id、name、version这些数据。

接着启动程序点击按钮解析出来的数据就打印出来了。

使用GSON

可以看到上面使用JSONObject解析JSON数据已经非常方便了,但其实还有更加方便的,那就是Google提供的GSON开源库。

GSON的方便之处在于,它可以将一段JSON格式的数据自动映射成一个对象,例如有一段JSON格式数据如下所示:

{"name":"Tom","age":"20"}

我们就可以先定义一个Person类,并加入name和age属性,接下来只需要使用下面代码即可将JSON数据解析成一个Person对象:

Gson gson=new Gson();
Person person=gson.formJson(jsonData,Person.class);

如果是解析一个JSON数组的话,我们就要借助TypeToken将期望解析成的数据类型传入formJson()方法中:

List<Person> people=gson.formJson(jsonData,new TypeToken<List<Person>>(){}.getType());

下面我们来使用GSON解析JSON数据。

  • 添加依赖
implementation ("com.google.code.gson:gson:2.9.0")
  • 新建App类,添加id、name、version这三个属性
public class App {
    private String id;
    private String name;
    private String version;
    
    public String getId() {return id;}
    public void setId(String id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getVersion() {return version;}
    public void setVersion(String version) {this.version = version;}
}
  • 实现一个parseJSONWithGSON()方法对JSON数据进行解析
	//使用GSON解析JSON数据
    private void parseJSONWithGSON(String jsonData){
        Gson gson=new Gson();
        List<App> appList=gson.fromJson(jsonData,new TypeToken<List<App>>(){}.getType());
        for (App app : appList) {
            Log.d("MainActivity","id is "+app.getId());
            Log.d("MainActivity","name is "+app.getName());
            Log.d("MainActivity","version is "+app.getVersion());
        }
    }

在这我们先new出一个Gson实例,接着调用formJson方法并将服务器返回的数据和我们期望解析成的数据格式传入,获得一个App集合,最后只需遍历集合获取数据打印即可。

Retrofit

Retrofit是在OkHttp的基础上进一步开发出来的应用层网络通信库,OkHttp注重的是底层通信的实现,而Retrofit注重的是上层接口的封装,Retrofit允许我们用更加面向对象的思维进行网络操作。

设计思想

  • 首先,Retrofit允许我们先配置好一个根路径,在指定服务器接口地址时只需要使用相对路径即可,这样我们就不用每次去指定完整的URL地址了。
  • 其次,Retrofit允许我们对服务器接口进行归类,将功能同属一类的服务器接口定义在同一个接口文件中,这样我们的代码结构会更加合理。
  • 最后,我们完全不用关心网络通信的细节,只需在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当我们的程序调用该方法时,Retrofit会自动向对应的服务器发起请求,并将响应的数据解析成返回值声明的类型。

这些设计思想就使得我们可以用更加面向对象的思维来进行网络操作了。

案例

重新新建一个项目RetrofitTest。

在这我们仍继续使用上面的get_data.json数据

  • 添加依赖
implementation ("com.squareup.retrofit2:retrofit:2.6.1")
implementation ("com.squareup.retrofit2:converter-gson:2.6.1")

第一条依赖会将Retrofit、OkHttp、Okio这几个库一起下载,第二条依赖会将GSON库下载下来,所以Retrofit会将返回的JSON数据自动解析成对象。

  • 新建App类
public class App {
    private String id;
    private String name;
    private String version;
    
    public String getId() {return id;}
    public void setId(String id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getVersion() {return version;}
    public void setVersion(String version) {this.version = version;}
}
  • 创建接口文件并在其内部定义具体的服务器接口方法。我们可以根据功能的不同对接口服务进行分类,例如在一个教务系统中,对老师的操作我们可以定义一个TeacherService,对学生的操作我们可以定义一个StudentService。
public interface AppService {

    @GET("get_data.json")
    public Call<List<App>> getAppData();

}

在这我们就定义了一个getAppData()方法,返回值类型是Call类型,@GET注解表示发送的是一条GET请求,后面接的是具体路径。这里返回值类型我们需要注意一下,返回值类型我们必须声明成Retrofit内置的Call类型,然后通过泛型指定服务器返回的数据转要换成什么类型,这里我们转换成List<App>。

  • 在布局中添加一个按钮用于发送请求
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/getAppDataBtn"
        android:text="Get App Data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>
  • 点击按钮发送请求并将返回的JSON数据解析出来打印到控制台
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button getData=(Button) findViewById(R.id.getAppDataBtn);
        getData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Retrofit retrofit= new Retrofit.Builder()
                    	//配置根路径->你自己主机的IP
                        .baseUrl("http://192.168.??.???:9000/AndroidStudy/")
                    	//指定解析数据时使用的转换库
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
                //创建出AppService接口的动态代理对象,接下来就可以随意调用该接口中的方法了
                AppService appService=retrofit.create(AppService.class);
                //调用getAppData方法之后会返回一个Call<List<App>>对象,接着调用enqueue()方法,Retrofit就会根据注解中配置的服务器接口地址去进行网络请求,服务器响应的数据也会回调到enqueue()方法中的Callback实现里
                appService.getAppData().enqueue(new Callback<List<App>>() {
                    @Override
                    public void onResponse(Call<List<App>> call, Response<List<App>> response) {
                        //调用response.body()后我们会得到Retrofit解析后的对象
                        List<App> appList = response.body();
                        if(appList!=null){
                            for (App app : appList) {
                                Log.d("MainActivity","id is "+app.getId());
                                Log.d("MainActivity","name is "+app.getName());
                                Log.d("MainActivity","version is "+app.getVersion());
                            }
                        }
                    }
                    @Override
                    public void onFailure(Call<List<App>> call, Throwable t) {
                        t.printStackTrace();
                    }
                });
            }
        });
    }
}

注意:我们在构建Retrofit对象时上面两个方法是必须调用的。发起请求时,Retrofit会自动在内部开启子线程,当数据回调到Callback中之后又会自动切回主线程,整个过程我们都不需要考虑线程切换问题。

  • 最后需要注意的是我们要在AndroidManifest.xml文件中需要加入网络权限以及在<application>标签中加入以下配置
<!--    网络权限-->
<uses-permission android:name="android.permission.INTERNET"/>

<application>
...
android:networkSecurityConfig="@xml/network_config"
</application>

在res->xml文件下创建network_config,内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

最后我们点击按钮发送网络请求返回的JSON数据就会被解析并将我们想要的数据打印在控制台了。

处理复杂的接口地址类型

  • 上面我们的接口地址是静态的,但在很多场景下接口地址是动态变化的,如以下接口地址:
GET http://example.com/<page>/get_data.json

上面的<page>表示页数,我们传入不同的页数,显示的内容也是不一样的,服务器返回的数据也是不同的,像这种动态接口地址在Retrofit中应该怎么写呢(实体类为Data,创建了一个DataService接口):

public interface DataService{
    
    @GET("{page}/get_data.json")
    public Call<Data> getData(@Path("page") int page);
        
}

在接口地址中,我们使用{page}来表示一个占位符,在getData()方法中添加了一个page参数,并使用@Path(“page”)注解来声明这个参数,这样当发送请求时,Retrofit会将page参数自动替换掉{page},这样不就实现了动态参数。

  • 另外很多服务器的接口要求我们传入多个参数,如以下接口地址:
GET http://examlpe.com/get_data.json?u=<user>&t=<token>

带参数的GET请求格式如上,使用?来连接参数部分,每个参数都是使用=连接的键值对,多个参数之间使用&分隔,上面的示例就表示我们要传入user和token这两个参数,对于这种接口地址,我们可以使用@Path注解来解决,如下:

public interface DataService{
    
    @GET("get_data.json?u={user}&t={token}")
    public Call<Data> getData(@Path("user") String user,@Path("token") String token);
        
}

也可以使用Retrofit针对这类GET请求提供的语法支持:

public interface DataService{
    
    @GET("get_data.json")
    public Call<Data> getData(@Query("u") String user,@Query("t") String token);
        
}

这两种方式都可以将接口地址中的<user>和<token>用user和token替换。

其他注解

  • @POST:提交数据
  • @PUT、@PATCH:修改数据
  • @DELETE:删除数据
DELETE http://example.com/data/<id>

上述接口地址表示要根据id删除一条数据,要想发出这样的请求我们可以写成下面这样

public interface DataService{
    
    @DELETE("data/{id}")
    public Call<ResponseBody> deleteData(@Path("id") String id);
        
}

可以看到上面我们将Call的泛型指定为ResponseBody,这是因为@POST、@PUT、@PATCH、@DELETE注解与@GET注解不同,它们时操作服务器上的数据而不是获取数据,所以它们对服务器响应的数据并不关心。使用ResponseBody表示Retrofit能接收任何类型的响应数据,并且不会对响应数据进行解析。

提交数据

向服务器提交数据,如以下接口地址

POST http://example.com/data/create

使用POST来提交数据,需要我们将数据放到HTTP请求的body部分,Retrofit给我们提供了一个@Body注解来完成

public interface DataService{
    
    @POST("data/create")
    public Call<ResponseBody> postData(@Body Data data);//Data是你自己定义的要提交的数据
        
}

这样当发送一个POST请求时,Retrofit会将Data对象中的数据转换成JSON格式的数据并放到HTTP请求的body部分。

关于Android网络技术的使用的分享到此结束,希望对您有帮助!

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

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

相关文章

HarmonyOS开发案例:【rating组件】

介绍 将引导开发者使用rating组件实现星级打分功能。 相关概念 [rating组件]&#xff1a;评分条&#xff0c;可根据用户判断进行打分。 环境搭建 软件要求 [DevEco Studio]版本&#xff1a;DevEco Studio 3.1 Release及以上版本。OpenHarmony SDK版本&#xff1a;API vers…

预见预判|AIRIOT智慧交通管理解决方案

随着机动车保有量的逐步增加&#xff0c;城市交通压力日益增大。同时&#xff0c;新能源车辆的快速发展虽然带来了环保效益&#xff0c;但也因不限号政策而进一步加剧了道路拥堵问题。此外&#xff0c;各类赛事和重大活动的交通管制措施也时常导致交通状况复杂多变。面对这些挑…

Linux--MyMiniTry--Vim

首先下载好vim,我们可以按以下的方式进行光标的移动&#xff08;也可以回车进行换行&#xff09; &#xff08;--> 进入教程&#xff09; &#xff08;初始的时候没有文本&#xff0c;你怎么按都没有用&#xff09; &#xff08;我们要先按 i &#xff0c;进行插入文本才…

maven修改默认编码格式为UTF-8

执行mvn -version查看maven版本信息发现&#xff0c;maven使用的编码格式为GBK。 为什么想到要修改编码格式呢&#xff1f;因为idea中我将文件格式统一设置为UTF-8&#xff08;如果不知道如何修改文件编码&#xff0c;可以参考文末&#xff09;&#xff0c;然后使用maven打包时…

[GXYCTF 2019]BabyUpload

过滤 <? 且后缀不能有 php 上传1.jpg文件&#xff0c;内容为&#xff1a; <script languagephp>eval($_POST[cmd]);</script> 但文件后缀为.jpg&#xff0c;蚁剑不能连接。那怎么办呢&#xff1f; .htaccess文件&#xff1a;解析.jpg文件中的php代码 &#xf…

LLaMA-Factory参数的解答(命令,单卡,预训练)

前面这个写过&#xff0c;但觉得写的不是很好&#xff0c;这次是参考命令运行脚本&#xff0c;讲解各个参数含义。后续尽可能会更新&#xff0c;可以关注一下专栏&#xff01;&#xff01; *这是个人写的参数解读&#xff0c;我并非该领域的人如果那个大佬看到有参数解读不对或…

vue echarts折线图 折线堆积图和折线面积图

vue echarts折线图 折线堆积图和折线面积图 1、折线堆积图和折线面积图的结合&#xff1b; 上代码 <template><section><divid"performaceLineChart"ref"performaceLineChartRef"style"width: 100%; height: 500px"></d…

Spark-机器学习(5)分类学习之朴素贝叶斯算法

在之前的文章中&#xff0c;我们学习了回归中的逻辑回归&#xff0c;并带来简单案例&#xff0c;学习用法&#xff0c;并带来了简单案例。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵…

k8s-身份认证与权限

认证概述 Kubernetes作为一个分布式集群的管理工具&#xff0c;保证集群的安全性是其一个重要的任务。所谓的安全性其实就是保证对Kubernetes的各种客户端进行认证和鉴权操作。 在Kubernetes集群中&#xff0c;客户端通常有两类&#xff1a; User Account&#xff1a;一般是独…

原型链prototype、__proto、constructor的那些问题整理

再了解原型链之前,我们先来看看构造函数和实例对象的打印结构 - 函数 这里我们定义一个构造函数Fn,然后打印它的结构吧 function Fn(){} console.dir(Fn)控制台得到结构 从上面结构我们能看的出来,函数有两种原型,一种是作为函数特有的原型:prototype,另一种是作为对象的__…

记录wordpress网站搭建及当天被SEO优化收录

网站是前不就前搭建的&#xff0c;但是一直没有做SEO优化&#xff0c;今天花了点时间做下优化。记录下&#xff0c;喜欢的朋友点赞收藏下。 1.wordpress后台下载插件Yoast SEO插件&#xff0c;setting中搜索XML sitemaps&#xff0c;点view the XML sitemap&#xff0c;暂时不…

传媒论坛编辑部传媒论坛杂志社传媒论坛杂志2024年第7期目录

专题│场景传播研究 场景传播&#xff1a;一场遮盖自我与寻找自我的博弈 胡沈明; 3 基于CiteSpace的中国场景传播研究热点分析 管倩;粟银慧; 4-610《传媒论坛》投稿&#xff1a;cnqikantg126.com 数字世界的美与危&#xff1a;场景传播的失范与应对之举 王依晗;章洁…

srpingMVC基本使用

文章目录 1. springMVC基本功能(1) maven坐标导入(2) 编写表现层(3) springMVC配置类编写(4) 部署tomcat访问 2. 各种请求方法get请求post请求put请求delete请求请求参数提取 3. 请求参数接收(1) param参数接受封装到对象中 (2) 路劲参数接收集合接受时间类型接收json参数接收m…

鸿蒙OpenHarmony【轻量系统 编写“Hello World”程序】 (基于Hi3861开发板)

编写“Hello World”程序 下方将通过修改源码的方式展示如何编写简单程序&#xff0c;输出“Hello world”。请在下载的源码目录中进行下述操作。 确定目录结构。 开发者编写业务时&#xff0c;务必先在./applications/sample/wifi-iot/app路径下新建一个目录&#xff08;或一…

Electron中使用Prisma(以SQLite为例)

1、安装 Prisma 打开终端&#xff0c;执行以下命令安装 Prisma CLI&#xff1a; npm install prisma -g 2、初始化 Prisma 项目 在工作目录中执行以下命令来初始化一个新的 Prisma 项目&#xff1a; prisma init 这将创建一个新的文件夹&#xff0c;包含了必要的文件和目…

proteus+stm32+CubeMX+dht11+lcd1602

浅浅记录下过程遇到的问题&#x1f921;&#x1f921;&#x1f921; 1 供电网配置错误&#xff08;加上就好了 新起个名也会出这个 / 电源不起名 不创建估计项目也会&#xff09;没zet6的 proteus 里 固件库 账号注册半天没成 就用的stm32F103R6的然后发现单片机不输出高低电平…

ElasticSearch 安装(docker)

下载安装包 阿里云链接&#xff1a; elasticSearch.exe https://www.alipan.com/s/3A356NnmWaJ 提取码: 93da 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 安装步骤 1、首先…

RabbitMQ发布确认和消息回退(6)

概念 发布确认原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker就会发送一个确认给生产者(包含消…

2024精武杯复现

第一部分&#xff1a;计算机和手机取证 1. 请综合分析计算机和手机检材&#xff0c;计算机最近一次登录的账户名是 用火眼分析后在登录信息查找最后登录的人&#xff0c;用户名是admin 2. 请综合分析计算机和手机检材&#xff0c;计算机最近一次插入的USB存储设备串号是 在u…

AIX7环境上一次艰难的Oracle打补丁经历

系统环境 AIX &#xff1a;7200-05-03-2148 Oracle&#xff1a;11.2.0.4 PSU: 11.2.0.4.201020&#xff08;31718723&#xff09; perl:5.28 问题一&#xff1a;AUTO patch #/u01/app/11.2.0/grid/OPatch/opatch auto /tmp/31718723 错误信息如下&#xff1a;匹配mos 2516761.1…