最近搞无线定位问题,碰到了一个问题,监听用户设备,实时的发送UDP报文,并将报文进行解析,解析完事存入数据库中,该数据库是实时动态更新的。其次就是用户输入设备点击显示去世的时候,给用户一个动态的报表趋势图,用来展示趋势图。
由于第一次接触网络,第一次接触报表,第一次使用springmvc框架,所以干了将近一周的时间,才算解决问题。我设计的这个实时动态更新数据,说白了就是刷新chart或者说是重新绘制chart,友谊都是第一次接触,所有做的不是很好,只是给同我一样处于迷茫状态的朋友,点一下。下面就讲述一下具体过程:
注:如果想看的明白,一定要仔细看注释,我大多都写在代码的注释中了
1、页面 useChart.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="js/jquery-1.7.2.min.js"></script>
<script src="fusioncharts/js/FusionCharts.min.js" type="text/javascript"></script>
<script type="text/javascript" src="fusioncharts/js/FusionCharts.js"></script>
<title>aotelan测试接口</title>
<script type="text/javascript">
var typeList = null;
var modelList = null;
var param = null;
var datelist = [];
var vulelist = [];
var namelist = [];
var staMac ;
// 点击事件
function getAllAp(){
staMac = document.getElementById("publishTime").value;
var w = $("#tongji").width();
var h = $(window).height() - 35;
lineChartUrl("ScrollLine2D.swf?ChartNoDataText=暂无数据显示!", w, (h - 65),
"usersiteTypeTrend");
}
// 数据处理
function lineChartUrl(swf, chartWidth, chartHeight, chartDiv, chartName) {
var namelist2=namelist;
var vulelist2=vulelist;
var datelist2=datelist;
$.ajax({
url : "showListener.do",
type : "post",
async : false,
data : "staMac="+staMac,
dataType:"json",
success : function(data) {
namelist2 = data.apList;
vulelist2 = data.rssiList;
datelist2 = data.collTimeList;
}
});
var chartStyle = " numdivlines='9' alternateHGridAlpha='0' canvasBgAlpha='0,0' canvasBorderAlpha='20' lineThickness='2' showValues='0' chartLeftMargin='0' chartRightMargin='15'chartTopMargin='5' chartBottomMargin='0' anchorRadius='3' anchorBgAlpha='100' numVDivLines='24' toolTipBgColor='304e79' showAlternateVGridColor='1' alternateVGridAlpha='3' showLegend='0' baseFontSize='14' showBorder='0' baseFontColor='00FFFF' animation='0' bgAlpha='0,0' "
var chartXMLData = "<chart caption='用户定位数据趋势图' >";
chartXMLData += "<categories >";
for ( var int = 0; int < datelist2.length; int++) {
chartXMLData += "<category name='" + datelist2[int] + "'/>";
}
chartXMLData += "</categories >";
for ( var int = 0; int < namelist2.length; int++) {
chartXMLData += "<dataset seriesName='" + namelist2[int] + "'>";
var vallist = vulelist2[int];
//var columncolor = colormap.get(namelist2[int]);
// alert(columncolor);
for ( var i = 0; i < vallist.length; i++) {
var values = vallist[i];
chartXMLData += "<set value='" + values
+ "' />";
}
chartXMLData += " </dataset>";
}
chartXMLData += "</chart>";
// alert("linexml:"+chartXMLData);
drawChart(chartDiv, swf, chartWidth, chartHeight, chartXMLData);
setInterval("getAllAp()",5000);
}
// 画图 (以指定 xml格式字符串为数据源)
function drawChart(divId, flashFileName, width1, height1, chartXMLData) {
var myChartId = new Date().getTime();
var myChart = new FusionCharts("charts/"
+ flashFileName, myChartId, width1, height1, "0", "1");
myChart.setDataXML(chartXMLData);
myChart.setTransparent(true);
myChart.addParam("wmode", "Opaque");
myChart.render(divId);
}
//转换日期格式
Date.prototype.format = function(format) {
var o = {
"M+" : this.getMonth() + 1, // month
"d+" : this.getDate(), // day
"h+" : this.getHours(), // hour
"m+" : this.getMinutes(), // minute
"s+" : this.getSeconds(), // second
"q+" : Math.floor((this.getMonth() + 3) / 3), // quarter
"S" : this.getMilliseconds()
// millisecond
}
if (/(y+)/.test(format))
format = format.replace(RegExp.$1, (this.getFullYear() + "")
.substr(4 - RegExp.$1.length));
for ( var k in o)
if (new RegExp("(" + k + ")").test(format))
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k]
: ("00" + o[k]).substr(("" + o[k]).length));
return format;
}
function listenerStart(){
var staMac = document.getElementById("publishTime").value;
$.ajax({
url : "login.do",
type : "post",
async : true,
data : "staMac="+staMac,
dataType:"json",
success : function(data) {
}
});
}
</script>
</head>
<body>
<div class="content" id="tongji">
<div class="content_data">
<div>
<fieldset class="query_fields">
<legend style="color: white;">
STA:
</legend>
<div>
起报时间:
<input id="publishTime" name="publishTime"
style="width: 100px" type="text"/>
<input style="width: 60px" value="启动监听" id="submit" type="button" οnclick="listenerStart();"/>
<input style="width: 60px" value="绘制报表" id="submit" type="button" οnclick="getAllAp();"/>
</div>
</fieldset>
<div id="usersiteTypeTrend" style="width: 800px; margin-top: 10px;hight:600px"></div>
</div>
</div>
</div>
</body>
</html>
以上的就是jsp页面的所有内容,为了大家能够更方便的了解,我就拆分一下代码:
页面展现如图:
(1)、很明显我把jsp页面做的比较简单,简单到不能再简单了。
<div class="content" id="tongji">
<div class="content_data">
<span style="white-space:pre"> </span><div>
<span style="white-space:pre"> </span><fieldset class="query_fields">
<legend style="color: white;">STA:</legend>
<div>起报时间:
<span style="white-space:pre"> </span><input id="publishTime" name="publishTime" style="width: 100px" type="text"/>
<input style="width: 60px" value="启动监听" id="submit" type="button" οnclick="listenerStart();"/>
<input style="width: 60px" value="绘制报表" id="submit" type="button" οnclick="getAllAp();"/>
</div>
</fieldset>
<div id="usersiteTypeTrend"style="width: 800px; margin-top: 10px;hight:600px"></div>
</div>
</div>
</div>
(2)、真正起作用的在js里面
用户点击启动监听,然后后台开始几首UDP报文,然后将UDP报文解析,解析之后,存入数据库。
用户点击绘制报表,才开始去画图。
流程如下:用户点击-----》获取输入框的值,通过ajax事件去请求后台------》后台调用业务逻辑层,然后业务逻辑层电泳数据库操作取数据-------》之后返回数据封装成json格式打印到前端---------》ajax接收到数据,开始赋值,绘制组装报表。
实时鼎泰刷新,其实就是js写的定时器,定时去请求ccontroller,然后,返回数据,在组装,再绘制chart,重复如此。
对应如下:
a、用户点击事件:
需要注意的是
// 点击事件
function getAllAp(){
staMac = document.getElementById("publishTime").value;//获取输入框的值
var w = $("#tongji").width();//设置chart的宽度
var h = $(window).height() - 35;//设置chart的高度
lineChartUrl("ScrollLine2D.swf?ChartNoDataText=暂无数据显示!", w, (h - 65),
"usersiteTypeTrend");//这里注意了,<span style="font-family: Arial, Helvetica, sans-serif;">usersiteTypeTrend对应的就是按钮下面的那个存放chart的div的id</span>
}
b、ajax请求后台
$.ajax({
url : "showListener.do",
type : "post",
async : false,//这里需要设置为同步,否则加载不出来,意思就是,必须要等数据出来,才可以画图
data : "staMac="+staMac,
dataType:"json",//这里需要转换为json格式
success : function(data) {//数据组装之后的json
namelist2 = data.apList;//这里定义的是,每条线的名字
vulelist2 = data.rssiList;//这里存放的是数据
datelist2 = data.collTimeList;//这里存放的是横坐标,我的是时间轴
}
});
c、后台代码
这个其实用什么都一样,我是用的springmvc,主要是数据封装的格式,其他的没啥
Java代码
package com.chenqk.springmvc.controller;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.chenqk.springmvc.entity.Location;
import com.chenqk.springmvc.service.LocationService;
import com.chenqk.springmvc.util.StationEntity;
import com.chenqk.springmvc.util.UDPReceiver;
/**
* 控制类
* @author chenqk
*
*/
@Controller
@RequestMapping("/")
public class UserController{
@Autowired
@Qualifier("LocationService")
private LocationService locationService;
private String staMac;
private static Logger logger = Logger.getLogger(UserController.class);
public LocationService getLocationService() {
return locationService;
}
public void setLocationService(LocationService locationService) {
this.locationService = locationService;
}
public String getStaMac() {
return staMac;
}
public void setStaMac(String staMac) {
this.staMac = staMac;
}
/**
* 启动监听
* @param staMac
*/
@RequestMapping("/login")
public void login(@RequestParam("staMac") String staMac){
logger.info("启动监听--------------------"+staMac);
// 启动接受udp报文,将参数传递给报文解析模块
UDPReceiver receiver = UDPReceiver.getInstance();
receiver.receiveToCache(staMac);
}
/**
* 准备数据
* 要求数据格式
* 时间轴:["time1","time2","time3"]
* ap名:["ap1","ap2","ap3","ap4","ap5"]
* 数据:{[num1,num2,num3],[num4,mun5,num6],[num7,num8,num9],[num10,num11,num12],[num13,num14,num15]}
* 其中数据的对一个格式为:集合大小为ap集合大小,每个集合的大小和时间的大小一致,用于前端生成报表
* @param staMac 用于启动监听将参数传递给解析报文
* @param printWriter 用于将json数据打印到前端
*/
@RequestMapping("/showListener")
@ResponseBody
public void showListener(@RequestParam("staMac") String staMac, PrintWriter printWriter){
Location location = new Location();
// 存放数据值
List<List<Double>> rssiList = new ArrayList<List<Double>>();
// 获取时间轴坐标数据
List<String> collTimeList = locationService.searchColltime(staMac);
// 取最近一秒
String colltime = collTimeList.get(collTimeList.size()-1);
// 取最近一秒的ap集合,并按照ap去绘制在时间轴上的趋势
location.setCollTime(colltime);
location.setStaMac(staMac);
List<Location> apList = locationService.getAllStaMacByTime(location);
// 存放ap的集合
List<String> ap = new ArrayList<String>();
// 设置数据
for (int i = 0; i < apList.size(); i++) {// 遍历很据ap和时间取数据值
List<Double> numTemp = new ArrayList<Double>();// 对应的是每个ap在时间轴的数据的数据
for (int j = 0; j < collTimeList.size(); j++) {
location.setApMac(apList.get(i).getApMac());
double rssi = 0.0;
location.setCollTime(collTimeList.get(j));
System.out.println("时间:="+collTimeList.get(j)+"-----ap="+apList.get(i).getApMac());
Location c = locationService.serchByApAndTime(location);
if(c!=null){// 如果该对象存在,则将rssi值添加到集合中
rssi = c.getRssi();
}
numTemp.add(rssi);
}
ap.add(apList.get(i).getApMac());// 将最近一秒的ap放到集合中
rssiList.add(numTemp);// 将5个ap对应的数值放到集合中
}
// 实体类封装集合,组装成指定的格式
StationEntity stationEntity = new StationEntity();
stationEntity.setApList(ap);
stationEntity.setCollTimeList(collTimeList);
stationEntity.setRssiList(rssiList);
// 将组合的数据对象转为json格式
JSONObject jSONObject = JSONObject.fromObject(stationEntity);
logger.info("获得数据为:"+jSONObject.toString());
// 将json打印到前台
printWriter.print(jSONObject);
printWriter.close();
}
}
主要是第二个方法;数据格式,我都加在注释中了。其中封装三个集合的bean如下:
package com.chenqk.springmvc.util;
import java.util.List;
/**
* 封装数据Bean
* @author chenqk
*
*/
public class StationEntity {
/**
* ap集合,每条线代表的名字集合
*/
private List<String> apList;
/**
* 数据值集合
*/
private List<List<Double>> rssiList;
/**
* 时间轴集合
*/
private List<String> collTimeList;
public List<String> getApList() {
return apList;
}
public void setApList(List<String> apList) {
this.apList = apList;
}
public List<List<Double>> getRssiList() {
return rssiList;
}
public void setRssiList(List<List<Double>> rssiList) {
this.rssiList = rssiList;
}
public List<String> getCollTimeList() {
return collTimeList;
}
public void setCollTimeList(List<String> collTimeList) {
this.collTimeList = collTimeList;
}
}
有个对应关系说一下:数据这个集合是跟句时间轴和每条线代表的名字集合构建的,其中数据值集合的大小为,名字集合的大小。数据值中每个小的集合里面的大小是根据时间轴的集合大小来的。
d、ajax获得返回值,然后赋值组装chart
// 数据处理
function lineChartUrl(swf, chartWidth, chartHeight, chartDiv, chartName) {
var namelist2=namelist;
var vulelist2=vulelist;
var datelist2=datelist;
$.ajax({
url : "showListener.do",
type : "post",
async : false,
data : "staMac="+staMac,
dataType:"json",
success : function(data) {
namelist2 = data.apList;
vulelist2 = data.rssiList;
datelist2 = data.collTimeList;
}
});
//这里开始组装报表
var chartStyle = " numdivlines='9' alternateHGridAlpha='0' canvasBgAlpha='0,0' canvasBorderAlpha='20' lineThickness='2' showValues='0' chartLeftMargin='0' chartRightMargin='15'chartTopMargin='5' chartBottomMargin='0' anchorRadius='3' anchorBgAlpha='100' numVDivLines='24' toolTipBgColor='304e79' showAlternateVGridColor='1' alternateVGridAlpha='3' showLegend='0' baseFontSize='14' showBorder='0' baseFontColor='00FFFF' animation='0' bgAlpha='0,0' "
var chartXMLData = "<chart caption='用户定位数据趋势图' >";
chartXMLData += "<categories >";
for ( var int = 0; int < datelist2.length; int++) {
chartXMLData += "<category name='" + datelist2[int] + "'/>";
}
chartXMLData += "</categories >";
for ( var int = 0; int < namelist2.length; int++) {
chartXMLData += "<dataset seriesName='" + namelist2[int] + "'>";
var vallist = vulelist2[int];
//var columncolor = colormap.get(namelist2[int]);
// alert(columncolor);
for ( var i = 0; i < vallist.length; i++) {
var values = vallist[i];
chartXMLData += "<set value='" + values
+ "' />";
}
chartXMLData += " </dataset>";
}
chartXMLData += "</chart>";
// alert("linexml:"+chartXMLData);
drawChart(chartDiv, swf, chartWidth, chartHeight, chartXMLData);
<span style="white-space:pre"> </span>//生成报表之后,设置定时器
setInterval("getAllAp()",5000);
}
调用下面方法需要注意:还有个问题就是,可能你的版面是白色的,而你chart的字体也是白色的,会在页面不显示,你需要在chartType中设置一下字体颜色。
drawChart(chartDiv, swf, chartWidth, chartHeight, chartXMLData)
// 画图 (以指定 xml格式字符串为数据源)
function drawChart(divId, flashFileName, width1, height1, chartXMLData) {
var myChartId = new Date().getTime();
<span style="white-space:pre"> </span>//下面的路径值得是你chart插件放的位置,我的如下图所示:
var myChart = new FusionCharts("charts/"
+ flashFileName, myChartId, width1, height1, "0", "1");
myChart.setDataXML(chartXMLData);
myChart.setTransparent(true);
myChart.addParam("wmode", "Opaque");
myChart.render(divId);
}
至此,报表就画完了!代码已上传,需要的朋友可以去下载!使用的框架技术为springmvc+mybatis,插件为fusioncharts,数据库为mysql,附带sql脚本。
一天一点进步-------------------------2014年11月15日17:09:49 (不醉怎能入睡)