REST服务准备
1Laravel
RESTful 路由: 通过简单的闭包就能响应HTTP请求。帮你快速开始构建非凡的应用。强大的数据操纵能力: Laravel自带了强大的Eloquent ORM 和迁移工具。能够完美的与MySQL、Postgres、SQL Server 和 SQLite协同工作。优雅的模版引擎: PHP代码或轻量级的Blade模版引擎都可无缝融合。Blade模版可以继承,并且拥有极快的解析速度。相信你会喜欢它的。为明天做准备: 构建大型的企业级应用或者只是提供简单的JSON API;书写强大的控制器或轻巧的RESTful路由,Laravel适应所有级别的开发工作。可靠的基石: Laravel 的基石是数个Symfony组件,这些经过千锤百炼、可靠的组件为你的应用提供坚实的基础。基于Composer管理器: Composer 是一套帮你管理第三方扩展包的工具。能够让你迅速在 Packagist 中找到需要的扩展包。强大的社区支持: 无论你是一个PHP新手还是经验丰富的架构师,都能在社区中找到需要的知识。你可以在IRC中讨论Idea,或者在论坛中发布问题。测试、重构: Laravel 从开始就将测试作为重点功能。我们提供了灵活的IoC容器,集成了PHPUnit 测试工具。不用担心,这些都很容易上手。Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
1.1为什么是 Laravel
因为个人喜爱,你也可以用 Ruby On Rails来搭建这样一个功能,或者是Java。PHP在我的服务器上运行得挺不错的,而且我又不需要重新去写配置那些配置。 Laravel 可以简单的开发我们所需要的功能,换句话说他是 PHP 世界的 Ruby On Rails。这里不会再重述之前的问题,这里只是将需要的步骤一个个写下来,然后丢到这里好好说一下。至于RESTful是什么,前面已经介绍了,就不再重复了。那么下面,我们就用Laravel来搭建一个平台给物联网用的。
2安装 Laravel
2.1GNU/Linux安装Composer
GNU/Linux Ubuntu/OpenSUSE下可以执行
$ curl -sS /installer | php
2.1.1Windows安装Composer
请直接下载
Composer-Setup
2.1.2Mac OS
1.安装Composer
brew install homebrew/php/composer
2.安装Laravel
composer global require "laravel/installer=~1.1"
3.创建Laravel工程
composer create-project laravel/laravel your-project-name --prefer-dist
2.1.3Mac OS
1.下载laravel.phar
wget /laravel.phar
2.重命名
mv laravel.phar laravel
3.移动到bin中
sudo mv laravel /usr/local/bin
4.创建项目
laravel new blog
3MySQL
3.1安装MySQL
出于某些原因,我建议用MariaDB替换MySQL,如果你"真正"需要mysql,将mariadb替换为mysql
ps: 在下文中我会继续用MySQL,而不是MariaDB,MairaDB是MySQL的一个分支,真正的开源分支。
Ubuntu/Debian/Mint
$ sudo apt-get install mariadb-server
Fedora/Centos
$ sudo yum install mariadb-server
openSUSE
$ sudo zypper install mariadb-server
Mac OS
$ brew install mariadb
3.2配置MySQL
修改database.php
app/config/database.php
要修改的就是这个
'mysql' => array('driver' => 'mysql','host'=> 'localhost','database' => 'iot','username' => 'root','password' => '940217','charset' => 'utf8','collation' => 'utf8_unicode_ci','prefix' => '',),
如果你已经有phpmyadmin,似乎对你来说已经很简单了,如果没有的话,就直接用
$ mysql -uroot -p
来创建一个新的
CREATE DATABASE IF NOT EXISTS iot default charset utf8 COLLATE utf8_general_ci;
数据库的目的在于存储数据等等的闲话这里就不多说了,创建一个RESTful的目的在于产生下面的JSON格式数据,以便于我们在Android、Java、Python、jQuery等语言框架或者平台上可以调用,最主要的是可以直接用Ajax来产生更炫目的效果。
{"id": 1,"temperature": 14,"sensors1": 12,"sensors2": 12,"led1": 0}
创建REST服务
1数据库迁移
这个名字是源自于Ruby On Rails在那时候的印象,不直接使用MySQL的目的在于让我们可以专注于过程。
1.1创建表
表的概念,类似于在Excel中的表,如果你真实不懂数据库。 让我们创建一个athomes的表,为什么是athomes,因为以前在写android程序的时候就叫的是athome,忽略掉这些次要的因素吧。
$ php artisan migrate:make create_athomes_table
打开 app/database/migrations/***create_athomes_table.php 这里的***是由日期和某些随机变量组成的,修改生成的PHP代码,如下:
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateAthomesTable extends Migration {public function up() {Schema::create('athomes', function(Blueprint $table) {$table--->increments('id'); $table->float('temperature'); $table->float('sensors1'); $table->float('sensors2'); $table->boolean('led1'); $table->timestamps(); }); } public function down() {Schema::drop('athomes'); } }
id值是自加的,也就是我们在localhost/athome/{id},当我们创建一个新的数据的时候,会自动加上去。最后一个timestamps批的是时间,会包含创建时间和修改时间。 剩下的temperature,sensors1,sensors2是小数,以及只有true和false的led1。
1.2数据库迁移
我们只是写了我们需要的数据的格式而并没有丢到数据库里,
$ php artisan migrate
这个就是我们执行迁移的命令,如果你用phpmyadmin可以直接打开查看,没有的话,可以。
$ mysql -uroot -p
use iot;select * from athomes;
就可以看到我们写的东西,那么接下来就是创建RESTful服务了
2创建RESTful
用下面的代码实现我们称之为Athomes控制器的创建
$ php artisan controller:make AthomesController
就会在app/controllers下面生成下面的代码
class AthomesController extends \BaseController {public function index() {} public function create() {} public function store() {} public function show($id) {} public function edit($id) {} public function update($id) {} public function destroy($id) {} }
3Laravel Resources
上面的代码过于沉重,请让我用 Ctrl+C 来带来点知识吧。
所以我们只需要专注于创建 create, edit, show, destory 等等。好吧,你可能没有耐心了,但是在修改这个之前我们需要先在 app/model 加个 class
class Athomes extends Eloquent {protected $table = 'athomes'; }
如果你想要的只是控制器Athomes的代码的话。。
class AthomesController extends \BaseController {public $restful=true;protected $athome;public function __construct(Athomes $athome){$this--->athome = $athome ;}public function index(){$maxid=Athomes::all();return Response::json($maxid);}public function create(){$maxid=Athomes::max('id');return View::make('athome.create')->with('maxid',$maxid);}public function store(){$rules = array('led1'=>'required','sensors1' => 'required|numeric|Min:-50|Max:80','sensors2' => 'required|numeric|Min:-50|Max:80','temperature' => 'required|numeric|Min:-50|Max:80');$validator = Validator::make(Input::all(), $rules);if ($validator->fails()) {return Redirect::to('athome/create')->withErrors($validator)->withInput(Input::except('password'));} else {$nerd = new Athomes;$nerd->sensors1 = Input::get('sensors1');$nerd->sensors2 = Input::get('sensors2');$nerd->temperature = Input::get('temperature');$nerd->led1 = Input::get('led1');$nerd->save();Session::flash('message', 'Successfully created athome!');return Redirect::to('athome');}}public function show($id){$myid=Athomes::find($id);$maxid=Athomes::where('id','=',$id)->select('id','temperature','sensors1','sensors2','led1')->get();return Response::json($maxid);}public function edit($id){$athome = Athomes::find($id);return View::make('athome.edit')->with('athome', $athome);}public function update($id){$rules = array('led1'=>'required|','sensors1' => 'required|numeric|Min:-50|Max:80','sensors2' => 'required|numeric|Min:-50|Max:80','temperature' => 'required|numeric|Min:-50|Max:80');$validator = Validator::make(Input::all(), $rules);if ($validator->fails()) {return Redirect::to('athome/' . $id . '/edit')->withErrors($validator);} else {$nerd = Athomes::find($id);$nerd->sensors1 = Input::get('sensors1');$nerd->sensors2 = Input::get('sensors2');$nerd->temperature = Input::get('temperature');$nerd->led1 = Input::get('led1');$nerd->save();Session::flash('message', 'Successfully created athome!');return Redirect::to('athome');}}public function destroy($id){$athome = Athomes::find($id);$athome->delete();if(is_null($athome)){return Response::json('Todo not found', 404);}Session::flash('message', 'Successfully deleted the nerd!');return Redirect::to('athome');}}
希望你能读懂,没有的话,继续。
下面这部分来自于之前的博客,这里就不多加论述了。 这个也就是我们要的模板,
3.1修改Create()
public function create(){$maxid=Athomes::max('id');return View::make('athome.create')->with('maxid',$maxid);}
这里需要在app/views/创建一个athome里面创建一个create.blade.php,至于maxid,暂时还不需要,后面会用到show。如果只需要模板,可以简化为
public function create(){return View::make('athome.create');}
这里只是对其中代码的进行一下说明。
3.2创建前台页面
3.2.1 开始之前
由于使用到了bootstrap以及bootstrap-select,记得添加css。
<link rel="stylesheet" type="text/css" href="<?= url('css/bootstrap.min.css') ?>" /><link rel="stylesheet" type="text/css" href="<?= url('css/bootstrap-select.min.css') ?>" />
以及javascript
<script type="text/javascript" src="<?= url('js/jquery.min.js')?>"></script><script type="text/javascript" src="<?= url('js/bootstrap.min.js') ?>"></script><script type="text/javascript" src="<?= url('js/bootstrap-select.min.js') ?>"></script><script>$('.selectpicker').selectpicker();</script>
3.2.2创建资源页面
这里用到的是之前提到的那个作者写下的,稍微修改了一下。
<div class="row-fluid">{{ HTML::ul($errors->all()) }}{{ Form::open(array('url' => 'athome')) }}<div class="form-group">{{ Form::label('led1', '开关1') }}{{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }}</div><div class="form-group">{{ Form::label('sensors1', 'sensors1') }}{{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }}</div><div class="form-group">{{ Form::label('sensors2', 'sensors2') }}{{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }}</div><div class="form-group">{{ Form::label('temperature', 'temperature') }}{{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }}</div>{{ Form::submit('Create!', array('class' => 'btn btn-primary')) }}{{ Form::close() }}</div>
开关一开始打算用 checkbox,加上 bootstrap-switch 实现
ON OFF
弱弱地觉得还是没掌握好的节奏,所以最后用 select 来实现。
还需要修改一下之前的 create(),添加一行
return Redirect::to('athome');
也就是添加完后,重定向到首页查看,最后例子给出的 create 如下
public function store(){$rules = array('led1'=>'required','sensors1' => 'required|numeric|Min:-50|Max:80','sensors2' => 'required|numeric|Min:-50|Max:80','temperature' => 'required|numeric|Min:-50|Max:80');$validator = Validator::make(Input::all(), $rules);if ($validator->fails()) {return Redirect::to('athome/create')->withErrors($validator);} else {// store$nerd = new Athomes;$nerd->sensors1 = Input::get('sensors1');$nerd->sensors2 = Input::get('sensors2');$nerd->temperature = Input::get('temperature');$nerd->led1 = Input::get('led1');$nerd->save();Session::flash('message', 'Successfully created athome!');return Redirect::to('athome');}}
效果图:
3.4更新资源页面
完整的 blade 模板文件
<!DOCTYPE html lang="zh-cn"><html><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><meta name="keywords" content=""><meta name="viewport" content="width=device-width"><meta name="description" content=""><title>@yield('title')</title><link rel="stylesheet" type="text/css" href="<?= url('css/bootstrap.min.css') ?>" /><link rel="stylesheet" type="text/css" href="<?= url('css/bootstrap-select.min.css') ?>" /><link rel="stylesheet" href="<?= url('css/justified-nav.css') ?>" type="text/css" media="screen" /></head><body><div class="container"><div class="container"><div class="row-fluid"><h1>Edit {{ $athome->id }}</h1><!-- if there are creation errors, they will show here -->{{ HTML::ul($errors->all()) }}{{ Form::model($athome, array('route' => array('athome.update', $athome->id), 'method' => 'PUT')) }}<div class="form-group">{{ Form::label('led1', '开关1') }}{{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }}</div><div class="form-group">{{ Form::label('sensors1', '传感器1') }}{{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }}</div><div class="form-group">{{ Form::label('sensors2', '传感器2') }}{{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }}</div><div class="form-group">{{ Form::label('temperature', '温度传感器') }}{{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }}</div>{{ Form::submit('Edit the Nerd!', array('class' => 'btn btn-primary')) }}{{ Form::close() }}</div></div><div class="footer"><p>© Company </p></div></div></div><script type="text/javascript" src="<?= url('js/jquery.min.js')?>"></script><script type="text/javascript" src="<?= url('js/bootstrap.min.js') ?>"></script><script type="text/javascript" src="<?= url('js/bootstrap-select.min.js') ?>"></script><script>$('.selectpicker').selectpicker();</script><script type="text/javascript" src="<?= url('js/log.js') ?>"></script></body></html>
效果图:
最后效果见:/
RESTful Evertywhere
1Javascript与ajax
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。AJAX = 异步 JavaScript和XML(标准通用标记语言的子集)。
1.1jQuery
Jquery是继prototype之后又一个优秀的Javascript框架。它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需定义id即可。
2Java与json
Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为串行化Java对象为JSON字符串,或反串行化JSON字符串成Java对象。
2.1Android
3Python与json
使用pySerial可以使Python很好地在Windows/Linux/BSD上执行串口操作。
使用urllib2库时
#!/usr/bin/env pythonimport jsonimport urllib2url="/athome/1"date=urllib2.urlopen(url)result=json.load(date)print result
3.1requests
Python 标准库中的 urllib2 模块提供了你所需要的大多数 HTTP 功能,但是它的 API 烂出翔来了。它是为另一个时代、另一个互联网所创建的。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务。
GET请求
#!/usr/bin/env pythonimport requestsurl = "/athome/1"r = requests.get(url)print r.text
POST请求
#!/usr/bin/env pythonimport requestsurl = "/athome/1"data = {"temperature": 19, "sensors1": 32, "sensors2": 7.5, "led1": 0, "method": "PUT"}r = requests.put(url, data)print r.text
前端显示
1库与车轮子
在多数的情况下我们都没有理由也没有必要去重新发明我们的车轮,在这时使用库会是一个比较好的做法。
2库
2.1jQuery Mobile
jQuery Mobile是jQuery 在手机上和平板设备上的版本。jQuery Mobile不仅会给主流移动平台带来jQuery核心库,而且会发布一个完整统一的jQuery移动UI框架。支持全球主流的移动平台。jQuery Mobile开发团队说:能开发这个项目,我们非常兴奋。移动Web太需要一个跨浏览器的框架,让开发人员开发出真正的移动Web网站。
3网站前台显示
3.1Highcharts
Highcharts有以下的特点
兼容性:兼容当今所有的浏览器,包括 iPhone、IE 和火狐等等;对个人用户完全免费;纯JS,无BS;支持大部分的图表类型:直线图,曲线图、区域图、区域曲线图、柱状图、饼装图、散布图;跨语言:不管是 PHP、 还是 Java 都可以使用,它只需要三个文件:一个是Highcharts 的核心文件 highcharts.js,还有 a canvas emulator for IE 和 Jquery类库或者 MooTools 类库;提示功能:鼠标移动到图表的某一点上有提示信息;放大功能:选中图表部分放大,近距离观察图表;易用性:无需要特殊的开发技能,只需要设置一下选项就可以制作适合自己的图表;时间轴:可以精确到毫秒;
在这里只需将需要处理的数据存储到数组中,便可以将其渲染成为图形,下面的温度走势图便是基于Highcharts的结果:
var dataLength = [];function drawTemp() {var zero = [];$.getJSON('/athome/', function(json) {var items = [];dataLength.push(json.length);$.each(json, function(key, val) {zero.push(val.temperature);});chart = new Highcharts.Chart({color: {linearGradient: {x1: 0,x2: 0,y1: 0,y1: 1},stops: [[0, '#003399'],[1, '#3366AA']]},chart: {renderTo: 'Tchart',type: 'spline'},title: {text: '本月温度情况'},subtitle: {text: ''},xAxis: {categories: [],title: {text: ''}},yAxis: {title: {text: '温度 (°C)'}},tooltip: {backgroundColor: '#FCFFC5',borderColor: 'black',borderRadius: 10,borderWidth: 1,enabled: true,formatter: function() {return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y + '°C';}},legend: {layout: 'vertical',align: 'right',verticalAlign: 'top',x: -10,y: 100,borderWidth: 0},plotOptions: {line: {dataLabels: {enabled: true},enableMouseTracking: false}},series: [{name: '本月',data: zero}, {name: '对比',data: [26.0]}]});});};function showTemper() {var length = dataLength[0];$.ajax({url: '/athome/' + length,type: 'GET',dataType: 'json',async: true,timeout: 1000,error: function() {},success: function(sdata) {$('.temperStatus').empty();$('.temperStatus').append(sdata.temperature);}});};$(document).ready(function() {setInterval("drawTemp();", 5000);setInterval("showTemper();", 800);drawTemp();showTemper();});