[teach you how to learn it] PRTG monitoring system cooperates with raspberry pie to collect internal wireless network quality

osc_ yea0up70 2020-11-12 13:50:39
teach learn prtg monitoring cooperates


@TOC

This paper introduces a kind of , How to collect internal wireless network quality through raspberry pie , Turn raspberry pie into wireless probes , And in PRTG The method of display on the network monitoring platform .

It can monitor the indicators of the wireless network that we are interested in , Include

Wireless packet loss
ping The test is the biggest 、 Minimum , Average , shake
Equipment temperature
Wireless channel
Wireless negotiation rate
Wireless connection quality
RF signal power





This is through the monitoring mechanism , Enterprise network managers can intuitively obtain the wireless quality of the area where the wireless probe is located . Timely detection such as wireless channel frequency hopping , Delay increases , Packet loss , Signal attenuation and other events .
 Insert picture description here
 Insert picture description here

Realization principle

Raspberry pie runs based on Debian Of Linux System . adopt iwconfig,ping,ifconfig,iproute etc. linux Common commands get the current network connection of the device , And pass Python After formatting the data , convert to PRTG The system can recognize XML Format data file .

Deployment method

One 、 Raspberry pie wireless network connection

The most common raspberry pies are Raspberry Pi 4,3+,3 Three major popular versions . The specific wireless support is as follows :
model
Supported wireless bands
Raspberry Pi 4B 5Ghz+2.4GHz
Raspberry Pi 3B+ 5Ghz+2.4GHz
Raspberry Pi 3B Only 2.4GHz

because 4B The various versions of have just been released , Mass deployment is not cost effective .3B Version not supported 5G.
In that case , Use 3B+ edition +POE The module is just right .
Pie raspberry is easy to connect to the wireless network , edit

/etc/wpa_supplicant/wpa_supplicant.conf 

The file records raspberry pie WIFI Related configuration of

network={
ssid=" Wireless network name "
psk=" Wifi password "
key_mgmt=WPA-PSK
}

Restart the network service after configuration

service networking restart

Because our goal is this raspberry pie, no matter where it's stuck in the net , It even reports the collected data directly through the wireless connection without connecting the cable , So it needs to be enabled at the same time eth and wlan so , And configure the priority of the default route ,eth The default route has higher priority . Edit the file

cat /etc/network/interfaces
auto eth0
iface eth0 inet dhcp
metric 10
#eth0 Of metric by 10 , If there is eth0 The default route for the next hop , This default route is preferred .
allow-hotplug wlan0
auto wlan0
iface wlan0 inet dhcp 
metric 100
#wlan Of metric Hop number configuration ratio eth0 high 
pre-up wpa_supplicant -B w -D wext -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf 
post-down killall -q wpa_supplicant
# relation WPA_Supplicat file 

When the configuration is complete , Restart network service , Restart the wireless card interface . If it's too troublesome, you can restart the device directly .

service networking restart
ifdown wlan0
ifup eth0

Under normal networking conditions , Let's check the routing table and network card address of the device , Make sure it's normal .
 Insert picture description here
 Insert picture description here

Two 、 To write shell Script

#!/bin/bash
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
cd /home/pi
if [ -f checkresult.txt ]; then
#echo "remove old checkresult.txt file ... "
rm -f checkresult.txt
fi
if [ -f $HOSTNAME-WIFI_Check_result.txt ]; then
#echo "$HOSTNAME-WIFI_Check_result.txt file ... "
rm -f $HOSTNAME-WIFI_Check_result.txt
fi
if [ -f IP-WIFI-Check-$HOSTNAME.txt ]; then
#echo IP-WIFI-Check-$HOSTNAME.txt file ... "
rm -f IP-WIFI-Check-$HOSTNAME.txt
fi
# Delete possible history files 
wlangwip=$(route | grep wlan0 | grep default)
wlangwip=${wlangwip##*default}
wlangwip=${wlangwip%%0.0.0.0*}
# This meal operation , It's to get the gateway of the current wireless network IP Address 
# We try our best to ensure that the script is universal , Therefore, it is necessary to obtain the gateway of current wireless network automatically IP
# route | grep wlan0 | grep default like this:
#default 10.0.192.1 0.0.0.0 UG 100 0 0 wlan0
# ↑ Just to get this field 
#-------------------------------------------------------------------
ping -c 200 -i 0.1 $wlangwip >> checkresult.txt
#100ms The interval is fast ping gateway IP, Result write checkresult.txt file 
iwconfig wlan0 >> checkresult.txt
#iwconfig The command is the state of the wireless card , Write state to checkresult.txt file 
#-------------------------------------------------------------------
echo '<device_temp>' >> checkresult.txt
cat /sys/class/thermal/thermal_zone0/temp >> checkresult.txt
echo '</device_temp>' >> checkresult.txt
# Write the current temperature of raspberry pie into checkresult.txt file 
#-------------------------------------------------------------------
echo '<device_eth0ip>' >> checkresult.txt
ifconfig eth0 | grep "inet " | awk '{print $2}' >> checkresult.txt
echo '</device_eth0ip>' >> checkresult.txt
#-------------------------------------------------------------------
echo '<device_wlanip>' >> checkresult.txt
ifconfig wlan0 | grep "inet " | awk '{print $2}' >> checkresult.txt
echo '</device_wlanip>' >> checkresult.txt
# Connect the cable network card , The wireless network card currently obtains IP Address write checkresult.txt file 
NIC=$(route -n | grep UG | awk '{print $8}'| awk 'NR==1')
ifconfig $NIC | grep "inet " | awk '{print $2}' >> IP-WIFI-Check-$HOSTNAME.txt
# These two sentences are explained in detail 
# The first sentence , Get the record of the first row of the current device default routing table , And extract the network card device name 
# The second sentence , Get the current IP Address 
# This address is the current primary address that raspberry pie communicates with the server . Wireless only connection is wlan0 IP Address , At the same time, it is connected with wired wireless eth0 IP Address 
# This address , After that, you can use it when you distribute the script centrally 
#-------------------------------------------------------------------
python checknetwork.py checkresult.txt $HOSTNAME-WIFI_Check_result.txt $HOSTNAME
# adopt Python, format checkresult.txt The content of , And output a HOSTNAME Named XML file 
#-------------------------------------------------------------------
tftp 10.0.20.178 << !
put $HOSTNAME-WIFI_Check_result.txt
put IP-WIFI-Check-$HOSTNAME.txt
quit
!
tftp 10.0.20.20 << !
put IP-WIFI-Check-$HOSTNAME.txt
quit
!
# adopt TFTP Upload the previously generated file , Directly to PRTG The server is the most convenient , You can also choose to use scp,FTP Or in some other way , Optional .
#-------------------------------------------------------------------
rm -f checkresult.txt
rm -f $HOSTNAME-WIFI_Check_result.txt
rm -f IP-WIFI-Check-$HOSTNAME.txt
Delete a bunch of temporary files just generated
#-------------------------------------------------------------------

I have annotated the function of each line of code , That's sweet enough ,0 The basics guarantee that you can understand .
Let's take a look now checkresult.txt file , This basically contains all the data we care about . next step , We go through Python Simple processing of these data .
 Insert picture description here

3、 ... and 、 To write Python

encoding=utf-8
import re
import os
import sys
import datetime
#-------------------------------------------------------------------
# Define a function to read a file , Before reading shell Script generated checkresult file 
def read_file_as_str(file_path):
# Determine that the path file exists 
if not os.path.isfile(file_path):
raise TypeError(file_path + " does not exist")
all_the_text = open(file_path).read()
# print type(all_the_text)
return all_the_text
#-------------------------------------------------------------------
# Define a keyword search function with fixed length before and after keywords 
def find_str_as_keyword(str_all,keyword,start,end):
start=int(start)
end=int(end)
len_start=str_all.find(keyword)+start
len_end=str_all.find(keyword)+end
#print len_start
#print len_end
echo_str=str_all[len_start:len_end]
return echo_str
#-------------------------------------------------------------------
# Define a function to find the content between two keywords 
def between_str_as_keyword(str_all,keyword1,keyword2,keyword1_start=0,keyword2_end=0):
keyword1_start=int(keyword1_start)
keyword2_end=int(keyword2_end)
len_start=str_all.find(keyword1)+keyword1_start
len_end=str_all.find(keyword2)+keyword2_end
#print len_start
#print len_end
echo_str=str_all[len_start:len_end]
return echo_str
#-------------------------------------------------------------------
def main(input_file_path,output_file_path,hostname):
checkresult=read_file_as_str(input_file_path)
# Be careful :
# The search results =find_str_as_keyword( String to search , keyword , Starting length of search results , Search end length )
# Search for keyword Promise not to repeat , Search for as long keywords as possible 
# Start and end length from keyword The first string starts with , And contains keyword Its length 
#packetloss=find_str_as_keyword(checkresult,"packet loss",-3,11)
packetloss=between_str_as_keyword(checkresult,"received,","% packet loss",10)
# Note that the packet loss rate length will change - Use between Function search interval 
minavgmaxmdev=between_str_as_keyword(checkresult,"min/avg/max/mdev","wlan0",19,-1)
PingMin=minavgmaxmdev[0:minavgmaxmdev.find("/")]
minavgmaxmdev=minavgmaxmdev[minavgmaxmdev.find("/")+1:]
PingAvg=minavgmaxmdev[0:minavgmaxmdev.find("/")]
minavgmaxmdev=minavgmaxmdev[minavgmaxmdev.find("/")+1:]
PingMax=minavgmaxmdev[0:minavgmaxmdev.find("/")]
minavgmaxmdev=minavgmaxmdev[minavgmaxmdev.find("/")+1:]
PingMdev=minavgmaxmdev[0:minavgmaxmdev.find(" ms")]
# The jitter value string is intercepted many times / And / Content between , The format of the original text is similar to :2.103/9.325/29.067/8.392 ms
totaltime=between_str_as_keyword(checkresult,"loss, time","rtt min/",11,-3)
# Note that the total time string length changes - Use between Function search interval 
AccessPoint=find_str_as_keyword(checkresult,"Access Point:",14,31)
Frequency=between_str_as_keyword(checkresult,"Frequency:"," GHz",10)
# Note that the length of the channel selection string changes - Use between Function search interval 
BitRate=between_str_as_keyword(checkresult,"Bit Rate="," Mb/s Tx-Power",9)
# Note that the connection rate length changes 
LinkQuality=between_str_as_keyword(checkresult,"Link Quality=","/70 Signal level",13)
# Pay attention to the connection quality length -- Probably -- Will change 
Signallevel=between_str_as_keyword(checkresult,"Signal level=","Rx invalid",13,-17)
WlanGWIP=between_str_as_keyword(checkresult,"--- "," ping statistics ---",4)
DeviceTemp=between_str_as_keyword(checkresult,"<device_temp>","</device_temp>",14,-1)
DeviceTemp=float(DeviceTemp)/1000
Eth0_IP=between_str_as_keyword(checkresult,"<device_eth0ip>","</device_eth0ip>",16,-1)
WLAN_IP=between_str_as_keyword(checkresult,"<device_wlanip>","</device_wlanip>",16,-1)
write_file_as_path(output_file_path,packetloss,PingMin,PingAvg,PingMax,PingMdev,totaltime,AccessPoint,Frequency,BitRate,LinkQuality,Signallevel,hostname,WlanGWIP,DeviceTemp,Eth0_IP,WLAN_IP)
if __name__ == '__main__':
main(sys.argv[1],sys.argv[2],sys.argv[3])

Here is XML Document generated code , Have a look first , After that, we will explain in detail PRTG Of XML File fields then

#-------------------------------------------------------------------
# The next big paragraph is generating xml Functions of files
def write_file_as_path(file_path,write_packetloss,write_PingMin,write_PingAvg,write_PingMax,write_PingMdev,write_totaltime,write_AccessPoint,write_Frequency,write_BitRate,write_LinkQuality,write_Signallevel,write_hostname,write_WlanGWIP,write_DeviceTemp,write_Eth0_IP,write_WLAN_IP):
f=open(file_path,'w')
#with open(file_path,'w',encoding='gbk') as f:
f.write('<?xml version="1.0" encoding="Windows-1252" ?>\n')
f.write('<prtg>\n')
f.write(' <result>\n')
f.write(' <channel>Packet loss</channel>\n')
f.write(' <unit>Percent</unit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <LimitMaxError>20</LimitMaxError>\n')
f.write(' <LimitMaxWarning>10</LimitMaxWarning>\n')
f.write(' <value>'+write_packetloss+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Ping Min Time</channel>\n')
f.write(' <CustomUnit>ms</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <value>'+write_PingMin+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Ping Max Time</channel>\n')
f.write(' <CustomUnit>ms</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <LimitMaxError>500</LimitMaxError>\n')
f.write(' <LimitMaxWarning>200</LimitMaxWarning>\n')
f.write(' <value>'+write_PingMax+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Ping Avg Time</channel>\n')
f.write(' <CustomUnit>ms</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <LimitMaxError>100</LimitMaxError>\n')
f.write(' <LimitMaxWarning>50</LimitMaxWarning>\n')
f.write(' <value>'+write_PingAvg+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Ping Mean Deviation Time</channel>\n')
f.write(' <CustomUnit>ms</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <value>'+write_PingMdev+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Ping Total Time</channel>\n')
f.write(' <CustomUnit>ms</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <value>'+write_totaltime+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Radio Frequency</channel>\n')
f.write(' <CustomUnit>GHz</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <value>'+write_Frequency+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Radio BitRate</channel>\n')
f.write(' <CustomUnit>Mb/s</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <LimitMinError>50</LimitMinError>\n')
f.write(' <LimitMinWarning>70</LimitMinWarning>\n')
f.write(' <value>'+write_BitRate+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Radio LinkQuality</channel>\n')
f.write(' <CustomUnit>/70</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <value>'+write_LinkQuality+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Radio Signallevel</channel>\n')
f.write(' <CustomUnit>dBm</CustomUnit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <value>'+write_Signallevel+'</value>\n')
f.write(' </result>\n')
f.write(' <result>\n')
f.write(' <channel>Probe Temperature</channel>\n')
f.write(' <Unit>Temperature</Unit>\n')
f.write(' <mode>Absolute</mode>\n')
f.write(' <float>1</float>\n')
f.write(' <LimitMaxError>60</LimitMaxError>\n')
f.write(' <LimitMaxWarning>55</LimitMaxWarning>\n')
f.write(' <value>'+str(write_DeviceTemp)+'</value>\n')
f.write(' </result>\n')
f.write(' <text>Updatetime:'+datetime.datetime.now().strftime('%H:%M:%S')+' Eth0_IP:'+write_Eth0_IP+' Wlan_IP:'+write_WLAN_IP+' WLAN Gateway IP:'+write_WlanGWIP+' AccessPoint:'+write_AccessPoint+'</text>\n')
f.write('</prtg>\n')
f.close()

Four 、PRTG The system configuration

stay PRTG The following script is written in the operating system where the probe is located .
Because of the raspberries XML They're all named files : Host name -WIFI_Check_result.txt
So our BAT The script can be passed through %1 Input parameters to print the report information of the corresponding host name device

@echo off
chcp 65001
type "C:\00-tftp\%1-WIFI_Check_result.txt"

Save to

C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML

then , stay PRTG Inside the system , Add sensors , Search for “EXE”, choice “ senior EXE/ Script ”
![ Insert picture description here ](https://img-blog.csdnimg.cn/20200308212054936.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3l0bHpxMDIyOA==,size_16,color_FFFFFF,t_70 =600x)
EXE/ The script selects the saved bat file
Parameter fill in the host name of raspberry pie , In this way, the local script will bring in the parameters , You will get the report information of your designated raspberry pie
The mutex name should be consistent with the parameter as much as possible .PRTG Will be executed one by one ( Not at the same time ) All... With the same mutex name EXE/ Script sensor . If you have a large number of sensors and want to avoid high resource usage caused by running processes at the same time , It's very useful .
 Insert picture description here
It's basically done here , You can see all kinds of information that raspberry pie has just collected in this sensor .
 Insert picture description here






5、 ... and 、 Raspberry pie shell The script is configured to execute regularly

Timing execution configuration is simple

crontab -e

Open the scheduled task execution list , Add a sentence at the end

*/1 * * * * sh /home/pi/checknetwork.sh

The script address is what we just wrote shell Script .
Be careful ,crontab The script is run without system variables , So we have written in advance in our previous scripts PATH Variable .

PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

Of course, there is another way , You write another script , To tune the script . For example, casually in root Write a script in the directory , Just write a sentence , call checknetwork.sh. It can also avoid PATH Out of sync .

#!/bin/bash
/home/pi/checknetwork.sh

Advanced

See here , The basic functions have been realized , But then we have some high-level applications

One 、 Multiple raspberry pie auto update scripts

For all the raspberry pies in the net , If shell Script or python The program is updated iteratively , We designed a way to issue new versions of shell Scripts and python To all the raspberry pies . This is when there are dozens of raspberry pies in the net , Very useful .
Find one linux The host is the version server , Write the following script

#!/bin/bash

TFTPPATH="/root/tftp_file"
IPLISTPATH="/root/PRTG_WIFI_Probe/IPlist"
rm -f $IPLISTPATH/*
mv $TFTPPATH/IP-WIFI* $IPLISTPATH/
find $IPLISTPATH/ -mmin +2 -name "IP-WIFI*" -exec rm {} \;
# Keep recent 2 Updated in minutes IP-WIFI-*****.txt file , Delete the previous one 
cat $IPLISTPATH/IP-WIFI* > /root/PRTG_WIFI_Probe/IPlist_all.txt
# Merge all IP-WIFI-*****.txt
for ip in `cat /root/PRTG_WIFI_Probe/IPlist_all.txt | tr -d "\r" `
do
echo "sent file to "$ip
scp /root/PRTG_WIFI_Probe/programfile/checknetwork.py $ip:/home/pi
scp /root/PRTG_WIFI_Probe/programfile/checknetwork.sh $ip:/home/pi
done
# Distribute all the documents 

Inside this , It's a little bit about the raspberry pie .

NIC=$(route -n | grep UG | awk '{print $8}'| awk 'NR==1')
ifconfig $NIC | grep "inet " | awk '{print $2}' >> IP-WIFI-Check-$HOSTNAME.txt
# These two sentences are explained in detail 
# The first sentence , Get the record of the first row of the current device default routing table , And extract the network card device name 
# The second sentence , Get the current IP Address 
# This address is the current primary address that raspberry pie communicates with the server . Wireless only connection is wlan0 IP Address , At the same time, it is connected with wired wireless eth0 IP Address 
# This address , After that, you can use it when you distribute the script centrally 

Is it that you suddenly want to send out ~ Oh ~ A sigh of admiration , Marvel at the subtlety of the design .
For convenience , You can put this server's SSH-Keygen The public key is sent to all raspberry pies , such scp There is no password to issue the file
 Insert picture description here

Two 、 Piper raspberry detection

In this case ,PRTG The system will read the generated XML file , As long as this file exists , The system will not alarm .
therefore , If something goes wrong with a raspberry pie , When you don't continue to update the reported information . We need a mechanism to detect ,XML Whether the file has been updated normally
stay PRTG On the server where the probe is located , Write the following BAT Script

@echo off&setlocal enabledelayedexpansion
for /f "tokens=1 delims=" %%i in ('dir C:\00-tftp /tw ^| find /i "%1-WIFI_Check_result.txt" ') do set timeresult=%%i
set ma=%timeresult:~15,2%
set mb=%time:~3,2%
set /a ma=1%ma%-100
set /a mb=1%mb%-100
# Remove the minutes for 08 It's abnormal .BAT Script for 08xxx The number of people will think that is 8 Base number 
set /a mc=%mb%-%ma%
if %mc% gtr 2 (echo %mc%:Error Time Out) else (echo %mc%:Active)

then , Put it in the following path

C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXE

Okay , Go to PRTG Add a custom sensor , Using this script , Pass the parameter to the device name .XML The document exceeds 2 It's not updated in minutes .

3、 ... and 、PRTG XML Format custom sensor XML explain

Here's an example

XML Return Format: Minimum Example:

<prtg>
<result>
<channel> passageway 1 name </channel>
<value> Value channel </value>
</result>
<result>
<channel> passageway 2 name </channel>
<value> Value channel </value>
</result>
<text> Custom text delivery </text>
<error> Custom error messages </error>
</prtg>

Get it done !

版权声明
本文为[osc_ yea0up70]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple