一:JS SDK

1.修改配置workspace

  

2.导入

  

3.Demo.html 

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>测试页面1</title>
<!-- 第一种集成方式 -->
<script type="text/javascript" src="./js/analytics.js"></script>
</head>
<body>
测试页面1<br/>
跳转到:
<a href="demo.html">demo</a>
<a href="demo2.html">demo2</a>
<a href="demo3.html">demo3</a>
<a href="demo4.html">demo4</a>
</body>
</html>

4.效果

  

5.产生新的日志

  tail -f access.log

  

二:重点

1.关于js的产生

  参考程序analytics.js的JS SDK

 (function() {
var CookieUtil = {
// get the cookie of the key is name
get : function(name) {
var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie
.indexOf(cookieName), cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(";", cookieStart);
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(
cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
},
// set the name/value pair to browser cookie
set : function(name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + "="
+ encodeURIComponent(value); if (expires) {
// set the expires time
var expiresTime = new Date();
expiresTime.setTime(expires);
cookieText += ";expires=" + expiresTime.toGMTString();
} if (path) {
cookieText += ";path=" + path;
} if (domain) {
cookieText += ";domain=" + domain;
} if (secure) {
cookieText += ";secure";
} document.cookie = cookieText;
},
setExt : function(name, value) {
this.set(name, value, new Date().getTime() + 315360000000, "/");
}
}; // 主体,其实就是tracker js
var tracker = {
// config
clientConfig : {
// TODO 这里的url需要传入具体的地址
serverUrl : "http://linux-hadoop3.ibeifeng.com/BEIfeng.gif",
sessionTimeout : 360, // 360s -> 6min 指定会话的过期时间,指的是操作停留最多的时间
maxWaitTime : 3600, // 3600s -> 60min -> 1h 指定的是单页面的最多停留时间,当前这个参数无效
ver : "1"
}, cookieExpiresTime : 315360000000, // cookie过期时间,10年 columns : {
// 发送到服务器的列名称
eventName : "en",
version : "ver",
platform : "pl",
sdk : "sdk",
uuid : "u_ud",
memberId : "u_mid",
sessionId : "u_sd",
clientTime : "c_time",
language : "l",
userAgent : "b_iev",
resolution : "b_rst",
currentUrl : "p_url",
referrerUrl : "p_ref",
title : "tt",
orderId : "oid",
orderName : "on",
currencyAmount : "cua",
currencyType : "cut",
paymentType : "pt",
category : "ca",
action : "ac",
kv : "kv_",
duration : "du"
}, keys : {
pageView : "e_pv",
chargeRequestEvent : "e_crt",
launch : "e_l",
eventDurationEvent : "e_e",
sid : "bftrack_sid",
uuid : "bftrack_uuid",
mid : "bftrack_mid",
preVisitTime : "bftrack_previsit", }, /**
* 获取会话id
*/
getSid : function() {
return CookieUtil.get(this.keys.sid);
}, /**
* 保存会话id到cookie
*/
setSid : function(sid) {
if (sid) {
CookieUtil.setExt(this.keys.sid, sid);
}
}, /**
* 获取uuid,从cookie中
*/
getUuid : function() {
return CookieUtil.get(this.keys.uuid);
}, /**
* 保存uuid到cookie
*/
setUuid : function(uuid) {
if (uuid) {
CookieUtil.setExt(this.keys.uuid, uuid);
}
}, /**
* 获取memberID
*/
getMemberId : function() {
return CookieUtil.get(this.keys.mid);
}, /**
* 设置mid
*/
setMemberId : function(mid) {
if (mid) {
CookieUtil.setExt(this.keys.mid, mid);
}
}, // 入口方法
startSession : function() {
// 加载js就触发的方法
if (this.getSid()) {
// 会话id存在,表示uuid也存在
if (this.isSessionTimeout()) {
// 会话过期,产生新的会话
this.createNewSession();
} else {
// 会话没有过期,更新最近访问时间
this.updatePreVisitTime(new Date().getTime());
}
} else {
// 会话id不存在,表示uuid也不存在
this.createNewSession();
}
this.onPageView();
}, onLaunch : function() {
// 触发launch事件
var launch = {};
launch[this.columns.eventName] = this.keys.launch; // 设置事件名称
this.setCommonColumns(launch); // 设置公用columns
this.sendDataToServer(this.parseParam(launch)); // 最终发送编码后的数据
}, onPageView : function() {
// 触发page view事件
if (this.preCallApi()) {
var time = new Date().getTime();
var pageviewEvent = {};
pageviewEvent[this.columns.eventName] = this.keys.pageView;
pageviewEvent[this.columns.currentUrl] = window.location.href; // 设置当前url
pageviewEvent[this.columns.referrerUrl] = document.referrer; // 设置前一个页面的url
pageviewEvent[this.columns.title] = document.title; // 设置title
this.setCommonColumns(pageviewEvent); // 设置公用columns
this.sendDataToServer(this.parseParam(pageviewEvent)); // 最终发送编码后的数据
this.updatePreVisitTime(time); // 更新最近访问时间
}
}, onChargeRequest : function(orderId, name, currencyAmount, currencyType,
paymentType) {
// 触发订单产生事件
if (this.preCallApi()) {
if (!orderId || !currencyType || !paymentType) {
this.log("订单id、货币类型以及支付方式不能为空");
return;
} if (typeof (currencyAmount) == "number") {
// 金额必须是数字
var time = new Date().getTime();
var chargeRequestEvent = {};
chargeRequestEvent[this.columns.eventName] = this.keys.chargeRequestEvent;
chargeRequestEvent[this.columns.orderId] = orderId;
chargeRequestEvent[this.columns.orderName] = name;
chargeRequestEvent[this.columns.currencyAmount] = currencyAmount;
chargeRequestEvent[this.columns.currencyType] = currencyType;
chargeRequestEvent[this.columns.paymentType] = paymentType;
this.setCommonColumns(chargeRequestEvent); // 设置公用columns
this.sendDataToServer(this.parseParam(chargeRequestEvent)); // 最终发送编码后的数据ss
this.updatePreVisitTime(time);
} else {
this.log("订单金额必须是数字");
return;
}
}
}, onEventDuration : function(category, action, map, duration) {
// 触发event事件
if (this.preCallApi()) {
if (category && action) {
var time = new Date().getTime();
var event = {};
event[this.columns.eventName] = this.keys.eventDurationEvent;
event[this.columns.category] = category;
event[this.columns.action] = action;
if (map) {
// map如果不为空,进行内容的添加
for ( var k in map) {
// 循环key
if (k && map[k]) {
// 当key和value不为空的时候,进行添加操作
event[this.columns.kv + k] = map[k]; // key添加前缀"kv_"
}
}
}
if (duration) {
event[this.columns.duration] = duration; // 当duration不为0的时候进行添加
}
this.setCommonColumns(event); // 设置公用columns
this.sendDataToServer(this.parseParam(event)); // 最终发送编码后的数据ss
this.updatePreVisitTime(time);
} else {
this.log("category和action不能为空");
}
}
}, /**
* 执行对外方法前必须执行的方法
*/
preCallApi : function() {
if (this.isSessionTimeout()) {
// 如果为true,表示需要新建
this.startSession();
} else {
this.updatePreVisitTime(new Date().getTime());
}
return true;
}, sendDataToServer : function(data) {
// 发送数据data到服务器,其中data是一个字符串
// TODO:发送以前发送失败的数据
var that = this;
var i2 = new Image(1, 1);
i2.onerror = function() {
// 这里可以进行重试操作
// 当请求失败的情况下,执行这块的代码,可以将数据保存到local stroage中,下次再重新发送数据
};
// 给定图片的请求url
i2.src = this.clientConfig.serverUrl + "?" + data;
}, /**
* 往data中添加发送到日志收集服务器的公用部分
*/
setCommonColumns : function(data) {
data[this.columns.version] = this.clientConfig.ver;
data[this.columns.platform] = "website";
data[this.columns.sdk] = "js";
data[this.columns.uuid] = this.getUuid(); // 设置用户id
data[this.columns.memberId] = this.getMemberId(); // 设置会员id
data[this.columns.sessionId] = this.getSid(); // 设置sid
data[this.columns.clientTime] = new Date().getTime(); // 设置客户端时间
data[this.columns.language] = window.navigator.language; // 设置浏览器语言
data[this.columns.userAgent] = window.navigator.userAgent; // 设置浏览器类型
data[this.columns.resolution] = screen.width + "*" + screen.height; // 设置浏览器分辨率
}, /**
* 创建新的会员,并判断是否是第一次访问页面,如果是,进行launch事件的发送。
*/
createNewSession : function() {
var time = new Date().getTime(); // 获取当前操作时间
// 1. 进行会话更新操作
var sid = this.generateId(); // 产生一个session id
this.setSid(sid);
this.updatePreVisitTime(time); // 更新最近访问时间
// 2. 进行uuid查看操作
if (!this.getUuid()) {
// uuid不存在,先创建uuid,然后保存到cookie,最后触发launch事件
var uuid = this.generateId(); // 产品uuid
this.setUuid(uuid);
this.onLaunch(); // 触发launch事件
}
}, /**
* 参数编码返回字符串
*/
parseParam : function(data) {
var params = "";
for ( var e in data) {
if (e && data[e]) {
// 对key和value进行编码操作
params += encodeURIComponent(e) + "="
+ encodeURIComponent(data[e]) + "&";
}
}
if (params) {
return params.substring(0, params.length - 1);
} else {
return params;
}
}, /**
* 产生uuid<br/>
* UUID的产生逻辑,可以参考Java中UUID的生产代码
*/
generateId : function() {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var tmpid = [];
var r;
tmpid[8] = tmpid[13] = tmpid[18] = tmpid[23] = '-';
tmpid[14] = '4'; for (i = 0; i < 36; i++) {
if (!tmpid[i]) {
r = 0 | Math.random() * 16;
tmpid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
return tmpid.join('');
}, /**
* 判断这个会话是否过期,查看当前时间和最近访问时间间隔时间是否小于this.clientConfig.sessionTimeout<br/>
* 如果是小于,返回false;否则返回true。
*/
isSessionTimeout : function() {
var time = new Date().getTime();
var preTime = CookieUtil.get(this.keys.preVisitTime);
if (preTime) {
// 最近访问时间存在,那么进行区间判断
return time - preTime > this.clientConfig.sessionTimeout * 1000;
}
return true;
}, /**
* 更新最近访问时间
*/
updatePreVisitTime : function(time) {
CookieUtil.setExt(this.keys.preVisitTime, time);
}, /**
* 打印日志
*/
log : function(msg) {
console.log(msg);
}, }; // 对外暴露的方法名称
window.__AE__ = {
startSession : function() {
tracker.startSession();
},
onPageView : function() {
tracker.onPageView();
},
onChargeRequest : function(orderId, name, currencyAmount, currencyType,
paymentType) {
tracker.onChargeRequest(orderId, name, currencyAmount,
currencyType, paymentType);
},
onEventDuration : function(category, action, map, duration) {
tracker.onEventDuration(category, action, map, duration);
},
setMemberId : function(mid) {
tracker.setMemberId(mid);
}
}; // 自动加载方法
var autoLoad = function() {
// 进行参数设置
var _aelog_ = _aelog_ || window._aelog_ || [];
var memberId = null;
for (i = 0; i < _aelog_.length; i++) {
_aelog_[i][0] === "memberId" && (memberId = _aelog_[i][1]);
}
// 根据是给定memberid,设置memberid的值
memberId && __AE__.setMemberId(memberId);
// 启动session
__AE__.startSession();
}; // 调用
autoLoad();
})();

2.同时在access.log收集日志

三:JAVA SDK

1.原理图

  

2.程序的重点

  将日志数据发送到队列

  取数据,将数据发送到nginx服务器

3.程序AnalyticsEngineSDK

 package com.ibeifeng.sdk.java.logmake;

 import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger; /**
* 分析引擎sdk java服务器端数据收集
*
* @author ibeifeng
* @version 1.0
*
*/
public class AnalyticsEngineSDK {
// 日志打印对象
private static final Logger log = Logger.getGlobal();
// 请求url的主体部分
public static final String accessUrl = "http://linux-hadoop3.ibeifeng.com/BEIfeng.gif";
private static final String platformName = "java_server";
private static final String sdkName = "jdk";
private static final String version = "1"; /**
* 触发订单支付成功事件,发送事件数据到服务器
*
* @param orderId
* 订单支付id
* @param memberId
* 订单支付会员id
* @return 如果发送数据成功(加入到发送队列中),那么返回true;否则返回false(参数异常&添加到发送队列失败).
*/
public static boolean onChargeSuccess(String orderId, String memberId) {
try {
if (isEmpty(orderId) || isEmpty(memberId)) {
// 订单id或者memberid为空
log.log(Level.WARNING, "订单id和会员id不能为空");
return false;
}
// 代码执行到这儿,表示订单id和会员id都不为空。
Map<String, String> data = new HashMap<String, String>();
data.put("u_mid", memberId);
data.put("oid", orderId);
data.put("c_time", String.valueOf(System.currentTimeMillis()));
data.put("ver", version);
data.put("en", "e_cs");
data.put("pl", platformName);
data.put("sdk", sdkName);
// 创建url
String url = buildUrl(data);
// 发送url&将url加入到队列
SendDataMonitor.addSendUrl(url);
return true;
} catch (Throwable e) {
log.log(Level.WARNING, "发送数据异常", e);
}
return false;
} /**
* 触发订单退款事件,发送退款数据到服务器
*
* @param orderId
* 退款订单id
* @param memberId
* 退款会员id
* @return 如果发送数据成功,返回true。否则返回false。
*/
public static boolean onChargeRefund(String orderId, String memberId) {
try {
if (isEmpty(orderId) || isEmpty(memberId)) {
// 订单id或者memberid为空
log.log(Level.WARNING, "订单id和会员id不能为空");
return false;
}
// 代码执行到这儿,表示订单id和会员id都不为空。
Map<String, String> data = new HashMap<String, String>();
data.put("u_mid", memberId);
data.put("oid", orderId);
data.put("c_time", String.valueOf(System.currentTimeMillis()));
data.put("ver", version);
data.put("en", "e_cr");
data.put("pl", platformName);
data.put("sdk", sdkName);
// 构建url
String url = buildUrl(data);
// 发送url&将url添加到队列中
SendDataMonitor.addSendUrl(url);
return true;
} catch (Throwable e) {
log.log(Level.WARNING, "发送数据异常", e);
}
return false;
} /**
* 根据传入的参数构建url
*
* @param data
* @return
* @throws UnsupportedEncodingException
*/
private static String buildUrl(Map<String, String> data) throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
sb.append(accessUrl).append("?");
for (Map.Entry<String, String> entry : data.entrySet()) {
if (isNotEmpty(entry.getKey()) && isNotEmpty(entry.getValue())) {
// key和value不为空
sb.append(entry.getKey().trim()).append("=").append(URLEncoder.encode(entry.getValue().trim(), "utf-8"))
.append("&");
// 解码
// URLDecoder.decode("需要解码的内容", "utf-8");
}
}
return sb.substring(0, sb.length() - 1);// 去掉最后&
} /**
* 判断字符串是否为空,如果为空,返回true。否则返回false。
*
* @param value
* @return
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().isEmpty();
} /**
* 判断字符串是否非空,如果不是空,返回true。如果是空,返回false。
*
* @param value
* @return
*/
private static boolean isNotEmpty(String value) {
return !isEmpty(value);
}
}

4.程序SendDataMonitor

 package com.ibeifeng.sdk.java.logmake;

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger; /**
* 发送url数据的监控者,用于启动一个单独的线程来发送数据
*
* @author ibeifeng
*
*/
public class SendDataMonitor {
// 日志记录对象
private static final Logger log = Logger.getGlobal();
// 队列,用户存储发送url, 并发控制的Int.maxSize大小的阻塞队列
private BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
// 用于单列的一个类对象
private static SendDataMonitor monitor = null; private SendDataMonitor() {
// 私有构造方法,进行单列模式的创建
} /**
* 获取单例的monitor对象实例
*
* @return
*/
public static SendDataMonitor getSendDataMonitor() {
if (monitor == null) {
synchronized (SendDataMonitor.class) {
if (monitor == null) {
monitor = new SendDataMonitor(); Thread thread = new Thread(new Runnable() { @Override
public void run() {
// 线程中调用具体的处理方法
SendDataMonitor.monitor.run();
}
});
// 测试的时候,不设置为守护模式
// thread.setDaemon(true);
thread.start();
}
}
}
return monitor;
} /**
* 添加一个url到队列中去
*
* @param url
* @throws InterruptedException
*/
public static void addSendUrl(String url) throws InterruptedException {
getSendDataMonitor().queue.put(url);
} /**
* 具体执行发送url的方法
*
*/
private void run() {
while (true) {
try {
// take 方法是阻塞方法,队列上有数据则取出,队列上没有数据则等待
String url = this.queue.take();
// 正式的发送url
HttpRequestUtil.sendData(url);
} catch (Throwable e) {
log.log(Level.WARNING, "发送url异常", e);
}
}
} /**
* 内部类,用户发送数据的http工具类
*
* @author ibeifeng
*
*/
public static class HttpRequestUtil {
/**
* 具体发送url的方法
*
* @param url
* @throws IOException
*/
public static void sendData(String url) throws IOException {
HttpURLConnection con = null;
BufferedReader in = null; try {
URL obj = new URL(url); // 创建url对象
con = (HttpURLConnection) obj.openConnection(); // 打开url连接
// 设置连接参数
con.setConnectTimeout(5000); // 连接过期时间
con.setReadTimeout(5000); // 读取数据过期时间
con.setRequestMethod("GET"); // 设置请求类型为get System.out.println("发送url:" + url);
// 发送连接请求
in = new BufferedReader(new InputStreamReader(con.getInputStream()));
// TODO: 这里考虑是否可以
} finally {
try {
if (in != null) {
in.close();
}
} catch (Throwable e) {
// nothing
}
try {
con.disconnect();
} catch (Throwable e) {
// nothing
}
}
}
}
}

5.测试

  

6.结果

  

7.程序Test

 package com.ibeifeng.sdk.java.logmake.test;

 import java.util.HashSet;
import java.util.Random;
import java.util.Set; import com.ibeifeng.sdk.java.logmake.AnalyticsEngineSDK; public class Test {
private static Random random = new Random(System.currentTimeMillis());
private static Set<Order> orders = new HashSet<>(); public static void main(String[] args) throws InterruptedException {
Order order = null;
while (true) {
order = getSuccessOrder();
// 发送订单付款行为数据
AnalyticsEngineSDK.onChargeSuccess(order.orderId, order.memberId);
Thread.sleep(random.nextInt(500));
if (random.nextInt(100) > 75) {
// 25%的订单发生退款行为
order = getRefundOrder();
if (order != null) {
// 发送订单退款行为数据
AnalyticsEngineSDK.onChargeRefund(order.orderId, order.memberId);
Thread.sleep(random.nextInt(500));
}
}
}
} private static Order getSuccessOrder() {
while (true) {
int orderId = random.nextInt(Math.max(200000, orders.size() * 2));
Order order = new Order();
order.orderId = "orderid" + orderId;
if (!orders.contains(order)) {
// 该order是一个新的order对象
order.memberId = "ibeifeng" + random.nextInt(1000);
orders.add(order);
return order;
}
}
} private static Order getRefundOrder() {
int count = 0;
Order[] os = orders.toArray(new Order[0]);
while (true) {
count++;
int index = random.nextInt(os.length); // 获取下标位置
Order order = os[index]; // 获取对应下标位置的数据
if (!order.refund) {
order.refund = true; // 设置为已经退款操作
return order;
} else if (count >= os.length) {
// 设置最多重试次数
return null;
}
}
} static class Order {
public String orderId;
public String memberId;
public boolean refund = false; @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((orderId == null) ? 0 : orderId.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Order other = (Order) obj;
if (orderId == null) {
if (other.orderId != null)
return false;
} else if (!orderId.equals(other.orderId))
return false;
return true;
}
}
}

8.测试

  

关于js SDK的程序,java SDK的程序的更多相关文章

  1. 阿里云SDK手册之java SDK

    进行阿里云sdk开发的前提是已经购买阿里云的相关服务才能调用阿里的相关接口进行开发.最近公司在做云管控的项目,于是进行下摘录总结. 一. 环境准备 阿里云针对不同的开发语言提供不同的sdk,由于项目用 ...

  2. 094实战 关于js SDK的程序,java SDK的程序

    一:JS SDK 1.修改配置workspace 2.导入 3.Demo.html <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Trans ...

  3. Java SDK夯住(Hang)问题排查

    夯住(Hang)是指程序仍在运行,卡在某个方法调用上,没有返回也没有异常抛出:卡住时间从几秒到几小时不等. Java程序发生Hang时,应该首先使用 jstack 把java进程的堆栈信息保存下来 , ...

  4. java sdk与jdk区别

    SDK是Software Development Kit的缩写,中文意思是"软件开发工具包".这是一个覆盖面相当广泛的名词,可以这么说:辅助开发某一类软件的相关文档.范例和工具的集 ...

  5. [转]在 Eclipse 中嵌入 NASA World Wind Java SDK

    使用此开源 SDK 开发 GIS 应用程序 NASA 开发的开源 World Wind Java (WWJ) SDK 为地理信息系统(Geographic Information Systems,GI ...

  6. 经常遇到Please ensure that adb is correctly located at 'D:\java\sdk\platform-tools\adb.exe' and can be e

     遇到问题描述: 运行android程序控制台输出 [2012-07-18 16:18:26 - ] The connection to adb is down, and a severe error ...

  7. 【阿里云产品公测】消息队列服务MQS java SDK 机器人应用初体验

    [阿里云产品公测]消息队列服务MQS java SDK 机器人应用初体验 作者:阿里云用户啊里新人   初体验 之 测评环境 由于MQS支持外网访问,因此我在本地做了一些简单测试(可能有些业余),之后 ...

  8. 解决Please ensure that adb is correctly located at 'D:\java\sdk\platform-tools\adb.exe' and can be executed.

    遇到问题描述: 运行android程序控制台输出 [2012-07-18 16:18:26 - ] The connection to adb is down, and a severe error ...

  9. CentOS 使用yum命令安装Java SDK(openjdk)

    CentOS 6.X 和 5.X 自带有OpenJDK runtime environment  (openjdk).它是一个在linux上实现开源的java 平台.CentOS  yum 命令 安装 ...

随机推荐

  1. [转]Mac 科研常用软件

    转自:http://bbs.feng.com/read-htm-tid-7698336.html 我的 Mac 是 2012 年的 Pro Retina,现在主要用的是 Mac 系统,Windows ...

  2. android pcm

    Android.media package里包含声音录放的两个类AudioRecord和AudioTrack.前者用来录制,后者用来播放. 配置 pcm: int channel = AudioFor ...

  3. [深入浅出Windows 10]模拟实现微信的彩蛋动画

    9.7 模拟实现微信的彩蛋动画 大家在玩微信的时候有没有发现节日的时候发一些节日问候语句如“情人节快乐”,这时候会出现很多爱心形状从屏幕上面飘落下来,我们这小节就是要模拟实现这样的一种动画效果.可能微 ...

  4. PHP递归小例子

    $news = M('productbase'); function digui($idd){ $child=M('navclass')->where('f_id='.$idd)->sel ...

  5. wxPython学习

    http://www.cnblogs.com/coderzh/archive/2008/11/23/1339310.html 一个简单的实例: #!/usr/bin/python import wx ...

  6. __attribute__ 变量对齐

    http://blog.163.com/sunm_lin/blog/static/9192142200741533038695/ 一.   __attribute__ ((aligned (n))) ...

  7. Java EE 学习总结

    1.Java EE WEB 工程项目文件结构 组成:静态HTML页.Servlet.JSP和其他相关的class: 每个组件在WEB应用中都有固定的存放目录. WEB应用的配置信息存放在web.xml ...

  8. Linux下rar命令详解

    Linux下rar命令详解 用法: rar <命令> -<选项1> ….-<选项N> < 操作文档> <文件…> <@文件列表…> ...

  9. About_PHP

    所谓PHP: 超文本预处理器 外文名称 Hypertext Preprocessor 编程范型 面向对象.命令式编程 php就是比js更高端的一种语言. 语法有两种: <?php      ?& ...

  10. 【LeetCode】16. 4Sum

    题目:Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = ...