开发自己的监控系统三、移动篇(android)

移动篇(android)

关键字:java、android、json、php

互联网已经进入移动时代,如果没有给自己的产品开发手机端的应用程序,出门都不好意思跟别人打招呼了~~
为了随时随地掌握服务器的运行状态,当然,也为了装ability,下面就来为我们的监控系统开发一个手机端(android)的应用。

原理

首先编写一个web接口,读取数据库服务器数据,返回json对象数组。android应用程序解析json数据,通过listvie控件显示。

以下是web接口,php编写,pdo方式连接数据库,使用json_encode将字符串转换为json对象格式,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
< ?php
$dbms='mysql'; //数据库类型 oracle 用ODI,对于开发者来说,使用不同的数据库,只要改这个,不用记住那么多的函数了
$host='localhost'; //数据库主机名
$dbName='monitor'; //使用的数据库
$user='user1'; //数据库连接用户名
$pass='Root123'; //对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";

try {
$dbh=new PDO($dsn,$user,$pass);//初始化一个PDO对象,就是创建了数据库连接对象$dbh
$jsonString=json_encode($dbh->query('select * from servers')->fetchAll(PDO::FETCH_ASSOC));
print_r($jsonString);
} catch (PDOException $e) {
die("Error!:".$e->getMessage());
}
?>

注:接口可以使用任何语言编写,只要能返回json对象数组就行。

使用浏览器访问该接口,返回json对象数组:
1567518973680

应用开发

大体思路:使用HttpClient接口向web接口提交get请求,取回json数据,然后解析json数据并显示在listview构造的表格中。
eclipse项目结构如下:
myMonitor_project_zps42e96b6c

AndroidManifest.xml:

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
< ?xml version= "1.0" encoding ="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cszhi.mymonitor"
android:versionCode= "1"
android:versionName= "1.0" >

<uses -sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses -permission android:name="android.permission.INTERNET" /><!-- 网路连接权限-->
<uses -permission android:name= "android.permission.ACCESS_NETWORK_STATE" /><!-- 允许访问网络状态-->
<application android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity android:screenOrientation="landscape"
android:name="com.cszhi.mymonitor.MainActivity"
android:label="@string/app_name" >
<intent -filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent>
</activity>
</application>

</manifest>

server_list.xml:

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
< ?xml version= "1.0" encoding ="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width= "wrap_content"
android:layout_height= "20dp"
android:orientation= "horizontal" >

<tablelayout android:id="@+id/table"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<tablerow>
<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/id"
android:layout_width="20dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/hostname"
android:layout_width="70dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/ip"
android:layout_width="100dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/rootpartion"
android:layout_width="100dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/uptime"
android:layout_width="100dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />
<textview android:id="@+id/time"
android:layout_width="85dp"
android:gravity="center"
android:layout_height="wrap_content" />

<view android:layout_width="1dip" android:background= "#FF909090" />

</tablerow>
</tablelayout>
</linearlayout>

activity_main.xml:

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
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools= "http://schemas.android.com/tools"
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:orientation= "vertical"
android:paddingBottom= "@dimen/activity_vertical_margin"
android:paddingLeft= "@dimen/activity_horizontal_margin"
android:paddingRight= "@dimen/activity_horizontal_margin"
android:paddingTop= "@dimen/activity_vertical_margin"
tools:context= ".MainActivity" >

<button android:id="@+id/bn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="刷新" />

<listview android:id="@+id/lvTitle"
android:background="#bfe1f2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<listview android:id="@+id/lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</linearlayout>

MyHttp.java:
用于提交get请求,获取接口返回的数据。

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
package com.cszhi.mymonitor;

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

public class MyHttp {
public String httpGet(String url){
String response= null;
HttpClient httpClient= new DefaultHttpClient();
HttpGet httpGet= new HttpGet(url);
HttpResponse httpResponse;
try{
httpResponse=httpClient.execute(httpGet);
int statusCode=httpResponse.getStatusLine().getStatusCode();
if(statusCode==HttpStatus.SC_OK){
response=EntityUtils. toString(httpResponse.getEntity());
}
} catch(ClientProtocolException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
return response;
}
}

MainActivity.java

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
package com.cszhi.mymonitor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONObject;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class MainActivity extends Activity {

//jsonstring 字符串,用于存放通过url获取的json数据
String jsonstring=null ;
//接口地址
String url= "http://60.191.231.17/get.php" ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//用于等待图标
requestWindowFeature(Window. FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout. activity_main);

Button bn=(Button) findViewById(R.id. bn);

//处理线程传递来的消息
final Handler myhandler =new Handler(){
public void handleMessage(Message msg){
ListView lv=(ListView) findViewById(R.id. lv);
String[] from={"id","hostname" ,"ip" ,"rootpartion" ,"uptime" ,"time" };
int[] to={R.id.id,R.id.hostname ,R.id.ip,R.id.rootpartion,R.id. uptime,R.id.time };

List<map <string,?>> listb= new ArrayList</map><map <string,?>>();
Map<string ,String> b= new HashMap</string><string , String>();
b.put( "id", "id" );
b.put( "hostname", "hostname" );
b.put( "ip", "ip" );
b.put( "rootpartion","rootpartion" );
b.put( "uptime","uptime" );
b.put( "time", "time" );
listb.add(b);

ListView lvtitle=(ListView) findViewById(R.id.lvTitle );
SimpleAdapter adapterb= new SimpleAdapter(MainActivity.this ,listb,R.layout.server_list,from,to);
lvtitle.setAdapter(adapterb);

List<map <string,?>> list= new ArrayList</map><map <string,?>>();
try{
JSONArray jsonArray= new JSONArray(jsonstring );

//解析json对象,并放入hashmap中
for(int i=0;i<jsonarray .length();i++){
JSONObject item=jsonArray.getJSONObject(i);
Map<string,String> m=new HashMap<string , String>();

m.put( "id", item.getString("id" ));
m.put( "hostname", item.getString("hostname" ));
m.put( "ip", item.getString("ip" ));
m.put( "rootpartion",item.getString("rootpartion" ));
m.put( "uptime", item.getString("uptime" ));
m.put( "time", item.getString("time" ));
list.add(m);
}
} catch(Exception e){
e.printStackTrace();
}

//这里的this是Handler,因为这个方法是在放在Handler里的,所以这里不应该使用this,而应该使用MainActivity.this(MainActivity是类名)
SimpleAdapter adapter= new SimpleAdapter(MainActivity.this ,list,R.layout.server_list,from,to);

lv.setAdapter(adapter);

//关闭等待图标(右上角的转圈)
setProgressBarIndeterminateVisibility( false);
}
};

//Runnable接口
final Runnable st=new Runnable() {
@Override
public void run() {
data( url);
myhandler.sendEmptyMessage(0);
}
};

//检查是否有网络连接
if(!checkNet( this)){
Toast. makeText(this, "网络连接失败,请检查网络" ,Toast.LENGTH_LONG).show();
} else{
new Thread(st).start();
setProgressBarIndeterminateVisibility( true);
}

//单击按钮
bn.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//如果有网路连接,创建新线程,传入 st接口,并启动该线程
if(!checkNet(MainActivity. this)){
Toast. makeText(MainActivity.this, "网络连接失败,请检查网络" ,Toast.LENGTH_LONG).show();
return;
} else{
new Thread(st).start();
//显示等待图标(右上角的转圈)
setProgressBarIndeterminateVisibility( true);
}
}
});
}

//获取url数据,并赋值给jsonstring
private void data(String url){
MyHttp myHttp= new MyHttp();
jsonstring= myHttp.httpGet(url);
}

//检查是否有网络的函数
public static boolean checkNet(Context context) {
try {
NetworkInfo networkInfo = (( ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE )).getActiveNetworkInfo();
if (networkInfo != null) {
Log. d("httpjson", "true");
return true ;
} else {
Log. d("httpjson", "false");
return false ;
}
} catch (Exception e) {
e.printStackTrace();
return false ;
}
}

}
</string></jsonarray></map></string></map>

编译,传到手机上安装运行:
1567519086881

可以根据自己需求添加其它功能,如定时刷新,声音报警等。
如下截图是我为部门运维服务器开发的手机端监控程序,支持按管理员监控服务器,支持按不同监控项目排序:
1567519123163

参考:

尚学堂科技.马士兵.JAVA视频教程
疯狂android讲义
http://developer.android.com/training/index.html