【应用】信息短时存储
功能
这是一个在线的应用(这里是地址),用来短时间存储一些信息,以实现在不同设备上共享这些信息的功能。其实目的就是可以将手机上的一些信息快速的复制到电脑上,尤其是在使用Linux系统的时候。下面是该应用的截图。其中阅后即焚是指信息被访问一次之后就会被销毁。
流程
程序主要的流程就是首先在文本框中输入或者粘贴一些内容,然后保存到服务器(使用的是新浪sae),保存成功之后会返回给客户端一个编号,通过该编号就可以访问存储的内容。因为就是为了给手机和电脑之间的复制粘贴提供一个介质,所以信息的有效时间暂时设为了2分钟,2分钟之后就会清除保存的信息。
前端实现
整体风格
程序使用的是bootstrap框架,如果你还没有用过这个前端框架,那么强烈推荐你试用一下,因为使用该框架可以极大的减少你的工作量,并且兼容手机设备。下面是页面的主要html代码,其中css样式几乎全部为bootstrap定义的样式,这样我们就可以将更多的时间放在功能实现,而不是网页设计上。
<div class="container ">
<div class="row ">
<div style="padding:10px; ">
<form class="bs-example bs-example-form" role="form">
<div class="col-lg-12">
<div class="input-group input-group-lg">
<span class="input-group-addon">编号</span>
<input type="text" class="form-control" id="textId">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="msgGet">获取信息</button>
</span>
</div>
<br>
<div class="form-group ">
<textarea class="form-control custom-control change_font" style="resize:none" rows="8"
placeholder="请输入信息" id="mainText"></textarea>
</div>
<div class="text-center">
<button type="button" class="btn btn-primary button_width" id="msgClear">清空</button>
<button type="button" class="btn btn-primary button_width2 " id="msgSave">保存</button>
<div class="bootstrap-switch ">
<input type="checkbox" name="onlyOne" data-label-text="阅后即焚" data-on-text="是"
data-off-text="否" onSwitchChange="changeOne">
</div>
</div>
</div>
</form>
</div>
</div>
</div>
bootstrap有自适应机制,页面内容的宽度会随浏览器窗口的大小改变而改变。但是在我们的页面中如果采用默认的自适应机制,就可能会造成在较宽的屏幕上输入框的宽度过大,从而使的页面看起来不美观。所以我们更改了一下其默认行为,当浏览器窗口宽度大于800px时,将网页内容的宽度固定为800px。实现方式很简单,加上下面的css代码即可。
@media screen and (min-width: 800px) {
.container {
width: 800px;
}
}
还有一点就是input的placeholder属性在较低的IE版本中不兼容,使用下面的js代码可以解决这个问题
var JPlaceHolder = {
//检测
_check: function () {
return 'placeholder' in document.createElement('input');
},
//初始化
init: function () {
if (!this._check()) {
this.fix();
}
},
//修复
fix: function () {
jQuery(':input[placeholder]').each(function (index, element) {
var self = $(this), txt = self.attr('placeholder');
self.wrap($('<div></div>').css({position: 'relative', zoom: '1', border: 'none', background: 'none', padding: 'none', margin: 'none'}));
var pos = self.position(), h = self.outerHeight(true), paddingleft = self.css('padding-left');
var holder = $('<span></span>').text(txt).css({position: 'absolute', left: pos.left, top: pos.top, height: h, lienHeight: h, paddingLeft: paddingleft, fontSize: '1.5em', color: '#aaa'}).appendTo(self.parent());
self.focusin(function (e) {
holder.hide();
}).focusout(function (e) {
if (!self.val()) {
holder.show();
}
});
holder.click(function (e) {
holder.hide();
self.focus();
});
});
}
};
//执行
jQuery(function () {
JPlaceHolder.init();
});
bootstrap开关切换插件
在选择"阅后即焚"功能的地方,我们使用了一个开关切换的插件——bootstrap switch,这里 是该插件的github地址,使用起来也十分简单,下面是一个简单的示例,更多的属性可以参考官方文档
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>bootstrap switch demo</title>
<link rel="stylesheet" href="css/bootstrap3/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap3/bootstrap-switch.min.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/bootstrap-switch.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("[name='my-checkbox']").bootstrapSwitch();
$('input[name="my-checkbox"]').on('switchChange.bootstrapSwitch', function(event, state) {
console.log(this); // DOM element
console.log(event); // jQuery event
console.log(state); // true | false
});
});
</script>
</head>
<body>
<input type="checkbox" name="my-checkbox" data-on-text="是" data-off-text="否" checked>
</body>
</html>
效果图如下所示
信息提示
一般来说使用alert就可以实现弹窗提示的功能,但是各个浏览器的弹窗样式都不相同并且也不美观,这里使用了jQuery Toaster插件,效果如下图所示,这里 是github地址。
这个插件需要bootstrap 3.0+,不过使用起来更加方便,只需要引入一个jquery.toaster.js即可,下面是一个示例
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>bootstrap toaster demo</title>
<link rel="stylesheet" href="css/bootstrap3/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/jquery.toaster.js"></script>
</head>
<body>
<div>
<button id="open" class="btn btn-primary ">Click Me</button>
</div>
<script type="text/javascript">
$("#open").click(function () {
$.toaster({message: 'Your message here', title: 'Your Title', priority: 'danger'});
})
</script>
</body>
</html>
在默认情况下,弹窗出现的位置是在右上角,我们可以修改一下css样式使其出现在屏幕中间,不过要首先去jquery.toaster.js中,将下面的代码注释掉(大概90行附近),
'css' :
{
'position' : 'fixed',
'top' : '10px',
'right' : '10px',
'width' : '300px',
'zIndex' : 50000
}
下面是修改后的代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>bootstrap toaster demo</title>
<link rel="stylesheet" href="css/bootstrap3/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/jquery.toaster.js"></script>
<style type="text/css">
@media screen and (min-width: 800px) {
.center_toaster {
right: 30%;
width: 40%;
}
}
@media screen and (min-width: 500px) and (max-width: 799px) {
.center_toaster {
right: 20%;
width: 60%;
}
}
@media screen and (min-width: 200px ) and (max-width: 499px) {
.center_toaster {
right: 5%;
width: 90%;
}
}
</style>
</head>
<body>
<div>
<button id="open" class="btn btn-primary ">Click Me</button>
</div>
<script type="text/javascript">
$.toaster({
settings: {
'toaster': {
'class': 'center_toaster',
'css': {
'position': 'fixed',
'top': '2px',
'zIndex': 50000
}
}
}
});
$("#open").click(function () {
$.toaster({message: 'Your222 message here', title: 'Your Title', priority: 'danger'});
})
</script>
</body>
</html>
不过按上面修改之后在低于IE9的浏览器中工作并不理想,可能是IE9以下对 @media 支持不太好,所以在js的代码中加了一个判断,如果浏览器支持html5的一些特性(使用jquery判断)就使用toaster,否则使用alert。
if ($.support.leadingWhitespace) {
$.toaster({ priority: 'warning', title: '警告', message: '编号不能为空'});
} else {
alert("警告:编号不能为空");
}
Loading插件
当用户点完获取数据或者保存按钮时,会弹出一个正在加载的弹出层,防止由于网络延迟等原因造成用户重复点击,下面是效果图
这里 是github地址。下面是一个简单的示例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>bootstrap watingDialog demo</title>
<link rel="stylesheet" href="css/bootstrap3/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/bootstrap-waitingfor.js"></script>
</head>
<body>
<div>
<button id="open" class="btn btn-primary ">Click Me</button>
</div>
<script type="text/javascript">
$("#open").click(function () {
waitingDialog.show();
setTimeout(function() {
waitingDialog.hide();
},2000);
})
</script>
</body>
</html>
底部固定
当页面内容的高度小于屏幕的高度时,将footer固定在底部,当页面内容的高度大于屏幕高度时,footer会随着滚动条滚动,不会遮盖到正常的内容,下面一个解决方法,这里 是原文地址。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>bootstrap fixed footer demo</title>
<link rel="stylesheet" href="css/bootstrap3/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<style type="text/css">
* {
margin: 0;
}
html, body {
height: 100%;
}
.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -6em;
}
/*push和footer的高度不一样是因为加了一条hr*/
.push {
height: 6em;
}
.footer, {
height: 4em;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="container">
<p>这里是内容</p>
</div>
<div class="push"></div>
</div>
<footer class="footer">
<div class=" col-lg-12 text-center">
<hr>
<p>Copyright © zhangjk 2015</p>
</div>
</footer>
</body>
</html>
服务端实现
平台及语言
服务器使用的新浪的sae,语言是使用的php。
php restful service
因为应用逻辑非常简单,就是一个存和取数据,所以简单的实现了几个restful的接口,并没有使用专门的框架(主要是对php不熟悉)。接口的实现参考自__这篇文章__,下面是该文章给出的代码:
<?php
/*
API Demo
This script provides a RESTful API interface for a web application
Input:
$_GET['format'] = [ json | html | xml ]
$_GET['method'] = []
Output: A formatted HTTP response
Author: Mark Roland
History:
11/13/2012 - Created
*/
// --- Step 1: Initialize variables and functions
/**
* Deliver HTTP Response
* @param string $format The desired HTTP response content type: [json, html, xml]
* @param string $api_response The desired HTTP response data
* @return void
**/
function deliver_response($format, $api_response){
// Define HTTP responses
$http_response_code = array(
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found'
);
// Set HTTP Response
header('HTTP/1.1 '.$api_response['status'].' '.$http_response_code[ $api_response['status'] ]);
// Process different content types
if( strcasecmp($format,'json') == 0 ){
// Set HTTP Response Content Type
header('Content-Type: application/json; charset=utf-8');
// Format data into a JSON response
$json_response = json_encode($api_response);
// Deliver formatted data
echo $json_response;
}elseif( strcasecmp($format,'xml') == 0 ){
// Set HTTP Response Content Type
header('Content-Type: application/xml; charset=utf-8');
// Format data into an XML response (This is only good at handling string data, not arrays)
$xml_response = '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<response>'."\n".
"\t".'<code>'.$api_response['code'].'</code>'."\n".
"\t".'<data>'.$api_response['data'].'</data>'."\n".
'</response>';
// Deliver formatted data
echo $xml_response;
}else{
// Set HTTP Response Content Type (This is only good at handling string data, not arrays)
header('Content-Type: text/html; charset=utf-8');
// Deliver formatted data
echo $api_response['data'];
}
// End script process
exit;
}
// Define whether an HTTPS connection is required
$HTTPS_required = FALSE;
// Define whether user authentication is required
$authentication_required = FALSE;
// Define API response codes and their related HTTP response
$api_response_code = array(
0 => array('HTTP Response' => 400, 'Message' => 'Unknown Error'),
1 => array('HTTP Response' => 200, 'Message' => 'Success'),
2 => array('HTTP Response' => 403, 'Message' => 'HTTPS Required'),
3 => array('HTTP Response' => 401, 'Message' => 'Authentication Required'),
4 => array('HTTP Response' => 401, 'Message' => 'Authentication Failed'),
5 => array('HTTP Response' => 404, 'Message' => 'Invalid Request'),
6 => array('HTTP Response' => 400, 'Message' => 'Invalid Response Format')
);
// Set default HTTP response of 'ok'
$response['code'] = 0;
$response['status'] = 404;
$response['data'] = NULL;
// --- Step 2: Authorization
// Optionally require connections to be made via HTTPS
if( $HTTPS_required && $_SERVER['HTTPS'] != 'on' ){
$response['code'] = 2;
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
$response['data'] = $api_response_code[ $response['code'] ]['Message'];
// Return Response to browser. This will exit the script.
deliver_response($_GET['format'], $response);
}
// Optionally require user authentication
if( $authentication_required ){
if( empty($_POST['username']) || empty($_POST['password']) ){
$response['code'] = 3;
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
$response['data'] = $api_response_code[ $response['code'] ]['Message'];
// Return Response to browser
deliver_response($_GET['format'], $response);
}
// Return an error response if user fails authentication. This is a very simplistic example
// that should be modified for security in a production environment
elseif( $_POST['username'] != 'foo' && $_POST['password'] != 'bar' ){
$response['code'] = 4;
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
$response['data'] = $api_response_code[ $response['code'] ]['Message'];
// Return Response to browser
deliver_response($_GET['format'], $response);
}
}
// --- Step 3: Process Request
// Method A: Say Hello to the API
if( strcasecmp($_GET['method'],'hello') == 0){
$response['code'] = 1;
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
$response['data'] = 'Hello World';
}
// --- Step 4: Deliver Response
// Return Response to browser
deliver_response($_GET['format'], $response);
?>
对于apache服务器,需要修改一下.htaccess文件,该成下面的形式
# Turn on the rewrite engine
Options +FollowSymlinks
RewriteEngine on
# Request routing
RewriteRule ^([a-zA-Z_-]*)\.(html|json|xml)?$ index.php?method=$1&format=$2 [nc,qsa]
其中RewriteRule部分是指将[a-zA-Z_-]*
匹配到的字符串赋值到 $1
的位置,将(html|json|xml)?
匹配的字符串赋值到 $2
的位置,访问 hello.json
就相当于访问 index.php?method=hello&format=json
。
在sae中,使用的服务器也是apache,不过它不能更改.htaccess文件,而是需要修改config.yaml文件,如果使用git方式管理代码,默认是不会将该文件下载到本地的,所以推荐使用svn方式管理代码,下面是具体配置
name: appname
version: 1
handle:
-rewrite: if(!is_dir() && !is_file() && path ~ "^([a-zA-Z_-]*).(html|json|xml)?$") goto "index.php?method=$1&format=$2"
信息存储--memcache
这里存储没有使用数据库,而是使用的memcache,主要是信息只是短期存储,并且数据量不会太大。官方对memcache的使用解释的并不是十分详细,这里主要参考了 这篇文章 ,下面是具体的代码:
<?php
//连接
$mem = memcache_init();
//保存数据
$mem->set('key1', 'This is first value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br />";
//替换数据
$mem->replace('key1', 'This is replace value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br />";
//保存数组
$arr = array('aaa', 'bbb', 'ccc', 'ddd');
$mem->set('key2', $arr, 0, 60);
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br />";
//删除数据
$mem->delete('key1');
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br />";
//清除所有数据
$mem->flush();
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br />";
//关闭连接
$mem->close();
其中$mem->set
的第四个参数就是数据的有效期,单位是秒。
ajax跨域访问
为了使服务端允许客户端的ajax跨域请求,需要在php代码中加上下面的代码。
header('Access-Control-Allow-Origin:*');
前端使用jquery 的 $.ajax 发送ajax请求,在IE10及以上的版本中,工作正常,但是IE9及以下的版本无法正确访问,找了半天也没有找到好的解决方法。索性就在sae上放了一个同样的应用首页,如果使用IE9及以下的浏览器,可以访问那个页面。