• 基于安卓的电力设备智能巡检APP设计


    目录
    摘 要 3
    Abstract 4
    第一章 绪论 7
    1.1 选题的背景 7
    1.1.1 电力设备巡检系统 7
    1.1.2 Android背景 7
    1.2 选题的意义 7
    1.3 论文主要结构 8
    第二章 系统分析 10
    2.1 需求分析 10
    2.2 功能分析 11
    2.3 可行性分析 11
    第三章 开发平台与技术介绍 13
    3.1 Android系统架构 13
    3.2 Android程序结构 14
    3.3 Android生命周期 15
    3.4 Android GPS定位模块 16
    3.5 电力设备命名及二维码模块 16
    3.6 Apache+MySQL+PHP 17
    第四章 系统设计 18
    4.1 功能设计 18
    4.2 系统数据库设计 20
    第五章 巡检系统的功能实现 28
    5.1 主界面 28
    5.2 个人信息 28
    5.3 巡检任务 29
    5.4 论坛交流 33
    5.5 突发情况 34
    5.6 巡检指导 36
    5.7 用户登录 37
    5.8 用户注销 38
    5.9 关于 38
    第六章 系统测试 39
    6.1 数据测试 39
    6.2 压力测试 39
    6.3 综合测试 39
    第七章 总结与展望 40
    7.1 总结 40
    7.2 展望 40
    感谢 41
    参考文献 42
    第二章 系统分析
    在对系统进行编码实现前,首先需要对巡检系统进行需求分析、功能设计、可行性分析等步骤,从而确定巡检系统的设计方案。一个好的方案才能设计出一个可行性良好的软件。
    2.1需求分析
    所谓的“需求分析”是指对要解决的问题进行详细的分析,明确用户的实际需求,从而设计出符合要求的系统[[[] 王继成,高珍.软件需求分析的研究[J].计算机工程与设计 , 2002年08期]]。需求分析的结果直接影响系统的功能设计。只有满足用户的实际需求并做出亮点,这个系统才能算是成功。下面通过分析现阶段存在的巡检系统并找出其不足之处,以此来作为本巡检系统的需求分析。
    (1)在传统的电力设备巡检中过程中,存在以下缺陷:
    任务派发步骤繁琐,每次有巡检任务都需要一层一层派发下去,效率低。
    在传统的电力设备巡检过程中,巡检结果采用手工记录、纸张保存,此方式以纸张为载体记录数据,极其不灵活,如果巡检的项目有任何的改变就需要重新印制巡检表格,容易造成极大的浪费。而且纸张容易损坏,对数据的长久保存有极大的挑战。如果需要对巡检表格上的数据进行二次录入,存入数据库,会出现数据录入错误、漏录等情况,导致信息丢失。不能对历史巡检数据进行很好的统计分析,无法对设备进行特定巡检。
    由于电力设备种类繁多,传统的人工巡检会给巡检人员带来很大的作业负担,而且巡检结果不规范,效率不高。
    同时,由于传统的人工巡检方式存在的天然短杆,即巡检人员的主观态度原因,巡检人员可能会在签到后直接离开巡检地点,更有甚者直接伪造巡检数据,而传统巡检又无法有效的考核巡检人员的工作状态,导致人员不到位、巡检不及时等情况时有发生,给电力企业造成难以估量的损失。
    (2)由于传统的电力设备巡检过程存在的缺陷,为了解决这些缺陷,国内也相继出现了一些新型的巡检方式和系统,如基于RFID数据终端的电力设备巡检系统、基于条形码识别技术的电力设备巡检系统[[[] 吴国忠 , 滕俊青 . 设备巡检系统中数据采集软件的开发与应用[J] . 浙江大学学报:工学版.2004(4):429~432]][[[] 丁鹏 . 条形码系统在电力设备巡检中的应用[J] . 企业导报 , 2012年第20期]]。该系统可以有效减少巡检人员的巡检负担,提高巡检人员的工作效率,规范巡检结果。但它存在以下缺陷:
    同传统的巡检方式一样,由于不存在GPS定位装置,这些系统同样无法准确考核巡检人员的工作状态,不能确定是否有本人巡检。
    经济可行性不高,该系统需要采购成套的硬件设施,前期投入成本极高。
    综合以上分析可以得出如下结论,本论文涉及到的基于Android的电力设备智能巡检系统至少需要包含以下功能:巡检任务获取、基于地理位置的巡检签到、设备的唯一识别及巡检、历史巡检数据的统计分析,而且系统要满足成本低、设备简单。接下来,将根据此问提及的功能进行软件的基本功能设计。
    2.2功能分析
    (1)巡检任务获取:本巡检系统通过HTTP协议从服务器端获取巡检任务,数据以JSON格式在服务器和Android终端进行传输。本系统可以很轻松的在服务器上更改指派给每个巡检人员任务,从而使巡检人员能直接获取任务信息,可以有效提高任务分派效率。同时,若后台完善之后,可以结合后台添加巡检任务推送机制,使巡检人员能及时接收到巡检任务。
    (2)基于地理位置的签到:如今的Android手机都自带GPS定位,也就是说通过Android手机定位用户成为可能。本巡检系统中,通过高德地图API来获取巡检人员实际的地理位置,同时系统会绑定手机的IMEI码进行绑定,而IMEI每台手机是唯一的,因此,这就可以很好的杜绝了巡检造假的情况。而且每次签到,系统都会记录签到的时刻,有效避免了巡检的不及时。
    (3)设备的唯一识别及巡检:通过设备所在基站、设备类型等信息,生成设备的唯一二维码,通过扫描二维码就可以唯一确定设备。同时获取该设备相关巡检内容,服务器端可以更改要巡检的细节,那样就可以着重某几个点进行巡检。巡检完毕后,可以将数据提交到后台,如果遇到网络不理想的情况,则可以暂时存储在本地,等网络状况良好时再次提交。
    (4)历史巡检数据的统计分析:由于所有巡检数据都提交到了后台数据库,所以使得巡检人员通过网络获取历史巡检数据成为可能。仍然采用JSON作为数据传输格式,获取历史巡检数据之后,本系统就会以图表形式显示当前设备的历史检修记录,使巡检人员可以着重检查某些关键项。
    (5)成本低、设备简单:本巡检系统是基于当前最大的Android移动平台进行开发,完全利用Android手机自带的硬件就可以完成相应功能,完全不用购买额外设备,仅需一台Android手机即可。如今,Android手机基本人手一台,而且Android手机价格相对低廉,故经济可行性极高。
    (6)巡检系统其它特色功能:相对于现存的一些巡检系统,基于Android开发的巡检系统的优势在此就可以明显显现出来。本文转载自http://www.biyezuopin.vip/onews.asp?id=15011除了以上功能外,还会添加突发状况上报、巡检指导、论坛等功能,这些功能会使巡检系统更加强大、也更加合理,考虑的更充分。
    2.3可行性分析
    (1)技术可行性
    本系统采用Android Studio开发工具,由Java语言开发,其中涉及到的GPS定位、SQLite数据库、网络通信等都是使用手机自带或者使用开放的API接口进行实现,因此,本系统在技术实现上不存在太大难度,可行性极高。
    (2)经济可行性
    本巡检系统只需要一部Android手机就可以使用,以现在Android手机的普及性及廉价性,相对于其它类型的巡检系统,基于Android设备的电力设备智能巡检系统可以说是成本为零,因此经济可行性非常高。
    (3)操作可行性
    就操作来说,用于只需要下载安装就可以使用,上手完全没难度。

    综上所述,基于Android的电力设备智能巡检系统的开发可行性极高,并且非常具有现实实用价值。

    package com.lion.graduation2;
    
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.widget.DrawerLayout;
    import android.support.v7.app.ActionBarActivity;
    import android.support.v7.app.ActionBarDrawerToggle;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.Toolbar;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.lion.graduation2.activity.AboutActivity;
    import com.lion.graduation2.activity.EmergencyActivity;
    import com.lion.graduation2.activity.GuideActivity;
    import com.lion.graduation2.activity.LoginActivity;
    import com.lion.graduation2.activity.SettingActivity;
    import com.lion.graduation2.activity.SupportActivity;
    import com.lion.graduation2.activity.UserActivity;
    import com.lion.graduation2.activity.WebViewActivity;
    import com.lion.graduation2.activity.nav.SimpleGPSNaviActivity;
    import com.lion.graduation2.bean.json.PlaceBean;
    import com.lion.graduation2.bean.json.TaskBean;
    import com.lion.graduation2.bean.json.UserBean;
    import com.lion.graduation2.bean.model.DrawerItemModel;
    import com.lion.graduation2.ui.DividerItemDecoration;
    import com.lion.graduation2.ui.adapter.DrawerRecyclerViewAdapter;
    import com.lion.graduation2.ui.fragment.base.BaseTourFragment;
    import com.lion.graduation2.ui.fragment.ContentFragment;
    import com.lion.graduation2.util.BitmapUtils;
    import com.lion.graduation2.util.Constant;
    import com.lion.graduation2.util.FileUtils;
    import com.lion.graduation2.util.HttpUtils;
    import com.lion.graduation2.util.TTSController;
    import com.lion.graduation2.util.circularImage.CircularImage;
    
    import net.tsz.afinal.FinalDb;
    import net.tsz.afinal.FinalHttp;
    import net.tsz.afinal.http.AjaxCallBack;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class MainActivity extends ActionBarActivity implements BaseTourFragment.OnDispalyHomeListener, BaseTourFragment.OnTitleSet {
    
        private List task;
        private List places;
        //Toolbar,用来代替ActionBar
        private Toolbar toolbar = null;
        //抽屉菜单
        private DrawerLayout mDrawerLayout = null;
        //抽屉菜单,用于点击条目关闭抽屉菜单使用
        private LinearLayout mLeftDrawer = null;
    
        private LinearLayout mNavDrawerHeader = null;
        //抽屉菜单显示用户头像的控件
        private CircularImage mCircularImage = null;
        //抽屉菜单显示用户姓名的控件
        private TextView mUserName = null;
    
        //DrawerLayout.DrawerListener的子类
        private ActionBarDrawerToggle mToggle = null;
        //抽屉菜单条目列表
        private List items = null;
        //主界面显示的Fragement
        private Fragment fragment = null;
    
        //抽屉菜单RecyclerView适配器
        private DrawerRecyclerViewAdapter mRecycleAdapter = null;
        private RecyclerView mRecyclerView;
        private RecyclerView.LayoutManager mLayoutManager;
    
        private List tasks = new ArrayList<>();
        /* final db*/
        private FinalDb db;
        //用户数据
        private UserBean user = null;
        //测试数据
        private int[] icon = {R.drawable.tasks1, R.drawable.forum, R.drawable.warning3, R.drawable.technical, R.drawable.manual, R.drawable.setting, R.drawable.about1};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //获取用户account
            db = FinalDb.create(this, Constant.DB);
            user = db.findAll(UserBean.class).get(0);
            //初始化
            init();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            initCircularImage();
        }
    
        private void init() {
            fragment = new ContentFragment();
            getSupportFragmentManager().beginTransaction().add(R.id.content_frame, fragment).commit();
    
            //初始化抽屉菜单信息
            initDrawerItem();
    
            //初始化ToolBar
            initBar();
    
            //初始化RecyclerAdapter
            initRecyclerAdapter();
    
            //初始化RecyclerView
            initRecyclerView();
    
            initNavDrawer();
            //
            mToggle = new ActionBarDrawerToggle(MainActivity.this, mDrawerLayout, toolbar, R.drawable.wolf, R.drawable.wolf) {
    
                @Override
                public void onDrawerOpened(View drawerView) {
                    super.onDrawerOpened(drawerView);
                }
    
                @Override
                public void onDrawerClosed(View drawerView) {
                    super.onDrawerClosed(drawerView);
                }
            };
    
            mDrawerLayout.setDrawerListener(mToggle);
    
        }
    
        /**
         * 初始化抽屉菜单条目信息
         */
        private void initDrawerItem() {
            String[] text = getResources().getStringArray(R.array.item_text);
            items = new ArrayList<>();
            DrawerItemModel item = null;
            for (int i = 0; i < text.length; i++) {
                item = new DrawerItemModel(icon[i], text[i]);
                items.add(item);
            }
        }
    
        /**
         * 初始化Toolbar
         */
        private void initBar() {
            //style.xml需设置Theme为NoActionBar,否则setSupportActionBar会出错
            toolbar = (Toolbar) findViewById(R.id.tool_bar);
            setSupportActionBar(toolbar);
    
            //给左上角图标的左边加上一个返回的图标
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
    
        private void initRecyclerAdapter() {
            mRecycleAdapter = new DrawerRecyclerViewAdapter(items);
            mRecycleAdapter.setOnItemClickListener(new DrawerRecyclerViewAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {
                    if (position == 0) {//任务界面
                        fragment = new ContentFragment();
                        getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
                    } else if (position == 1) {
                        Intent intent = new Intent(MainActivity.this, WebViewActivity.class);
                        startActivity(intent);
                    } else if (position == 2) {
                        Intent intent = new Intent(MainActivity.this, EmergencyActivity.class);
                        startActivity(intent);
                    } else if (position == 3) {
                        Intent intent = new Intent(MainActivity.this, SupportActivity.class);
                        startActivity(intent);
                    } else if (position == 4) {
                        Intent intent = new Intent(MainActivity.this, GuideActivity.class);
                        startActivity(intent);
                    } else if (position == 5) {
                        Intent intent = new Intent(MainActivity.this, SettingActivity.class);
                        startActivity(intent);
                    } else if (position == 6) {
                        Intent intent = new Intent(MainActivity.this, AboutActivity.class);
                        startActivity(intent);
                    }
    
                    //getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
                    mDrawerLayout.closeDrawer(mLeftDrawer);
                    Log.d(Constant.TAG, "NavDrawer item click.postion:" + position + ".content:" + items.get(position).getText());
                }
            });
            mRecycleAdapter.notifyDataSetChanged();
        }
    
        private void initRecyclerView() {
            mRecyclerView = (RecyclerView) findViewById(R.id.navdrawer_recycler);
    
            // use this setting to improve performance if you know that changes
            // in content do not change the layout size of the RecyclerView
            mRecyclerView.setHasFixedSize(true);
    
            // use a linear layout manager
            mLayoutManager = new LinearLayoutManager(this);
            mRecyclerView.setLayoutManager(mLayoutManager);
    
            //添加分割线
            mRecyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this, DividerItemDecoration.VERTICAL_LIST));
            // specify an adapter (see also next example)
            mRecyclerView.setAdapter(mRecycleAdapter);
        }
    
        private void initNavDrawer() {
            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            //mDrawList = (ListView) findViewById(R.id.left_drawer_list);
            mLeftDrawer = (LinearLayout) findViewById(R.id.navdrawer);
    
            initNavDrawerHeader();
        }
    
        private void initNavDrawerHeader() {
            mNavDrawerHeader = (LinearLayout) mLeftDrawer.findViewById(R.id.navdrawer_header);
    
            mUserName = (TextView) mNavDrawerHeader.findViewById(R.id.navdrawer_user_name);
            mUserName.setText(user.getName());
        }
    
        /**
         * 初始话抽屉菜单显示的圆形用户头像
         */
        private void initCircularImage() {
            final String pic_path = Constant.Path.IMAGE + user.getAccount() + Constant.PIC_SUFFIX;
            //设置抽屉菜单显示圆形头像
            mCircularImage = (CircularImage) mNavDrawerHeader.findViewById(R.id.navdrawer_user_head);
            //如果头像未下载过,则显示问号并进行下载,否则直接显示用户头像
            if (user.getPic_path() == null) {
                downloadPic(pic_path);
            } else {
                try {
                    mCircularImage.setImageDrawable(BitmapUtils.getImage(MainActivity.this, pic_path));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mCircularImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, UserActivity.class);
                    startActivity(intent);
                }
            });
    
    
        }
    
        private void downloadPic(final String pic_path) {
            //判断目录是否存在,不存在则创建一个
            if (!FileUtils.isDirExist(Constant.Path.IMAGE)) {
                FileUtils.makeDir(Constant.Path.IMAGE);
            }
    
            FinalHttp fh = new FinalHttp();
            fh.download(HttpUtils.HttpUrl.DOMAIN_URL + "/img/user/116040384.jpg", pic_path, false, new AjaxCallBack() {
                @Override
                public void onSuccess(File file) {
                    super.onSuccess(file);
                    Log.e("afinal", "下载成功");
                    try {
                        user.setPic_path(pic_path);
                        mCircularImage.setImageDrawable(BitmapUtils.getImage(MainActivity.this, pic_path));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void onLoading(long count, long current) {
                    super.onLoading(count, current);
                }
    
                @Override
                public void onFailure(Throwable t, String strMsg) {
                    super.onFailure(t, strMsg);
                    Log.e("afinal", "下载失败:" + strMsg);
                }
            });
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
    
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_login_out) {
                login_out();
                return true;
            } else if (id == R.id.rich_scan) {
                Intent gpsNaviIntent = new Intent(MainActivity.this, SimpleGPSNaviActivity.class);
                gpsNaviIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(gpsNaviIntent);
            }
    
            return super.onOptionsItemSelected(item);
        }
    
        private void login_out() {
            new AlertDialog.Builder(this).setTitle("注销").setNegativeButton("是", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    db.delete(user);
                    Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                    startActivity(intent);
                    finish();
                }
            }).setPositiveButton("否", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            }).show();
        }
    
        @Override
        public void showDisplayHome(boolean showDrawerToggle) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(showDrawerToggle);
        }
    
        @Override
        public void setTitle(String title) {
            getSupportActionBar().setTitle(title);
        }
    
        @Override
        public void restoreTitle() {
        }
    
        public List getTasks() {
            return tasks;
        }
    
        public void setTasks(List tasks) {
            this.tasks = tasks;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    「笔试刷题」:腐烂的苹果
    docker部署gitlab内存占用过大的解决
    MyBatis的逆向工程
    数据分析工具Polars实现CSV读写、排序、应用函数、lazy API
    div 2 896 d1
    网页在线打开PDF_网站中在线查看PDF之pdf.js
    Leetcode 451. Sort Characters By Frequency (用堆)
    开发 Chrome 扩展 之 Hello World 心血来潮
    JavaScript01(JavaScript入门语法)
    C/S架构学习之组播
  • 原文地址:https://blog.csdn.net/sheziqiong/article/details/126914840