jsp的request及增进研究【5】--系列总结与最新源码公开
2013-05-01 11:26
447 查看
经过一系列的提出问题解决问题,还真觉得自己似乎懂了不少。
欢迎大家指出我的错漏指出。
Q:java里面可以不可以直接获取get(url)参数及post参数?
A:不可以,java里面的标准api获取用户请求的方式有request.getParameter(),对于查找一个参数名称为“username”的参数,getParameter的执行过程是先查找post里面有没有这个参数,没有的话查找url里面有没有这个参数,即是说,post里面的参数可能会被url里面的参数覆盖,这个是严重的基本问题。网上一般的解决方法是:通过request.getMethod判断是采用get还是采用post来提交,但本人认为不可取,原因在于:当遇到这个例子:form method=“post”
action="add.jsp?username=user1&pwd=pwd1"
还是无效,有主张采用servlet的doget dopost方法的,个人认为还是无法解决第一种方式的问题,而且每写一个servlet要遵循一堆规则还要注册路径,相当麻烦;我认为只能自己开发底层的api解释用户提交的表单,里面的get参数,post参数及文件上传。
Q:html里面提交参数有多少种方式,具体格式如何,流程如何,怎么样解释数据?
A:html提交参数的话具体来说有两大分类,
一、通过URL提交数据(form的get方式和直接填写url地址是一样的,譬如:article.jsp?articleid=785这种方式。),一般格式为:article.jsp?id=78&categoryid=7,浏览器会按照
里面的contentType来对url编码,服务端会采用默认的编码(譬如:tomcat会采用:iso8859-1来解码数据),服务端里面调用的reqeuset.getQueryString是已经经过了解码而得到的数据,通常对于英文及数字而言,这个过程不会出现乱码,但是,对于中文而言,譬如:serch.jsp?namelike=护肤品&price=不限 之类的网址,各个浏览器会先转换成为中间字符串,再通过cotentType规定的字符集编码,譬如:chrome会转换成为%xxx形式的只包含数字字母及%符号的16进制字符串形式,firefox类似,ie则不知所谓,所以建议,假如使用带有特殊字符及中文的网址,请统一用javascript自带的encodeURL函数来转换,然后到服务端用URLDecoder.decode(字符串."提交的编码")进行转换。
这样不会出现乱码。
二、通过form的post提交数据,其中可以选择三种enctype方式,分别是:application/x-www-form-urlencoded,mutipart/form-data,text/plain,其中application/x-www-form-urlencoded为默认方式,三种数据格式分别如下:
1、application/x-www-form-urlencoded
格式与get,url一致,不同的是参数存放的位置,get,url都直接放在url后面,而这种方式及(所有post的数据)都放在数据正文里面,里面的解码与get,url一致。
2、mutipart/form-data
这种协议是用于上传文件的,该http里面包含有一个content-Type,里面指示了这个协议及协议采用的边界,如下面格式:
java: F:\java项目\核心项目\Easis\src\com\alibaba\fastjson\serializer\JSONSerializer.java:51: -source 1.3 中不支持泛型
边界用于确认分隔开每一个form data,其中:"--"+边界+"\r\n"用于分隔,"--"+边界+"--"+"\r\n"是结束符号,
每一个form data里面,用"\r\n\r\n"分隔开参数名称(假如是文件的话还有一个文件名称及contentType),及参数内容(假如是文件的话,就是文件内容)了。
格式如下:(详情可以参看我写的系列文章)
对于表单post数据的三种方式而言,第一种方式与url的格式及解释方式都一样,就存放位置不一样,可以用相同的规则进行解释(URLDecoder.decode()方法);
而第二种及第三种表单都是直接编码,并且 服务端会根据自己的默认解码方式(tomcat的是is9588-1)来解码,这时候为了避免乱码,我们需要利用new string(string.getBytes('iso9588-1','表单的编码格式')来获得正确的数据。
Q:html表单名称相同的checkbox数组是如何传递数据的?
A:譬如: <input type="checkbox" checked value="ok" name="checkbox1">选框一
<input type="checkbox" checked value="no" name="checkbox1">选框2
假如两个都选择的话,那么对于 get,url及application/x-www-form-urlencoded方式而言,他们的参数形式都是:
checkbox1=ok&checkbox1=no
其他参数方式类似,即会用相同name的参数出现。
据此可以制定获取数组的规则。
下面是一些代码:
【这个代码是理论阶段完成的,进行部分实现通过,但是没有经过应用阶段,所以可能会有bug。】
补充:http协议里面也有:application/octet-stream 这种传输方式,通常哪些地方会用?flash上传时候,就这种,它的特征是只是上传文件数据,分隔符为:
按照上面这个分组(字符流先读取成为字节流),然后将相关字节流写入文件即可。
欢迎大家指出我的错漏指出。
Q:java里面可以不可以直接获取get(url)参数及post参数?
A:不可以,java里面的标准api获取用户请求的方式有request.getParameter(),对于查找一个参数名称为“username”的参数,getParameter的执行过程是先查找post里面有没有这个参数,没有的话查找url里面有没有这个参数,即是说,post里面的参数可能会被url里面的参数覆盖,这个是严重的基本问题。网上一般的解决方法是:通过request.getMethod判断是采用get还是采用post来提交,但本人认为不可取,原因在于:当遇到这个例子:form method=“post”
action="add.jsp?username=user1&pwd=pwd1"
还是无效,有主张采用servlet的doget dopost方法的,个人认为还是无法解决第一种方式的问题,而且每写一个servlet要遵循一堆规则还要注册路径,相当麻烦;我认为只能自己开发底层的api解释用户提交的表单,里面的get参数,post参数及文件上传。
Q:html里面提交参数有多少种方式,具体格式如何,流程如何,怎么样解释数据?
A:html提交参数的话具体来说有两大分类,
一、通过URL提交数据(form的get方式和直接填写url地址是一样的,譬如:article.jsp?articleid=785这种方式。),一般格式为:article.jsp?id=78&categoryid=7,浏览器会按照
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
里面的contentType来对url编码,服务端会采用默认的编码(譬如:tomcat会采用:iso8859-1来解码数据),服务端里面调用的reqeuset.getQueryString是已经经过了解码而得到的数据,通常对于英文及数字而言,这个过程不会出现乱码,但是,对于中文而言,譬如:serch.jsp?namelike=护肤品&price=不限 之类的网址,各个浏览器会先转换成为中间字符串,再通过cotentType规定的字符集编码,譬如:chrome会转换成为%xxx形式的只包含数字字母及%符号的16进制字符串形式,firefox类似,ie则不知所谓,所以建议,假如使用带有特殊字符及中文的网址,请统一用javascript自带的encodeURL函数来转换,然后到服务端用URLDecoder.decode(字符串."提交的编码")进行转换。
这样不会出现乱码。
二、通过form的post提交数据,其中可以选择三种enctype方式,分别是:application/x-www-form-urlencoded,mutipart/form-data,text/plain,其中application/x-www-form-urlencoded为默认方式,三种数据格式分别如下:
1、application/x-www-form-urlencoded
格式与get,url一致,不同的是参数存放的位置,get,url都直接放在url后面,而这种方式及(所有post的数据)都放在数据正文里面,里面的解码与get,url一致。
2、mutipart/form-data
这种协议是用于上传文件的,该http里面包含有一个content-Type,里面指示了这个协议及协议采用的边界,如下面格式:
java: F:\java项目\核心项目\Easis\src\com\alibaba\fastjson\serializer\JSONSerializer.java:51: -source 1.3 中不支持泛型
边界用于确认分隔开每一个form data,其中:"--"+边界+"\r\n"用于分隔,"--"+边界+"--"+"\r\n"是结束符号,
每一个form data里面,用"\r\n\r\n"分隔开参数名称(假如是文件的话还有一个文件名称及contentType),及参数内容(假如是文件的话,就是文件内容)了。
格式如下:(详情可以参看我写的系列文章)
------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="imagefiles"; filename="" \r\n Content-Type: application/octet-stream \r\n\r\n \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="head"; filename="testupload.txt" \r\n Content-Type: text/plain \r\n\r\n this is the txt upload file,yes,you can select this file to upload for read. \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="fileNormal"; filename="" \r\n Content-Type: application/octet-stream \r\n\r\n \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="userName" \r\n\r\n myUserName \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="password" \r\n\r\n input passowrd \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="checkcode" \r\n\r\n checkcode is??? \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC\r\n Content-Disposition: form-data; name="none" \r\n\r\n \r\n ------WebKitFormBoundaryiM5Ip2MHB86rZWFC--\r\n3、text/plain格式的数据:
userName=myUserName \r\n password=input passowrd \r\n checkcode=checkcode is??? \r\n none=
对于表单post数据的三种方式而言,第一种方式与url的格式及解释方式都一样,就存放位置不一样,可以用相同的规则进行解释(URLDecoder.decode()方法);
而第二种及第三种表单都是直接编码,并且 服务端会根据自己的默认解码方式(tomcat的是is9588-1)来解码,这时候为了避免乱码,我们需要利用new string(string.getBytes('iso9588-1','表单的编码格式')来获得正确的数据。
Q:html表单名称相同的checkbox数组是如何传递数据的?
A:譬如: <input type="checkbox" checked value="ok" name="checkbox1">选框一
<input type="checkbox" checked value="no" name="checkbox1">选框2
假如两个都选择的话,那么对于 get,url及application/x-www-form-urlencoded方式而言,他们的参数形式都是:
checkbox1=ok&checkbox1=no
其他参数方式类似,即会用相同name的参数出现。
据此可以制定获取数组的规则。
下面是一些代码:
【这个代码是理论阶段完成的,进行部分实现通过,但是没有经过应用阶段,所以可能会有bug。】
package Easis.HTTP; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; import java.util.regex.Pattern; import Easis.HTTP.RequestFile; import Easis.Common.StringUtil; import java.net.URLDecoder; /** * Created with IntelliJ IDEA. * User: Administrator * Date: 13-4-28 * Time: 下午9:03 * To change this template use File | Settings | File Templates. */ public class RequestEnhance { private String _QueryString="";//url及get方式的pathinfo private String _urlEncoding="UTF-8";//客户端对url地址的编码方式。与页面的charset保持一致 private String _ServerDecoding="ISO-8559-1";//服务端采用的解码方式--tomcat默认的解码方式为ISO-8559-1 private String _FormEncoding="UTF-8"; //表单提交post表单时候,采用的编码方式,通常是由jsp页面的page charset确定的,推荐设定为utf-8. public static String RequestEncoding_GBK="GBK"; public static String RequestEncoding_UTF8="utf-8"; public static String ReqeusetEncoding_ISO_8559_1="iso-8559-1"; private HttpServletRequest _RequestCopy=null; private StringBuilder _RequestContent=new StringBuilder(); private String _RequestContent_Handled=""; //参数的容器 private Hashtable<String,String> _paras_by_get=new Hashtable<String, String>();//针对于get,url参数的容器 private Hashtable<String,List<String>> _paras_list_by_get=new Hashtable<String, List<String>>();//针对于get,url重复名称参数(列表)的容器 private Hashtable<String,String> _paras_by_post=new Hashtable<String, String>();//针对于post的三种方式的容器 private Hashtable<String,List<String>> _paras_list_by_post=new Hashtable<String, List<String>>();//针对于post的三种方式参数列表的容器 private Hashtable<String,RequestFile> _files=new Hashtable<String, RequestFile>();//特别针对于mutipart/form-data的文件容器 private Hashtable<String,List<RequestFile>> _files_list=new Hashtable<String, List<RequestFile>>();//特别针对于mutipart/form-data的文件列表容器 public RequestEnhance(HttpServletRequest request,String URLEncoding,String FormEncoding,String ServerDecoding){ _init(request,URLEncoding,FormEncoding,ServerDecoding); } ///这里要利用原始的requeset对象来获取querystring及getReader, ///注意:使用了getReander以后你就无法在 ///原始的request对象再使用getParameter,getInputStream及getReader了, ///作为补偿,这里用getRequestContent来给大家访问最原始的request正文内容。 public RequestEnhance(HttpServletRequest request){ _init(request,"UTF-8","UTF-8","ISO-8559-1"); } private void _init(HttpServletRequest request,String urlEncoding,String FormEncoding,String ServerDecoding){ this._urlEncoding=urlEncoding; this._ServerDecoding=ServerDecoding; this._RequestCopy=request; this._FormEncoding=FormEncoding; try{ this._QueryString=request.getQueryString(); BufferedReader bf=request.getReader(); char[] carr_tmp=new char[4096]; int readSize=bf.read(carr_tmp); String tttt=""; while(readSize>0){ for(int i_index=0;i_index<readSize;i_index++){ //this._RequestContent.append() this._RequestContent.append(carr_tmp[i_index]); } // this._RequestContent.append(carr_tmp); readSize=bf.read(carr_tmp); tttt=""; } bf.close(); //--我就是衰在这里, // POST传过去的都是单字节数据.所以POST传来的数据编码都是ISO-8859-1的单字节数据.因此英文和数字不会有乱码... // 在这种情况下.过滤器和server.xml里的设置都是无效的.当然request.setCharacterEncoding()也是无效的因为setCharacterEncoding的原理跟过滤器一样; // 正确的取法: String str = new String(getParameter("message").getBytes("ISO-8859-1"),"UTF-8") this._RequestContent_Handled=new String(this._RequestContent.toString().getBytes(this._ServerDecoding),this._FormEncoding); this.InitParamByGet(this._QueryString); //--处理表单数据,注意三种方式,“multipart/form-data”、“text/plain”、“application/x-www-form-urlencoded” InitParamByPost(); String End11=""; } catch (Exception e){ e.printStackTrace(); } } public String getQueryString(){ return _QueryString; } public String getRequestContent(){ return _RequestContent_Handled; } private void InitParamByPost() throws Exception { String _contentType= this._RequestCopy.getContentType(); if(_contentType==null){return;} if(_contentType.equals("text/plain")){ _initParam_text_plain(); } else if(_contentType.equals("application/x-www-form-urlencoded")){ _initParam_application_x_www_form_urlencoded(); } else if(_contentType.indexOf("multipart/form-data;")==0){ String _boundary=_contentType.replaceAll("multipart/form-data;",""); _boundary=_boundary.trim().replaceFirst("boundary=",""); _initParam_multipart_form_data(_boundary); } else{ throw new Exception("please make sure that you form data has a certain content type(one of \"text/plain\" or \"application/x-www-form-urlencoded\" or \"multipart/form-data\")"); } } private void InitParamByGet(String URLQUERY) throws Exception{ String _str=URLQUERY; if(URLQUERY==null||URLQUERY.trim().length()<1){} else{ _str=URLQUERY.trim(); _str= URLQUERY.replaceAll("&+","&"); String[] str_res= _str.split("&+"); if(str_res!=null&&str_res.length>0){ for(String tmp_mix:str_res){ String[] t_arr_key_value=tmp_mix.split("=",2); if(t_arr_key_value!=null&&t_arr_key_value.length>1){ String s1= t_arr_key_value[0]; String tKey=URLDecoder.decode(t_arr_key_value[0],this._urlEncoding); String tValue=URLDecoder.decode(t_arr_key_value[0],this._urlEncoding); this.addParamGet(tKey,tValue); } }}}} ///这个用于处理普通post文档,application/x-www-form-urlencoded,(浏览器默认的是这个无法传送文件,解释方式与url的一样) private void _initParam_application_x_www_form_urlencoded() throws Exception{ String _str=this._RequestContent==null?"":this._RequestContent.toString().trim(); if(_str==null||_str.trim().length()<1){} else{ _str= _str.replaceAll("&+","&"); String[] str_res= _str.split("&+"); if(str_res!=null&&str_res.length>0){ for(String tmp_mix:str_res){ String[] t_arr_key_value=tmp_mix.split("=",2); if(t_arr_key_value!=null&&t_arr_key_value.length>1){ String s1= t_arr_key_value[0]; String tKey=URLDecoder.decode(t_arr_key_value[0],this._urlEncoding); String tValue=URLDecoder.decode(t_arr_key_value[1],this._urlEncoding); this.addParamPost(tKey,tValue); } }}} } ///只有encryptype为multipart/form-data的表单会发送文档流。 private void _initParam_multipart_form_data(String _boundary) throws Exception{ String _end_boundary=_boundary+"--"; String _realBoundary="--"+_boundary; //分割字符流 String[] arr_str=null; if(this._RequestContent==null||this._RequestContent.toString().length()<1){ return; } arr_str=this._RequestContent.toString().split(_realBoundary); if(arr_str==null||arr_str.length<1){ return; } if(arr_str.length==1){ if(arr_str[0].trim().equals("--\r\n")){ return; } } //--遍历数组,分析参数或者文件内容 for(String str_item:arr_str){ String[] str_parts=str_item.split("\r\n\r\n",2); if(str_parts==null||str_parts.length<1){ continue; } //--查看第一部分,看看是参数还是文件 if(str_parts[0]==null||str_parts[0].length()<1||StringUtil.ignoreCaseIndexOf(str_parts[0].trim(),"Content-Disposition: form-data;")!=0){ continue; } String keyInfos=str_parts[0].trim().substring("Content-Disposition: form-data;".length(),str_parts[0].trim().length()); //--判断是文件还是普通参数 if(keyInfos.contains("\r\n")){ //--文件 String __paraName=""; String __fileName=""; String __contentType=""; String[] arr_names_and_contentType=keyInfos.split("\r\n",2); for (String ii_tkeys:arr_names_and_contentType[0].split(";")){ String[] for_key_value3=ii_tkeys.split("=",2); if(for_key_value3[0].trim().toLowerCase().equals("name")){ __paraName=for_key_value3[1].replace("\"",""); } else if(for_key_value3[0].trim().toLowerCase().equals("filename")){ __fileName=for_key_value3[1].replace("\"",""); } } String tmpstr1=arr_names_and_contentType[1].trim(); __contentType=tmpstr1.substring(tmpstr1.indexOf(":")+1,tmpstr1.length()).trim(); tmpstr1=str_parts[1]; String __fileContent=tmpstr1.substring(0,tmpstr1.lastIndexOf("\r\n")); RequestFile rfile=new RequestFile(); rfile.FileName=new String(__fileName.getBytes(this._ServerDecoding),this._FormEncoding); rfile.FileContent=new String(__fileContent.getBytes(this._ServerDecoding),this._FormEncoding); rfile.ContentType=__contentType; __paraName=new String(__paraName.getBytes(this._ServerDecoding),this._FormEncoding); this.addFile(__paraName,rfile); } else{ //--普通参数 String[] arr_key_valuePairs=keyInfos.split("=",2); String __paraName=arr_key_valuePairs[1].trim().replace("\"",""); __paraName=new String(__paraName.getBytes(this._ServerDecoding),this._FormEncoding); String tmpstr1=str_parts[1]; String __paraValue=tmpstr1.substring(0,tmpstr1.lastIndexOf("\r\n")); __paraValue=new String(__paraValue.getBytes(this._ServerDecoding),this._FormEncoding); this.addParamPost(__paraName,__paraValue); } } } ///这个处理text/plain方式的字符串(不知道如何处理,假如是a1=value1&a2=value2,那么就变成:a1=value1a2=value2,处理不了。) private void _initParam_text_plain() throws Exception{ String theRequestContent=this._RequestContent.toString(); //--分割符号 String[] arr_parts=theRequestContent.split("\r\n"); if(arr_parts==null||arr_parts.length<1){ return; } for (String stritem:arr_parts){ String[] arr_key_value=stritem.split("=",2); if(arr_key_value==null||arr_key_value.length<1){ continue; } String theKey=new String(arr_key_value[0].getBytes(this._ServerDecoding),this._FormEncoding); String theValue=new String(arr_key_value[0].getBytes(this._ServerDecoding),this._FormEncoding); this.addParamPost(theKey,theValue); } } //--统一控制添加get参数 private void addParamGet(String key,String value){ if(this._paras_list_by_get.contains(key)){ this._paras_list_by_get.get(key).add(this._paras_list_by_get.get(key).size(),value); } else if(this._paras_by_get.containsKey(key)){ List<String> strTmplist=new ArrayList<String>(); strTmplist.add(0,this._paras_by_get.get(key)); strTmplist.add(1,value); this._paras_by_get.remove(key); this._paras_list_by_get.put(key,strTmplist); } else{ this._paras_by_get.put(key,value); } } //--统一控制添加post参数 private void addParamPost(String key,String value){ if(this._paras_list_by_post.containsKey(key)){ this._paras_list_by_post.get(key).add(this._paras_list_by_post.get(key).size(),value); } else if(this._paras_by_post.containsKey(key)){ List<String> strTmplist=new ArrayList<String>(); strTmplist.add(0,this._paras_by_post.get(key)); strTmplist.add(1,value); this._paras_by_post.remove(key); this._paras_list_by_post.put(key,strTmplist); } else{ this._paras_by_post.put(key,value); } } //--统一控制添加file private void addFile(String key,RequestFile rfile){ if(this._files_list.containsKey(key)){ this._files_list.get(key).add(this._files_list.get(key).size(),rfile); } else if(this._files.containsKey(key)){ List<RequestFile> tmpList=new ArrayList<RequestFile>(); tmpList.add(0,this._files.get(key)); tmpList.add(1,rfile); this._files.remove(key); this._files_list.put(key,tmpList); } else{ this._files.put(key,rfile); } } //*********************************************************// //***************所有供调用的获取参数的方法****************// //*********************************************************// public Hashtable<String,String> AllParas_ByGet(){ return this._paras_by_get; } public Hashtable<String,List<String>> AllParasList_ByGet(){ return this._paras_list_by_get; } public Hashtable<String,String> AllParas_ByPost(){ return this._paras_by_post; } public Hashtable<String,List<String>> AllParasList_ByPost(){ return this._paras_list_by_post; } public Hashtable<String,RequestFile> AllFiles(){ return this._files; } public Hashtable<String,List<RequestFile>> AllFilesList(){ return this._files_list; } public String fetchParamByGet(String key){ return this._paras_by_get.get(key); } public List<String> fetchParamListByGet(String key){ if(this._paras_list_by_get.containsKey(key)){ return this._paras_list_by_get.get(key); } else if(this._paras_by_get.containsKey(key)){ List<String> list1=new ArrayList<String>(1); list1.add(0,this._paras_by_get.get(key)); return list1; } else{ return null; } } public String fetchParamByPost(String key){ return this._paras_by_post.get(key); } public List<String> fetchParamListByPost(String key){ if(this._paras_list_by_post.containsKey(key)){ return this._paras_list_by_post.get(key); } else if(this._paras_by_post.containsKey(key)){ List<String> list1=new ArrayList<String>(1); list1.add(0,this._paras_by_post.get(key)); return list1; } else{ return null; } } public RequestFile fetchFile(String key){ return this._files.get(key); } public List<RequestFile> fetchFileList(String key){ if(this._files_list.containsKey(key)){ return this._files_list.get(key); } else if(this._files.containsKey(key)){ List<RequestFile> list1=new ArrayList<RequestFile>(1); list1.add(0,this._files.get(key)); return list1; } else{ return null; } } }
补充:http协议里面也有:application/octet-stream 这种传输方式,通常哪些地方会用?flash上传时候,就这种,它的特征是只是上传文件数据,分隔符为:
--------------------
按照上面这个分组(字符流先读取成为字节流),然后将相关字节流写入文件即可。
相关文章推荐
- jsp的request及增进研究【4】--URL传参,post传参乱码原因及修正
- jsp的request及增进研究【1】--资料准备
- jsp的request及增进研究【2】--编写代码解释Get及Post来的数据
- jsp的request及增进研究【3】--给自己的类加上文件上传功能
- Tcpdump源码分析系列4:main函数继续研究
- Entity FrameWork 365日系列文章源码研究 (1)
- [转] 程序员面试、算法研究、编程艺术、红黑树4大系列集锦与总结
- 飞鸽传书官方网站 2012 最新源码公开
- Silverlight 5 beta新特性探索系列:3.Silverlight5中的文字增进控制【附带实例源码】
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结
- .NET Framework源码研究系列之---马甲List
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
- jQuery源码分析系列(37) : Ajax 总结
- JFreeChart最新版本1.0.8a的研究系列——简单介绍
- jQuery-1.9.1源码分析系列(三) Sizzle选择器引擎——总结与性能分析
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结
- 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结