The NoteBook of EricKong

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

#

前言
Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象。Javascript可以通过一定的设计模式来实现面向对象的编程,其中this “指针”就是实现面向对象的一个很重要的特性。但是this也是Javascript中一个非常容易理解错,进而用错的特性。特别是对于接触静态语言比较久了的同志来说更是如此。

示例说明
我们先来看一个最简单的示例:

 var name = "Kevin Yang";

function sayHi(){
alert(
"你好,我的名字叫" + name);
}
sayHi();

      这段代码很简单,我们定义了一个全局字符串对象name和函数对象sayHi。运行会弹出一个打招呼的对话框,“你好,我的名字叫Kevin Yang”。

我们把这段代码稍微改一改:

     var name = "Kevin Yang";

    function sayHi(){
       alert(
"你好,我的名字叫" + this.name);
    }
    sayHi();

      这段代码和上段代码的区别就在于sayHi函数在使用name的时候加上了this.前缀。运行结果和上面一摸一样。这说明this.name引用的也还是全局的name对象。

开头我们不是说了,函数也是普通的对象,可以将其当作一个普通变量使用。我们再把上面的代码改一改:

    var name = "Kevin Yang";
    
function sayHi(){
       alert(
"你好,我的名字叫" + this.name);
    }
    
var person = {}; //创建一个对象.
    person.sayHello = sayHi;
    person.sayHello();

 

这一次,我们又创建了一个全局对象person,并将sayHi函数对象赋给person对象的sayHello属性。运行结果如下:


     这一次打招呼的内容就有点无厘头了,我们发现this.name已经变成undefined了。这说明,在sayHello函数内部执行时已经找不着this.name对象了(person对象没有定义一个name属性)。如果我们重新定义person对象,在其上面加上一个name属性又会怎么样呢?

var person = {name:"Marry"};运行代码发现打招呼的“人”变了:


是不是看出点道道了呢?

判别this指针的指导性原则
在Javascript里面,this指针代表的是执行当前代码的对象的所有者。

在上面的示例中我们可以看到,第一次,我们定义了一个全局函数对象sayHi并执行了这个函数,函数内部使用了this关键字,那么执行this这行代码的对象是sayHi(一切皆对象的体现),sayHi是被定义在全局作用域中。其实在Javascript中所谓的全局对象,无非是定义在window这个根对象下的一个属性而已。因此,sayHi的所有者是window对象。也就是说,在全局作用域下,你可以通过直接使用name去引用这个对象,你也可以通过window.name去引用同一个对象。因而this.name就可以翻译为window.name了。

      再来看第二个this的示例。我们定义了一个person的对象,并定义了它的sayHello属性,使其指向sayHi全局对象。那么这个时候,当我们运行person.sayHello的时候,this所在的代码所属对象就是sayHello了(其实准确来说,sayHi和sayHello是只不过类似两个指针,指向的对象实际上是同一个),而sayHello对象的所有者就是person了。第一次,person里面没有name属性,因此弹出的对话框就是this.name引用的就是undefined对象(Javascript中所有只声明而没有定义的变量全都指向undefined对象);而第二次我们在定义person的时候加了name属性了,那么this.name指向的自然就是我们定义的字符串了。

理解了上面所说的之后,我们将上面最后一段示例改造成面向对象式的代码。

      var name = "Kevin Yang";

    function sayHi(){
       alert(
"你好,我的名字叫" + this.name);
    }
    
function Person(name){
        
this.name = name;
    }
    Person.prototype.sayHello 
= sayHi;
    
var marry = new Person("Marry");   
    marry.sayHello();
    
var kevin = new Person("Kevin");
    kevin.sayHello();

      在上面这段代码中,我们定义了一个Person的“类”(实际上还是一个对象),然后在这个类的原型(类原型相当于C++中的静态成员变量的概念)中定义了sayHello属性,使其指向全局的sayHi对象。运行代码我们可以看到,marry和kevin都成功的向我们打了声“招呼”。

      在这段代码中有两点需要思考的,一个是new我们很熟悉,但是在这里new到底做了什么操作呢?另外一个是,这里执行sayHello的时候,this指针为什么能够正确的指向marry和kevin对象呢?

我们来把上面定义“类”和实例化类对象的操作重新“翻译”一下:

    var name = "Kevin Yang";
    
function sayHi(){
       alert(
"你好,我的名字叫" + this.name);
    }
    
function Person(name){
        
var this;
        
this.name = name;
        
return this;
    }
    Person.prototype.sayHello 
= sayHi;
    
var marry = Person("Marry");   
    marry.sayHello();
    
var kevin = Person("Kevin");
    kevin.sayHello();

 

      当然这段代码并不能正确执行,但是它可以帮助你更好的理解这个过程。

      当我们使用new关键字实例化一个“类”对象的时候,Javascript引擎会在这个对象内部定义一个新的对象并将其存入this指针。所有此对象内部用到this的代码实际上都是指向这个新的对象。如this.name = name,实际上是将参数中的name对象赋值给了这个新创建的对象。函数对象执行完之后Javascript引擎会将此对象返回给你,于是就有marry变量得到的对象的name为“Marry”,而kevin变量得到的对象的name属性确实“Kevin”。

容易误用的情况
理解了this指针后,我们再来看看一些很容易误用this指针的情况。

示例1——内联式绑定Dom元素的事件处理函数

   function sayHi(){

       alert("当前点击的元素是" + this.tagName);
    }  
<input id="btnTest" type="button" value="点击我" onclick="sayHi()">

在此例代码中,我们绑定了button的点击事件,期望在弹出的对话框中打印出点击元素的标签名。但运行结果却是:


     也就是this指针并不是指向input元素。这是因为当使用内联式绑定Dom元素的事件处理函数时,实际上相当于执行了以下代码:

     document.getElementById("btnTest").onclick = function(){
        sayHi();
    }

     在这种情况下sayHi函数对象的所有权并没有发生转移,还是属于window所有。用上面的指导原则一套我们就很好理解为什么this.tagName是undefined了。

那么如果我们要引用元素本身怎么办呢?

我们知道,onclick函数是属于btnTest元素的,那么在此函数内部,this指针正是指向此Dom对象,于是我们只需要把this作为参数传入sayHi即可。

   function sayHi(el){

       alert("当前点击的元素是" + el.tagName);
    }
<input id="btnTest" type="button" value="点击我" onclick="sayHi(this)">

等价代码如下:

 document.getElementById("btnTest").onclick = function(){

        sayHi(this);
    }

 示例2——临时变量导致的this指针丢失

       var Utility = {

        decode:function(str){
            
return unescape(str);
        },
        getCookie:
function(key){
            
//  省略提取cookie字符串的代码
            var value = "i%27m%20a%20cookie";
            
return this.decode(value);
        }
    };
    alert(Utility.getCookie(
"identity"))

     我们在写稍微有点规模的Js库的时候,一般都会自己封装一个Utility的类,然后将一些常用的函数作为Utility类的属性,如客户端经常会用到的getCookie函数和解码函数。如果每个函数都是彼此独立的,那么还好办,问题是,函数之间有时候会相互引用。例如上面的getCookie函数,会对从document.cookie中提取到的字符串进行decode之后再返回。如果我们通过Utility.getCookie去调用的话,那么没有问题,我们知道,getCookie内部的this指针指向的还是Utility对象,而Utility对象时包含decode属性的。代码可以成功执行。

但是有个人不小心这样使用Utility对象呢?

   function showUserIdentity(){

        // 保存getCookie函数到一个局部变量,因为下面会经常用到
        var getCookie = Utility.getCookie;
        alert(getCookie(
"identity"));
    }
    showUserIdentity();

      这个时候运行代码会抛出异常“this.decode is not a function”。运用上面我们讲到的指导原则,很好理解,因为此时Utility.getCookie对象被赋给了临时变量getCookie,而临时变量是属于window对象的——只不过外界不能直接引用,只对Javascript引擎可见——于是在getCookie函数内部的this指针指向的就是window对象了,而window对象没有定义一个decode的函数对象,因此就会抛出这样的异常来。

这个问题是由于引入了临时变量导致的this指针的转移。

解决此问题的办法有几个:

•不引入临时变量,每次使用均使用Utility.getCookie进行调用 
•getCookie函数内部使用Utility.decode显式引用decode对象而不通过this指针隐式引用(如果Utility是一个实例化的对象,也即是通过new生成的,那么此法不可用) 
•使用Funtion.apply或者Function.call函数指定this指针

 
     前面两种都比较好理解,第三种需要提一下。正是因为this指针的指向很容易被转移丢失,因此Javascript提供了两个类似的函数apply和call来允许函数在调用时重新显式的指定this指针。

修正代码如下:

  function showUserIdentity(){

        // 保存getCookie函数到一个局部变量,因为下面会经常用到
        var getCookie = Utility.getCookie;
        alert(getCookie.call(Utility,
"identity"));
        alert(getCookie.apply(Utility,[
"identity"]));
    }
    showUserIdentity();

call和apply只有语法上的差异,没有功能上的差别。

示例3——函数传参时导致的this指针丢失

我们先来看一段问题代码:

     var person = {

        name:"Kevin Yang",
        sayHi:
function(){
            alert(
"你好,我是"+this.name);
        }
    }
    setTimeout(person.sayHi,
5000);

这段代码期望在访客进入页面5秒钟之后向访客打声招呼。setTimeout函数接收一个函数作为参数,并在指定的触发时刻执行这个函数。可是,当我们等了5秒钟之后,弹出的对话框显示的this.name却是undefined。

      其实这个问题和上一个示例中的问题是类似的,都是因为临时变量而导致的问题。当我们执行函数的时候,如果函数带有参数,那么这个时候Javascript引擎会创建一个临时变量,并将传入的参数复制(注意,Javascript里面都是值传递的,没有引用传递的概念)给此临时变量。也就是说,整个过程就跟上面我们定义了一个getCookie的临时变量,再将Utility.getCookie赋值给这个临时变量一样。只不过在这个示例中,容易忽视临时变量导致的bug。

函数对象传参
对于函数作为参数传递导致的this指针丢失的问题,目前很多框架都已经有方法解决了。

Prototype的解决方案——传参之前使用bind方法将函数封装起来,并返回封装后的对象

   var person = {

        name:"Kevin Yang",
        sayHi:
function(){
            alert(
"你好,我是"+this.name);
        }
    }
    
var boundFunc = person.sayHi.bind(person,person.sayHi);
    setTimeout(boundFunc,
5000);

bind方法的实现其实是用到了Javascript又一个高级特性——闭包。我们来看一下源代码:

function bind(){
    
if (arguments.length < 2 && arguments[0=== undefined) 
        
return this;
    
var __method = this, args = $A(arguments), object = args.shift();
    
return function(){
        
return __method.apply(object, args.concat($A(arguments)));
    }
}

     首先将this指针存入函数内部临时变量,然后在返回的函数对象中引用此临时变量从而形成闭包。

微软的Ajax库提供的方案——构建委托对象

     var person = {

        name:"Kevin Yang",
        sayHi:
function(){
            alert(
"你好,我是"+this.name);
        }
    }    
    
var boundFunc = Function.createDelegate(person,person.sayHi);
    setTimeout(boundFunc,
5000);

其实本质上和prototype的方式是一样的。

著名的Extjs库的解决方案采用的手法和微软是一样的。 

 

posted @ 2010-08-04 15:40 Eric_jiang 阅读(575) | 评论 (0)编辑 收藏

比如,当我要添加一个信用卡的时候,我需要信用卡的CardType, 这些数据是存在数据库中的,我要先通过action 的一个 create方法,取到信用卡的类型:

public String create(){
        creditCardTypeList = this.creditCardTypeService.getList();
       
        
return SUCCESS;
}
 

Struts的配置文件:

<action name="create" method="create" class="example.CreditCardAction">     <result name="success">input.jsp</result>
</action>

input.jsp

...
<
s:select name="creditCard.creditCardTypeId" list="creditCardTypeList" listKey="creditCardTypeId" 
                listValue
="ccType" />
....

当提交input.jsp 的时候,Validate 检查没有通过,这时我需要回到input.jsp,此时应该下拉列表框的CreditType应该被保留,只需要在example.CreditCardAction 实现 Preparable接口,并实现prepare 方法,然后在add的 action中加上

<interceptor-ref name="prepare"/>
<interceptor-ref name="defaultStack"/>
就可以了
prepare方法:
public void prepare(){
    creditCardTypeList = this.creditCardTypeService.getList(); 
}

Add Acton:
<action name="add" method="add" class="example.CreditCardAction">
    
<interceptor-ref name="prepare"/>
    
<interceptor-ref name="defaultStack"/>
    
<result name="input">input.jsp</result>            
    
<result name="success" type="redirect-action">
            
<param name="namespace">/credit</param>
        
<param name="actionName">list</param>
    
</result>
</action>

  这样,在验证前将首先调用 prepare方法,即使失败了回到input.jsp页面creditCardType选择框的值仍然存在。

<interceptor-ref name="defaultStack"/> 中的 defaultStack 是我们在struts.xml 中配置的,其中我们注释掉了 <interceptor-ref name="prepare"/> 这样在example.CreditCardAction中的其他Action就不会首先执行prepare方法,只有加上了 <interceptor-ref name="prepare"/> 的才会去首先执行 prepare方法。

<package name="project-default" abstract="true" extends="struts-default">
         
<interceptors>
         
<interceptor-stack name="defaultStack">
                
<interceptor-ref name="exception"/>
                
<interceptor-ref name="alias"/>
                
<interceptor-ref name="servletConfig"/>
                
<!--                           
                <interceptor-ref name="prepare"/>
                 
-->                              
                
<interceptor-ref name="i18n"/>
                
<interceptor-ref name="chain"/>
                
<interceptor-ref name="debugging"/>
                
<interceptor-ref name="profiling"/>
                
<interceptor-ref name="scopedModelDriven"/>
                
<interceptor-ref name="modelDriven"/>
                
<interceptor-ref name="fileUpload"/>
                
<!-- 
                <interceptor-ref name="checkbox">  
                       <param name="uncheckedValue">no</param>  
                </interceptor-ref>
                
-->
                
<interceptor-ref name="staticParams"/>
                
<interceptor-ref name="params">
                  
<param name="excludeParams">dojo..*</param>
                
</interceptor-ref>
                
<interceptor-ref name="conversionError"/>
                
<interceptor-ref name="validation">
                    
<param name="excludeMethods">input,back,cancel,browse</param>
                
</interceptor-ref>
                
<interceptor-ref name="workflow">
                    
<param name="excludeMethods">input,back,cancel,browse</param>
                
</interceptor-ref>
            
</interceptor-stack>
       
</interceptors>
    
</package> 
posted @ 2010-08-03 21:56 Eric_jiang 阅读(713) | 评论 (0)编辑 收藏

我遇到到是第三种

解决hibernate 删除异常: deleted object would be re-saved by cascade (remove deleted object from associations) 收藏
在hibernate 删除关联时会出现eleted object would be re-saved by cascade (remove deleted object from associations)的异常,结合别人的和自己的经验通常有三种解决的方案:

方法1 删除Set方的cascade:
方法2 解决关联关系后,再删除

    onside.getManys().remove(thisMany);   //在所关联的一方的set中移走当前要删除的对象
    thisMany.setOne(null);                          //设置所对应的一方为空,解除它们之间的关系
    manyDao.delete(thisMany);
方法3 在many-to-one方增加cascade 但值不能是none

posted @ 2010-07-31 20:58 Eric_jiang 阅读(3115) | 评论 (0)编辑 收藏

SQL Server 2005支持用CLR语言(C# .NET、VB.NET)编写过程、触发器和函数,因此使得正则匹配,数据提取能够在SQL中灵活运用,大大提高了SQL处理字符串,文本等内容的灵活性及高效性。

操作步骤:

1.新建一个SQL Server项目(输入用户名,密码,选择DB),新建好后,可以在属性中更改的

2.新建一个类“RegexMatch.cs”,选择用户定义的函数

可以看到,该类为一个部分类:public partial class UserDefinedFunctions

现在可以在该类中写方法了,注意方法的属性为:[Microsoft.SqlServer.Server.SqlFunction]

现在类中增加以下两个方法:


是否匹配正则表达式
/// <summary>
/// 是否匹配正则表达式
/// </summary>
/// <param name="input">输入的字符串</param>
/// <param name="pattern">正则表达式</param>
/// <param name="ignoreCase">是否忽略大小写</param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction]
public static bool RegexMatch(string input, string pattern, bool ignoreCase)
{
    
bool isMatch = false;
    
if (!string.IsNullOrEmpty(input) && !string.IsNullOrEmpty(pattern))
    {
        
try
        {
            Match match 
= null;
            
if (ignoreCase)
                match 
= Regex.Match(input, pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
            
else
                match 
= Regex.Match(input, pattern, RegexOptions.Multiline | RegexOptions.Compiled);

            
if (match.Success)
                isMatch 
= true;
        }
        
catch { }
    }
    
return isMatch;
}


获取正则表达式分组中的字符
/// <summary>
/// 获取正则表达式分组中的字符
/// </summary>
/// <param name="input">输入的字符串</param>
/// <param name="pattern">正则表达式</param>
/// <param name="groupId">分组的位置</param>
/// <param name="maxReturnLength">返回字符的最大长度</param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction]
public static string GetRegexMatchGroups(string input, string pattern, int groupId, int maxReturnLength)
{
    
string strReturn = string.Empty;
    
if (!string.IsNullOrEmpty(input) && !string.IsNullOrEmpty(pattern))
    {
        
try
        {
            Match match 
= Regex.Match(input, pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
            
if (match.Success && (groupId < match.Groups.Count))
            {
                strReturn 
= match.Groups[groupId].Value;
                strReturn 
= (strReturn.Length <= maxReturnLength) ? strReturn : strReturn.Substring(0, maxReturnLength);
            }
        }
        
catch
        {
            
return string.Empty;
        }
    }
    
return strReturn;
}


3.下一步就是部署的问题了,点击项目右键--》部署即可

提示部署成功了,可以在数据库的标量值函数中多了这两个方法了。

使用方法和正常的SQL函数一样:

select dbo.RegexMatch('/Book/103.aspx','/book/("d+).aspx','true')
消息 6263,级别 16,状态 1,第 1 行
禁止在 .NET Framework 中执行用户代码。启用 "clr enabled" 配置选项。

——出现此错误,配置下:

exec sp_configure 'clr enabled',1;
reconfigure with override;

是否匹配:

select dbo.RegexMatch('/Book/103.aspx','/book/("d+).aspx','true')

返回1,表示匹配成功

select dbo.RegexMatch('/Book/103.aspx','/book/("d+).aspx','false')

表示0,匹配失败(不忽略大小写)。

数据提取:

select dbo.GetRegexMatchGroups('/Book/103.aspx','/book/("d+).aspx',1,50)
返回103,非常方便的提取。


注意:SQL中使用CLR时,尽量使用try catch…以免出现异常


作者:MaoBisheng
出处:http://maobisheng.cnblogs.com/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted @ 2010-07-27 10:24 Eric_jiang 阅读(1458) | 评论 (0)编辑 收藏

     摘要: 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。   ⑵深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言...  阅读全文
posted @ 2010-07-22 09:49 Eric_jiang 阅读(292) | 评论 (0)编辑 收藏

javaMai 为建立邮件和消息服务提供了框架,因而应用程序可以发送和接收邮件.JavaMail API 是一个用于阅读、编写和发送电子消息的可选包(标准扩展),可以用来建立基于标准的电子邮件客户机,它配置了各种因特网邮件协,包括SMTP 、POP 、IMAP和 MIME ,还包括相关的NNTP 、S/MIME 及其它协议。
   通常开发JavaMail 程序通常需要mail.jar 和 activation.jar 两个架包。mail.jar包含mailapi.jar、pop3.jar 和 smtp.jar。mailapi.jar包含核心的API 类, pop3.jar 和 smtp.jar为各自的邮件协议包含实现方法. activation.jar处理 MIME (多用途因特网邮件扩展)类型。

   核心JavaMail API 由七个类组成:Session 、Message 、Address 、Authenticator 、Transport 、Store 及 Folder ,它们都来自javax.mail 、即JavaMail API 顶级包。可以用这些类完成大量常见的电子邮件任务,包括发送消息、检索消息、删除消息、认证、回复消息、转发消息、管理附件、处理基于HTML文件格式的 消息以及搜索或过滤邮件列表。
这里只具体说明一下发送邮件的JavaMail类:
1.Session
这个Session类代表JavaMail 中的一个邮件session. 每一个基于 JavaMail的应用程序至少有一个session但是可以有任意多的session。
     在这个例子中, Session对象需要知道用来处理邮件的SMTP 服务器。JavaMail需要Properties来创建一个session对象
Session sendMailSession;
    Properties props = new Properties ();
props.put("mail.smtp.host", "smtp.sina.com.cn");//可以换上你的smtp主机名。
sendMailSession = Session.getInstance(props, null);
2.Transport
Transport 是用来发送信息的.
用法:Transport transport;
transport = sendMailSession.getTransport("smtp");
用JavaMail Session对象的getTransport 方法来初始化Transport。传过去的字符串申明了对象所要使用的协议,如"smtp"。这是因为JavaMail以境内置了很多协议的实现方法。
注意: JavaMail并不是绝对支持每一个协议,目前支持IMAP、 SMTP和 POP3。
3.Message
Message对象将存储我们实际发送的电子邮件信息,Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session。
使用方法:Message newMessage = new MimeMessage(sendMailSession);
4.MimeMessage
    实现Message接口,以显示Mime风格的消息
5.InternetAddress
    存储电子邮件中关于“from”、“to”域的信息


用JavaMail发送电子邮件的过程比较简单,大致分为以下5个步骤:
1.创建Properties 对象,设置邮件服务器属性:mail.smtp.host ,即指定你的SMTP服务器。
2.建立一个邮件会话
3.创建你的邮件信息对象,该对象包含了你的邮件的全部内容,包括发送人,接受人,标题,正文,附件等内容
4.完成发送前的服务器验证
5.发送邮件
import java.io.*;                                                                                                               
import java.text.*;                                                                                                             
import java.util.*;                                                                                                             
import javax.activation.DataHandler;                                                                                              
import javax.activation.FileDataSource;                                                                                         
import javax.mail.*;                                                                                                            
import javax.mail.internet.*;                                                                                                   
                                                                                                                                
public class SimpleSender {                                                                                                     
                                                                                                                                
 
public static void main(String args[]) {                                                                                       
  
try {                                                                                                                         
   String smtpServer 
= "smtp.sina.com.cn";                                                                                      
   String to 
= "test1@sina.com.cn";                                                                                             
   String from 
= "test2@sina.com.cn";                                                                                           
   String subject 
= "hello";                                                                                                    
   String body 
= "";                                                                                                            
   send(smtpServer, to, from, subject, body);                                                                                   
  } 
catch (Exception ex) {                                                                                                      
   System.out.println(
"Usage: java test.SimpleSender"                                                                           
     
+ " smtpServer toAddress fromAddress subjectText bodyText");                                                               
  }                                                                                                                             
                                                                                                                                
 }                                                                                                                              
                                                                                                                                
 
public static void send(String smtpServer, String to, String from,                                                             
   String subject, String body) {                                                                                               
  
try {                                                                                                                         
    Properties props 
= System.getProperties();                                                                                  
    props.put(
"mail.smtp.host", smtpServer);                                                                                    
    props.put(
"mail.smtp.auth","true");                                                                                         
    Authenticator  sa 
= new SmtpAuth(from, "");                                                                                 
           Session session 
= Session.getDefaultInstance(props,sa);                                                              
           InternetAddress     fromadress   
=   new   InternetAddress(from);                                                    
           javax.mail.internet.InternetAddress   toadress
=   new   javax.mail.internet.InternetAddress   (to);                  
           javax.mail.internet.MimeMessage     mymessage   
=   new   javax.mail.internet.MimeMessage   (session);               
           mymessage.setFrom(fromadress);                                                                                       
           mymessage.setRecipient(Message.RecipientType.TO   ,toadress);                                                        
           mymessage.setSentDate(
new   java.util.Date());                                                                       
           mymessage.addHeader(
"header","test")   ;                                                                             
           mymessage.setSubject(subject)   ;                                                                                    
           mymessage.setText(
"hello")   ;                                                                                       
           Transport   tt
=session.getTransport("smtp");                                                                         
           tt.send(mymessage);                                                                                                  
  } 
catch (Exception ex) {                                                                                                      
   System.out.println(ex.toString());                                                                                           
  }                                                                                                                             
                                                                                                                                
 }                                                                                                                              
}
                                                                                                                             

posted @ 2010-07-21 17:18 Eric_jiang 阅读(1001) | 评论 (1)编辑 收藏

package jdbc;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
public class Test {
    private Connection conn = null;
 
     public Test() {
      super();
     }
 
     public void getConnection() {
      try {
       Class
        .forName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
        .newInstance();
       String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=testDB";
       String USER = "sa"; // 根据你自己设置的数据库连接用户进行设置
       String PASSWORD = "123"; // 根据你自己设置的数据库连接密码进行设置
       conn = DriverManager.getConnection(URL, USER, PASSWORD);
      } catch (java.lang.ClassNotFoundException ce) {
       System.out.println("Get Connection error:");
       ce.printStackTrace();
      } catch (java.sql.SQLException se) {
          System.out.println("Get Connection error:");
          se.printStackTrace();
      } catch (Exception e) {
          System.out.println("Get Connection error:");
          e.printStackTrace();
      }
     }
 
     public void testConnection() {
      if (conn == null)
       this.getConnection();
      try {
       String sql = "SELECT * FROM user";
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery(sql);
       while (rs.next()) {
           System.out.print(rs.getString("ID")+" ");
           System.out.print(rs.getString("Name")+" ");
           System.out.println(rs.getString("Email"));
       }
       rs.close();
       stmt.close();
      } catch (SQLException e) {
          System.out.println(e.getMessage());
          e.printStackTrace();
      } finally {
       if (conn != null)
        try {
         conn.close();
        } catch (SQLException e) {
        }
      }
     }
     public static void main(String[] args) {
      Test bean = new Test();
      bean.testConnection();
     }
}
运行程序,没啥意外的话应该就OK了。连接代码与SQLServer2000的有所不同。这两句可以记下来备用~
Class.forName(”com.microsoft.sqlserver.jdbc.SQLServerDriver”).newInstance();
String URL = “jdbc:sqlserver://localhost:1433;DatabaseName=数据库名称”;
posted @ 2010-07-21 16:39 Eric_jiang 阅读(168) | 评论 (0)编辑 收藏

最常用的Http请求无非是get和post,get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给servlet,post与get的不同之处在于post的参数不是放在URL字串里面,而是放在http请求的正文内。
在Java中可以使用HttpURLConnection发起这两种请求,了解此类,对于了解soap,和编写servlet的自动测试代码都有很大的帮助。
下面的代码简单描述了如何使用HttpURLConnection发起这两种请求,以及传递参数的方法:
public class HttpInvoker {

    
public static final String GET_URL = "http://localhost:8080/welcome1";

    
public static final String POST_URL = "http://localhost:8080/welcome1";

    
public static void readContentFromGet() throws IOException {
        
// 拼凑get请求的URL字串,使用URLEncoder.encode对特殊和不可见字符进行编码
        String getURL = GET_URL + "?username="
                
+ URLEncoder.encode("fat man""utf-8");
        URL getUrl 
= new URL(getURL);
        
// 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,
        
// 返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection
        HttpURLConnection connection = (HttpURLConnection) getUrl
                .openConnection();
        
// 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到
        
// 服务器
        connection.connect();
        
// 取得输入流,并使用Reader读取
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));
        System.out.println(
"=============================");
        System.out.println(
"Contents of get request");
        System.out.println(
"=============================");
        String lines;
        
while ((lines = reader.readLine()) != null{
            System.out.println(lines);
        }
        reader.close();
        
// 断开连接
        connection.disconnect();
        System.out.println(
"=============================");
        System.out.println(
"Contents of get request ends");
        System.out.println(
"=============================");
    }

    
public static void readContentFromPost() throws IOException {
        
// Post请求的url,与get不同的是不需要带参数
        URL postUrl = new URL(POST_URL);
        
// 打开连接
        HttpURLConnection connection = (HttpURLConnection) postUrl
                .openConnection();
        
// Output to the connection. Default is
        
// false, set to true because post
        
// method must write something to the
        
// connection
        
// 设置是否向connection输出,因为这个是post请求,参数要放在
        
// http正文内,因此需要设为true
        connection.setDoOutput(true);
        
// Read from the connection. Default is true.
        connection.setDoInput(true);
        
// Set the post method. Default is GET
        connection.setRequestMethod("POST");
        
// Post cannot use caches
        
// Post 请求不能使用缓存
        connection.setUseCaches(false);
        
// This method takes effects to
        
// every instances of this class.
        
// URLConnection.setFollowRedirects是static函数,作用于所有的URLConnection对象。
        
// connection.setFollowRedirects(true);

        
// This methods only
        
// takes effacts to this
        
// instance.
        
// URLConnection.setInstanceFollowRedirects是成员函数,仅作用于当前函数
        connection.setInstanceFollowRedirects(true);
        
// Set the content type to urlencoded,
        
// because we will write
        
// some URL-encoded content to the
        
// connection. Settings above must be set before connect!
        
// 配置本次连接的Content-type,配置为application/x-www-form-urlencoded的
        
// 意思是正文是urlencoded编码过的form参数,下面我们可以看到我们对正文内容使用URLEncoder.encode
        
// 进行编码
        connection.setRequestProperty("Content-Type",
                
"application/x-www-form-urlencoded");
        
// 连接,从postUrl.openConnection()至此的配置必须要在connect之前完成,
        
// 要注意的是connection.getOutputStream会隐含的进行connect。
        connection.connect();
        DataOutputStream out 
= new DataOutputStream(connection
                .getOutputStream());
        
// The URL-encoded contend
        
// 正文,正文内容其实跟get的URL中'?'后的参数字符串一致
        String content = "firstname=" + URLEncoder.encode("一个大肥人""utf-8");
        
// DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写道流里面
        out.writeBytes(content); 

        out.flush();
        out.close(); 
// flush and close
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));
        String line;
        System.out.println(
"=============================");
        System.out.println(
"Contents of post request");
        System.out.println(
"=============================");
        
while ((line = reader.readLine()) != null{
            System.out.println(line);
        }
        System.out.println(
"=============================");
        System.out.println(
"Contents of post request ends");
        System.out.println(
"=============================");
        reader.close();
        connection.disconnect();
    }

    
/** *//**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
        try {
            readContentFromGet();
            readContentFromPost();
        } 
catch (IOException e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

上面的readContentFromGet()函数产生了一个get请求,传给servlet一个username参数,值为"fat man"。
readContentFromPost()函数产生了一个post请求,传给servlet一个firstname参数,值为"一个大肥人"。
HttpURLConnection.connect函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。无论是post还是get,http请求实际上直到HttpURLConnection.getInputStream()这个函数里面才正式发送出去。

readContentFromPost() 中,顺序是重中之重,对connection对象的一切配置(那一堆set函数)都必须要在connect()函数执行之前完成。而对 outputStream的写操作,又必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。

http 请求实际上由两部分组成,一个是http头,所有关于此次http请求的配置都在http头里面定义,一个是正文content,在connect()函 数里面,会根据HttpURLConnection对象的配置值生成http头,因此在调用connect函数之前,就必须把所有的配置准备好。

紧接着http头的是http请求的正文,正文的内容通过outputStream写入,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是在流关闭后,根据输入的内容生成http正文。

至 此,http请求的东西已经准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个 输入流,用于读取服务器对于此次http请求的返回信息。由于http请求在getInputStream的时候已经发送出去了(包括http头和正 文),因此在getInputStream()函数之后对connection对象进行设置(对http头的信息进行修改)或者写入 outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生
上节说道,post请求的OutputStream实际上不是网络流,而是写入内存,在getInputStream中才真正把写道流里面的内容作为正文 与根据之前的配置生成的http request头合并成真正的http request,并在此时才真正向服务器发送。

HttpURLConnection.setChunkedStreamingMode 函数可以改变这个模式,设置了ChunkedStreamingMode后,不再等待OutputStream关闭后生成完整的http request一次过发送,而是先发送http request头,正文内容则是网路流的方式实时传送到服务器。实际上是不告诉服务器http正文的长度,这种模式适用于向服务器传送较大的或者是不容易 获取长度的数据,如文件。
public static void readContentFromChunkedPost() throws IOException {
        URL postUrl 
= new URL(POST_URL);
        HttpURLConnection connection 
= (HttpURLConnection) postUrl
                .openConnection();
        connection.setDoOutput(
true);
        connection.setDoInput(
true);
        connection.setRequestMethod(
"POST");
        connection.setUseCaches(
false);
        connection.setInstanceFollowRedirects(
true);
        connection.setRequestProperty(
"Content-Type",
                
"application/x-www-form-urlencoded");
        
/**//*
         * 与readContentFromPost()最大的不同,设置了块大小为5字节
         
*/
        connection.setChunkedStreamingMode(
5);
        connection.connect();
        
/**//*
         * 注意,下面的getOutputStream函数工作方式于在readContentFromPost()里面的不同
         * 在readContentFromPost()里面该函数仍在准备http request,没有向服务器发送任何数据
         * 而在这里由于设置了ChunkedStreamingMode,getOutputStream函数会根据connect之前的配置
         * 生成http request头,先发送到服务器。
         
*/
        DataOutputStream out 
= new DataOutputStream(connection
                .getOutputStream());
        String content 
= "firstname=" + URLEncoder.encode("一个大肥人                                                                               " +
                
"                                          " +
                
"asdfasfdasfasdfaasdfasdfasdfdasfs""utf-8");
        out.writeBytes(content); 

        out.flush();
        out.close(); 
// 到此时服务器已经收到了完整的http request了,而在readContentFromPost()函数里,要等到下一句服务器才能收到http请求。
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));
        
        out.flush();
        out.close(); 
// flush and close
        String line;
        System.out.println(
"=============================");
        System.out.println(
"Contents of post request");
        System.out.println(
"=============================");
        
while ((line = reader.readLine()) != null{
            System.out.println(line);
        }
        System.out.println(
"=============================");
        System.out.println(
"Contents of post request ends");
        System.out.println(
"=============================");
        reader.close();
        connection.disconnect();
    }

posted @ 2010-07-21 16:11 Eric_jiang 阅读(48821) | 评论 (9)编辑 收藏

怎么在Javascript实现OO编程?恐怕最佳的方式就是充分利用prototype属性。关于prototype的介绍有非常多,我就不赘述了。比较基本的原理是,当你用prototype编写一个类后,当你new一个新的object,浏览器会自动把prototype中的内容替你附加在object上。这样,通过利用prototype,你也就实现了类似OO的Javascript。
在Javascript中,object就是个associative array。一个function就是个类。当你编写如下function时,其实就是定义了一个类,该function就是他的构造函数。
function MyObject(name, size)
       {
              this.name = name;
              this.size = size;
       }
之后,你能方便的通过MyObject类的prototype属性来方便的扩充他。比如,你能给他添加其他的属性和方法。
       MyObject.prototype.tellSize = function()
       {
              return "size of "+this.name+" is "+this.size;
       }
      
       MyObject.prototype.color = "red";
       MyObject.prototype.tellColor = function()
       {
              return "color of "+this.name+" is "+this.color;
       }
      
       var myobj1 = new MyObject("tiddles", "7.5 meters");
       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";
你能想象,当你调用tellColor()方法后,结果是这样的:
color of tiddles is red
非常方便的是,prototype属性能动态添加。比如,你需要往MyObject中加入一个height属性,并希望其提供一个tellHeight()方法来获得height属性的值。你能在上面的代码后,继续添加如下的代码:
       MyObject.prototype.height = "2.26 meters";
       MyObject.prototype.tellHeight = function()
       {
              return "height of "+this.name+" is "+this.height;
       }
之后,你能访问一下myobj1的tellHeight()方法,你能得到如下的结果:
height of tiddles is 2.26 meters
prototype的这些动态的特性看起来有些迷人,不过我倒是反而觉得有些凉飕飕的。确实,这些特性给你非常大的灵活性,能给和你runtime改动类属性和方法的能力。不过,稍微发掘一下,会有些不良的习惯产生。
首先,如果能动态添加属性和方法,那么非常容易让人想到,当我调用时,我想要调用的属性或方法存在不?这是个非常严肃的问题,如果当我们调用时根本没有该属性或方法,将可能导致我们的脚本down掉。
不过也有解决办法。比如,在上面的代码中,当还没有tellHeight()方法时,我们能如下编写代码避免发生错误:
       if (myobj1.tellHeight)
       {
              domDiv.innerHTML += myobj1.tellHeight()+"<br /><br />";
       }
注意,一定要在if语句中,不要加方法后面的那对(),否则,直接就down掉了。有兴趣的读者能打印一下,看看分别访问myobj1.tellHeight和myobj1.tellHeight()时有什么差别。
也许,你觉得这个是小意思。加个判断嘛,不就好了?
对,不过下面一个问题更令人头痛。
属性和方法在不在的问题简单,可是属性和方法变不变化的问题可就严重了。在不在我们能检测,变不变呢?比如,请看下面的代码:
       function MyObject(name, size)
       {
              this.name = name;
              this.size = size;
       }
      
       MyObject.prototype.color = "red";
       MyObject.prototype.tellColor = function()
       {
              return "color of "+this.name+" is "+this.color;
       }
      
       var myobj1 = new MyObject("tiddles", "7.5 meters");
       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";
      
       MyObject.prototype.color = "green";
      
       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";
该代码将产生如下结果:
color of tiddles is red
color of tiddles is green
请注意,你修改的是类MyObject的color属性。不过你惊奇的看到你之前实例化的对象myobj1的属性值竟然也变化了。天!如果你的项目代码是多人合作,那么,也许某个人会在编程时为了图一己之便,擅自修改你的类。于是,所有人的对象都变化了。于是,你们陷入了漫长的debug过程中。。。。。。(不要说我没有告诉你啊)
上面是属性,更有方法:
       function MyObject(name, size)
       {
              this.name = name;
              this.size = size;
       }
      
       MyObject.prototype.color = "red";
       MyObject.prototype.tellColor = function()
       {
              return "color of "+this.name+" is "+this.color;
       }
      
       var myobj1 = new MyObject("tiddles", "7.5 meters");
       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";
      
       MyObject.prototype.color = "green";
       MyObject.prototype.tellColor = function()
       {
              return "your color of "+this.name+" is "+this.color;
       }
      
       domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";
这段代码的结果是:
color of tiddles is red
your color of tiddles is green
哈?原来方法也能变,汗!
    问题来了。Javascript太灵活的编程方式多少让人不适应。如果整个Team的水平都比较高还能,没人会犯这样的错误。不过,当有个毛头小伙子不知情,擅自修改类,将导致所有的人的对象都发生变化,无论是属性还是方法。在Javascript代码变得越来越多的Ajax时代,这是个严重的问题。
这说明,编写Javascript时,好的编程风格更加重要。记得某人原来说过这样的话,想Java和C#这些比较严格的语言,虽然降低了灵活性,但也减少了犯错误的可能。这样,即使一个新手,他写出的代码也不会和高手差太多。不过,像Javascript这样的脚本语言,由于太灵活,所以,高手写出的是天使,而新手写的,可能是魔鬼!
posted @ 2010-07-21 14:03 Eric_jiang 阅读(209) | 评论 (0)编辑 收藏

1.关于WinINet
WinINet不是给服务端用的,服务端用Microsoft Windows HTTP Services (WinHTTP)
WinINet抽象了Gopher,FTP,HTTP协议的一些细节。
2.HINTERNET 句柄

WinINet函数创建、使用的句柄都是HINTERNET类型的,这种类型的句柄无法被转换成其 它类型的句柄。换句话说,最好别用ReadFile、CloseHandle之类的函数来操作这些句柄。同样的,也别用WinINet函数来访问、操作其 他类型的句柄。比如,用InternetReadFile访问CreateFile创建句柄是无法得到你想要的结果的。想关闭HINTERNET句柄要使 用InternetCloseHandle函数。

3.句柄架构



InternetOpen 创建的句柄在顶层,由接下来的一层的 InternetOpenUrlInternetConnect 使用,而 InternetConnect 创建的句柄又被之后的几个函数使用。

下面这张图是依赖 InternetOpenUrl 创建的句柄的几个函数,灰色的方框是返回 HINTERNET 句柄的函数,而白色的框就是使用被创建的 HINTERNET 句柄的函数



FTP Hierarchy






HTTP Hierarchy






注意这张图,这张图的意思是 HttpSendRequestEx 先访问 HttpOpenRequest 创建的句柄之后, HttpEndRequest, InternetReadFileExInternetWriteFile 才能访问这个句柄。 HttpEndRequest 被调用之后,才轮的到InternetReadFile, InternetSetFilePointerInternetQueryDataAvailable 来访问这个句柄。

4.内容编码

HTTP 协议 (RFC 2616) 规定了应用程序可以要求服务器用编码的方式(encoded format)返回HTTP响应。在Windows Server 2008 与 Windows Vista之前,发送给应用程序的内容编码了的请求需要应用程序自己处理,从Windows Server 2008 and Windows Vista开始, 应用程序可以让 WinINet 来解码了(gzip与deflate)。有三种方式开启解码选项(基于会话、请求、连接),它们的作用域不同。可以使用InternetOpen(基于会话), InternetConnect(基于连接), HttpOpenRequest(基于请求)返回的句柄调用InternetSetOption 来打开或关闭解码选项,打开则将 dwOption 参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer 指向一个为true的boolean变量. 关闭则dwOption 参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer 指向一个为false的boolean变量 .

设置解码选项之后, WinInet 在你调用 InternetReadFile 是就会执行一次解码。不过就算你打开了解码选项,它也不一定就为你解码……当这种情况发生时, InternetReadFile 函数会失败并返回ERROR_INTERNET_DECODING_FAILED.这个时候你可以选择去掉Accept-Encoding头重新发送一次请求,或者把解码关掉然后自己来解码(这时你就得检查Content-Encoding头来判断编码方式了)。

5.协议无关函数

Function Description
InternetFindNextFile 继续文件的枚举或搜索. 需要以下函数创建的句柄 FtpFindFirstFile, GopherFindFirstFile, InternetOpenUrl
InternetLockRequestFile 允许用户锁定文件. 需要以下函数创建的句柄 FtpOpenFile, GopherOpenFile, HttpOpenRequest, InternetOpenUrl .
InternetQueryDataAvailable 查询可用数据的数量. 需要以下函数创建的句柄 FtpOpenFile, GopherOpenFile, HttpOpenRequest .
InternetQueryOption 查询 Internet 设置.
InternetReadFile 读取 URL 数据. 需要以下函数创建的句柄 InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest .
InternetSetFilePointer 设置文件指针. 需要以下函数创建的句柄 InternetOpenUrl ( HTTP URL only) HttpOpenRequest (GET 方法).
InternetSetOption 配置 Internet 设置.
InternetSetStatusCallback 设置一个接收状态信息的回调函数. 分配一个回调函数给指定的 HINTERNET 句柄及从其演化而来的句柄.
InternetUnlockRequestFile 解锁被 InternetLockRequestFile 锁定的文件.

读文件

函数 InternetReadFile 用来从一个由函数 InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest 返回的 HINTERNET 句柄下载资源.

WinINet 提供了两种方法来下载整个资源

寻找文件

先使用 FtpFindFirstFile, GopherFindFirstFile, 或 InternetOpenUrl ,然后将其返回的句柄作为参数 传递给 InternetFindNextFile 进行继续查找,持续调用 InternetFindNextFile 知道返回扩展的错误信息 ERROR_NO_MORE_FILES 来完成整个搜索,调用 GetLastError 来获取最后的错误信息.

6.HTTP 会话



使用 WinINet 函数访问WWW资源

(1)初始化 WWW 连接

将服务类型设为 INTERNET_SERVICE_HTTP 调用 InternetConnect 来建立一个 HTTP 会话

HINTERNET InternetConnect(
__in HINTERNET hInternet, //InternetOpen 返回的句柄
__in LPCTSTR lpszServerName, //可以描述目标服务器的字符串
__in INTERNET_PORT nServerPort,//目标服务器的端口
__in LPCTSTR lpszUsername,//用户名
__in LPCTSTR lpszPassword,//密码
__in DWORD dwService,//使用的服务类型
__in DWORD dwFlags,
__in DWORD_PTR dwContext
);
nServerPort
Value Meaning

INTERNET_DEFAULT_FTP_PORT

Uses the default port for FTP servers (port 21).

INTERNET_DEFAULT_GOPHER_PORT

Uses the default port for Gopher servers (port 70).

INTERNET_DEFAULT_HTTP_PORT

Uses the default port for HTTP servers (port 80).

INTERNET_DEFAULT_HTTPS_PORT

Uses the default port for Secure Hypertext Transfer Protocol (HTTPS) servers (port 443).

INTERNET_DEFAULT_SOCKS_PORT

Uses the default port for SOCKS firewall servers (port 1080).

INTERNET_INVALID_PORT_NUMBER

Uses the default port for the service specified by dwService.

ldwService
Value Meaning

INTERNET_SERVICE_FTP

FTP service.

INTERNET_SERVICE_GOPHER

Gopher service.

INTERNET_SERVICE_HTTP

HTTP service.

(2)建立请求

调用 HttpOpenRequest 来建立一个 HTTP 请求,不过这个函数不会自动把请求发送出去,要发送请求需要调用 HttpSendRequest

HttpOpenRequest 原型


HINTERNET HttpOpenRequest(
__in HINTERNET hConnect, // InternetConnect 函数返回的句柄
__in LPCTSTR lpszVerb, // 动作,有GET, PUT, POST。也可以设置为 NULL ,会被当成默认的 GET 来用
__in LPCTSTR lpszObjectName, // 一个描述你请求资源的字符串,当请求一个默认页面时令这个参数指向一个空串
__in LPCTSTR lpszVersion, // HTTP 版本,这个参数为 NULL 时,默认使用""HTTP/1.1""
__in LPCTSTR lpszReferer, // 说明了lpszObjectName是取自哪个文件,可以设为NULL
__in LPCTSTR *lplpszAcceptTypes, //
是一个指向LPCTSTR数组的指针!数组以一个NULL指针结束。指定了程序接受的内容的类型,设为空则不接受 任何类型的内容,设为空串则等价于""text/*"",即不接受文本文件以外的图片等文件,只接受某种特定的文件可以用类似"image/gif, image/jpeg"的方式。关于更多内容类型 请看这里
__in DWORD dwFlags, // 一般都可以设置为 0
__in DWORD_PTR dwContext // 一般都可以设置为 0
);

(3)添加请求

HttpAddRequestHeaders 原型

BOOL HttpAddRequestHeaders(
   __in HINTERNET hConnect,//HttpOpenRequest 返回的句柄
   __in LPCTSTR lpszHeaders,//包含要添加到请求中的头的字符串的指针,每个头都要以一个 CR/LF ( "r"n"r"n ) 对结束
   __in DWORD dwHeadersLength,//lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度
   __in DWORD dwModifiers
);
dwModifiers

可以是下面这些值的组合

Value Meaning

HTTP_ADDREQ_FLAG_ADD

Adds the header if it does not exist. Used with HTTP_ADDREQ_FLAG_REPLACE.

HTTP_ADDREQ_FLAG_ADD_IF_NEW

Adds the header only if it does not already exist; otherwise, an error is returned.

HTTP_ADDREQ_FLAG_COALESCE

Coalesces headers of the same name.

HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA

Coalesces headers of the same name. For example, adding "Accept: text/*" followed by "Accept: audio/*" with this flag results in the formation of the single header "Accept: text/*, audio/*". This causes the first header found to be coalesced. It is up to the calling application to ensure a cohesive scheme with respect to coalesced/separate headers.

HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON

Coalesces headers of the same name using a semicolon.

HTTP_ADDREQ_FLAG_REPLACE

Replaces or removes a header. If the header value is empty and the header is found, it is removed. If not empty, the header value is replaced.

(4)发送一个请求

HttpSendRequest

BOOL HttpSendRequest(
__in HINTERNET hRequest, //HttpOpenRequst 返回的句柄
__in LPCTSTR lpszHeaders, //附加到请求上的头,可以为NULL
__in DWORD dwHeadersLength, //lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,当调用的是HttpSendRequestA时则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度。当调用的是 HttpSendRequestW时就会产生一个错误
__in LPVOID lpOptional, //当使用POST或PUT方法时,这个参数指向的数据会紧接着请求被发送出去。没有需要发送的数据则可以设置为NULL
__in DWORD dwOptionalLength //lpOptional数据的字节长度,无数据时设置为0
);

(5)向服务器发送数据

方法一:参见上面HttpSentRequest的lpOptional参数的说明

方法二:使用 InternetWriteFile 向一个句柄里发送数据,然后使用 HttpSendRequestEx 发送

(6)查询一个请求的信息

HttpQueryInfo

BOOL HttpQueryInfo(
__in      HINTERNET hRequest, /*由 HttpOpenRequest 或 InternetOpenUrl 返回的句柄*/
__in      DWORD dwInfoLevel,/*
Query Info Flags.*/
   __inout LPVOID lpvBuffer, /*用于存储查询结果的缓冲区,不可为NULL*/
__inout LPDWORD lpdwBufferLength,/*lpvBuffer指向的缓冲区的字节长度
         若函数执行成功,这个变量存储的是写到缓冲区里的数据长度。如果数据是字符串则返回的长度不包括字符串的结束字符
         如果函数发生 ERROR_INSUFFICIENT_BUFFER 错误, 则这个变量里保存的是数据的实际字节长度程序需要根据这个长度重新分配内存,再执行一次这个函数*/
__inout LPDWORD lpdwIndex /*没看大明白,不过似乎可以设置为NULL
        Pointer to a zero-based header index used to enumerate multiple headers with the same name.
        When calling the function, this parameter is the index of the specified header to return.
        When the function returns, this parameter is the index of the next header.
        If the next index cannot be found, ERROR_HTTP_HEADER_NOT_FOUND is returned.*/
);

(7) WWW 上下载资源

在调用 HttpOpenRequestHttpSendRequest 之后, 程序可以使用 InternetReadFile, InternetQueryDataAvailable, InternetSetFilePointer 来下载HTTP服务器上的资源了。

BOOL InternetQueryDataAvailable(//查询数据的长度
__in HINTERNET hFile, //由 InternetOpenUrl, FtpOpenFile, GopherOpenFile, 或 HttpOpenRequest
返回的句柄
__out LPDWORD lpdwNumberOfBytesAvailable, //用于存放数据长度的指针
__in DWORD dwFlags, //保留参数,置0
__in DWORD_PTR dwContext //保留参数,置0
);
BOOL InternetReadFile( //读取句柄的数据
__in    HINTERNET hFile, // InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest 创建的句柄
__out LPVOID lpBuffer, // 存放数据的缓冲区
__in    DWORD dwNumberOfBytesToRead, // 准备读取的字节数
__out LPDWORD lpdwNumberOfBytesRead // 读取了的字节数
);

DWORD InternetSetFilePointer( //设置InternetReadFile的文件位置(莫非多线程下载就是用这个实现的?),服务器不支持随机访问的话函数调用会失败,如果 InternetReadFile已经读取到了文件的末尾,这个函数的调用也会失败。
__in HINTERNET hFile, //由 InternetOpenUrl (on an HTTP or HTTPS URL)创建。 或由HttpOpenRequest 创建(使用 GET 或 HEAD方法,而且句柄已经被 HttpSendRequest 访问过了).
这个句柄也不可以使用 INTERNET_FLAG_DONT_CACHE 或 INTERNET_FLAG_NO_CACHE_WRITE 标志
__in LONG lDistanceToMove, //移动的字节数。正数向后移动,负数向前移动
__in PVOID pReserved, //保留参数,为NULL
__in DWORD dwMoveMethod, //指定了移动指针时的参考点。FILE_BEGIN(使用这个标志时,移动的字节数被当作无符号数处理)、FILE_CURRENT、FILE_END(如果内容的长度无法获得,则使用这个标志时会失败)
__in DWORD_PTR dwContext //保留参数,为NULL
);
posted @ 2010-07-21 12:57 Eric_jiang 阅读(3621) | 评论 (1)编辑 收藏

仅列出标题
共57页: First 上一页 46 47 48 49 50 51 52 53 54 下一页 Last