一个简单的HttpClient多线程工具类

近期发现某项目运行一段时间后,端口占用非常多,导致程序运行异常。

经查发现里面有使用HttpClient的方式如下:

HttpClient client = new HttpClient();

…..

client.executeMethod(method)

该代码在服务器不主动关闭连接的情况下会发起大量的网络请求导致资源耗尽。

大部分人使用HttpClient都是使用类似上面的代码,包括Apache官方的例子也是如此。

具体大家可以移步:http://seanhe.iteye.com/blog/234759 作者做了较详细的分析。

考虑到接口的是定期获取采集数据的,访问比较频繁,连接也无需关闭,顺手写了一个简单HttpClient连接池。

package com.stock.util;

import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;

 

/**
 * 多线程HTTP 调用工具类 <br>
 * Date: 2015-7-15
 *
 * @author snow2back
 * @version 1.0
 *
 */
public class HttpUtil {
	private static Queue<HttpClient> clientQueue = new LinkedBlockingDeque<HttpClient>();

	private static int queueSize = 0;

	/**
	 * 最大连接数
	 **/
	private static final int MAX_QUEUE_SIZE = 3;

	static ThreadLocal<HttpClient> local = new ThreadLocal<HttpClient>();

	public static HttpClient getClient() {
		// System.out.println(Thread.currentThread().getId()+"获取httpclient");
		HttpClient client = null;
		synchronized (clientQueue) {
			client = local.get();
			if (client == null) {
				// 获取一个
				if (clientQueue.size() > 0) {
					client = clientQueue.poll();
				} else {
					if (queueSize <= MAX_QUEUE_SIZE) {
						queueSize++;
						client = new HttpClient();
						client.getHttpConnectionManager().getParams()
						        .setSoTimeout(5000);
						client.getHttpConnectionManager().getParams()
						        .setConnectionTimeout(10000);
					} else {
						try {
							clientQueue.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						client = getClient();
					}
				}
				local.set(client);
			}
		}
		return client;
	}

	public static void release() {
		synchronized (clientQueue) {
			// System.out.println(Thread.currentThread().getId()+"归还httpclient");
			// 归还HTTPCLient
			clientQueue.add(local.get());
			local.remove();
			clientQueue.notify();
		}
	}

	public static final String fetchUrl(String url) {
		String rep = "";
		// ajax 数据抓取
		GetMethod method = new GetMethod(url);
		method.addRequestHeader("Accept",
		        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		method.addRequestHeader("Accept-Language:", "zh-CN,zh;q=0.8");
		method.addRequestHeader(
		        "User-Agent",
		        "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36");
		try {
			// 设置http代理
			// getClient().getHostConfiguration().setProxy("10.119.6.6", 8886);
			int status = getClient().executeMethod(method);
			if (status == 200) {
				rep = method.getResponseBodyAsString();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		release();
		return rep;
	}

	public static void main(String args[]) {
		String resp = HttpUtil
		        .fetchUrl("http://10.119.0.17/PhdSvervice/TagTime.asmx");
		System.out.println(resp);
	}
}

重新部署,程序稳定运行,问题得到解决~

大家也可以考虑更换默认的ConnectionManager为MultiThreadedHttpConnectionManager,也可以达到一样的效果。

可以看下这篇文章:http://blog.csdn.net/kobejayandy/article/details/16921265

JAVA-Jna在64位系统下调用32位DLL

最近有个项目需要调用第三方的dll,之前没接触过,花了点时间进行调研。

基本上有jacob, jawin,jni,jna等几种方法,大致都试了一试,jna算是简单易用就它了(期间发现介绍比较详细的文章一篇 传送门)。

本人机器是32位的,应用jna的jar包,将要调用的test.dll,放到系统变量目录下(一般c:\windows\system32即可)。

写个这样的接口:

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface TestInterface extends Library {
	TestInterface INSTANCE = (TestInterface) Native.loadLibrary("test", TestInterface.class);

	public int test(byte[] arg1, byte[] arg2, int arg3);

}

之后的使用异常简单:

 TestInterface.INSTANCE.deTdata(databuffer, hid, databuffer.length);

一切ok,测试了下也没有问题。
直到拿去部署到64位server2008服务器上,dll一拷,war包一上,半天系统没正常运行,日志提示:
java.lang.UnsatisfiedLinkError: Unable to load library xxxx。

一想dll也拷贝过去了,没准是dll是32位的dll不支持64位系统。
拿PEiD,Depends等乱七八糟的破解工具一看VC6.0写的Win32 GUI DLL啊,还引用了KERNEL32.DLL,难不成我反汇编下这个dll把里面的代码还原出来啊,不要说汇编不会,C++ 也忘光了,没辙了。

服务器上闲逛着,无意间发现任务管理器上有几个32位的程序xxxx*32.exe,我想你32位exe能跑我32位dll怎么不能跑。
网上下了32位的jdk装了,把dll放到了sysWoW64目录下,觉得不保险regsvr32 test.dll注册了下,提示错误不理会, 之后修改tomcat的文件catalina.bat,services.bat中的JAVA_HOME切换到这个JAVA_HOME2(指向32位jdk),运行startup.bat。

启动后任务管理器中进程变成了java*32.exe了,32位的dll调用一切正常。

这样做的坏处是我这个应用只能用1.5个G的内存了,多了不支持。

我这里不涉及另外乱七八糟的dll依赖,大家碰到类似情况,建议先用depends工具看看有没有别的dll依赖,环境缺啥补啥。

漫长的战役

碎语:

工作的时候,突然会想起来是时候应该写写博客总结下自己的所学了,但是一到休假,总是懒得动手,而平常的时候工作任务比较重,拖着拖着,博客已然是一副被弃用的样子,自己都看不下去。进公司已经一段时间了,经手了几个项目,各个阶段的都有,有大有小,有简有易,开发当中真觉得当一个coder的不容易,一整天下来写程序,调程序,写程序,调程序反复循环,曾经我一休息都是直接窝电脑前,现在下了班都不怎么想看电脑,看的眼睛都累。说来惭愧,由于过多注重开发,倒很少看书感觉自己进步不多,这真心不是个好现象。买了些自认为有帮助的书,努力进阶!

工作后感觉对于自身而言,提升最快的在于对于jQuery的使用,日常工作中使用jQuery操作元素的状态,ajax数据更新,以及一些插件的应用,不得不说其带给了我太多太多的便利,个人感觉jquery使用上面的的重点在于选择器的使用、元素状态修改、事件的响应、ajax这几个点上面,日常工作中多的也是在这上面。

随着时间的推移,对于不会的技术心态也有了变化,不会怎么办?学呗,没有一个人是一开始就会的,之前只知道SSH,从没用过什么LigerUI,flex,siteMesh,activeMq,基于注解的配置,报表,hibernate的高级特性等等之类,但是经过一段时间的使用渐渐也能上手了,不要求全部懂,但是要求的东西总是能够做出来了。如果有不懂,自己调研,问问谷歌百度,再不行问问老员工,每次遇到问题都是一次成长,下次遇到类似的问题基本都可以顺利解决。

几个项目下来,感觉项目初期是最麻烦最难熬的,一开始,项目里面什么都没有,只有个空架子,工具类啊,插件啊,公共的实现啊什么的,统统都要自己来写。好歹还有些老项目可以借鉴,不至于一穷二白,一个个都自己敲出来。开发步入正轨之后就好过多了,开发完成后复制粘贴复制粘贴,复制粘贴多了闲麻烦就重构下,通用功能基本都不用再操心了。

接触的多了,反而觉得自己懂的少了,下阶段打算学习下java高级特性、虚拟机、springMVC框架,针对自身不足进行改进,为成为大牛而奋斗!

 

2013年读书计划

近期读书计划

学无止境,消除惰性。

1.Android开发完全讲义(第二版)  10%

2.Core Java I  0%

3.Core Java II  0%

4.JAVA并发编程实战  10% (基本概念不是很清楚,补下内存模型内容)

5.深入理解 Java 虚拟机 (JVM 高级特性与最佳实践) 50%

如何在iframe之间共享数据

近期开始工作了,接手的第一个项目是已近开发完成的,后期有些bug和操作方式要进行修改,我主要负责修改操作方式。

原来系统使用的是用下拉框的方式来选择项目,这种方式简单方便,但是当数据很多的时候,不仅会降低系统运行效率,在上千条的数据中选择记录基本是一件不可能的事情,针对这个问题,我们有两种解决方法::第一种,使用autocomplete插件,用户数据少量数据,可以把数据补全。第二种,专门弹出 一层来选择需要选择的内容,弹出层可以分页、搜索。

我们选择了后一种方法,这就涉及到了iframe之间数据共享的问题。

实现的主要思路如下(点击图片查看大图)

iframe之间共享数据

主框架页弹出两个框架页,子框架页通过主框架页来共享数据,项目使用了ligerUI。

主框架页

	// 流程中弹出窗处理
	function popWindow(url, title, width, height) {
        $.ligerDialog.open({
			url : url,
          	height : height,
          	title : title,
          	width : width,
          	close : function(dialog){
				dialog.frame.$("#classForm").validationEngine("hideAll");
            },
            buttons : [{
              	text : '保存',
              	onclick : function(item, dialog) {
                	var carForm = dialog.frame.$("#classForm");
                	if(carForm.validationEngine("validate")){
                  		//验证通过 保存表单内容
                  		dialog.frame.saveInfo();
                  		// 关闭窗口
                  		dialog.close();
               		}
              	}
            }]
		});
	}

	var monitorEquipId = "";
	var monitorEquip = "";

	function setMonitorEquipInfo(id, name) {
		monitorEquipId = id;
		monitorEquip = name;
	}

	function getMonitorEquipId() {
		return monitorEquipId;
	}

	function getMonitorEquip() {
		return monitorEquip;
	}
 

信息填写页

// 选择监测设备
	function showSelectEquip() {
		var id = $$('#monitorequipid').val();
		var name = $$('#monitorequip').val();
		var config = {
			url : "/baseinfo/abilityChooseAction!chooseEquip.action?polltype="
										+ parent.polltype,
			title : "选择监测设备",
			height : 500,
			width : 600,
			buttons : [ {
				text : "确定",
				onclick : function(item, dialog) {
                                        // 点击确定后,从主框架页获取数据
					$$('#monitorequipid').val(parent.getMonitorEquipId());
					$$('#monitorequip').val(parent.getMonitorEquip());
					dialog.close();
				}
			} ]
		};
                 //调用主框架页的弹出
		parent.popInfoWindow(config);
	}

信息选择页面

	function chooseOk(id, name) {
		parent.setMonitorEquipInfo(id, name);
	}

JAVA EE 学习笔记(四)–SSH WEB程序员的必修课之hibernate

碎语:

很久没上博客,突然发现博客多了不少评论,想起建站时候听到的一句话,只要你建博客,肯定会有垃圾评论,无论你的水平如何,应验了。

想起建博的初衷,记录下成长的点点滴滴,回首过去,展望未来,激励自己去不停进步,总有一天我会从一个菜鸟渐渐变成一个高手,而我这走过的路,也可以帮助到一些在学习路上的朋友。

学习整理:

SSH三大框架可以说是一个合格的WEB程序员的必修课,Struts,hibernate,spring各施其职,可以说是解放了程序员。我们为什么用框架,我个人目前的理解是:1,它让开发更加便捷。2,它让程序更有效率。

Hibernate部分:

在这三个框架中,hibernate可以说是最复杂的,学习过后小总结一下。

hibernate的作用主要是提供一个ORM映射,让从数据库取出数据变得更加方便,省略了一次次无聊的get。

hibernate主要适用于oa系统,行业软件(crm,财务管理),不适合联机数据查询分析为主的系统,对性能要求高的,也不适用。

大致使用:

在hibernate.cfg.xml中配置数据库的信息,配置对应对象的*.hbm.xml文件,建立关系映射。

sessiongFactory->session->开启事务->获取query->进行操作->提交事务->关闭资源

可以使用Myeclipse给我们生成的一个HibernateSessionFactory.java来进行操作,建议去看下其具体实现,很有好处。

HQL:这个是重点了,基本上都是在和hql文打交道。

hql也支持sql中常见的distinct, between,in / not in, group by ,having 等语句,写的时候注意要基于对象来写。

使用hql来实现分页可以说是非常简单,只要设定每页数量 setMaxResult,和起始位置setFirstResult就可以了。

给一个分页的示例

/**
	 * queryVo 中除了带有查询字段外,还有 分页大小,当前页,总记录数,总页数等信息
	 * @param queryVo
	 * @return
	 */
public List<ActiveVo> findActiveVoListByQry(ActiveQryVo queryVo){
		Session session = null;
		List<ActiveVo> result = null;
		/**
		 * 查询条件
		 */
		List<Object> conditions = new ArrayList<Object>();
		/**
		 * 查询语句 / 查询总记录数 /拼接条件
		 */
		StringBuilder hql = new StringBuilder();
		StringBuilder rowsHql = new StringBuilder();
		StringBuilder sb = new StringBuilder();
		hql.append("select new com.cares.vo.ActiveVo(id,activeName,startDate,endDate,sponsors,state,creater,createTime) from TblActive where 1=1");
		rowsHql.append("select count(*) from TblActive where 1=1");
		// 拼接hql
		if (!StringUtil.isEmpty(queryVo.getActiveName())) {
			sb.append(" and activeName like ?");
			conditions.add("%"+queryVo.getActiveName()+"%");
		}
		if (queryVo.getStartDate()!=null) {
			sb.append(" and startDate >= ?");
			conditions.add(queryVo.getStartDate());
		}
		if (queryVo.getEndDate()!=null) {
			sb.append(" and endDate <= ?");
			conditions.add(queryVo.getEndDate());
		}
		if (!"-1".equals(queryVo.getState())){
			sb.append(" and state = ?");
			conditions.add(queryVo.getState());
		}
		/**
		 * 拼接
		 */
		hql.append(sb);
		rowsHql.append(sb);
		try {
			session = HibernateSessionFactory.getSession();
			Query query = session.createQuery(hql.toString());
			Query queryRow = session.createQuery(rowsHql.toString());

			for (int i = 0; i < conditions.size(); i++) {
					Object obj = conditions.get(i);
					query.setParameter(i, obj);
					queryRow.setParameter(i,obj);
			}
			// 设定总记录数
			int n = ((Long)queryRow.iterate().next()).intValue();;
			queryVo.setAllSize(n);

			// 设定分页
			query.setFirstResult((queryVo.getCurPage()-1)*queryVo.getPageSize());
			query.setMaxResults(queryVo.getPageSize());
			result = query.list();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			HibernateSessionFactory.closeSession();
		}
		return result;
	}
关系映射:主要有三种
many to one  会生成 外键的一个对象(可以配置many to one 特例,一对一)
one to many  会生成 对象的集合
one to one  一对一

缓存:

使用query接口查询数据,是不会从缓存中获取数据的,但是其获取的数据会放到缓存中供get/load来使用。

hibernate有二级缓存,不会默认开启,要手动配置缓存,有挺多缓存框架可以用,以下是OScache的示例,其它配置大同小异。

<property name="cache.use_second_level_cache" >true</ property>
<property name="cache.provider_class" >org.hibernate.cache.OSCacheProvider</ property>
<property name="hibernate.generate_statistics" >true</ property>
<class-cache usage="read-only" class ="com.cares.pojo.TblInterest" />
解决懒加载问题
建议many-to-one可以配置下
解决方法:
1.扩展session作用域(sessionInView)
2.配置xml 中对应的对象lazy 为 false
3.显示初始化对象集合hibernate.initialize()
4.ssh整合的时候 可以注解方式 (这个没使用过)
主键生成策略,手册第五章
①increament:用于long,short,int类型生成唯一标识。// 单进程状态可以使用
<id name=”id” type=”java.lang.String”>
<generator />
<id>
②identity:需要数据库支持,mysql ,sqlserver。
③sequence:db2,oracle可以使用。
④native:根据底层数据库,选择identity,sequence,hilo中的一种。
⑤hilo:高地位算法
<id name=”id” type=”java.lang.Integer” column=”ID”>
<generator>
<param name=”table”>my_hi_value</param>
<param name=”column”>next_value</param>
</generator>
</id>
⑥uuid
128位2
⑦assigned
用户自己设定的主键
(8)复合主键
(9)foreign
sequence / identify / uuid / hilo
使用原则
Oracle 主键是 int/long/short  使用sequence
          主键是字符串,uuid/assigned
Mysql  int/long/short   使用increament
          字符串,uuid/assigned

jsp File browser 1.2(jsp网马)解决中文乱码问题

jsp File browser 1.2这个工具还是比较好用的,支持简单的文件操作,作者在写的时候没有考虑到在非英文系统下的乱码问题,导致很多操作都无法实现,近期正好有空,就做了乱码修复。

简单来看下:

作者在写的时候直接把编码写成了ISO-8859-1,压根没想中文正常显示的想法吧。。

我们可以全部设定编码为UTF-8来解决乱码问题,但是他在代码里都只直接使用request.getParameter(“key”)方式来进行数据的获取的,如果是get提交数据上去的话,不用说,数据肯定都是不正常的,而且作者使用post方式提交文件路径(文件路径的URL在返回的时候进行了URLEncode,但是没有指定编码)。

简单想了下解决办法:

1.针对post方法提交数据大部分都是正常的,不做处理

2.针对get提交的普通数据,要进行返回到字节码,再重新编码的过程(服务器用iso8859错误解码了)。

3.URLEncode过的数据,使用post传回来,这个要进行url解码。

具体实施:

编码统一使用UTF-8,URLEncode的时候指定编码。URLDecode的时候也使用指定编码。

使用一张HashMap来保持进行乱码处理后的数据,然后要获取数据的时候从hashmap里面去取。

	// 自定义获取对象方法
	static String getParameter(String name){
		String[] obj = (String[])hm.get(name);
		if(obj!=null &amp;amp;&amp;amp; obj.length&amp;gt;=1){
			return obj[0];
		}
		return null;
	}
	static String[] getParameterValues(String name){
		String[] values = (String[]) hm.get(name);
		return values;
	}

       // 定义个hashmap,来放所有的数据
	hm = new HashMap();
	// 如果是post的话直接拷贝
	if(request.getMethod()==&amp;quot;POST&amp;quot;){
		Enumeration enumeration = request.getParameterNames();
		while(enumeration.hasMoreElements()){
			String nameStr = enumeration.nextElement().toString();
			String values[] = request.getParameterValues(nameStr);
			if(&amp;quot;selfile&amp;quot;.equals(nameStr)){
				//因为这个数据是在服务器编码 ,传给浏览器,然后浏览器post回来的
				for(int i=0;i&amp;lt;values.length;i++){
					values[i] = URLDecoder.decode(values[i],ENCODE);
				}
			}
			hm.put(nameStr,values);
		}
	}else{
		// 遍历全部参数转码  iso-8859-1  到 utf-8 通过url提交 被服务器以iso-8859-1解码了
		Enumeration enumeration = request.getParameterNames();
		while(enumeration.hasMoreElements()){
			String nameStr = enumeration.nextElement().toString();
			String values[] = request.getParameterValues(nameStr);
			// 遍历转换
			for(int i=0;i&amp;lt;values.length;i++){
				values[i] = new String(values[i].getBytes(&amp;quot;iso-8859-1&amp;quot;),ENCODE);
			}
			hm.put(nameStr,values);
		}
	}
// 使用的时候 这么使用
request.setAttribute(&amp;quot;dir&amp;quot;, getParameter(&amp;quot;dir&amp;quot;));

这么修改以后添加删除,命令行的使用都可以支持中文了。
点击下载:adminfix

独辟蹊径解决win7 64位windows installer无法启动的问题。

独辟蹊径解决win7 64位windows installer无法启动的问题。
近期安装软件的时候,软件无法安装提示windows installer服务无法使用。
图片1
运行services.msc进去一看 windows installer 无法启动,提示访问被拒绝。
网上找了各种方法:
1.修改注册表
2.重装windows installer(这个是扯淡,4.5完全是xp用的,win7用的版本还没出呢)
3.用系统盘进行恢复(咱没盘)

我试了试用命令行的方式启动,依旧是拒绝访问。
怀疑是misexec.exe文件被病毒感染了,提取了一个新的文件覆盖,问题依旧。

又怀疑访问被拒绝可能是和UAC和NTFS文件权限有关,改了半天,无果而终。

网上逛的时候,发现有人windows installer服务的选项丢失,好奇点了注册表进去。
发现新大陆了。
在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\msiserver下面
发现有ImagePath填写的就是服务的启动方式。
话不多说,直接把msiexec.exe文件从system32里面拷贝到了别的地方,将ImagePath改成了新的位置。
修改路径
这个时候再去服务里面看的时候,路径已经改成了新路径了。启动一下,成功了!
回services.msc检查
赶紧去安装软件,使用一切正常~各位要遇到这个问题不妨试试我这个办法~

JAVA EE 学习笔记(三)–JavaScript让人既爱又恨

碎语:

近期发生了很多事情,心情很是烦躁。一是实习方面,很多朋友都出去实习了,实习工资开得还挺高,虽然我是本着实习是学习的心态,但是这也是要能够基本温饱的情况,年纪挺大了,老问父母要钱也听不好意思。实习的话还有纠结的则是实习的公司的选择,我有信心让大公司看上我,我各方面都还算得上优秀,大学期间挺多时间去学习计算机相关的知识,但是在毕业刚刚开始的几年是最关键的,在大公司优厚的待遇和小公司有一展拳脚的空间,我有些难以取舍,在我的个人规划中近几年我会经历很多家公司,直到时机成熟的时候,成立自己的公司。现在的问题则是从哪里开始更加有利于日后的发展,这个问题我觉得有必要请教下前辈的经验了。

笔记:

Javascript是一门神奇的语言,让人既爱又恨(这很多东西都不一样啊),总的来说,它的作用是操作DOM,给用户更友好的交流体验。

先晒下学习成果吧,自己写的一个弹出层示例。

自己写的alert提示框

这个重点是写个利用createElement创建元素,配合一个遮罩层来实现。

tips:还有prompt和confirm如果要写的话无法通过阻塞方式实现的,只能通过回调函数(N多资料后的结论)。

以下则是我整理出来的一些重点~

数组的定义

var arr = new Array();
var arr = new Array(3);
var arr = new Array(“1″,”2″,”3”);
var arr = [“1″,”2”];

判断条件

等于== 全等于=== 全等于要求类型也相等

函数定义方式

1.变量定义:
var getNumber = new function(){};
2.直接定义 function a(){}

函数调用方式:

1.作为事件处理程序调用(onclick = “”)。

2.绑定事件处理程序。
document.all.BUTTON_name.click();
3.全局调用 (直接写代码,基本没怎么用的)

4.元素对象属性字符串中调用。//不怎么看到
<script language=”javascript” for=”document” event=”oncontextmenu”>
window.event.returnValue = false;
</script>

document all 集合的使用方法

id name index tagName
all[id] all[name] all[index]
all.item(index)与上面等效
//是tags方法不是集合
all.tags(tagName)[0].tagName

以上方法已经被替代掉了,用下面的吧
getElementById
getElementsByName
getElementsByTagName

tips:火狐调试发现document.getElementById提示找不到对象,Javascript最好等dom树建立后再去运行。

tips:  不要乱用iframe,建立DOM树慢了一个数量级,会消耗连接,延缓onload事件,用户的感觉就是很慢。

表单的使用:

调用:
1.表单名 document.form1.username.value
2.对象集合 document.forms[]
form1.username //通过name直接应用
两个重要方法:
1.form.submit();
2.form.reset();
两个重要的事件句柄
1.onreset
2.onsubmit
提交参数设置:
form.method = “post/get”
form.action =”mailto:[email protected]
元素操作
focus //设置焦点到需要修改项
select

Cookie的使用

设置:
document.cookie = “id=12”;
document.cookie = “ff=teset”;
提取
arr.split(;);
str.indexOf() 配合substring()来截取
加密escape unescape
有效期
date.setTime(date.getTime() + n*3600*24*1000);
document.cookie = name + “=” uname + “;expire=” + date.toGMTString();

javascript innerHTML、outerHTML、innerText、outerText的区别
HTML是操作HTML代码 Text操作文本//特殊字符会自动转义
inner是标签内部的 outer操作的是标签本身

以下内容我觉得是目前Javascript的重中之重

AJAX重要摘记:
XMLHttpRequest对象:
创建不同浏览器不一样,通用方法如下:

function ajaxFunction()
{
var xmlHttp;
try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("您的浏览器不支持AJAX!");
return false;
}
}
}
}

XMLHttpRequest对象的属性:
一个例子来说明:

if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;
xmlhttp.open("GET",url,true);
xmlhttp.send(null);
}
function state_Change(){
if (xmlhttp.readyState==4)
{// 4 = "loaded"
if (xmlhttp.status==200)
{// 200 = OK
// ...our code here...
}
else
{
alert("Problem retrieving XML data");
}
}
}

设置事件句柄:
事件句柄:
onreadystatechange
每次 readyState 属性改变的时候调用的事件句柄函数。当 readyState 为 3 时,它也可能调用多次。

readyState:
状态 名称 描述
0 Uninitialized 初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。
1 Open open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。
2 Sent Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3 Receiving 所有响应头部都已经接收到。响应体开始接收但未完成。
4 Loaded HTTP 响应已经完全接收。
status
由服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 “Not Found” 错误。
当 readyState 小于 3 的时候读取这一属性会导致一个异常。
使用基本流程:
1.绑定onreadystatechange
2.初始化请求参数open()
3.send()提交
如果之前调用的 open() 参数 async 为 false,这个方法会阻塞并不会返回,
直到 readyState 为 4 并且服务器的响应被完全接收。否则,如果 async 参数为 true,或者这个参数省略了,send() 立即返回.
4.onreadystatechange绑定函数中的操作
xmlhttp 对象
xmlhttp.readyState == 4 //onload
xmlhttp.status == 200 //ok readyState must be 4
xmlhttp.responseText;

JavaScript,调用函数的5种方法

这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助!

JavaScript,调用函数的5种方法
一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性, 当我们选择面对它的时候,这将成为我们前进的阻碍.
作为初学者,我们来测试五种函数调用的方法,从表面来看我们会认为那些函数与C#中函数的作用非常相似,但是我们一会儿可以看到还是有非常重要的不同的地方的,忽视这些差异无疑会导致难于跟踪的bug。首先让我们创建一个简单的函数,这个函数将在将在下文中使用,这个函数仅仅返回当前的this的值和两个提供的参数.

 

1
2
3
4
5
<script type="text/javascript">
function makeArray(arg1, arg2){
    return [ this, arg1, arg2 ];
}
</script>

最常用的方法,但不幸的,全局的函数调用
当我们学习Javascript时,我们了解到如何用上面示例中的语法来定义函数。
,我们也知道调用这个函数非常的简单,我们需要做的仅仅是:

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
makeArray('one', 'two');
// => [ window, 'one', 'two' ]
Wait a minute. What's that window
alert( typeof window.methodThatDoesntExist );
// => undefined
alert( typeof window.makeArray);
// =>
window.makeArray('one', 'two');
// => [ window, 'one', 'two' ]

我说最普遍的调用方法是不幸的是因为它导致我们声明的函数默认是全局的.我们都知道全局成员不是编程的最佳实践.这在JavaScript里是特别的正确,在JavaScript中避免使用全局的成员,你是不会为之后悔的.

JavaScript函数调用规则1

在没有通过明确所有者对象而直接调用的函数中,如myFunction(),将导致this的值成为默认对象(浏览器中的窗口)。

函数调用
让我们现在创建一个简单的对象,使用 makeArray函数作为它的一个方法,我们将使用json的方式来声明一个对象,我们也来调用这个方法

 

 

1
2
3
4
5
6
7
8
9
10
11
12
//creating the object
var arrayMaker = {
    someProperty: 'some value here',
    make: makeArray
};
//invoke the make() method
arrayMaker.make('one', 'two');
// => [ arrayMaker, 'one', 'two' ]
// alternative syntax, using square brackets
arrayMaker['make']('one', 'two');
// => [ arrayMaker, 'one', 'two' ]

 
看到这里的不同了吧,this的值变成了对象本身.你可能会疑问原始的函数定义并没有改变,为何它不是window了呢.好吧,这就是函数在JSavacript中传递的方式,函数在JavaScript里是一个标准的数据类型,确切的说是一个对象.你可以传递它们或者复制他们.就好像整个函数连带参数列表和函数体都被复制,且被分配给了 arrayMaker里的属性make,那就好像这样定义一个 arrayMaker:

 

1
2
3
4
5
6
var arrayMaker = {
    someProperty: 'some value here',
    make: function (arg1, arg2) {
        return [ this, arg1, arg2 ];
    }
};

 

JavaScript函数调用规则2

在一个使用方法调用语法,像 obj.myFunction()或者 obj[‘myFunction’](),这时this的值为obj

这是事件处理代码中bug的主要源头,看看这些例子

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<input type="button" value="Button 1" id="btn1"  />
<input type="button" value="Button 2" id="btn2"  />
<input type="button" value="Button 3" id="btn3"  onclick="buttonClicked();"/>
<script type="text/javascript">
function buttonClicked(){
    var text = (this === window) ? 'window' : this.id;
    alert( text );
}
var button1 = document.getElementById('btn1');
var button2 = document.getElementById('btn2');
button1.onclick = buttonClicked;
button2.onclick = function(){   buttonClicked();   };
</script>

 

点击第一个按钮将会显示”btn”因为它是一个方法调用,this为所属的对象(按钮元素) 点击第二个按钮将显示”window”因为 buttonClicked是被直接调用的(不像 obj.buttonClicked().) 这和我们第三个按钮,将事件处理函数直接放在标签里是一样的.所以点击第三个按钮的结果是和第二个一样的.
使用像jQuery的JS库有这样的优点,当在jQuery里定义了一个事件处理函数,JS库会帮助重写this的值以保证它包含了当前事件源元素的引用,

//使用jQuery
$(‘#btn1’).click( function() {
alert( this.id ); // jQuery ensures ‘this’ will be the button
});

jQuery是如何重载this的值的呢?继续阅读
另外两个:apply()和call()
你越多的使用JavaScript的函数,你就越多的发现你需要传递函数并在不同的上下文里调用他们,就像Qjuery在事件处理函数里所做的一样,你往往经常需要重置this的值.记住我告诉你的,在Javascript中函数也是对象,函数对象包含一些预定义的方法,其中有两个便是apply()和call(),我们可以使用它们来对this进行重置.

 

1
2
3
4
5
var gasGuzzler = { year: 2008, model: 'Dodge Bailout' };
makeArray.apply( gasGuzzler, [ 'one', 'two' ] );
// => [ gasGuzzler, 'one' , 'two' ]
makeArray.call( gasGuzzler,  'one', 'two' );
// => [ gasGuzzler, 'one' , 'two' ]

这两个方法是相似的,不同的是后面的参数的不同,Function.apply()是使用一个数组来传递给函数的,而Function.call()是将这些参数独立传递的,在实践中你会发现apply()在大多数情况下更方便.

JSavacript函数调用规则3

如果我们想在不复制函数到一个方法而想重载this的值的时候,我们可以使用 myFunction.apply( obj ) 或 myFunction.call( obj ).

构造器
我不想深入研究在Javascript中类型的定义,但是在此刻我们需要知道在Javascript中没有类,而且任何一个自定义的类型需要一个初始化函数,使用原型对象(作为初始化函数的一个属性)定义你的类型也是一个不错的主义,让我们来创建一个简单的类型
//声明一个构造器

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function ArrayMaker(arg1, arg2) {
    this.someProperty = 'whatever';
    this.theArray = [ this, arg1, arg2 ];
}
// 声明实例化方法
ArrayMaker.prototype = {
    someMethod: function () {
        alert( 'someMethod called');
    },
    getArray: function () {
        return this.theArray;
    }
};
var am = new ArrayMaker( 'one', 'two' );
var other = new ArrayMaker( 'first', 'second' );
am.getArray();
// => [ am, 'one' , 'two' ]

 

一个非常重要并值得注意的是出现在函数调用前面的new运算符,没有那个,你的函数就像全局函数一样,且我们创建的那些属性都将是创建在全局对象上(window),而你并不想那样,另一个话题是,因为在你的构造器里没有返回值,所以如果你忘记使用new运算符,将导致你的一些变量被赋值为 undefined.因为这个原因,构造器函数以大写字母开头是一个好的习惯,这可以作为一个提醒,让你在调用的时候不要忘记前面的new运算符.
带着这样的小心,初始化函数里的代码和你在其他语言里写的初始化函数是相似的.this的值将是你将创建的对象.

Javascript函数调用规则4

当你将函数用作初始化函数的时候,像MyFunction(),Javascript的运行时将把this的值指定为新建的对象.

我希望理解各种函数调用方式的不同会使你的Sjavacript代码远离bugs,有些这样的bug会确保你总是知道this的值是避免他们第一步。

转自:http://lhb25.cnblogs.com/